介绍
Vitest 是一个原生支持 Vite 的测试框架。非常快速!
Vue Test Utils 是 Vue.js 官方的单元测试实用工具库。
安装相关依赖需要注意,一般默认最新版本是针对 Vue 3 的,对于 Vue 2 需要声明版本:
-
@vue/test-utils 需要安装 1.x 版本,2.x 是针对 Vue 3 的
-
需要安装 @vitejs/plugin-vue2,而不是 Vue 3 的 Vite 插件 @vitejs/plugin-vue
# 安装所需依赖
npm install vite vitest @vue/test-utils@1 @vitejs/plugin-vue2 jsdom --save-dev
我测试的项目是 Vue CLI 3,安装 vite 仅用于测试,与 Vue CLI 3 不冲突。
Vitest 是由 Vite 驱动的下一代测试框架。Vitest 旨在将自己定位为 Vite 项目的首选测试框架,即使对于不使用 Vite 的项目也是一个可靠的替代方案。
Vitest 1.0 需要 Vite >= 5.0.0 和 Node >= 18
- @vue/test-utils@1
Vue Test Utils 是官方的偏底层的组件测试库,它是为用户提供对 Vue 特定 API 的访问而编写的。
另一个选择 @testing-library/vue,不过我更喜欢用 Vue Test Utils。
- @vitejs/plugin-vue2
Vite plugin for Vue 2.7
用于解析 .vue
文件。
- jsdom
Vitest 中的默认测试环境是一个 Node.js 环境。如果要测试 Web 端应用,可以使用 jsdom
或 happy-dom
这种类似浏览器(browser-like)的环境来替代 Node.js。
先安装 jsdom 依赖,然后在配置项中设置 environment: 'jsdom'
。
使用
- 配置文件
vitest.config.js
import vue from '@vitejs/plugin-vue2'
import { defineConfig } from 'vitest/config'
export default defineConfig({
plugins: [vue()],
test: {
environment: 'jsdom' // 默认值: 'node'
}
})
- 运行命令
package.json
"scripts": {
"test": "vitest --config ./vitest.config.js"
},
- 测试 Vue 组件
Comp.vue
<template>
<div>
<input type="text" v-model="bbb" />
<p>{{ aaa }}: {{ bbb }}</p>
</div>
</template>
<script>
export default {
name: 'Comp',
components: {},
props: {
aaa: String
},
data() {
return {
bbb: ''
}
},
watch: {
bbb() {
this.$emit('modify')
}
}
}
</script>
- 执行测试
comp.test.js
一般情况下,执行测试的文件名中必须包含 ".test." 或 ".spec." 。
import { expect, test, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import { nextTick } from 'vue'
import Component from './Comp.vue'
test('test Comp', async () => {
const handleModify = vi.fn()
// 使用 mount 创建一个包含被挂载和渲染的 Vue 组件的 Wrapper,
// 该 Wrapper 对象包含了一个挂载的组件或 vnode,以及测试该组件或 vnode 的方法。
const wrapper = mount(Component, {
propsData: {
aaa: '输入内容'
},
listeners: {
modify: handleModify
}
})
// getComponent: 返回第一个匹配的 Vue 组件的 Wrapper。
// 如果未匹配到给定的选择器时会抛出错误。
const inputWrapper = wrapper.getComponent('input')
// 设置一个文本输入框的值并更新 v-model 绑定的数据。
// 以下三种方式均可行:
// 1: value & trigger
// inputWrapper.element.value = '123'
// trigger 会返回一个 Promise,当这个 Promise 被解决时,会确保组件已经被更新。
// await inputWrapper.trigger('input')
// 2: 使用原生的 dispatchEvent
// inputWrapper.element.value = '123'
// await inputWrapper.element.dispatchEvent(new Event('input'))
// 3: 使用 setValue
// setValue 用于设置一个文本控件或 select 元素的值并更新 v-model 绑定的数据。
await inputWrapper.setValue('123')
// 是接下来这段代码的别名
// inputWrapper.element.value = '123'
// await inputWrapper.trigger('input')
// 任何导致操作 DOM 的改变都应该在断言之前 await nextTick 函数。
// 在更新响应式 property 之后,我们可以直接 await 类似 trigger 或 trigger.vm.$nextTick 方法,等待 Vue 完成 DOM 更新。
// 从 vue 引入 nextTick
await nextTick()
// 或者从 wrapper.vm 拿 $nextTick
// await wrapper.vm.$nextTick()
expect(wrapper.find('p').element.textContent).toEqual('输入内容: 123')
expect(handleModify).toBeCalled()
})