关于组件测试

Vue 有官方的组件测试库Vue Test Utils,这是一个比较偏底层的组件测试库,
如果对其不熟悉的话,官方建议是使用Vue Testing Library,
它是对 Vue Test Utils 的抽象

项目添加组件测试

  1. 使用 vite 创建 Vue 应用
1
yarn create vite <project_name> --template vue
  1. 安装依赖

testing library 目前只针对 Vue2 进行了适配,如果需要在 Vue3 中使用,需要安装 6.x.x 版本

在使用 testing library 处理组件,它会返回一些选择器,让你根据不同的方式获取组件中的 DOM 元素,
所以在用 testing library 测试的时候,可能会需要确认某个 DOM 是否被正确的渲染出来,但 jest 本身
并没有提供这些断言的方法,所以才需要jest-dom来扩充对 DOM 的断言方式

1
yarn add jest @testing-library/vue@next babel-jest @babel/core @babel/preset-env -D
  1. babel 配置
1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current'
}
}
]
]
};
  1. jest 配置

transform 配置中添加了针对不同文件的转换规则,如果需要测试的文件
不是 Vue3 和 js 则需要安装对应的插件并修改 transform 配置,例如如果使用
Vue2 的话可以安装@vue/vue2-jest,使用 ts 话则可以安装 ts-jest

1
2
3
4
5
6
7
8
9
10
module.exports = {
testEnvironment: 'jsdom',
transform: {
'^.+\\.vue$': '@vue/vue3-jest',
'^.+\\js$': 'babel-jest'
},
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.js$',
moduleFileExtensions: ['vue', 'js'],
transformIgnorePatterns: ['/node_modules/(?!testing-library)']
};
  1. 修改 package.json,添加测试命令
1
2
3
"scripts": {
"test": "jest"
},

简单的测试

1
2
3
4
5
6
7
8
9
10
11
12
13
import '@testing-library/jest-dom';
import { render } from '@testing-library/vue';
import HelloWorld from './HelloWorld.vue';

describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message';
const { getByText } = render(HelloWorld, {
props: { msg }
});
expect(getByText(msg)).toBeInTheDocument();
});
});
  1. 在需要测试的组件的同级目录下创建同名测试文件,例如上述针对 HelloWorld 的组件需要创建 HelloWorld.spec.js 文件
  2. 在测试文件中引入 jest-dom 来扩充 jest 的断言方法
  3. 上面的测试用例是用来测试组件是否正确地渲染,所以需要从 DOM 中获取渲染的内容,render 方法用来渲染组件,而 getByText
    会试着去获取内容为 msg 的 DOM,并交给 jest 的 expect 方式,最后用 jest-dom 扩充的 toBeInTheDocument 去验证,看 getByText 有没有
    找到 DOM,如果有的话就代表 HelloWorld 通过了测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import '@testing-library/jest-dom';
import { render, fireEvent } from '@testing-library/vue';
import Counter from './Counter.vue';

describe('increments value on click', () => {
it('click twice', async () => {
const { getByText } = render(Counter);

getByText('Times clicked: 0');

const button = getByText('increment');

await fireEvent.click(button);
await fireEvent.click(button);

expect(getByText('Times clicked: 2')).toBeInTheDocument();
});
});

有时,我们也想看一下带有交互事件的组件是否能正常工作,这个时候就需要用到 fireEvent 函数了.
fireEvent 用来模拟用户交互行为.在上面 Counter 测试中,用户点击两次后查看 DOM 中是否有含有
特定字符串的节点.