课程名称:web前端架构师
课程章节:第11周 第三章
主讲老师:张轩
课程内容:掌握测试基本工具,给组件库添加单元测试
课程收获和心得
课程中使用了 webpack + jest + vue-test-utils 为组件添加测试,由于 vite 的打包速度比webpack快了几十倍,所以我根据我在这里使用了vitest代替 jest,vite 代替webpack。会使用 jest 基本上可以直接使用 vitest
环境准备
安装依赖
pnpm i vitest vue-test-utils jsdom @vitest/coverage-c8 -D
在 package.json 文件中增加启动命令
"scripts": {
"test": "vitest",
"test:run": "vitest run --coverage"
}
要测试 vue组件,需要在 vite.config.ts 文件中配置 vitest。如下面所示,environment 用来设置环境,默认时node 环境,web 浏览器环境可以使用 jsdom 或 happy-dom(https://cn.vitest.dev/config/#environment); coverage.provider 用来设置覆盖工具(https://cn.vitest.dev/guide/coverage.htm)
+ /// <reference types="vitest" />
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import eslintPlugin from 'vite-plugin-eslint'
import path from 'path'
export default defineConfig({
resolve: {
alias: {
'@': path.join(__dirname, 'src')
}
},
plugins: [
vue(),
eslintPlugin()
],
+ test: {
+ environment: 'jsdom',
+ coverage: {
+ provider: 'c8'
+ }
}
})
测试渲染和元素获取
<script setup lang="ts">
defineProps<{msg: string}>()
</script>
<template>
<h1>{{ msg }}</h1>
</template>
测试代码
describe('HelloWorld.vue', () => {
const msg = 'Vue + Ts + Vitest'
const wrapper = shallowMount(HelloWorld, {
props: {
msg
}
})
it('render props message when passed', () => {
expect(wrapper.get('h1').text()).toBe('Vue + Ts + Vitest')
})
}
wrapper.get 和 wrapper.find 都可以用来获取元素。使用 get 时没有找到匹配元素时就会中断报错
测试代码
import { shallowMount } from '@vue/test-utils'
describe('HelloWorld.vue', () => {
const msg = 'Vue + Ts + Vitest'
// 也可以使用 mount
const wrapper = shallowMount(HelloWorld, {
props: {
msg
}
})
it('render props message when passed', () => {
expect(wrapper.get('h1').text()).toBe('Vue + Ts + Vitest')
})
}
查找组件,可以使用wrapper.findComponent 或 wrapper.getComponent
import HelloWorld from '@/components/HelloWorld.vue'
describe('App.vue', () => {
it('mount HelloWorld', () => {
expect(wrapper.getComponent(HelloWorld))
})
}
触发事件
使用 trigger 用来触发事件
it('test click', async () => {
await wrapper.get('button').trigger('click')
console.log(wrapper.get('.card').text())
expect(wrapper.get('.card').text()).toBe('count is 1')
})
更新表单
可以使用 setValue 设置输入值
it('test input', async () => {
const textInput = wrapper.find('input[type="text"]')
const inputVal = 'todos'
await textInput.setValue(inputVal)
expect(textInput.element.value).toBe(inputVal)
}
验证事件是否发送
wrapper.emmit
it('test emmit', async () => {
...
// 当按下 enter 键时,向父组件发送事件 commit
await textInput.trigger('keyup.enter')
expect(wrapper.emitted()).toHaveProperty('commit')
const events = wrapper.emitted('commit')
expect(events[0]).toEqual([inputVal])
})
测试异步请求
模板代码
<script setup lang="ts">
import axios from 'axios'
import { ref } from 'vue'
interface User{
id: number
name: string
email: string
phone: string
}
const user = ref<User | null>(null)
const loadError = ref(false)
const loading = ref(false)
function loadData () {
loading.value = true
loadError.value = false
axios.get<User>('https://jsonplaceholder.typicode.com/users/1').then(res => {
user.value = res.data
}).catch(e => {
loadError.value = true
}).finally(() => {
loading.value = false
})
}
loadData()
</script>
<template>
<div
v-if="loading"
class="loading"
>
加载中
</div>
<div v-else>
<div class="username">
姓名:{{ user.name }}
</div>
<div class="phone">
电话:{{ user?.phone }}
</div>
<div class="email">
邮箱:{{ user?.email }}
</div>
</div>
<div
v-if="loadError"
class="err"
>
加载出错
</div>
<button
@click="loadData"
>
重新加载
</button>
</template>
测试代码
vi.mock('axios')
describe('Async App.vue', () => {
it.only('test async request', async () => {
axios.get.mockResolvedValue({ data: { id: 2, name: 'shibin', email: 'shibin.xx@xx.com', phone: '11111111111' } })
const wrapper = shallowMount(App)
expect(axios.get).toHaveBeenCalled()
expect(axios.get).toHaveBeenCalledWith('https://jsonplaceholder.typicode.com/users/1')
expect(wrapper.find('.loading').exists()).toBeTruthy()
// 所有异步数据加载完毕
await flushPromises()
expect(wrapper.find('.loading').exists()).toBeFalsy()
expect(wrapper.find('.err').exists()).toBeFalsy()
expect(wrapper.get('.username').text()).toBe('姓名:shibin')
expect(wrapper.get('.phone').text()).toBe('电话:11111111111')
expect(wrapper.get('.email').text()).toBe('邮箱:shibin.xx@xx.com')
})
})
写测试代码没有什么难度,多看看文档就可以了
相关文档链接
- vue-test-utils https://test-utils.vuejs.org
- jest https://jestjs.io
- vitest https://vitest.dev/