weex开发到现在,我们一直在找机会启用单元测试,但由于需求繁多,时间和精力不太允许。在weex的开发过程中,除了产品需求,我们也一直在做公共组件的开发,由于公共组件的日渐增多,个人认为在公共组件内进行单元测试还是有一定的必要性。
开年那段时间需求不多,正好研究了下rider-weex项目引入单元测试。
根据官方的一些文档以及自己开发过程中的经验,我选择了jest作为测试运行器。vue官网上对它的评价是:
Jest是功能最全的测试运行器。它所需的配置是最少的,默认安装了 JSDOM,内置断言且命令行的用户体验非常好。
话休饶舌,开撸!
首先,安装全家桶
npm install --save-dev jest @vue/test-utils vue-jest babel-jest babel-preset-env
接下来在 package.json中创建一个 jest 块:
"jest": {
"moduleFileExtensions": [
"js",
"vue"// 告诉 Jest 处理 `*.vue` 文件
],
"transform": {
// 用 `vue-jest` 处理 `*.vue` 文件
".*\\.(vue)$": "vue-jest",
// 用 `babel-jest` 处理 js
"^.+\\.js$": "<rootDir>/node_modules/babel-jest"
},
"moduleNameMapper": {
// 处理 webpack 别名,如果你在 webpack 中配置了别名解析,那么你也需要用 moduleNameMapper 选项为 Jest 增加一个匹配配置
"^views/(.*)$": "<rootDir>/src/views/$1",
"^util/(.*)$": "<rootDir>/src/util/$1",
"^components/(.*)$": "<rootDir>/src/components/$1",
"^__mocks__/(.*)$": "<rootDir>/test/__mocks__/$1"
}
}
在scripts
里增加test
命令,colors
会显示颜色,coverage
会显示覆盖率报告
"test": "jest --colors --coverage",
修改.babelrc文件
{
"presets": [["env", { "modules": false }], "es2015", "stage-0"],
"plugins": [
[
"transform-runtime",
"component",
{
"libraryName": "weex-ui",
"libDir": "packages",
"style": false
}
]
],
"env": {
"test": {
"presets": [["env", { "targets": { "node": "current" } }]],
}
},
}
这里会有个大坑~
babel的安装版本不能为7以上,否则会报
.plugins[0][1] must be an object, false, or undefined
错误
特别要注意的是,高版本的babel-jest
里也会安装7以上的babel
,注意安装23.6.0以内的babel-jest
。
然后,我们来写一个最简单的测试文件。
在主目录下,新建文件夹test/components,再新建dwdDatetimePicker.test.js文件
dwdDatetimePicker是一个日期组件
// dwdDatetimePicker.test.js
// 从测试实用工具集中导入 `shallowMount()` 方法
// 同时导入你要测试的组件以及组件中用到的函数
import { shallowMount } from '@vue/test-utils'
import dwdDatetimePicker from 'components/dwdDatetimePicker/dwdDatetimePicker'
import { parseDate, getYears, getMonths, getDays, getHours, getMinutes, formatDate, arrayIndexOf } from 'components/dwdDatetimePicker/util';
import weex from 'weex-vue-render'
describe('dwdDatetimePicker', () => {
// 现在挂载组件,你便得到了这个包裹器
const wrapper = shallowMount(dwdDatetimePicker)
...
}
接下去,我们开始写断言,关于jest的一些用法,可以去它的官网学习https://jestjs.io/docs/zh-Hans/23.x/getting-started.html
setProps(props)
可以设置Wrapper vm
的prop
并强制更新。你也可以传递一个propsData
对象,这会用该对象来初始化Vue
示例
具体关于Vue Test Utils的API,可以去这里查看
test('打开dwdDatetimePicker', () => {
wrapper.setProps({
show: true
})
// 你可以通过 `wrapper.vm` 访问实际的 Vue 实例
// 当show为true时,overlayShow和pickerShow也改为true
expect(wrapper.vm.overlayShow).toBeTruthy()
expect(wrapper.vm.pickerShow).toBeTruthy()
})
可以查看渲染是否正确
test('设置title', () => {
wrapper.setProps({
title: '标题',
})
// 找到class为header-center-text的text,并且内容应该为`标题`
expect(wrapper.find('text.header-center-text').text()).toBe('标题')
})
设置了年月日后,是否显示正确
test('设置value', () => {
wrapper.setProps({
show: true,
value: '2018-09-10',
})
expect(wrapper.vm.currentYear).toBe(18)
expect(wrapper.vm.currentMonth).toBe(8)
expect(wrapper.vm.currentDay).toBe(9)
})
触发点击交互
Wrapper
暴露了一个trigger
方法。它可以用来触发DOM
事件
每个挂载的包裹器都会通过其背后的Vue
实例自动记录所有被触发的事件。你可以用wrapper.emitted()
方法取回这些事件记录。
test('点击confirm', () => {
wrapper.find('div.header-right-view').trigger('click')
// dwdConfirm方法有被触发
expect(wrapper.emitted().dwdConfirm).toBeTruthy()
// 并且数据为2018-10-10
expect(wrapper.emitted().dwdConfirm[0]).toEqual(['2018-10-10'])
})
完整的测试文件示例:
// dwdDatetimePicker.test.js
// 从测试实用工具集中导入 `shallowMount()` 方法
// 同时导入你要测试的组件以及组件中用到的函数
import { shallowMount } from '@vue/test-utils'
import dwdDatetimePicker from 'components/dwdDatetimePicker/dwdDatetimePicker'
import { parseDate, getYears, getMonths, getDays, getHours, getMinutes, formatDate, arrayIndexOf } from 'components/dwdDatetimePicker/util';
import weex from 'weex-vue-render'
describe('dwdDatetimePicker', () => {
// 现在挂载组件,你便得到了这个包裹器
const wrapper = shallowMount(dwdDatetimePicker)
// 触发断言
test('打开dwdDatetimePicker', () => {
wrapper.setProps({
show: true
})
expect(wrapper.vm.overlayShow).toBeTruthy()
expect(wrapper.vm.pickerShow).toBeTruthy()
})
test('设置title', () => {
wrapper.setProps({
title: '标题',
})
expect(wrapper.find('text.header-center-text').text()).toBe('标题')
})
test('设置value', () => {
wrapper.setProps({
show: true,
value: '2018-09-10',
})
expect(wrapper.vm.currentYear).toBe(18)
expect(wrapper.vm.currentMonth).toBe(8)
expect(wrapper.vm.currentDay).toBe(9)
})
test('设置startDate,endDate', () => {
wrapper.setProps({
show: true,
value: '2018-09-10',
startDate: '2018-10-10',
endDate: '2019-10-10',
})
expect(wrapper.vm.currentYear).toBe(0)
expect(wrapper.vm.currentMonth).toBe(0)
expect(wrapper.vm.currentDay).toBe(0)
})
test('点击confirm', () => {
wrapper.find('div.header-right-view').trigger('click')
expect(wrapper.emitted().dwdConfirm).toBeTruthy()
expect(wrapper.emitted().dwdConfirm[0]).toEqual(['2018-10-10'])
})
test('点击cancel', () => {
wrapper.find('div.header-left-view').trigger('click')
expect(wrapper.emitted().dwdCancel).toBeTruthy()
})
test('测试util', () => {
expect(parseDate('YYYY-MM-DD', '2018-01-01', 'v-model日期和format格式不匹配')).toEqual({
year: '2018',
month: '01',
day: '01',
hour: undefined,
minute: undefined,
noon: undefined
})
expect(getYears({year: '2018',month: '01',day: '01'}, {year: '2019',month: '01',day: '01'})).toEqual([
{
title: '2018年',
value: 2018
},
{
title: '2019年',
value: 2019
}
])
expect(arrayIndexOf([1, 2], 1)).toBe(0)
})
})
最后,跑npm run test
测试通过
覆盖率如下
本人才疏学浅,此文仅作为抛砖引玉,期待有更好的技术方案