祖传项目(vue)接入单元测试

最近在做财务项目,用着祖传的项目脚手架,秉承着能升级就升级,该用的就用了原则增加了单元测试。

Vue-Test-Utils 和 Jest

Vue-Test-Utils 是 Vue.js 官方的单元测试实用工具库,它提供了一系列的 API 来使得我们可以很便捷的去写 Vue 应用中的单元测试。

Jest 是一个由 Facebook 开发的测试框架,他是是功能最全的测试运行器。它所需的配置是最少的,默认安装了 JSDOM,内置断言且命令行的用户体验非常好。

本文主要利用 Vue-Test-Utils + Jest 结合

安装依赖

插件模式

直接在项目中添加一个 unit-jest 插件

1
vue add @vue/unit-jest

安装完成后配置自动完成

新建项目

对于新建项目通过脚手架 vue-cli 来新建项目,选择了 Unit Testing 单元测试,选择的是 Jest 作为测试运行器,项目创建好后,会自动配置好单元测试需要的环境。

老项目接入

安装依赖包
1
yarn add --dev @vue/test-utils jest vue-jest @vue/babel-preset-app babel-core@^7.0.0-bridge.0
  • @vue/test-utils
  • jest
  • vue-jest
  • @vue/babel-preset-app
配置 Jest

在根目录新建一个文件 jest.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
moduleFileExtensions: ["js", "vue"],
transform: {
"^.+\\.vue$": "<rootDir>/node_modules/vue-jest",
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
},
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
snapshotSerializers: ["jest-serializer-vue"],
testMatch: ["**/__tests__/**/*.spec.js"],
transformIgnorePatterns: ["<rootDir>/node_modules/"],
};

置项说明:

  • moduleFileExtensions 告诉 Jest 需要匹配的文件后缀
  • transform 匹配到 .vue 文件的时候用 vue-jest 处理, 匹配到 .js 文件的时候用 babel-jest 处理
  • moduleNameMapper 处理 webpack 的别名,比如:将 @ 表示 /src 目录
  • snapshotSerializers 将保存的快照测试结果进行序列化,使得其更美观
  • testMatch 匹配哪些文件进行测试
  • transformIgnorePatterns 不进行匹配的目录

本地文件 babel.config.js 新增

1
2
3
4
5
6
7
module.exports = {
env: {
test: {
presets: [["@babel/env", { targets: { node: "current" } }]],
},
},
};

顺利的话已经完成了

过程遇到的一些问题

  • babel-preset-app

vue-cli 这边用的 babel 预设集合是自己封装的 @vue/app,他是封装了 @babel/preset-env 且配置 useBuiltIns: ‘usage’

而且最新版本是依赖 core-js@3 的所以当安装最新本版本会引起下面问题

  • core-js@3 的更新引起的连锁反应

@babel/polyfill 无法提供 core-js@2 向 core-js@3 过渡 Babel > 7.4.0 不在使用
@babel/preset-env 也因 core-js@3 的原因,需要配置 corejs 参数去指定使用的 corejs 版本

如果使用 corejs@3 根据 useBuiltIns 配置参数不同,需要做转译 ES 的新语法 + 新 API 升级

关于 Babel

因为处理上面 babel 的问题所以这两天研究了一些,简单说下

  • @babel/preset-env

preset-env 是 ES 语法插件的合集,官方已经不再推荐使用 preset-201x 之类的包,该包可以通过配置自动兼容代码,包括自动引入 polyfill 垫片处理新的 API

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"presets": [
[ "@babel/preset-env", {
"targets": {},
"useBuiltIns": false,
"corejs": false
}]
]
}
// useBuiltIns的不同可以分为三种,即 entry(引入了所有的es扩展包), usage(按需) 和 false(只做了语法转换)。
// corejs: false 其实等同于使用 @babel/polyfill 时的 useBuiltIns: false,只对ES语法进行了转换。
// corejs:2 等同于 Babel 6时的 polyfill: true
// corejs: 3 是在 corejs: 2的基础上进而解决了之前无法实例方法的窘况,同时也保持了不污染全局空间

preset-env 在不引入 polyfill 时无法处理,实例的扩展 Array.prototype.includes 等,以及很多内置函数如:Promise、Symbol。而为了解决这样的问题,我们通常有两种方法:使用 Polyfill 或 Babel-runtime 进行功能填充。

  • @babel/polyfill
1
import @babel/polyfill

等同于

1
2
import 'core-js/stable';
import 'regenerator-runtime/runtime';

Babel > 7.4.0 之前,通常我们会安装 @babel-polyfill,而 7.4.0 之后我们需要安装 core-js 替代 babel-polyfill

  • @babel/runtime

能实现按需加载,沙箱环境,公用函数的统一抽象

总结

不可否认 vue-cli 作为非常优秀的脚手架,它可以实现在终端内输入一行指令就能生成模板,非常便利。我们在日常工作中享受工具带给我们的便利同时是不是也应该多花点时间了解脚手架前端工程化方面的内容,这样在日后项目优化,升级会有很大的便利。