一. Jest 是什么
由 Facebook 开发的一套用于前端 JavaScript 的测试框架。Jest 的一个理念是提供一套完整集成的“零配置”测试体验。
二. 配置
NPM 包
*Vue-Cli3.0 内置了 Babel7,关于需要 Babel 包的这边就不提及了。
- jest -
npm i ``babel-jest jest - babel-jest -
npm i babel-jest babel-jest自动编译 JavaScript 代码 - @vue/test-utils -
npm i @vue/test-utils官方提供了 Vue 组件单元测试的方法 - vue-jest -
npm i ``vue-jest变压器和源映射支持
VUE 单文件组件支持
- “@vue/cli-plugin-unit-jest”: “^3.11.0”,
- “@vue/test-utils”: “1.0.0-beta.29”,
- “babel-core”: “7.0.0-bridge.0”,
babel.config.js
我们假设 webpack 使用了
babel-preset-env,这时默认的 Babel 配置会关闭 ES modules 的转译,因为 webpack 已经可以处理 ES modules 了。然而,我们还是需要为我们的测试而开启它,因为 Jest 的测试用例会直接运行在 Node 上。 同样的,我们可以告诉babel-preset-env面向我们使用的 Node 版本。这样做会跳过转译不必要的特性使得测试启动更快。 为了仅在测试时应用这些选项,可以把它们放到一个独立的env.test配置项中 (这会被babel-jest自动获取)。
env: {test: {presets: [['@babel/preset-env', { targets: { node: 'current' } }]]}}
jest.config.js
module.exports = {/** 是否为浏览器环境 */browser: true,/** 模块支持的后缀名 */moduleFileExtensions: ['js', 'json', 'vue', 'jsx'],/** 解析文件配置 */transform: {'^.+\\.js$': 'babel-jest','.*\\.(vue)$': 'vue-jest','^.+\\.vue$': 'vue-jest','.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub','^.+\\.jsx?$': 'babel-jest'},/** 模块别名设置 */moduleNameMapper: {'^@/(.*)$': '<rootDir>/src/$1','\\.(css|less)$': 'identity-obj-proxy'},/** 测试文件匹配 */testMatch: ['**/__tests__/**/*.[jt]s?(x)','**/?(*.)+(spec).[tj]s?(x)','**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'],/** 忽略文件 */transformIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/dist/', '/node_modules/'],/** 是否开启测试覆盖率统计 */collectCoverage: false,/** 测试覆盖率数据来源 */collectCoverageFrom: ['<rootDir>/src/utils/**/*.{js,vue}', '!**/node_modules/**'],/** 测试覆盖率报告默认格式 */coverageReporters: ['html', 'text-summary'],/** 测试覆盖率生成报告目录 */coverageDirectory: '<rootDir>/test/unit/coverage',/** 文件忽略的配置 */watchPathIgnorePatterns: ['<rootDir>/node_modules', '<rootDir>/dist', '<rootDir>/static'],/** 层次显示测试套件中每个测试的结果 */// bail: trueverbose: true,/** 在遇到第一个失败后就停止继续运行测试用例 */ snapshotSerializers: ['jest-serializer-vue'],testURL: 'http://localhost/',watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname']}
package.json “scripts”
"test": "jest","test:watch": "jest --watch","test:unit": "jest --coverage && npm run test:coverage","test:coverage": "open test/unit/coverage/index.html"
例子🌰
utils
import customFunc from '@/utils/customFunc'/** 数组索引项互换方法 */describe('customFunc.js', () => {test('数组指定索引项移动方法,源数组 [1, 2, 3, 4, 5] 将下标 0 的元素移动到下标 3,目标数组为 [2, 3, 4, 1, 5]', () => {const arrayBefore = [1, 2, 3, 4, 5]const arrayAfter = [2, 3, 4, 1, 5]const fromIndex = 0const toIndex = 3expect(customFunc.moveItem(arrayBefore, fromIndex, toIndex)).toStrictEqual(arrayAfter)})})
components
import { createLocalVue, shallowMount } from '@vue/test-utils'import Vue from 'vue'import ElementUI from 'element-ui'import 'element-ui/lib/theme-chalk/index.css'import CommonBreadcrumb from '@/components/common/CommonBreadcrumb.vue'import { Breadcrumb, BreadcrumbItem } from 'element-ui'const localVue = createLocalVue()localVue.use(ElementUI)Vue.use(Breadcrumb)Vue.use(BreadcrumbItem)/** 挂载函数并返回已渲染的文本的工具函数 */function getRenderedText(propsData) {const wrapper = shallowMount(CommonBreadcrumb, {propsData: {fileBreadcrumb: propsData}})return wrapper.text()}function renderedTextIndexOfParams(args, renderedText) {return args.filter(ele => renderedText.indexOf(ele) === -1).length === 0}test('评估通用面包屑组件渲染文案', () => {// 默认文件夹expect(renderedTextIndexOfParams(['默认文件夹'],getRenderedText([{pid: 0,label: '默认文件夹'}]))).toBe(true)// 默认文件夹/层级一expect(renderedTextIndexOfParams(['默认文件夹', '层级一'],getRenderedText([{pid: 0,label: '默认文件夹'},{pid: 1,label: '层级一'}]))).toBe(true)})
