详解使用jest对vue项目进行单元测试


Posted in Javascript onSeptember 07, 2018

最近领导对前端提出了新的要求,要进行单元测试。之前使用vue做了一个快报名小程序的pc端页面,既然要做单元测试,就准备用这个项目了,之前有些react的经验,vue还是第一遭

vue-cli3.0单元测试方面更加完备,就先升级到了cli3.0,因为项目是用typescript写的,需要ts-jest,得到jest的配置如下

{
 "jest": {
  "moduleFileExtensions": [
   "js",
   "jsx",
   "json",
   "vue",
   "ts",
   "tsx"
  ],
  "transform": {
   "^.+\\.vue$": "vue-jest",
   ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub",
   "^.+\\.tsx?$": "ts-jest"
  },
  "moduleNameMapper": {
   "^@/(.*)$": "<rootDir>/src/$1"
  },
  "snapshotSerializers": [
   "jest-serializer-vue"
  ],
  "testMatch": [
   "**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"
  ],
  "testURL": "http://localhost/"
 }
}

先从简单的开始,测试了一个正则字符串常量文件,完美,一点问题没有

然后开始测方案页面的Scheme.vue组件,这个地方主要就想测一个computed属性,将三种有代表性的情况写完测试案例,兴冲冲运行yarn test:unit Scheme.test.ts,结果还不错,三个it测试用例都通过了,但后面还有一片红是什么鬼

console.error node_modules/vue/dist/vue.runtime.common.js:589
[Vue warn]: Invalid prop: type check failed for prop "headerPic". Expected String, got Object.

原来是这个地方调用了一个组件,这个组件需要一个headerPic属性,用作图片的src,看源码

<SideNav :header-pic="require('../../assets/scheme/schemeSideNavPic.jpg')">

感觉没毛病啊,去vue-devtool,"/img/schemeSideNavPic.f988623b.jpg"是字符串啊,一点毛病没有,应该不是require的问题啊,应该是require在jest里面的处理问题,再查看jest配置,已经对jpg等静态文件做处理了,看了一下jest-transform-stub模块的源码,很简单

module.exports = {
 process: function() {
  return ''
 }
}

既对这些静态文件返回空字符串,不做处理,这不就更不应该了呀,幸亏有vscode这款利器,可以方便调试源码,使用vscode调试没有报错,也没能让调试器进入vue文件,没办法,在ts文件里const pic = require('../../../assets/scheme/schemeSideNavPic.jpg'),再次调试,发现

详解使用jest对vue项目进行单元测试

正是jest-transform-stub的内容,确实是个对象,跟在命令行内运行结果一致,也就是说只需要一直处理方式让其返回为

module.exports = ""

查看jest官网,搜了一下css,运气不错?, 处理静态文件,moduleNameMapper选项完全可以满足需求啊,

"moduleNameMapper": {
   "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js"
  }

fileMock.js内容

// __mocks__/fileMock.js

module.exports = 'test-file-stub';

就是说只要返回字符串就OK了,加上moduleNameMapper,测试完美的跑通了

接下来对Scheme.vue组件发起模拟点击测试

const createScheme = wrapper.findAll('.sn-item').at(1)
createScheme.trigger('click')
expect((wrapper.vm as any).isCreateDialogShow).toBeTruthy()
expect(wrapper.find('.create-list-dialog').isVisible()).toBeTruthy()

使用vue-test-utils的api获取createScheme元素,对其触发点击,测试isCreateDialogShow这个data值被设置成true, 使用的element-ui

<el-dialog
   :visible.sync="isCreateDialogShow"
   width="600px"
   class="create-list-dialog"
   title="创建方案">
   ...
</el-dialog>

此dialog可见,顺利通过

接下来再实验一下新功能,快照,使用toMatchSnapshot方法也顺利通过了

接下来来个大的,测试一下Login.vue,登陆页面,主要测其调接口,然后成功设置store值,但不能走真实的网络接口啊,这太慢不说,具体结果还不能预测,得使用mock数据

在项目中创建了axios.plugin.ts vue插件,这可怎么mock呀,再看官方文档,感觉Manual Mocks部分最合适,但是举例也不适合vue 插件mock啊,继续浏览网站,不知道是受哪的启发还是突然开窍了,应该是受fs模块启发,突然知道怎么mock插件了,mock一个模块只需要模仿其型即可,具体实现,就无所谓了,这个http请求插件的mock必须能返回我们期望的值啊,fs模块的__setMockFiles又给了我启示,可以直接给接口的返回result设值啊,然后就有来下面的

__mocks__/axios.plugin.ts文件

const MockAxios = {} as any

let result = {} as any
MockAxios.install = (Vue: any, options: any) => {
 Vue.prototype.$axios = function () {
  /* eslint-disable prefer-promise-reject-errors */
  return new Promise((resolve, reject) => {
   if (result.ResultCode === '200') {
    return result.Info
   } else {
    reject({ code: result.ResultCode, msg: result.Message, info: result.Info })
   }
  })
 }
}

MockAxios.__setMockData = (data: any) => {
 result = data
}

export default MockAxios

然后一马平川了,localVue.use(Vuex), localVue.use(AxiosPlugin)

