详解使用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 Boolean、Nnumber、String 强制类型转换的区别详细介绍
Dec 13 Javascript
JQuery获取样式中的background-color颜色值的问题
Aug 20 Javascript
深入分析JQuery和JavaScript的异同
Oct 23 Javascript
jQuery中(function($){})(jQuery)详解
Jul 15 Javascript
JavaScript利用Date实现简单的倒计时实例
Jan 12 Javascript
详解webpack分包及异步加载套路
Jun 29 Javascript
JS解决IOS中拍照图片预览旋转90度BUG的问题
Sep 13 Javascript
vue实现在线预览pdf文件和下载(pdf.js)
Nov 26 Javascript
微信小程序中限制激励式视频广告位显示次数(实现思路)
Dec 06 Javascript
vue项目启动出现cannot GET /服务错误的解决方法
Apr 26 Javascript
浅谈Vue3.0新版API之composition-api入坑指南
Apr 30 Javascript
javascript递归函数定义和用法示例分析
Jul 22 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写的采集程序
2007/03/16 PHP
PHP5 面向对象程序设计
2008/02/13 PHP
php面向对象全攻略 (九)访问类型
2009/09/30 PHP
PHP simple_html_dom.php+正则 采集文章代码
2009/12/24 PHP
php中unserialize返回false的解决方法
2014/09/22 PHP
在PHP站点的页面上添加Facebook评论插件的实例教程
2016/01/08 PHP
JavaScript 用cloneNode方法克隆节点的代码
2012/10/15 Javascript
jQuery调用AJAX时Get和post公用的乱码解决方法实例说明
2013/06/04 Javascript
javascript中match函数的用法小结
2014/02/08 Javascript
浅析Javascript中“==”与“===”的区别
2014/12/23 Javascript
javascript 中的事件委托详解
2016/10/25 Javascript
vue多级多选菜单组件开发
2020/09/08 Javascript
js canvas实现擦除效果示例代码
2017/04/26 Javascript
用Vue-cli搭建的项目中引入css报错的原因分析
2017/07/20 Javascript
[js高手之路]图解javascript的原型(prototype)对象,原型链实例
2017/08/28 Javascript
js 将canvas生成图片保存,或直接保存一张图片的实现方法
2018/01/02 Javascript
vue之浏览器存储方法封装实例
2018/03/15 Javascript
vue 父组件调用子组件方法及事件
2018/03/29 Javascript
Vue源码探究之状态初始化
2018/11/14 Javascript
详解javascript对数组和json数组的操作
2019/04/15 Javascript
vue限制输入框只能输入8位整数和2位小数的代码
2019/11/06 Javascript
js实现省级联动(数据结构优化)
2020/07/17 Javascript
[15:57]教你分分钟做大人:斧王
2014/10/30 DOTA
Python实现建立SSH连接的方法
2015/06/03 Python
Python网络编程之TCP与UDP协议套接字用法示例
2018/02/02 Python
详解python3中的真值测试
2018/08/13 Python
Python3将数据保存为txt文件的方法
2019/09/12 Python
Python搭建代理IP池实现获取IP的方法
2019/10/27 Python
TFRecord格式存储数据与队列读取实例
2020/01/21 Python
纯CSS3实现的阴影效果
2014/12/24 HTML / CSS
Linux不知道文件后缀名怎么判断文件类型
2012/04/26 面试题
Servlet的生命周期
2013/08/25 面试题
新员工试用期自我评价
2015/03/10 职场文书
学校光盘行动倡议书
2015/04/28 职场文书
励志语录:你若不勇敢,谁替你坚强
2019/11/08 职场文书
关于@OnetoMany关系映射的排序问题,使用注解@OrderBy
2021/12/06 Java/Android