Jest 是 FaceBook 用来测试 JavaScript 应用的一套测试框架,这些应用当然也包括了 React 应用。它的优点之一是自带了对 React 的支持,同时也很容易支持其它框架。
从最简单的开始,我们可以看看如何用 Jest 测试纯 JS 项目。
假设你需要测试 sum.js
:
export default (a, b) => a + b
你只需要对应地新建一个 sum.test.js
[1]:
import sum from './sum'
test('sum', () => {
expect(sum(2, 3)).toBe(5)
})
关于这里的 `expect` 语法
这里的 expect
toBe
是 Jest 默认使用的断言语法,也就是用来比较 值
的 API,详见相关文档。
然后在终端运行 jest
命令的时候就会自动找到这个文件,执行这里面的测试:
额,报错了,原来 Jest 默认只支持你所使用的 node.js 版本所支持的 JS 特性,例如 import
export
就不支持,所以要么你的代码使用系统 node.js 兼容的语法写 (也就是使用 require
),要么在这里使用 Babel 转义一下。
在 Jest 中使用 Babel 很简单,只需要安装 babel-jest
并新建一个 .babelrc
加入你想要的配置就行了,Jest 会自动使用 babel-jest
。这里我们简单地使用 babel-preset-env
即可,对应的 .babelrc
是:
{
"presets": ["env"]
}
然后重新运行 jest 测试便通过了:
对于 React 应用,基本和纯 JS 项目类似,不过你需要在 .babelrc
中配置对 JSX
的支持,在大多数时候你的项目本身就已经在使用 .babelrc
了,所以这一步甚至也省略掉了。
资源文件
当你要测试的代码引用了非 JS 文件时,Jest 就不知道如何使用这些文件了,例如你的 Webpack 项目中的一个文件:
import './style.css'
正如你需要在 Webpack 中配置了 css-loader
一样,你也需告诉 Jest 如何处理 CSS 文件。
📝 package.json:
{
"jest": {
"transform": {
"^.+\\.(js|jsx)$": "babel-jest",
"^.+\\.css$": "<rootDir>/jest/css-transform.js"
}
}
}
关于 babel-jest
当你手动在 package.json
里设置了 jest.transform
时 babel-jest
不再会被自动使用了,我们需要在这里手动配置。
对应的 ./jest/css-transform.js
// 大多数测试并不关心 CSS 文件里的内容
// 所以这里我们直接返回一个空的对象
module.exports = {
process() {
return 'module.exports = {};'
},
getCacheKey() {
// The output is always the same.
return 'css-cache'
}
}
类似地,你可以使用 transform
来设定如何处理其它类型的文件,比如 .vue
[2] .svg
文件。
浏览器 API
假设你要测试的是一个 Web 应用,依赖于一些浏览器 API 比如 window
document
,它在 Jest 中同样可以正常运行,因为 Jest 默认使用了 js-dom 来模拟浏览器环境,不需要浏览器环境时可以通过使用命令行参数 --env node
或者配置文件来禁用。
Snapshot 测试
当你期望某个值不会改变的时候,可以使用 snapshot 测试。简单地说,它就是记录这个值的状态到本地自动生成的 snapshot 文件里,然后在下一次测试中用新的值来和其进行对比。这对 UI 之类的测试很有帮助:
import React from 'react'
import Link from '../Link.react'
import renderer from 'react-test-renderer'
it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.facebook.com">Facebook</Link>)
.toJSON()
expect(tree).toMatchSnapshot()
})
这确保了 <Link page="http://www.facebook.com">Facebook</Link>
渲染出的内容不会出错。
当你更改了 <Link>
组件的逻辑,需要更新 snapshot 文件时,可以加上 --updateSnapshot
或者 -u
来更新。
类似的,Snapshot 测试不止于 UI 测试中,假设你写了个 Markdown 解析器,你可以用它来确保解析出的内容不会改变:
import renderMarkdown from './my-markdown-parser'
test('render correctly', () => {
const html = renderMarkdown('# markdown code')
expect(html).toMatchSnapshot()
})
查看相关文档。
异步代码测试
facebook.github.io/jest/docs/e…
我就懒得写了… 反正用 Promise
或者 async/await
就对了。