const mockData = {
 ResultCode: '200',
 Msg: true,
 Info: {
  OpenId: 99,
  UserId: 92003,
 },
}
AxiosPlugin.__setMockData(mockData)
(wrapper.vm as any).login({ code: '29992' }).then(() => {
 expect(wrapper.vm.$store.state.userInfo.OpenId).toBe(mockData.Info.OpenId)
 expect(wrapper.vm.$store.state.userInfo.UserId).toBe(mockData.Info.UserId)
})

完美通过,vue的单元测试框架算是基本搭好了,也能给领导说说了

给领导看还得有个覆盖率报告

yarn test:unit --coverage

覆盖的文件比较少啊,不包含所有的源文件啊,需要加入collectCoverageFrom配置项,至此整个单元测试就比较完备了
下面是完整jest的配置

{
 "jest": {
  "moduleFileExtensions": [
   "js",
   "jsx",
   "json",
   "vue",
   "ts",
   "tsx"
  ],
  "transform": {
   "^.+\\.vue$": "vue-jest",
   ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub",
   "^.+\\.tsx?$": "ts-jest"
  },
  "moduleNameMapper": {
   "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
   "^@/(.*)$": "<rootDir>/src/$1"
  },
  "snapshotSerializers": [
   "jest-serializer-vue"
  ],
  "testMatch": [
   "**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"
  ],
  "testURL": "http://localhost/",
  "collectCoverageFrom": [
   "**/*.{vue,ts}",
   "!**/node_modules/**",
   "!**/*.d.ts"
  ]
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery中的$(document).ready()与window.onload的区别
Nov 18 Javascript
解析JSON对象与字符串之间的相互转换
Dec 18 Javascript
js+HTML5基于过滤器从摄像头中捕获视频的方法
Jun 16 Javascript
jquery实现的树形目录实例
Jun 26 Javascript
JavaScript实现Base64编码转换
Apr 23 Javascript
js实现目录链接,内容跟着目录滚动显示的简单实例
Oct 15 Javascript
Bootstrap基本插件学习笔记之按钮(21)
Dec 08 Javascript
JS多物体实现缓冲运动效果示例
Dec 20 Javascript
详谈DOM简介及节点、属性、查找节点的方法
Nov 16 Javascript
解决layui中的form表单与button的点击事件冲突问题
Aug 15 Javascript
小程序登录态管理的方法示例
Nov 13 Javascript
JS+canvas画布实现炫酷的旋转星空效果示例
Feb 13 Javascript
Vue 实现列表动态添加和删除的两种方法小结
Sep 07 #Javascript
koa-router源码学习小结
Sep 07 #Javascript
Vue.js实现表格渲染的方法
Sep 07 #Javascript
vue基于element的区间选择组件
Sep 07 #Javascript
vue-cli监听组件加载完成的方法
Sep 07 #Javascript
原生JS实现DOM加载完成马上执行JS代码的方法
Sep 07 #Javascript
vue加载完成后的回调函数方法
Sep 07 #Javascript
You might like
php adodb连接带密码access数据库实例,测试成功
2008/05/14 PHP
PHP中如何判断AJAX提交的数据
2012/02/05 PHP
PHP禁止个别IP访问网站
2013/10/30 PHP
PHP实现会员账号单唯一登录的方法分析
2019/03/07 PHP
laravel异步监控定时调度器实例详解
2019/06/21 PHP
laravel 实现根据字段不同值做不同查询
2019/10/23 PHP
tp5框架基于ajax实现异步删除图片的方法示例
2020/02/10 PHP
基于Jquery的温度计动画效果
2010/06/18 Javascript
ASP.NET jQuery 实例1(在TextBox里面创建一个默认提示)
2012/01/13 Javascript
Javascript new Date().valueOf()的作用与时间戳由来详解
2013/04/24 Javascript
jQuery Ajax使用实例
2015/04/16 Javascript
JavaScript中实现map功能代码分享
2015/06/11 Javascript
浅谈JavaScript对象的创建方式
2016/06/13 Javascript
jQuery实现可以编辑的表格实例详解【附demo源码下载】
2016/07/09 Javascript
Highcharts学习之坐标轴
2016/08/02 Javascript
原生js实现jquery函数animate()动画效果的简单实例
2016/08/21 Javascript
最通俗易懂的javascript变量提升详解
2017/08/05 Javascript
js计算最大公约数和最小公倍数代码实例
2019/09/11 Javascript
jQuery cookie的公共方法封装和使用示例
2020/06/01 jQuery
解决vue+router路由跳转不起作用的一项原因
2020/07/19 Javascript
three.js欧拉角和四元数的使用方法
2020/07/26 Javascript
python插入数据到列表的方法
2015/04/30 Python
python神经网络编程实现手写数字识别
2020/05/27 Python
浅谈pytorch中torch.max和F.softmax函数的维度解释
2020/06/28 Python
Python logging日志模块 配置文件方式
2020/07/12 Python
纯CSS3打造属于自己的“小黄人”
2016/03/14 HTML / CSS
BONIA官方网站:国际奢侈品牌和皮革专家
2016/11/27 全球购物
医院护士的求职信
2014/01/03 职场文书
决定成败的关键——创业计划书
2014/01/24 职场文书
员工考核管理制度
2014/02/02 职场文书
户外活动总结范文
2014/04/30 职场文书
2014中学教师节广播稿
2014/09/10 职场文书
领导干部贪图享乐整改措施
2014/09/21 职场文书
介绍信范文
2015/01/31 职场文书
js Proxy的原理详解
2021/05/25 Javascript
CSS极坐标的实例代码
2021/06/03 HTML / CSS