Jest 测试 Vue 组件
在前端项目开发过程中,有很多时候也会要进行测试工作。本文将重点介绍如何利用 JavaScript 测试框架 Jest 进行高效的测试。Jest 是由 FaceBook 开发的顶级测试框架之一,广受开发者们的欢迎和信赖。在接下来的内容中,我们将通过简明扼要的解释和代码示例,向大家展示如何使用 Jest 这个强大的测试工具。无论你是初学者还是有经验的开发者,都能从下面的内容中获得深入的理解和实践的启发。
目录
- Jest 测试 Vue 组件
- 1 Vue项目导入Jest
- 2 Jest 测试 Vue组件
- 3 Jest 中测试 Vue 应用组件
- 4 Jest 中 describe 函数
- 5 Jest 测试 Vue 中的元素
- 6 Jest事件测试
- 7 Jest 测试emit 事件
第一章 Vue3项目创建 1 Vue CLI 创建vue项目
第一章 Vue3项目创建 2 使用 Webpack 5 搭建 vue项目
第一章 Vue3项目创建 3 Vite 创建 vue项目
第二章 Vue3 基础语法指令
第三章 Vue Router路由器的使用
第四章 VUE常用 UI 库 1 ( element-plus,Ant ,naiveui,ArcoDesign)
第四章 VUE常用 UI 库 2 ( ailwind 后台框架)
第五章 Vue 组件应用 1( Props )
第五章 Vue 组件应用 2 ( Emit )
第五章 Vue 组件应用 3( Slots )
第五章 Vue 组件应用 4 ( provide 和 inject )
第五章 Vue 组件应用 5 (Vue 插件)
第六章 Pinia,Vuex与axios,VueUse 1(Pinia)
第六章 Pinia,Vuex与axios,VueUse 2(Vuex)
第六章 Pinia,Vuex与axios,VueUse 3(VueUse)
第六章 Pinia,Vuex与axios,VueUse 4(axios)
第七章 TypeScript 上
第七章 TypeScript 中
第七章 TypeScript 下 创建Trello 任务管理器
第八章 ESLint 与 测试 ( ESLint )
第八章 ESLint 与 测试 ( Jest )
第八章 ESLint 与 测试 (TypeScript 中Jest与检测环境集成)
1 Vue项目导入Jest
在开发过程中,我们常常面临这样的困扰:为已经运行良好的应用程序添加新功能,却担心新加入的代码可能会对原有功能产生破坏。虽然测试不能完全消除这种焦虑,但它能有效地降低我们的担忧。
通过编写可测试的代码并进行测试,我们可以把代码切分成独立的组件。大部分难以测试的代码往往功能复杂或者各部分相互交织,难以将其作为独立的组件进行隔离。但如果我们能将代码切割成一个个独立、可测试的组件,那么代码复用的可能性就会大大增加,重构和调试也会变得更加容易。而且,通过检查测试结果,我们可以更好地了解被测试组件的行为,从而利用这些信息来编写设计文档。
然而,有些人可能不清楚如何对 Vue.js 进行测试。本文主要介绍的是对 Vue.js 组件进行单元测试,确保每个组件都能按照预期正确运行。具体来说,我们会检查组件是否能正确处理 props,比如传递的 props 是否能按预期显示在浏览器上。同时,我们还会测试事件处理,例如点击事件是否能在浏览器上产生预期的效果。
1 创建测试环境
https://jestjs.io/zh-Hans/docs/getting-started
导入@vue/test-utils与jest需要的组件。
npm init vite@latest vue-jest
npm install --save-dev @vue/test-utils
npm install --save-dev jest
npm install --save-dev @vue/vue3-jest
npm install --save-dev babel-jest
npm install --save-dev @babel/core
npm install --save-dev @babel/preset-env
npm install --save-dev @vue/babel-preset-app or @vue/cli-plugin-babel
npm install --save-dev jest-environment-jsdom
package.json 文件中
```
"scripts": {
"test": "jest"
}
```
最后,运行测试:
```
npm run test
Vue测试功能需要使用的以下几种基础组件
1 @vue/test-utils Vue.js 的官方测试实用程序库,用于vue脚本测试。官网地址https://test-utils.vuejs.org/
2 jest 是现在主流的JavaScript 测试框架。 https://jestjs.io
3 vue/vue3-jest Vue 单文件组件的 Jest 转换器。是一个基于jest的Vue.js测试框架,它可以帮助开发者简化Vue单元测试的操作,它提供了一系列的Vue特定的模拟器和matchers,可以帮助开发者更加容易地测试Vue组件,并且可以更好地支持Vue3的特性。
2 创建第一个测试程序
安装完成后,test.spec.js
文件会自动保存在 tests/unit
文件夹中。这意味着您可以立即进行测试,无需等待安装完成。虽然在本文档中,我们不会使用默认编写的 test.spec.js
文件中的代码,但为了逐步加深对测试的理解,我们将首先使用 test.spec.js
进行测试。
Jest 会自动检测和测试以 .spec.js
或 .test.js
结尾的文件。这两种文件都是 Jest 的测试文件,用于编写测试用例。
-
.spec.js
-
.test.js
test('2+2=4', () => {
expect(2 + 2).toBe(4);
});
在编写测试用例时,我们通常会在测试函数的第一个参数中描述测试的目标。这样做可以帮助我们更好地理解测试的内容,即使在未来回顾这些测试时也是如此。测试实际上将在第二个参数的函数中进行。
在测试过程中,我们需要进行断言以确保代码的行为符合预期。断言通过使用 expect
函数并为其参数指定一个值来进行。例如,如果我们想要测试 2+2 的结果是否为 4,我们就可以在 toBe
函数中指定值 4,并将其与 expect
函数中的加法运算结果进行比较。
toBe
函数是 Jest 提供的匹配器函数之一,它用于检查 expect
函数中指定的值是否与 toBe
函数中指定的值相匹配。在大多数常规测试中,我们会使用 expect
和 toBe
来验证两个值是否一致。
如果你想了解 Jest 中其他匹配器的使用方法,可以访问 Jest 的官方文档:https://jestjs.io/zh-Hans/docs/using-matchers
npm run test
> vue-jest@0.0.0 test
> jest
PASS src/test.spec.js
√ 2+2=4 (7 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.973 s
Ran all test suites.
Jest中还存在各种其他匹配器功能。稍后我们可以更改条件以将 expect 的值与 matchers 函数相匹配,使用 matchers 函数而不是 toBe 函数来进行对比。
它是使用 test 函数编写的,但我们也可以使用 it 函数代替 test 函数。使用哪一个都没有关系。
it('2+2=4', () => {
expect(2 + 2).toBe(4);
});
更新 test.spec.js 文件后,可以通过在命令行上运行 npm run test:unit 来运行测试。
查看npm run test:unit的执行消息,可以看到消息中对测试函数第一个参数二加二等于四的测试内容的描述。如果显示PASS,则表示本次测试成功。
如果在更改后执行 npm run test:unit ,则可以检查执行消息为 FAIL 而不是 PASS。您还可以从执行消息中看到,预期为 4 (Expected: 4) 的值包含 3 (Received: 3)。它还会提示测试的哪一部分有错误,而不仅仅是测试的通过或失败。
it('2+2=4', () => {
expect(2 + 2).toBe(5);
});
npm run test
> vue_typescript_lint@0.0.0 test
> jest
FAIL src/tests/test.spec.js
× 2+2=4 (7 ms)
● 2+2=4
expect(received).toBe(expected) // Object.is equality
Expected: 5
Received: 4
1 |
2 | it('2+2=4', () => {
> 3 | expect(2 + 2).toBe(5);
| ^
4 | });
at Object.toBe (src/tests/test.spec.js:3:19)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.102 s
Ran all test suites.
2 Jest 测试 Vue组件
通过前面的学习,我们已经掌握了如何在项目中安装和使用 Jest。但是,我们的目标是测试 Vue.js 组件,这才是我们使用 Jest 的初衷。因此,接下来我们将利用 test.spec.js
文件来编写测试代码。
为了完成 Vue 组件的测试,我们需要引入 Vue Test Utils 组件库中的 mount
测试函数。Vue Test Utils 是 Vue 官方提供的一套测试工具库,其中包含了所有用于测试 Vue.js 所需的函数。
通过使用 Vue Test Utils,我们可以更高效、更深入地测试 Vue.js 组件的行为和状态,从而确保它们能够按照我们的预期正确运行。
import { mount } from '@vue/test-utils';
test('2+2=4', () => {
expect(2 + 2).toBe(4);
});
运行npm run test 命令,这个时候并没有出现测试成功的提示,而是出现了下面的解析错误提示。
这是因为 Jest 在 Node.js 环境中运行测试,默认不支持使用 import
语句。相反,它建议使用 require
语句来导入模块。为了解决这个问题,我们可以使用像 Babel 这样的工具来转译我们的 JavaScript 代码,将其中的 import
语句转换为 Node.js 可以理解的 require()
语句。这样,我们就可以在 Jest 测试代码中使用 import
语句了。
为了实现这个转换,我们需要引入 babel-jest
这个包,并将其配置为 Jest 的转译器。babel-jest
会将测试代码中的 import
语句转换成 Node.js 可以执行的代码。这样,我们就可以在测试中使用 import
语句来导入需要的模块了。
Babel官网地址 https://babeljs.io/
- 安装
babel-jest
包 是一个用于在 Vue 3 中使用 Babel 的 Jest 测试框架。它可以帮助开发人员在 Vue 3 中使用 Babel 来编写测试代码,并且可以使用 Babel 来将测试代码转换为 JavaScript 代码。
- 安装
@babel/preset-env
Babel解析编辑工具插件。
npm install --save-dev babel-jest
npm install --save-dev @babel/core
npm install --save-dev @babel/preset-env
在项目根目录中创建**.babelrc**文件,在文件中配置@babel/preset-env
插件到测试环境中。
// .babelrc
{
"presets" : [ "@babel/preset-env" ]
}
我们在执行测试命令,可以看到我们测试通过,证明babel-jest
组件将import
语句转录成功。
npm run test
> vue-jest@0.0.0 test
> jest
PASS src/test.spec.js
√ 2+2=4 (4 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.168 s
Ran all test suites.
上面我们导入Vue Test Utils中的测试函数mount成功,现在我们要使用mount函数来测试一下正式的vue模板是否能正常运行。我们在test.spec.js 文件中加入以Vue模板字符串,在使用mount函数验证这个Vue模板字符是否是一个标准的Vue组件。
import { mount } from '@vue/test-utils';
const App = {
template:`<div>欢迎使用vue/jest</div> `
}
test("测试 Vue3 Component",function(){
const wrapper = mount(App);
console.log(wrapper.text())
})
运行npm run test 后会看到编辑器又出现了错误提示。
这个错误的原因是mount函数无法理解Vue组件中的template模板的 HTML 代码,解决这个错误关键是要样Jest能够理解Vue模板中的语法 。
上述错误背后的原因是,jest 无法理解和处理 .vue 文件!
在前面,我们已经导入了 @vue/vue3-jest
组件,现在是时候使用它了。我们需要在 Jest 测试框架中添加这个组件,并使用 @vue/vue3-jest
组件中的 .vue
文件转换器来解析 Vue 模板,以便 Jest 程序能够理解 .vue
文件中的代码。
为了实现这个目标,我们需要在 jest.config.js
文件中添加对 @vue/vue3-jest
组件的解析配置。通过配置 Jest 的转换器,我们可以让 Jest 理解和处理 .vue
文件中的代码。
// jest.config.js
module.exports = {
transform: {
"^.+\\.jsx?$": "babel-jest",
'^.+\\.vue$' : '@vue/vue3-jest' ,
},
};
配置完成后,我们再次运行测试 npm run test 还是又新的错误出现。
这个错误信息是因为当前执行的代码上下文中未定义 document
对象。在 Web 浏览器中,通常会提供这个 DOM 对象树,但是在 Node.js 环境中运行的 Jest 测试程序中是没有这个 DOM 对象的。因此,我们需要在 Node.js 环境中模拟一个 DOM 对象,以便在 Jest 程序中进行测试使用。
为了解决这个问题,我们可以使用 jsdom
这个库来模拟一个 DOM 环境。jsdom
可以在 Node.js 环境中创建一个虚拟的 DOM 对象树,使得我们可以在 Jest 测试中使用类似于浏览器环境的 API,比如 document
对象。
下面我们通过安装 jsdom
包,并在 Jest 的配置文件中进行相应的配置,来实现在 Jest 中使用模拟的 DOM 环境进行测试。
jest-environment-jsdom 包是一个 Jest 测试环境,它使用 jsdom 模拟浏览器环境,使Jest 测试代码在运行时,可以引用到浏览器的 API 和 DOM 对象。
npm install --save-dev jest-environment-jsdom
安装完jest-environment-jsdom 包,后在jest.config.js文件中配置 jsdom 模拟浏览器到node运行环境中来。配置文件中testEnvironment属性设置jsdom在,表示jest以 js 语法进行测试。
module.exports = {
testEnvironment: 'jsdom',
testEnvironmentOptions: {
customExportConditions: ["node", "node-addons"],
},
transform: {
"^.+\\.jsx?$": "babel-jest",
'^.+\\.vue$' : '@vue/vue3-jest' ,
},
};
配置成功后运行测试指令,这回终于看到vue组件模板测试通过。
npm run test
> vue-jest@0.0.0 test
> test
> jest
console.log
欢迎使用vue/jest
at Object.log (src/test.spec.js:7:11)
PASS src/test.spec.js
√ 测试 Vue3 Component (78 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.796 s
Ran all test suites.
package.json文件中记录了vue使用jest测试所需要的组件。
"devDependencies": {
"@babel/preset-env": "^7.20.2",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/test-utils": "^2.2.9",
"@vue/vue3-jest": "^29.2.2",
"babel-jest": "^29.4.1",
"jest": "^29.4.1",
"jest-environment-jsdom": "^29.4.1",
"vite": "^4.0.0"
}
vue组件导入测试
接下来,让我们使用vue文件组件而不是vue模板字符串进行测试。在src文件夹下中的App.vue文件里写入以下代码。
<script setup>
</script>
<div>欢迎使用vue/jest</div>
<style scoped>
</style>
在 test.spec.js 文件中,导入 App.vue组件使用mount函数装入App.vue组件的对象。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
test("测试 Vue3 Component",function(){
const wrapper = mount(app);
console.log(wrapper.text())
})
运行jest测试命令,看到运行测试成功并且测试通过。
npm run test
> vue-jest@0.0.0 test
> jest
console.log
欢迎使用vue/jest
at Object.log (src/test.spec.js:6:11)
PASS src/test.spec.js
√ 测试 Vue3 Component (58 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.263 s
Ran all test suites.
到目前为止,大家已经能够理解如何使用Jest测试文件进行测试了。对于第一次使用Jest测试Vue.js组件的人来说,应该能轻松掌握了Jest与Vue测试环境的搭建了,也知道如何测试Vue组件的单元测试。在实际的开发过程中会发现不同Vue版本中测试环境的搭建是有所不同的,大家要根据以后组件的升级自己就调整他们对应的组件兼容性。
3 Jest 中测试 Vue 应用组件
vue组件中不仅有模板标签中的 HTML,还会有各种元素属性,props、emit,slort,provide 和 inject ,数据与计算属性,反应函数等等内容,他们都可以成为我们测试的对象。
1 props 传递值测试
我们将进行一个示例来演示如何在测试代码中将 props 传递给 App 组件,并且让大家更好地理解 App 组件如何根据传入的 props 值生成相应的 HTML 字符串。我们需要修改 App.vue 中的代码。在脚本部分,我们可以设置一个名为 name 的属性,并将其类型设置为字符串(String),并传入我们想要测试的 props 值。
<script setup>
const props =defineProps({
name: {
type: String,
}
});
</script>
<template>
<div>欢迎你 {{name}}</div>
</template>
<style>
</style>
单元测试是用来测试每个组件的,因此需要在测试中传递 props,而不是从其他组件传递 props。
在 Vue Test Utils 文档中,对 mount 函数有详细的描述。您可以在第二个参数中,将除了 props 之外的内容作为挂载选项传递给组件。下面是一个示例,使用 mount 函数的第二个参数来传递字符串 ‘World’ 给 props 的 msg 属性.
- props() 方法查询测试test对象中设置的 props 值。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
test("测试 Vue3 Component",function(){
const test = mount(app,{
props:{
name: "韬哥"
}
});
console.log(test.props());
expect(test.text()).toBe('欢迎你 韬哥')
})
当运行测试时,World 字符串在 props 中传递,所以 App 组件的内容将是 Hello World。所以你可以通过考试。
npm run test
> vue-jest@0.0.0 test
> jest
console.log
{ name: '韬哥' }
at Object.log (src/test.spec.js:10:11)
PASS src/test.spec.js
√ 测试 Vue3 Component (74 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.331 s
Ran all test suites.
2 数据对象值测试
在Vue组件中设置数据对象内容,我们可以在测试文件中tset.vm 属性获得到vue组件中设置的数据对象内容。在通过 expect().toBe() 方法进行测试。
- Vue组件中的数据对象 使用 .vm获得
在 App.vue组件中设置一个dpetname 数据属性。
<script setup>
const props =defineProps({
name: {
type: String,
}
});
let dpetname="部门一";
</script>
<template>
<div>欢迎你 {{name}}</div>
</template>
<style>
</style>
测试文件内容
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
test("测试 Vue3 Component",function(){
const test = mount(app,{
props:{
name: "韬哥"
}
});
expect(test.text()).toMatch('欢迎你');
expect(test.vm.dpetname).toMatch('部门一');
})
运行测试内容
npm run test
> vue-jest@0.0.0 test
> jest
console.log
{ name: '韬哥' }
at Object.log (src/test.spec.js:10:11)
console.log
部门一
at Object.log (src/test.spec.js:11:11)
PASS src/test.spec.js
√ 测试 Vue3 Component (77 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.166 s
Ran all test suites.
3 computed计算属性
我们可以测试计算属性是否按预期工作。例如,您可以测试设置数据属性 name 的值是否由计算属性 upperCaseName 转换为大写。
<script setup>
import {computed} from "vue";
const props =defineProps({
name: {
type: String,
}
});
//计算函数设置name 字符大写
const upperCaseName=computed(() => {
return props.name.toUpperCase()
});
</script>
<template>
<div>欢迎你 {{upperCaseName}}</div>
</template>
<style>
</style>
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
test("测试 Vue3 Component",function(){
const test = mount(app,{
props:{
name: "zht"
}
});
expect(test.text()).toMatch('欢迎你 ZHT');
})
npm run test
> vue-jest@0.0.0 test
> jest
PASS src/test.spec.js
√ 测试 Vue3 Component (26 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.086 s
Ran all test suites.
4 Jest 中 describe 函数
在编写测试代码时,我们可以在测试或 it 函数之外编写 describe 函数,用于组织多个测试函数。这样可以使测试代码更加清晰和易读。如果只有一个测试函数,describe 函数不是必需的,但如果要运行多个测试函数,可以将它们组合在一起。
在 describe 函数中,我们可以设置组件的名称作为第一个参数,用于描述要测试的内容。通过这样的设置,我们可以更好地理解每个测试函数的目的和作用。
举个例子,假设我们要测试一个名为 app 的组件。我们可以使用 describe 函数来描述该组件的测试内容。
在 describe 函数中,我们可以编写多个测试函数,比如一个 test 函数和一个 it 函数。每个测试函数都有自己的描述和测试逻辑。通过这样的组织方式,我们可以更好地管理和执行多个测试函数,并保持代码的简洁性和可读性。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
it("测试 Vue3 Component",function(){
const test = mount(app,{
props:{
name: "zht"
}
});
expect(test.text()).toMatch('欢迎你 ZHT');
})
test("测试 Vue3 Component",function(){
const test = mount(app,{
props:{
name: "zht"
}
});
expect(test.text()).toMatch('欢迎你 ZHT');
})
});
如果任何一个测试用例失败,将显示以下内容。可以看到测试套件失败,因为 2 个测试用例中的 1 个用例失败。
npm run test
> vue-jest@0.0.0 test
> jest
FAIL src/test.spec.js
app
√ 测试 Vue3 Component (26 ms)
× 测试 Vue3 Component (16 ms)
● app › 测试 Vue3 Component
expect(received).toMatch(expected)
Expected substring: "欢迎你 zht"
Received string: "欢迎你 ZHT"
18 | }
19 | });
> 20 | expect(test.text()).toMatch('欢迎你 zht');
| ^
21 | })
22 | });
23 |
at Object.toMatch (src/test.spec.js:20:25)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 passed, 2 total
Snapshots: 0 total
Time: 3.136 s
Ran all test suites.
describe('app', () => {
it("测试 Vue3 Component",function(){
......
expect(test.text()).toMatch('欢迎你 ZHT');
})
test("测试 Vue3 Component",function(){
......
expect(test.text()).toMatch('欢迎你 ZHT');
})
});
当我运行测试时,我看到已经运行了两个测试并且两个测试都通过了。describe 函数也称为 Tes Suites,它也是执行消息中显示的测试单元。这次有两个测试成功了,所以一个Test Suite成功了,就代表两个测试用例Tests成功了。
npm run test
> vue-jest@0.0.0 test
> jest
PASS src/test.spec.js
app
√ 测试 Vue3 Component (25 ms)
√ 测试 Vue3 Component (7 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3 s
Ran all test suites.
describe only 只允行函数
如果只想运行describe中设置的一个测试函数(it function),可以在test后加上only,跳过其他测试函数,只运行指定的测试函数。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
it.only("测试 Vue3 Component",function(){
const test = mount(app,{
props:{
name: "zht"
}
});
expect(test.text()).toMatch('欢迎你 ZHT');
})
test("测试 Vue3 Component",function(){
const test = mount(app,{
props:{
name: "zht"
}
});
expect(test.text()).toMatch('欢迎你 ZHT');
})
});
运行测试命令,可以看到describe函数中只运行了only方法。
npm run test
> vue-jest@0.0.0 test
> jest
PASS src/test.spec.js
app
√ 测试 Vue3 Component (25 ms)
○ skipped 测试 Vue3 Component
Test Suites: 1 passed, 1 total
Tests: 1 skipped, 1 passed, 2 total
Snapshots: 0 total
Time: 2.999 s
Ran all test suites.
5 Jest 测试 Vue 中的元素
我们将了解如何使用 Wrapper 对象的 get、find、exists、isVisible 和 setData 方法来获得和设置Vue组件中的元素属性值,在操作这些属性值进行测试,也可以对Vue模板中的 v-if 条件指令进行测试。
在 App.vue 文件中写入以下代码。在脚本中创建isname属性,在模板中的创建一个a元素,a元素中设置v-if指令将isname与它绑定,isname为true时显示”大家好“,为false时不显示”大家好“。在设置一个id为profile的a元素,我们在下面的测试中将获得这元素的内容。
<script setup>
let isname=true;
</script>
<template>
<nav>
<a id="profile" href="/profile">我是一个a属性</a>
<a v-if="isname" id="isname" href="/isname">大家好</a>
</nav>
</template>
<style>
</style>
在test.spec.js测试文件中我们使用 mount 函数获取 Wapper 对象,在使用 Wrpper 对象的 get 方法获取指定ID元素的 DOMWrapper 对象,最后通过text 方法将DOMWrapper 元素的内容信息打印出来。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
it("测试 app Component",function(){
const wrapper = mount(app);
const profile = wrapper.get('#profile'); //DOMWrapper
console.log(profile.text());
const isname = wrapper.get('#isname'); //DOMWrapper
console.log(isname.text());
})
})
运行npm run test命令,看到控制台打印出来模板中profile与isname元素内容。
npm run test
> vue-jest@0.0.0 test
> jest
console.log
我是一个a属性
at Object.log (src/test.spec.js:8:13)
console.log
大家好
at Object.log (src/test.spec.js:10:13)
PASS src/test.spec.js
app
√ 测试 app Component (189 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.622 s, estimated 9 s
Ran all test suites.
不仅 get 方法可以获得指定ID元素的内容,find 方法也具有相同的功能可以获得元素的内容,两者都返回相同的 DOMWrapper。但是唯一不同的地方时,如果元素不存在get 方法会抛出错误,find方法会返回空值。
get 方法 与 find方法区别
- get 如果元素不存在会抛出错误。
- find 如果元素不存在不会抛出错误。
在App.vue文件代码中将isname设置为false,这样会使 v-if 指令将元素隐藏起来。然后我们在这种情况下进行测试看看会发生什么。
运行测试,get方法出现错误提示测试失败。
npm run test
> vue-jest@0.0.0 test
> jest
console.log
我是一个a属性
at Object.log (src/test.spec.js:8:13)
FAIL src/test.spec.js
app
× 测试 app Component (112 ms)
● app › 测试 app Component
Unable to get #isname within: <nav><a id="profile" href="/profile">我是一个a属性</a>
<!--v-if-->
</nav>
7 | const profile = wrapper.find('#profile'); //DOMWrapper
8 | console.log(profile.text());
> 9 | const isname = wrapper.get('#isname'); //DOMWrapper
| ^
10 | console.log(isname.text());
11 | })
12 | })
at VueWrapper.Object.<anonymous>.BaseWrapper.get (node_modules/@vue/test-utils/dist/vue-test-utils.cjs.js:7212:15)
at Object.get (src/test.spec.js:9:28)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 10.196 s
1 setData方法
setData 方法用于测试中设置vue组件中脚本里的变量属性值。如果在上面的测试代码中你使用 setData重新覆盖了 isname值,运行测试后get方法也会出现错误。
2 exists 方法
exists 方法的返回值只有 true 或 false。所有它需要配合toBe 方法一起使用来进行测试。在测试代码中使用find方法获得元素值,在使用exists对值内容进行判断。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
it("测试 app Component",function(){
const wrapper = mount(app);
const isname = wrapper.find('#isname');
expect(isname.exists()).toBe(false)
})
})
3 v-show
让我们先重新回忆一下 v-show 和 v-if 指令的区别。在v-if中除了可以使用v-else之外,还有一个显示上的区别,v-if中的元素显示是使用javascript脚本控制的。在v-show的情况下,显示或不显示是由style属性的显示值控制的,当显示值为block表示显示,none表示隐藏。另一方面,v-if 只有在元素可见时才添加元素,如果隐藏则元素不存在。所以在v-show的隐藏模式下,测试wrapper对象使用get方法,也可以通过get方法获取元素并且不会报错。因为无论显示还是隐藏,元素本身都是存在于dom树中。
将 App.vue 文件中的 v-if 指令更改为 v-show 指令。
<script setup>
let isname=false;
</script>
<template>
<nav>
<a id="profile" href="/profile">我是一个a属性</a>
<a v-show="isname" id="isname" href="/isname">大家好</a>
</nav>
</template>
<style>
</style>
测试类中使用get方法,运行测试命令,控制台没有出现错误。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
it("测试 app Component",function(){
const wrapper = mount(app);
const isname = wrapper.get('#isname');r
expect(isname.exists()).toBe(true)
})
})
6 Jest事件测试
在Vue.js中,通过在各个地方设置事件来实现与用户的交互。我们将检查如何在事件中设置频繁使用的点击事件时进行测试。
如下更新 App.vue 文件。设置数据属性计数并将初始值设置为 0。给button元素添加点击事件,点击按钮时执行increment方法,将count的值加1。s
<script setup>
import { ref } from 'vue';//从 vue 中引入 ref 函数
const count = ref(0);
const oncount=()=>{
count.value++;
}
</script>
<template>
<p>数据 : {{ count }}</p>
<button @click="oncount"></button>
</template>
<style>
</style>
1 trigger 触发方式
在测试代码中,如果你第一次测试点击事件,可能不知道如何模拟按钮点击。下面是一种方法来模拟点击按钮。
首先,使用 get
方法(或 find
方法)获取按钮元素,并触发 DOM 元素的点击事件,这个里我们使用DOMwrapper函数获取按钮元素并触发事件 。例如:
const wrapper = mount(app);
wrapper.get('button').trigger('click');
接下来,通过检查包含特定文本的组件内容来验证点击后是否正确更新了状态。例如,如果希望验证组件内容包含 “Count is: 1”,可以使用 toContain
函数进行断言。
expect(wrapper.text()).toContain('Count is: 1');
原因是在测试期间,当单击按钮时,DOM 不会立即更新。这就是为什么在使用 setData
方法时,如果没有使用异步函数(如 async/await
),测试将失败。同样,在模拟点击按钮时,也需要使用异步函数。通过在测试函数前添加 async
关键字,并在触发按钮点击后使用 await
关键字,可以解决这个问题。
it('should update count when button is clicked', async () => {
const wrapper = mount(app);
await wrapper.get('button').trigger('click');
expect(wrapper.text()).toContain('Count is: 1');
});
trigger
方法不仅适用于 click
事件,还适用于其他事件,如 submit
和 keyup
。稍后我们将在表单测试中使用 submit
事件。虽然官方文档中描述了使用 nextTick
方法的两种方法,但建议不使用 nextTick
,因为这样代码会更加简洁和清晰。
2 nextTick 更新 DOM
NextTick 是从 vue 导入的,但是由于可以从 wrapper 对象的 vm 属性访问 Vue 实例,因此也可以使用 wrapper.vm 执行 nextTick。在这种情况下, 我们不需要从 vue 导入 nextTick
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
it("测试 app Component", async function(){
const wrapper = mount(app);
wrapper.get('button').trigger('click');
await wrapper.vm.$nextTick()
console.log(wrapper.text());
expect(wrapper.text()).toContain('数据 : 1')
})
})
在编辑器中运行测试指令看到以下结果。
npm run test
> vue-jest@0.0.0 test
> jest
console.log
数据 : 1
at log (src/test.spec.js:9:13)
PASS src/test.spec.js
app
√ 测试 app Component (85 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.183 s
Ran all test suites.
3 beforeEach
在测试代码中,可以使用 beforeEach
函数来初始化每个测试处理。这样,在每个测试运行之前,都会执行 beforeEach
中的代码。这对于在多个测试中共享相同的设置非常有用。
举个例子,假设在 Countup 测试中运行了两个测试函数。这两个测试函数都需要先运行 mount(App)
来创建组件的包装器。如果将 mount(App)
放在每个测试函数内部,代码会重复出现,不够简洁。为了避免重复代码,可以使用 beforeEach
函数,在每个测试运行之前,先运行一次 mount(App)
。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
let wrapper;
beforeEach(() => {
wrapper = mount(app)
})
it("click button count up", async () => {
await wrapper.get('button').trigger('click')
console.log(wrapper.text());
expect(wrapper.text()).toContain('数据 : 1')
})
it("click button count up", async () => {
await wrapper.get('button').trigger('click')
expect(wrapper.text()).toContain('数据 : 1')
})
})
在上面的示例中,我们使用 beforeEach
函数来初始化 wrapper
变量,然后在每个测试函数中使用该变量。这样可以避免重复代码,并确保每个测试都有一个新的包装器。
请注意,在定义 wrapper
变量时使用 let
而不是 const
。如果使用 const
,会导致错误,因为 const
值无法被覆盖。
除了 beforeEach
函数外,还有其他一些类似的函数可用于在测试运行之前或之后执行常见的处理。例如,如果您希望在每个测试之后执行一些常见的处理,可以使用 afterEach(() => {})
。如果您有一些希望在每次测试之前只运行一次的共同操作,可以使用 beforeAll(() => {})
。
7 Jest 测试emit 事件
我刚刚检查了如何测试 props,但与 props 相反,Vue.js 在将数据从子组件传递到父组件时使用 emit 事件。检查 emit 事件是如何测试的
<script setup>
const count = 0;
const oncount=()=>{
this.count += 1;
this.$emit('initCount',this.count)
}
</script>
<template>
<p>数据 : {{ count }}</p>
<button @click="oncount"></button>
</template>
<style>
</style>
当按钮被点击时,click事件执行increment方法,emit方法将事件名称为incrementCount的payload中设置的this.count值传递给父组件。
测试应该获得由 emit 触发的事件 incrementCount。可以通过包装对象的 emitted 方法获取 Emit 事件。将 App 组件的事件名称 incrementCount 指定为发出的参数。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
it("click button count up", async () => {
const wrapper = mount(app);
wrapper.get('button').trigger('click')
console.log(wrapper.emitted('initCount'))
})
})
测试
npm run test
> vue-jest@0.0.0 test
> jest
console.log
[ [ 0 ] ]
at log (src/test.spec.js:8:13)
PASS src/test.spec.js
app
√ click button count up (79 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.031 s
this.count 的值存储在一个数组中,可以使用wrapper.emitted('incrementCount')[0][0]
访问。
您可以使用 toBe 函数来检查从 emit 事件中获取的值。当我运行测试时,它通过了。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
it("click button count up", async () => {
const wrapper = mount(app);
wrapper.get('button').trigger('click')
console.log(wrapper.emitted('initCount'))
expect(wrapper.emitted('initCount')[0][0]).toBe(0)
})
})
测试通过 count 变量测试成功。
npm run test
> vue-jest@0.0.0 test
> jest
console.log
[ [ 0 ] ]
at log (src/test.spec.js:8:13)
PASS src/test.spec.js
app
√ click button count up (96 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.289 s
我们在App组件中emit传入多个值。
<script setup>
import { ref } from 'vue';//从 vue 中引入 ref 函数
const count = ref(0);
const emit = defineEmits();
const oncount=()=>{
emit('initCount',count.value++,'测试字符串');
}
</script>
<template>
<p>数据 : {{ count }}</p>
<button @click="oncount"></button>
</template>
<style>
</style>
在那种情况下,在测试端,您可以像下面这样在数组中获取它。还要检查多次执行点击事件时的数据
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
it("click button count up", async () => {
const wrapper = mount(app);
wrapper.get('button').trigger('click')
wrapper.get('button').trigger('click')
console.log(wrapper.emitted('initCount'))
expect(wrapper.emitted('initCount')[0][0]).toBe(0)
})
})
运行测试我们可以看到我们通过测试组件获得测试结果。
npm run test
> vue-jest@0.0.0 test
> jest
console.log
[ [ 0, '测试字符串' ], [ 1, '测试字符串' ] ]
at log (src/test.spec.js:9:13)
PASS src/test.spec.js
app
√ click button count up (91 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
如下更新 App.vue 文件以查看如何测试输入表单。当您在只有一个输入元素的简单表单中单击“提交”按钮时,submitForm 方法由表单标记中设置的提交事件执行。在 submitForm 方法中,将保存在 input 元素中输入的值的数据属性的名称与 emit 事件提交的事件名称一起传递给父组件。
<script setup>
import { ref } from 'vue';//从 vue 中引入 ref 函数
const name = ref("");
const dept = ref("");
const emit = defineEmits();
const OnForm=()=>{
emit('Onsubmit',{"name":name,"dept":dept});
}
</script>
<template>
<form @submit.prevent="OnForm">
<input type="text" v-model="name" />
<input type="text" v-model="dept" />
<button type="submit">Submit</button>
</form>
</template>
<style>
</style>
** 1 from表单提交验证**
对于提交事件,可以像点击事件一样使用触发方法。这次我们同样使用emit事件,但与上次不同的是,我们为payload指定了一个对象。
通常,输入元素是由用户在浏览器上输入的。我不知道如何在测试代码中将值设置为 input 元素,所以我将首先检查该方法。
使用 setValue 方法将值设置为输入元素。由于这里只有一个input元素,所以在get方法中只指定了input,但是如果有多个input,则需要给input元素设置一个可以识别的属性,比如id。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
it("测试 from",() => {
const wrapper = mount(app);
const input = wrapper.get('input')
input.setValue('zht')
const input1 = wrapper.get('#dept').setValue('部门一')
wrapper.trigger('submit')
console.log(wrapper.emitted('Onsubmit'))
expect(wrapper.emitted('Onsubmit')[0][0]).toEqual({
name:"zht",dept:"部门一"
})
})
})
当我运行测试时,console.log 显示在提交的事件中收到的有效负载。可以看到数组中有对象。使用匹配器函数的 toEqual 函数进行断言。您可以使用 toEqual 函数来检查数组数据是否匹配。当您运行测试时,您可以确认它通过(成功)。这是一个只有输入元素的简单表单,但我能够检查如何测试表单。
npm run test
> vue-jest@0.0.0 test
> jest
console.log
[ [ { name: 'zht', dept: '部门一' } ] ]
at Object.log (src/test.spec.js:11:13)
PASS src/test.spec.js
app
√ 测试 from (101 ms)