背景
前段时间由于公司测试左移,很多需求的测试任务都落到了开发身上。但是由于组内人均需求较多,自测不充分所导致的线上问题时有发生。为了减少此类问题,我们循序渐进的在大多数项目里接入了babel-plugin-istanbul这个babel插件,然后将对应的覆盖率数据上传到内部平台进行可视化展示,从而掌握此次新需求所涉及到的代码改动是否都已自测覆盖到。
接入流程
假如你的项目是通过vue-cli创建的:
vue create vue-demo
如果初始化项目的时候遇到了如下问题:
是因为vue-cli使用了自己定义的镜像,可以通过which vue
得到vue命令所在位置,然后进入bin命令同级的lib/node_modules/@vue/cli
,即可找到安装到全局的vue-cli位置,然后通过vscode的code .
命令打开项目:
找到这个路径对应的文件@vue/cli/lib/util/registries.js
:
const registries = {
npm: 'https://registry.npmjs.org',
yarn: 'https://registry.yarnpkg.com',
taobao: 'https://registry.npm.taobao.org',
pnpm: 'https://registry.npmjs.org'
}
module.exports = registries
将taobao镜像换成https://registry.npmmirror.com
即可。
创建好项目后,安装babel-plugin-istanbul:
npm install --save-dev babel-plugin-istanbul
配置babel.config.js
:
module.exports = {
plugins: [
[
'istanbul',
{
// 是否使用内联sourceMap
useInlineSourceMaps: false,
// 填入需要获取覆盖率的文件后缀,注意带'.'
extension: ['.js', '.ts', '.vue']
}
]
]
}
启动项目:
npm run serve
打开控制台可以通过__coverage__
,得到对应的覆盖率数据:
存在的问题
运行到这儿我们就把上述__coverage__
数据通过自定义的webpack plugin上传到了内部平台,上传后发现咱的数据根本就不对,我们可以在HelloWorld.vue
中添加一些js代码,如:
export default {
name: 'HelloWorld',
props: {
msg: String
},
mounted() {
const num = Math.random()
if (num > 0.5) {
console.log('num > 0.5')
} else {
console.log('num < 0.5')
}
}
}
打开控制台,找到该文件对应的覆盖率数据:
其中8
、9-13
、10
分别与下图的行列号对应:
但实际上我们的源文件还有template
上的代码,正确的位置应该为:40
、41-44
、42
,也就是说这个数据产生了偏移:
产生如上问题的原因是:在babel-loader处理代码之前,源码经过了一系列别的loader的二次编译(如vue-loader、ts-loader等),istanbul基于编译后的代码进行插桩上报,所以行列号是基于编译后的代码而非原始代码,如:
解决方案
为了解决这个问题我们收集了loader之间的sourceMap进行逐层溯源,通过自定义babel-plugin更改ast代码,将插桩后的行列号映射到原代码的行列号,目前已经封装为单独的npm包:coverage-source-map-trace-plugin。
我们在demo项目里安装:
npm install coverage-source-map-trace-plugin -D
配置好vue.config.js
:
const CoverageSourceMapTracePlugin = require('coverage-source-map-trace-plugin')
module.exports = {
chainWebpack: config => {
config
.plugin('coverage-source-map-trace-plugin')
.use(CoverageSourceMapTracePlugin)
}
}
然后重新启动项目,再次检查控制台的__coverage__
数据:
可以看到,此时的覆盖率数据则是准确的。此插件不仅仅针对Vue文件,只要项目是基于webpack
的,配置了babel-loader
处理js代码,那么所有类型的文件,经过合适loader处理之后,最终都会经过babel-loader去处理,那么就可以进行sourceMap溯源。
但是有一种情况可能导致数据不正确,那就是项目不产生sourceMap,此时可以在webpack中添加如下配置:
devtool: 'source-map'
然后结合__coverage__
数据中的_tracedSourceMapList
这个字段,查看当前文件已经溯源的loader列表:
如果说该vue文件的script部分是ts
语法的,那么上述列表里应该还有ts-loader
,如果缺少了,那么就可以检查一下你的项目里是否正确配置了sourceMap
: