详解使用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学习笔记(十二) RegExp类型介绍
Jun 20 Javascript
利用JavaScript的AngularJS库制作电子名片的方法
Jun 18 Javascript
javascript实现3D变换的立体圆圈实例
Aug 06 Javascript
纯javascript实现分页(两种方法)
Aug 26 Javascript
跟我学习javascript的this关键字
May 28 Javascript
详解jQuery中基本的动画方法
Dec 14 Javascript
Angular的自定义指令以及实例
Dec 26 Javascript
CSS3+JavaScript实现翻页幻灯片效果
Jun 28 Javascript
javascript数组拍平方法总结
Jan 20 Javascript
vue-router实现编程式导航的代码实例
Jan 19 Javascript
JS常用排序方法实例代码解析
Mar 03 Javascript
vue路由分文件拆分管理详解
Aug 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 IN_ARRAY 函数使用注意事项
2010/07/24 PHP
简单实用的PHP防注入类实例
2014/12/05 PHP
php curl上传、下载、https登陆实现代码
2017/07/23 PHP
php 自定义函数实现将数据 以excel 表格形式导出示例
2019/11/13 PHP
event.X和event.clientX的区别分析
2011/10/06 Javascript
javascript:history.go()和History.back()的区别及应用
2012/11/25 Javascript
用jquery模仿的a的title属性(兼容ie6/7)
2013/01/21 Javascript
JS控制表格实现一条光线流动分割行的方法
2015/03/09 Javascript
javascript实现详细时间提醒信息效果的方法
2015/03/11 Javascript
js完美解决IE6不支持position:fixed的bug
2015/04/24 Javascript
jQuery仿天猫实现超炫的加入购物车
2015/05/04 Javascript
KnockoutJS 3.X API 第四章之数据控制流component绑定
2016/10/10 Javascript
AngularJS实现Input格式化的方法
2016/11/07 Javascript
JavaScript实现动态增删表格的方法
2017/03/09 Javascript
基于vue+ bootstrap实现图片上传图片展示功能
2017/05/17 Javascript
js中变量的连续赋值(实例讲解)
2017/07/08 Javascript
微信小程序progress组件使用详解
2018/01/31 Javascript
如何根据业务封装自己的功能组件
2019/04/19 Javascript
监控微信小程序中的慢HTTP请求过程详解
2019/07/05 Javascript
Vue+Typescript中在Vue上挂载axios使用时报错问题
2019/08/07 Javascript
在vue项目实现一个ctrl+f的搜索功能
2020/02/28 Javascript
[01:07:19]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第一场 1月19日
2021/03/11 DOTA
探究Python多进程编程下线程之间变量的共享问题
2015/05/05 Python
Python编程中归并排序算法的实现步骤详解
2016/05/04 Python
python版飞机大战代码分享
2018/11/20 Python
TensorFlow2.0:张量的合并与分割实例
2020/01/19 Python
python爬虫用scrapy获取影片的实例分析
2020/11/23 Python
使用简单的CSS3属性实现炫酷读者墙效果
2014/01/08 HTML / CSS
绿色美容,有机护肤品和化妆品:Safe & Chic
2018/10/29 全球购物
致百米运动员广播稿
2014/01/29 职场文书
社团活动总结书
2014/06/27 职场文书
党的群众路线整改落实情况汇报
2014/10/28 职场文书
二审答辩状格式
2015/05/22 职场文书
志愿者服务宣传标语口号
2015/12/26 职场文书
DjangoRestFramework 使用 simpleJWT 登陆认证完整记录
2021/06/22 Python
动作冒险《Hell Is Us》将采用虚幻5 消灭怪物探索王国
2022/04/13 其他游戏