Skip to content
该翻译已同步到了 的版本,其对应的 commit hash 是 7c55128
同时该文档仍处于校对中,如有任何疑问或想参与校对工作,请移步这里了解更多。

复用与组合

主要内容:

  • 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
// 模拟 API 请求
jest.spyOn(axios, 'get').mockResolvedValue({ data: { id: 1, name: 'User' } })

test('fetch user on mount', async () => {
  const TestComponent = defineComponent({
    props: {
      // 定义 props,以便使用不同的输入参数测试组合式函数
      userId: {
        type: Number,
        required: true
      }
    },
    setup(props) {
      return {
        // 调用组合式函数并将所有返回值暴露到我们的组件实例中,以便我们可以通过 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' })
})

Provide (提供) / Inject (注入)

Vue 提供了一种通过 provideinject 将 props 传递给所有子组件的方法。测试这种行为的最佳方式是测试整个树 (父组件 + 子组件)。但有时这并不可能,因为树结构过于复杂,或者你只想测试单个组合式函数。

测试 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 的组件

Released under the MIT License.