详解使用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 相关文章推荐
javascript动画效果类封装代码
Aug 28 Javascript
chrome浏览器不支持onmouseleave事件的解决技巧
May 31 Javascript
文本框倒叙输入让输入框的焦点始终在最开始的位置
Sep 01 Javascript
javascript实现无限级select联动菜单
Jan 02 Javascript
基于jquery实现表格无刷新分页
Jan 07 Javascript
基于JavaScript实现在新的tab页打开url
Aug 04 Javascript
JS实现字符串转驼峰格式的方法
Dec 16 Javascript
详解angularjs结合pagination插件实现分页功能
Feb 10 Javascript
Angular2实现组件交互的方法分析
Dec 19 Javascript
Angular实现较为复杂的表格过滤,删除功能示例
Dec 23 Javascript
angular 服务随记小结
May 06 Javascript
JS三级联动代码格式实例详解
Dec 30 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类详解
2008/03/25 PHP
Windows下XDebug 手工配置与使用说明
2010/07/11 PHP
PHP 在5.1.* 和5.2.*之间 PDO数据库操作中的不同之处小结
2012/03/07 PHP
phpmailer发送gmail邮件实例详解
2013/06/24 PHP
php环境套包 dedeampz 伪静态设置示例
2014/03/26 PHP
Linux php 中文乱码的快速解决方法
2016/05/13 PHP
PHP利用pdo_odbc实现连接数据库示例【基于ThinkPHP5.1搭建的项目】
2019/05/13 PHP
PHP的imageTtfText()函数深入详解
2021/03/03 PHP
js闭包实例汇总
2014/11/09 Javascript
使用JS获取当前地理位置方法汇总
2014/12/18 Javascript
jQuery通过ajax方法获取json数据不执行success的原因及解决方法
2016/10/15 Javascript
基于jQuery实现的幻灯图片切换
2016/12/02 Javascript
Angular客户端请求Rest服务跨域问题的解决方法
2017/09/19 Javascript
angular第三方包开发整理(小结)
2018/04/19 Javascript
element-ui中Table表格省市区合并单元格的方法实现
2019/08/07 Javascript
[15:56]Heroes18_暗影萨满(完美)
2014/10/31 DOTA
Python的Scrapy爬虫框架简单学习笔记
2016/01/20 Python
Python ldap实现登录实例代码
2016/09/30 Python
python中文分词教程之前向最大正向匹配算法详解
2017/11/02 Python
python+openCV利用摄像头实现人员活动检测
2019/06/22 Python
python pycharm的安装及其使用
2019/10/11 Python
opencv 图像腐蚀和图像膨胀的实现
2020/07/07 Python
Python新建项目自动添加介绍和utf-8编码的方法
2020/12/26 Python
HTML5 video 上传预览图片视频如何设置、预览视频某秒的海报帧
2018/08/28 HTML / CSS
客服端调用EJB对象的几个基本步骤
2012/01/15 面试题
EJB包括(SessionBean,EntityBean)说出他们的生命周期,及如何管理事务的
2015/07/24 面试题
师范大学音乐表演专业求职信
2013/10/23 职场文书
大学自我鉴定
2013/12/20 职场文书
社区党员先进事迹
2014/01/22 职场文书
数学系个人求职信范文
2014/01/30 职场文书
元旦联欢会策划方案
2014/06/11 职场文书
2014年有孩子的离婚协议书范本
2014/10/08 职场文书
就业推荐表院系意见
2015/06/05 职场文书
利用python做表格数据处理
2021/04/13 Python
python 机器学习的标准化、归一化、正则化、离散化和白化
2021/04/16 Python
MySql 缓存查询原理与缓存监控和索引监控介绍
2021/07/02 MySQL