The safest way to try to get what you want is to try to deserve what you want

用 Jest 写 Vue 单元测试

Posted on By Frank·J

为什么用 Jest

做项目的时候本来打算直接使用 vue-cli 的测试套餐,但是看了一下觉得太繁琐了,又不愿意花时间去学习这个东西,因此打算不使用全家桶的测试,而是后续增加上但愿测试,这里使用的是 Jest,官网上一段描述:Jest 被 Facebook 用来测试包括 React 应用在内的所有 JavaScript 代码。Jest 的一个理念是提供一套完整集成的 “零配置” 测试体验。我们发现,当向开发人员提供了现成可用的工具后,他们会愿意写更多的测试,这也使得他们的代码库更加稳定和健康。

使用

官网中基于 Vue 使用的文档,下面我们通过文档来实现引入以及开始编写测试

npm install --save-dev jest babel-jest vue-jest @vue/test-utils

这个时候出现了一个问题: npm WARN ajv-keywords@3.2.0 requires a peer of ajv@^6.0.0 but none is installed. You must install peer dependencies yourself.不要慌,我们手动安装 ajv@^6.0.0 就好了

npm install ajv@^6.0.0

package.json 中添加以下配置:

// ...
"jest": {
  "moduleNameMapper": {
    "^@/(.*)$": "<rootDir>/src/$1"
  },
  "moduleFileExtensions": [
    "js",
    "json",
    "vue"
  ],
  "transform": {
    "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
    ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
  }
}
// ...

// 在 script字段中添加
"scripts": {
  // ...
  "test": "jest"
},

运行测试:npm test,结果如下

test0.png

为了更直观的生成测试报告,可以进行如下配置:

// 参数的解释:
// verbose:用于显示每个测试用例的通过与否
// coverageDirectory:指定输出测试覆盖率报告的目录
// collectCoverage,是否要收集覆盖率信息,
// coverageReporters:指定输出的测试覆盖率报告的形式
"jest": {
  // ...
  "verbose": true,
  "coverageDirectory": "test/coverage",
  "collectCoverage": true,
  "coverageReporters": [
    "lcov",// 会生成lcov测试结果以及HTML格式的漂亮的测试覆盖率报告
    "text-summary" // 会在命令行界面输出简单的测试报告
  ]
}

再次运行测: npm test,结果如下:

test1.png

在test目录下会生产一个 coverage 文件夹,该文件夹中有 HTMl 格式的测试报告:

test2.png

PS: 我在运行测试的时候报错:Unknown plugin “dynamic-import-node” specified in “xxx/.babelrc.env.test” at 2 … 这个是插件未装,这里装一下就好了 npm install babel-plugin-dynamic-import-node --save-dev

配合 Vue Router 使用

这里是一个特别需要注意的问题,比如我们的组件内包含 <router-view/> 就会导致测试如下问题:

[Vue warn]: Unknown custom element: <router-view> - did you register the component correctly? Fo
r recursive components, make sure to provide the "name" option.

router 在我们实例化 Vue 的时候用的,自组件内当然就没有对该组件的组册了,官方文档也有解释,因此我们需要做一下修改,这样才能为有使用 <router-view/><router-link/> 此类的文件写测试用例,具体例子如下:

组件: Temp.vue

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      msg: "hello jest"
    }
  }
}
</script>

测试用例: Temp.spec.js

import { shallowMount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
import Temp from '../src/Temp'

const localVue = createLocalVue()
localVue.use(VueRouter)

describe('Temp.spec.js', () => {
  let cmp

  beforeEach(() => {
    cmp = shallowMount(Temp, {
      ocalVue
    }) // Create a copy of the original component
  })

  it('equals msg to "hello jest"', () => {
    expect(cmp.vm.msg).toEqual("hello jest")
  })
})

PS:这里有个 issues 可能包含了会遇到的问题