详解使用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.ajax 用户登录验证代码
Oct 29 Javascript
如何确保JavaScript的执行顺序 之jQuery.html深度分析
Mar 03 Javascript
js 剪切板的用法(clipboardData.setData)与js match函数介绍
Nov 19 Javascript
清除div下面的所有标签的方法
Feb 17 Javascript
js中的hasOwnProperty和isPrototypeOf方法使用实例
Jun 06 Javascript
JS实现从表格中动态删除指定行的方法
Mar 31 Javascript
Jquery简单分页实现方法
Jul 24 Javascript
js基于cookie记录来宾姓名的方法
Jul 19 Javascript
js合并两个数组生成合并后的key:value数组
May 09 Javascript
150行代码带你实现微信小程序中的数据侦听
May 17 Javascript
深入了解query和params的使用区别
Jun 24 Javascript
vue+node 实现视频在线播放的实例代码
Oct 19 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
一个多文件上传的例子(原创)
2006/10/09 PHP
php生成二维码的几种方式整理及使用实例
2013/06/03 PHP
ThinkPHP6.0如何利用自定义验证规则规范的实现登陆
2020/12/16 PHP
js 新浪的一个图片播放图片轮换效果代码
2008/07/15 Javascript
jQuery 源代码显示控件 (Ajax加载方式).
2009/05/18 Javascript
javascript调试过程中找不到哪里出错的可能原因
2013/12/16 Javascript
Jquery实现点击按钮,连续地向textarea中添加值的实例代码
2014/03/08 Javascript
js+HTML5实现视频截图的方法
2015/06/16 Javascript
使用Node.js配合Nginx实现高负载网络
2015/06/28 Javascript
javascript连续赋值问题
2015/07/08 Javascript
基于Bootstrap使用jQuery实现简单可编辑表格
2016/05/04 Javascript
javascript表单处理具体实现代码(表单、链接、按钮)
2016/05/07 Javascript
js实现漫天星星效果
2017/01/19 Javascript
解决ionic和angular上拉加载的问题
2017/08/03 Javascript
vue2.0 路由不显示router-view的解决方法
2018/03/06 Javascript
Node错误处理笔记之挖坑系列教程
2018/06/05 Javascript
nuxt.js 缓存实践
2018/06/25 Javascript
vue中解决微信html5原生ios虚拟键返回不刷新问题
2020/10/20 Javascript
Python 元组(Tuple)操作详解
2014/03/11 Python
python得到单词模式的示例
2018/10/15 Python
python 多线程中子线程和主线程相互通信方法
2018/11/09 Python
python-opencv 将连续图片写成视频格式的方法
2019/01/08 Python
Python使用numpy模块实现矩阵和列表的连接操作方法
2019/06/26 Python
从numpy数组中取出满足条件的元素示例
2019/11/26 Python
python+requests接口压力测试500次,查看响应时间的实例
2020/04/30 Python
Python新手学习函数默认参数设置
2020/06/03 Python
The Hut英国:英国领先的豪华在线百货商店
2019/07/26 全球购物
医院护士专业个人的求职信
2013/12/09 职场文书
毕业生自我鉴定实例
2014/01/21 职场文书
商务考察邀请函范文
2014/01/21 职场文书
《小草和大树》教学反思
2014/02/16 职场文书
店面出租协议书范本
2014/11/28 职场文书
乡镇法制宣传日活动总结
2015/05/05 职场文书
《正面管教》读后有感:和善而坚定的旅程
2019/12/19 职场文书
php 获取音视频时长,PHP 利用getid3 获取音频文件时长等数据
2021/04/01 PHP
Ruby处理YAML和json数据
2022/04/18 Ruby