介绍
之前的文章已经做好了安装,然后我们需要配置测试模块。这里就涉及到如何取写配置。如何测试。比如页面是否正常渲染,是否含有对应的模块。按钮点击之后页面的变化,输入文本框内容的变化等等。经过测试发现复杂一点的页面完全不能测,写测试案例的成本比写代码的成本还高,哪怕是智能体帮你写。建议用puppeteer来测,也就是无头浏览器。
教程
基础模版
代码如下:
import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import TestView from './index.vue'
/**
* 测试TestView组件的功能
* 该测试套件包含对组件渲染、交互功能的全面测试
*/
describe('TestView', () => {
/**
* 测试组件是否正确渲染
* 验证页面中关键文本内容是否存在
*/
it('renders correctly', () => {
// 挂载TestView组件
const wrapper = mount(TestView)
// 验证页面包含预期的关键文本
expect(wrapper.text()).toContain('自动化测试专用页面')
expect(wrapper.text()).toContain('测试组件')
expect(wrapper.text()).toContain('表单测试')
})
})
describe创建测试,所有的测试列都在第二个回调参数里写。
it编写测试列,参数1为名称(名称可以随意编写),参数2为回调。
wrapper 挂载组件进来。
wrapper.text() 获取文档内容。
expect(wrapper.text()).toContain('自动化测试专用页面') 判断文档里是否含有这几个字。
运行日志
如下代码则表示 Login Component 表示上面的describe函数的第一个参数。
renders login form correctly则为it里的第一个参数。

