# 官网
https://jestjs.io/zh-Hans/docs/getting-started
# 慢速上手
慢点阅读文档,避免犯错
- 安装:之后会用到 jest 命令,建议全局安装
npm install jest --global | |
# 非全局安装 | |
npm install --save-dev jest |
- 编写被测试文件和测试文件
// src/api/sum-js.js | |
module.exports = function sum(a, b) { | |
return a + b; | |
} | |
// test/sum-js.test.js | |
const sum = require('../src/api/sum.js') | |
test('add 1 + 2 = 3', () => { | |
expect(sum(1, 2)).toBe(3); | |
}); |
- 配置
package.json
:
{ | |
"scripts": { | |
"test": "jest" | |
} | |
} |
然后执行 npm dev test
即可测试。
但是有些项目使用的是 typescript
,对这种进行测试,步骤如下:
- 安装
jest
,之前写了,就不再写了 - 生成基础配置文件:
jest --init |
- 安装
babel
:
npm install --save-dev babel-jest @babel/core @babel/preset-env |
- 配置
babel.config.js
:这个需要注意,检查以下package.json
是否有type: module
。有就表示使用的是 ECMAScript 模块 (ESM) 来导入和导出模块。没有使用的就是 CJS
module.exports = { | |
presets: [ | |
['@babel/preset-env', {targets: {node: 'current'}}], | |
'@babel/preset-typescript', | |
], | |
}; |
这种写法对于 CJS 是正确的,如果是在 ESM 运行环境,就要显示地将文件后缀改为 cjs
才不会报错。
建议使用 babel.config.json
格式,ESM 和 CJS 都可以使用:
{ | |
"presets": [ | |
[ | |
"@babel/preset-env", | |
{ | |
"targets": { | |
"node": "current" | |
} | |
} | |
], | |
"@babel/preset-typescript" | |
] | |
} |
# 配置选项
这些配置都在 jest.config.ts
或者 jest.config.js
中
# moduleFileExtensions
用于指定 Jest 在查找测试文件时应该搜索哪些文件扩展名。默认情况下,Jest 会搜索以 .js、.jsx、.ts 和 .tsx 结尾的文件。
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'] |
# testMatch
用于指定 Jest 查找测试文件,默认情况下,Jest 会在项目根目录下查找所有以 .test.js
、 .spec.js
或 .test.ts
、 .spec.ts
结尾的文件,并运行其中的测试用例。
即默认值: [ "**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)" ]
。
# coverageDirectory
Default: undefined
The directory where Jest should output its coverage files.
# preset
用作 Jest 配置基础的预设。 预设应该指向一个 npm 模块,该模块在根目录下有一个 jest-preset.json、jest-preset.js、jest-preset.cjs 或 jest-preset.mjs 文件。
# transform
Default: {"\\.[jt]sx?$": "babel-jest"}
Jest 会在项目里以原始的 JavaScript 执行,所以如果你用了一些 Node 环境不支持的语法 (比如 JSX, TypeScript, Vue 模板语法),那就要把你的代码转译成原始的 JavaScript,这就跟你在构建浏览器前端代码时要做的转译工作一样。Jest 提供 transform
配置来支持 Js 转译。
转译器(Transformer) 是一个能提供转译源代码能力的模块。 举个例子,假如你想在你的业务和测试代码中使用一些还没被 Node 支持的新语言特性,你可以引入一个代码预处理器来将新版本的 JavaScript 转译成当前支持的版本。
Jest 已经内置了一个现成的转译器 babel-jest
。 它会加载你项目的 Babel 配置,然后转译所有能正确匹配 /\.[jt]sx?$/
正则表达式的文件 (也即所有 .js
, .jsx
, .ts
或 .tsx
文件)。
如果你想将它和其他代码预处理器一起使用,那必须要显式地引入默认的 babel-jest
转译器:
"transform": { | |
"\\.[jt]sx?$": "babel-jest", | |
"\\.css$": "some-css-transformer", | |
} |
# transformIgnorePatterns
转换器需要忽略的文件,Default: ["/node_modules/", "\\.pnp\\.[^\\\/]+$"]
。
# moduleNameMapper
通常,静态文件在测试中无足轻重,因为我们可以安全地 mock 他们。 然而, 如果你使用 CSS 模块,那么最好是给你的类名查找模拟一个代理。
"moduleNameMapper": { | |
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js", | |
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js" | |
} |
所有 mock 文件本身:
// __mocks__/styleMock.js | |
module.exports = {}; | |
// __mocks__/fileMock.js | |
module.exports = 'test-file-stub'; |
# collectCoverage
默认: false
指出是否收集测试时的覆盖率信息。 由于要带上覆盖率搜集语句重新访问所有执行过的文件,这可能会让你的测试执行速度被明显减慢。为 false
时也不会生成 coverageDirectory
指定的目录。
# api 使用
# 匹配器
test
和 it
是一样的,只是与可读性有关。它们需要和匹配器 expect
一起使用
test('two plus two is four', () => { | |
expect(2 + 2).toBe(4); | |
}); |
匹配器提供了很多个精准 api,关于 expect
适用于哪些对象,使用的时候查官网即可:https://jestjs.io/zh-Hans/docs/using-matchers
# 测试异步代码
异步方式运行当前代码,jest 需要知道当前它测试的代码是否已完成。jest 由以下两个方法处理该情况。
- promise:测试一个异步方法,可以将匹配器放在返回的
promise
对象中
test('the data is peanut butter', () => { | |
return fetchData().then(data => { | |
expect(data).toBe('peanut butter'); | |
}); | |
}); |
- async/await:在传递给
test
函数前加上async
test('the data is peanut butter', async () => { | |
const data = await fetchData(); | |
expect(data).toBe('peanut butter'); | |
}); |
# mock 函数
mock 函数允许你测试代码之间的连接,现在假设要测试 foreach
内部实现:
export function forEach(items, callback) { | |
for (let index = 0; index < items.length; index++) { | |
callback(items[index]); | |
} | |
} |
为了测试该函数,我们可以使用一个 mock 函数,然后检查 mock 函数的状态来确保回调函数如期调用:
const forEach = require('./forEach'); | |
const mockCallback = jest.fn(x => 42 + x); | |
test('foreach mock function', () => { | |
forEach([0,1], mockCallback); | |
// 匹配 mock 函数被调用两次 | |
expect(mockCallback.mock.calls).toHaveLength(2); | |
// 第一个 mock 调用的第一个参数是 0 | |
expect(mockCallback.mock.calls[0][0]).toBe(0); | |
}) |
jest.fn()
是创建 Mock
函数最简单的方式,如果没有定义函数内部的实现, jest.fn()
会返回 undefined
作为返回值。
通过 .mock
,我们还可以得到更多的信息:
.mock.results[0].value
:第一次调用的返回值.mock.contexts[0]
:该函数用特定的 this 上下文调用.mock.instances.length
:该函数被实例化了几次
# 挂载
在测试 vue 文件里的方法(export default)时,我们需要将其挂载( mount
或者 shallowMount
),获得组件包装器对象 wrapper
,该对象提供了方法来访问和操作包装的组件:
- 访问和断言组件的属性、状态和计算属性。
- 触发组件的事件,以模拟用户交互。
- 查找和断言组件中的元素和子组件。
- 修改组件的属性和状态。
最基本的就是通过 wrapper.vm
来访问组件实例
# husky
官网文档:https://typicode.github.io/husky/
# 自动安装
npx husky-init && npm install |
它会:
- 添加
prepare
到package.json
中 - 创建
pre-commit
勾子 - 配置 git 勾子路径
# 手动安装
1. 安装 husky
:
npm install husky --save-dev |
2. 启用 git 勾子(会产生.husky 目录):
npx husky install |
3. 编辑 package.json
用于安装后自动启用勾子,该命令会自动修改 package.json
文件:
npm pkg set scripts.prepare="husky install" |
4. 增加一个勾子:
npx husky add .husky/pre-commit "npm test" | |
# 如果是其他需要执行的命令,自己修改即可 | |
git add .husky/pre-commit |
5. 尝试做一次提交:
git commit -m "Keep calm and commit" |
勾子有些文件是需要放在 .git
目录下,会默认 .git
目录和 package.json
同级,如果不同级,就会报找不到 package.json
或者 npm 的 help 信息。
假设有一个独立的项目, package.json
相对于仓库的路径为: project/package.json
, .git
目录相对于仓库的路径就是 ./.git
。现在我们的终端就位于 /project
。现在重新开始操作:
1. 安装 husky
:
npm install husky --save-dev |
2. 修改 package.json
文件:
npm set-script prepare "cd .. && husky install project/.husky" |
如果执行不成功,那么就自己手动修改即可。
3. 执行安装,这一步如果显示 husky 找不到该命令,说明你的 husky 版本太低了:此时就会在 project
目录下创建
npm run prepare |
4. 增加勾子(如果无法成功,可以使用 npx,后面引号的部分先不加,文件创建好后手动去加):
npm husky add .husky/pre-commit "cd project && npm run test" |
之后 commit
就会执行对应的命令。
# 工作改错
背景描述:从 git 上将项目拉一下,然后 npm install
,安装相关依赖。然后执行 jest
测试,需要测试的文件是 ts
文件,模块为 ES6
。测试结果就是跑不通,报的错如下描述。
总结:估计是上一个测试同学没有把他的 package.json
传到 git 上,我相关的依赖在 install
就缺失了。
吐槽:上一个测试开发代码能力真的低。
- 错误 1:找不到 ts 后缀的测试文件,在
jest.config.js
中的moduleFileExtensions
中加入ts
。 - 错误 2:路径找不到,因为被测试文件是
ts
,这里import
时是js
,去掉后缀即可
Configuration error: | |
Could not locate module @/utils/index.js mapped as: | |
F:\Code\front-end\ssc\business-platform-basic-frontend\business-platform-basic-main\src\utils/index.js. |
- 错误 3:更正错误 2 后遇到了错误 3,显示为 Jest 无法解析
export
和import
。这是因为Jest
不支持es
模块,需要通过babel
来处理。
Test suite failed to run | |
Jest encountered an unexpected token | |
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript. |
安装 babel 以及配置 babel.config.ts/js
,这部分请参考上面的慢速上手(先别急着装,继续看下面的话)。如果有需要,还要配置 jest.config.js
中的 transform
:
transform: { | |
'^.+\\.jsx?$|^.+\\.tsx?$': 'babel-jest' | |
}, |
如果你的项目版本太老了,安装 @babel/preset-typescript
失败了,要么把该 preset
版本降低,或者安装 @babel/plugin-transform-typescript
,他俩的关系是: preset
包含了 plugin
。该插件的功能为:添加对 TypeScript 编程语言使用的类型语法的支持。
npm install --save-dev @babel/plugin-transform-typescript |
然后在 babel.config.json
修改:
{ | |
"plugins": ["@babel/plugin-transform-typescript"] | |
} |
这部分请看 babel 官网。