跳至内容

可重用性与组合

大多数

  • global.mixins.
  • global.directives.

测试可组合函数

在使用组合 API 并创建可组合函数时,您通常只想测试可组合函数本身。让我们从一个简单的例子开始

typescript
export function useCounter() {
  const counter = ref(0)

  function increase() {
    counter.value += 1
  }

  return { counter, increase }
}

在这种情况下,您实际上不需要 @vue/test-utils。以下是相应的测试

typescript
test('increase counter on call', () => {
  const { counter, increase } = useCounter()

  expect(counter.value).toBe(0)

  increase()

  expect(counter.value).toBe(1)
})

对于更复杂的可组合函数,它们使用生命周期钩子(如 onMountedprovide/inject 处理),您可以创建一个简单的测试辅助组件。以下可组合函数在 onMounted 钩子中获取用户数据。

typescript
export function useUser(userId) {
  const user = ref()
  
  function fetchUser(id) {
    axios.get(`users/${id}`)
      .then(response => (user.value = response.data))
  }

  onMounted(() => fetchUser(userId))

  return { user }
}

要测试此可组合函数,您可以在测试中创建一个简单的 TestComponentTestComponent 应该以与真实组件完全相同的方式使用可组合函数。

typescript
// Mock API request
jest.spyOn(axios, 'get').mockResolvedValue({ data: { id: 1, name: 'User' } })

test('fetch user on mount', async () => {
  const TestComponent = defineComponent({
    props: {
      // Define props, to test the composable with different input arguments
      userId: {
        type: Number,
        required: true
      }
    },
    setup (props) {
      return {
        // Call the composable and expose all return values into our
        // component instance so we can access them with wrapper.vm
        ...useUser(props.userId)
      }
    }
  })

  const wrapper = mount(TestComponent, {
    props: {
      userId: 1
    }
  })

  expect(wrapper.vm.user).toBeUndefined()

  await flushPromises()

  expect(wrapper.vm.user).toEqual({ id: 1, name: 'User' })
})

提供/注入

Vue 提供了一种使用 provideinject 将道具传递给所有子组件的方法。测试此行为的最佳方法是测试整个树(父级 + 子级)。但有时这不可行,因为树过于复杂,或者您只想测试单个可组合函数。

测试 provide

假设您要测试以下组件

vue
<template>
  <div>
    <slot />
  </div>
</template>

<script setup>
provide('my-key', 'some-data')
</script>

在这种情况下,您可以渲染一个实际的子组件并测试 provide 的正确使用,或者您可以创建一个简单的测试辅助组件并将其传递到默认插槽中。

typescript
test('provides correct data', () => {
  const TestComponent = defineComponent({
    template: '<span id="provide-test">{{value}}</span>',
    setup () {
      const value = inject('my-key')
      return { value }
    }
  })

  const wrapper = mount(ParentComponent, {
    slots: {
      default: () => h(TestComponent)
    }
  })

  expect(wrapper.find('#provide-test').text()).toBe('some-data')
})

如果您的组件不包含插槽,您可以使用 stub 并用您的测试辅助组件替换子组件

vue
<template>
  <div>
    <SomeChild />
  </div>
</template>

<script setup>
import SomeChild from './SomeChild.vue'

provide('my-key', 'some-data')
</script>

以及测试

typescript
test('provides correct data', () => {
  const TestComponent = defineComponent({
    template: '<span id="provide-test">{{value}}</span>',
    setup () {
      const value = inject('my-key')
      return { value }
    }
  })

  const wrapper = mount(ParentComponent, {
    global: {
      stubs: {
        SomeChild: TestComponent
      }
    }
  })

  expect(wrapper.find('#provide-test').text()).toBe('some-data')
})

测试 inject

当您的组件使用 inject 并且您需要使用 provide 传递数据时,您可以使用 global.provide 选项。

vue
<template>
  <div>
    {{ value }}
  </div>
</template>

<script setup>
const value = inject('my-key')
</script>

单元测试可能看起来像这样

typescript
test('renders correct data', () => {
  const wrapper = mount(MyComponent, {
    global: {
      provide: {
        'my-key': 'some-data'
      }
    }
  })

  expect(wrapper.text()).toBe('some-data')
})

结论

  • 测试简单的可组合函数,无需组件和 @vue/test-utils
  • 创建一个测试辅助组件来测试更复杂的可组合函数
  • 创建一个测试辅助组件来测试您的组件是否使用 provide 提供了正确的数据
  • 使用 global.provide 将数据传递给使用 inject 的组件