FAIL src/views/login.test.js > Login Component > renders login form correctly
FAIL src/views/login.test.js > Login Component > should validate required fields
FAIL src/views/login.test.js > Login Component > should call login function when form is submitted with valid data
FAIL src/views/login.test.js > Login Component > should handle login error correctly
FAIL src/views/login.test.js > Login Component > should set cookies when rememberMe is checked
FAIL src/views/login.test.js > Login Component > should remove cookies when rememberMe is unchecked
验证函数
const wrapper = mount(TestView)
expect(wrapper.text()).toContain('点击次数: 0')
验证页面内容中是否含有此文字内容。
验证函数toContain与toBe的区别
-
toBe匹配器- 用于精确匹配 ,验证两个值是否完全相等(使用
Object.is进行比较) - 适用于基本数据类型的完全匹配,如数字、字符串等
- 要求实际值与期望值完全一致
- 用于精确匹配 ,验证两个值是否完全相等(使用
-
toContain匹配器- 用于包含匹配,验证一个字符串是否包含指定的子字符串
- 适用于检查文本内容中是否包含特定内容
- 只要实际值中包含期望值即可,不要求完全一致
触发按钮点击
const buttons = wrapper.findAll('button')
const clickButton = buttons[0] // "点击测试" button
await clickButton.trigger('click')
expect(wrapper.text()).toContain('点击次数: 1')
等待点击之后,再验证一下页面内容的变化,是否含有改文字内容。
测试文本框输入
const input = wrapper.findAll('input').at(0) // 第一个input是测试输入框
// 设置输入框值并验证更新
await input.setValue('测试输入')
expect(input.element.value).toBe('测试输入')
案例
登录测试文件,真的是太复杂了,各种报错。根本就没法进行,测试代码比我业务代码还多,问题也比业务代码还多。这个用vue组件来测试确实是太鸡肋了。完全是拖后腿。
import { mount } from '@vue/test-utils'
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { nextTick } from 'vue'
import Cookies from 'js-cookie'
import login from './login.vue'
import useUserStore from '@/store/modules/user'
import { setPassword } from '@/utils/password'
// Mock 依赖
vi.mock('@/api/login', () => ({
getCodeImg: vi.fn()
}))
vi.mock('@/utils/jsencrypt', () => ({
encrypt: vi.fn((val) => val),
decrypt: vi.fn((val) => val)
}))
vi.mock('@/utils/password', () => ({
setPassword: vi.fn((val) => val)
}))
vi.mock('@/store/modules/user', () => {
const mockLoginFn = vi.fn()
return {
default: vi.fn(() => ({
login: mockLoginFn,
token: ''
})),
mockLoginFn
}
})
// Mock window.location.reload
const mockReload = vi.fn()
Object.defineProperty(window, 'location', {
configurable: true,
value: { reload: mockReload }
})
describe('Login Component', () => {
let wrapper
const mockPush = vi.fn()
const mockRouter = {
push: mockPush
}
beforeEach(() => {
vi.clearAllMocks()
// 创建组件实例
wrapper = mount(login, {
global: {
mocks: {
$router: mockRouter
},
provide: {
router: mockRouter
},
stubs: {
'svg-icon': {
template: '<span data-test="svg-icon" />'
},
'el-form': {
template: '<form><slot /></form>',
props: ['model', 'rules', 'ref']
},
'el-form-item': {
template: '<div><slot /></div>',
props: ['prop']
},
'el-input': {
template: '<input :value="modelValue" @input="$emit(\'update:modelValue\', $event.target.value)" />',
props: ['modelValue', 'placeholder', 'type', 'size']
},
'el-button': {
template: '<button><slot /></button>',
props: ['loading', 'type', 'size']
},
'el-checkbox': {
template: '<div><input type="checkbox" :checked="modelValue" @change="$emit(\'update:modelValue\', $event.target.checked)" /> <slot /></div>',
props: ['modelValue']
},
'router-link': {
template: '<a><slot /></a>',
props: ['to']
}
}
}
})
})
it('renders login form correctly', () => {
expect(wrapper.find('.login-form').exists()).toBe(true)
expect(wrapper.find('#idgesRa3').exists()).toBe(true)
expect(wrapper.find('#idAlETvN').exists()).toBe(true)
expect(wrapper.find('#id5OXvv3').exists()).toBe(true)
expect(wrapper.find('#idLGUsOP').exists()).toBe(true)
})
it('should validate required fields', async () => {
const button = wrapper.find('#idLGUsOP')
await button.trigger('click')
// 检查 validate 方法是否被调用
expect(wrapper.vm.$refs.loginRef.validate).toHaveBeenCalled()
})
it('should call login function when form is submitted with valid data', async () => {
const userStore = useUserStore()
userStore.login.mockResolvedValueOnce()
const usernameInput = wrapper.find('#idgesRa3')
const passwordInput = wrapper.find('#idAlETvN')
const loginButton = wrapper.find('#idLGUsOP')
await usernameInput.setValue('testuser')
await passwordInput.setValue('testpass')
await loginButton.trigger('click')
await nextTick()
// 检查是否调用了密码加密函数
expect(setPassword).toHaveBeenCalled()
// 检查是否调用了登录函数
expect(userStore.login).toHaveBeenCalled()
})
it('should handle login error correctly', async () => {
const userStore = useUserStore()
userStore.login.mockRejectedValueOnce(new Error('Login failed'))
const usernameInput = wrapper.find('#idgesRa3')
const passwordInput = wrapper.find('#idAlETvN')
const loginButton = wrapper.find('#idLGUsOP')
await usernameInput.setValue('testuser')
await passwordInput.setValue('testpass')
await loginButton.trigger('click')
await nextTick()
// 检查错误处理逻辑
expect(userStore.login).toHaveBeenCalled()
// 检查 validate 方法是否被调用
expect(wrapper.vm.$refs.loginRef.validate).toHaveBeenCalled()
})
it('should set cookies when rememberMe is checked', async () => {
const setSpy = vi.spyOn(Cookies, 'set')
const usernameInput = wrapper.find('#idgesRa3')
const passwordInput = wrapper.find('#idAlETvN')
const rememberCheckbox = wrapper.find('#idwEZhKM input')
const loginButton = wrapper.find('#idLGUsOP')
await usernameInput.setValue('testuser')
await passwordInput.setValue('testpass')
await rememberCheckbox.setChecked(true)
await loginButton.trigger('click')
await nextTick()
expect(setSpy).toHaveBeenCalledWith('username', 'testuser', { expires: 30 })
expect(setSpy).toHaveBeenCalledWith('password', 'testpass', { expires: 30 })
expect(setSpy).toHaveBeenCalledWith('rememberMe', true, { expires: 30 })
})
it('should remove cookies when rememberMe is unchecked', async () => {
const removeSpy = vi.spyOn(Cookies, 'remove')
const rememberCheckbox = wrapper.find('#idwEZhKM input')
await rememberCheckbox.setChecked(false)
const loginButton = wrapper.find('#idLGUsOP')
await loginButton.trigger('click')
await nextTick()
expect(removeSpy).toHaveBeenCalledWith('username')
expect(removeSpy).toHaveBeenCalledWith('password')
expect(removeSpy).toHaveBeenCalledWith('rememberMe')
})
})