运行测试
注意:此功能适用于
react-scripts@0.3.0
及更高版本。
Create React App 使用 Jest 作为其测试运行器。 为了准备这种整合,我们对Jest进行了 重大改造,所以如果你在几年前听到有关它的不好的消息,那现在就再试一次吧。
Jest 是一个基于 Node 的运行器。 这意味着测试始终在 Node 环境中运行,而不是在真实的浏览器中运行。 这使我们能够实现快速迭代并防止片状。
虽然 Jest 通过 jsdom 提供了 window
等浏览器全局变量,但它们只是真实浏览器行为的近似值。 Jest 旨在用于逻辑和组件的单元测试,而不是为了测试 DOM 一些奇怪的行为。
如果你需要,我们建议你使用单独的工具进行浏览器端到端的测试。 它们超出了 Create React App 的范围。
文件名约定
Jest 将使用以下任何流行的命名约定来查找测试文件:
__tests__
文件夹中带有.js
后缀的文件。- 带有
.test.js
后缀的文件。 - 带有
.spec.js
后缀的文件。
.test.js
/ .spec.js
文件(或 __tests__
文件夹)可以是位于顶级文件夹 src
下任何深度的文件夹中。
我们建议将测试文件(或 __tests__
文件夹)放在他们正在测试的代码旁边,以便相对路径导入时路径更短。 例如,如果 App.test.js
和 App.js
位于同一文件夹中,则测试只需从 import App from './App'
而不是很长的相对路径。 主机托管的情况下还有助于在大型项目中更快地找到测试。
命令行界面
当你运行 npm test
时,Jest 将以 watch(观察) 模式启动。 每次保存文件时,它都会重新运行测试,就像 npm start
重新编译代码一样。
watcher(观察者) 包括一个交互式命令行界面,能够运行所有测试,或专注于搜索模式。 它以这种方式设计,以便你可以保持打开状态并享受快速重新运行。 你可以使用 “Watch Usage” 打印的注释中学习命令:
When you run npm test
, Jest will launch in the watch mode. Every time you save a file, it will re-run the tests, just like npm start
recompiles the code.
The watcher includes an interactive command-line interface with the ability to run all tests, or focus on a search pattern. It is designed this way so that you can keep it open and enjoy fast re-runs. You can learn the commands from the “Watch Usage” note that the watcher prints after every run:
版本控制集成
默认情况下,当你运行 npm test
时,Jest 将仅运行与上次提交后更改的文件相关的测试。 这是一项优化,旨在使你的测试快速运行,无论你拥有多少测试。 但是,它假定你不经常提交未通过测试的代码。
Jest 将始终明确提到它只运行与自上次提交后更改的文件相关的测试。 你也可以在监视模式下按 a
强制 Jest 运行所有测试。
Jest 将始终在 持续集成服务器 上运行所有测试,或者如果项目不在 Git 或 Mercurial 仓库中。
编写测试
要创建测试,请使用测试名称及其代码添加 it()
(或 test()
)块。 你可以选择将它们包装在 describe()
块中以进行逻辑分组,但这既不是必需的也不是推荐的。
Jest 提供了一个内置的 expect()
全局函数来进行断言。 基本测试可能如下所示:
import sum from './sum';
it('sums numbers', () => {
expect(sum(1, 2)).toEqual(3);
expect(sum(2, 2)).toEqual(4);
});
Jest 支持的所有 expect()
匹配器都在 这里有详细的记录。
你还可以使用 jest.fn()
和 expect(fn).toBeCalled()
来创建 “spies” 或模拟函数。
测试组件
有广泛的组件测试技术。 它们的范围从“冒烟测试”验证组件渲染而不抛出,浅层渲染和测试一些输出,到完全渲染和测试组件生命周期和状态更改。
不同的项目根据组件更改的频率以及它们包含的逻辑程度来选择不同的测试权衡。 如果你尚未确定测试策略,我们建议你首先为组件创建简单的冒烟测试:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});
此测试将安装一个组件,并确保它在渲染过程中不会抛出。 像这样的测试只需很少的努力即可提供很多有价值的信息,因此它们非常适合作为测试起点,你可以在src/App.test.js
中可以找到这个测试。
当你遇到因更改组件而导致的错误时,你将更深入地了解它们的哪些部分值得在你的应用程序中进行测试。 这可能是引入更具体的测试以确定特定预期输出或行为的好时机。
选项 1:浅层渲染
如果你希望测试独立于它们渲染的子组件的组件,我们建议使用 Enzyme 的 shallow()
渲染API。 要安装它,请运行:
npm install --save enzyme enzyme-adapter-react-16 react-test-renderer
或者你可以使用 yarn
:
yarn add enzyme enzyme-adapter-react-16 react-test-renderer
从 Enzyme 3 开始,你需要安装 Enzyme 以及与你正在使用的 React 版本相对应的适配器。 (上面的例子使用 React 16 的适配器。)
还需要在 全局设置文件 中配置适配器:
src/setupTests.js
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
注意:当使用带有 Babel 的 TypeScript 时,所有文件都需要至少有一个导出,否则你将收到错误
Cannot compile namespaces when the '--isolatedModules' flag is provided.
。要解决此问题,你可以添加export default undefined
到src/setupTests.ts
。
注意:请记住,如果你决定在创建
src/setupTests.js
之前 “eject” ,则生成的package.json
文件将不包含对它的任何引用。阅读此处 以了解如何在 “eject” 后添加此项。
现在你可以用它写一个冒烟测试:
import React from 'react';
import { shallow } from 'enzyme';
import App from './App';
it('renders without crashing', () => {
shallow(<App />);
});
与之前使用 ReactDOM.render()
的冒烟测试不同,此测试仅渲染 <App>
并且不会更深入。例如,即使 <App>
本身渲染的 <Button>
抛出错误,该测试也会通过。浅层渲染非常适合隔离单元测试,但你可能仍希望创建一些完整的渲染测试以确保组件正确集成。 Enzyme 支持 使用 mount()
进行完全渲染,你还可以使用它来测试状态更改和组件生命周期。
你可以阅读 Enzyme 文档 以获取更多测试技术。Enzyme 文档使用 Chai 和 Sinon 进行断言,但你不必使用它们,因为 Jest 为 spies 提供了内置的 expect()
和 jest.fn()
。
以下是 Enzyme 文档中的一个示例,它断言特定的输出,并使用 Jest 匹配器重写:
import React from 'react';
import { shallow } from 'enzyme';
import App from './App';
it('renders welcome message', () => {
const wrapper = shallow(<App />);
const welcome = <h2>Welcome to React</h2>;
// expect(wrapper.contains(welcome)).toBe(true);
expect(wrapper.contains(welcome)).toEqual(true);
});
所有 Jest 匹配器都在 这里有详细的记录。
不过,如果你愿意,可以使用像 Chai 这样的第三方断言库,如下所述。
此外,你可能会发现 jest-enzyme 有助于使用可读匹配器简化测试。 上面 contains
的代码可以用jest-enzyme 更简单地编写。
expect(wrapper).toContainReact(welcome);
要启用此功能,请安装 jest-enzyme
:
npm install --save jest-enzyme
或者你可以使用 yarn
:
yarn add jest-enzyme
在 src/setupTests.js
中导入它以使其匹配器在每个测试中可用:
import 'jest-enzyme';
选项2:反应测试库
作为 enzyme
的替代或伴侣,你可以考虑使用 react-testing-library
。 react-testing-library
是一个用于以类似于最终用户使用组件的方式测试 React 组件的库。 它非常适用于 React 组件和应用程序的单元,集成和端到端测试。 它更直接地与 DOM 节点一起工作,因此建议使用 jest-dom
来改进断言。
要安装 react-testing-library
和 jest-dom
,你可以运行:
npm install --save react-testing-library jest-dom
或者你可以使用 yarn
:
yarn add react-testing-library jest-dom
与 enzyme
类似,你可以创建 src/setupTests.js
文件以避免测试文件中的样板:
// react-testing-library 将你的组件渲染给 document.body ,
// 这将确保在每次测试后将其删除。
import 'react-testing-library/cleanup-after-each';
// 这会添加 jest-dom 的自定义断言
import 'jest-dom/extend-expect';
下面是使用 react-testing-library
和 jest-dom
测试 <App />
组件渲染 “Welcome to React” 的示例。
import React from 'react';
import { render } from 'react-testing-library';
import App from './App';
it('renders welcome message', () => {
const { getByText } = render(<App />);
expect(getByText('Welcome to React')).toBeInTheDocument();
});
了解有关 react-testing-library
提供的实用程序的更多信息,以便于测试异步交互以及从 react-testing-library
文档 和 示例 中选择表单元素。
使用第三方断言库
我们建议你对断言使用 expect()
,对 spies 使用 jest.fn()
。 如果你遇到问题请 向 Jest 提出问题,我们会修复它们。 我们打算继续使它们更好地用于 React ,例如,支持 将React 元素漂亮打印为 JSX。
但是,如果你已经习惯了其他库,例如 Chai 和 Sinon ,或者如果你有使用它们的现有代码,那么你可以将它们正常导入,如下所示:
import sinon from 'sinon';
import { expect } from 'chai';
然后像往常一样在测试中使用它们。
初始化测试环境
注意:此功能适用于 react-scripts@0.4.0
及更高版本。
如果你的应用程序使用需要在测试中模拟的浏览器API,或者在运行测试之前只需要全局设置,请将 src/setupTests.js
添加到项目中。 它将在运行测试之前自动执行。
例如:
src/setupTests.js
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn(),
clear: jest.fn(),
};
global.localStorage = localStorageMock;
注意:请记住,如果你决定在创建
src/setupTests.js
之前 “eject” ,则生成的package.json
文件将不包含对它的任何引用。因此你应该在 Jest 的配置中手动创建属性setupTestFrameworkScriptFile
, 类似以下内容:
"jest": {
// ...
"setupTestFrameworkScriptFile": "<rootDir>/src/setupTests.js"
}
聚焦问题和排除测试
你可以用 xit()
替换 it()
以临时排除测试被执行。
同样,fit()
可让你专注于特定测试而无需运行任何其他测试。
覆盖率报告
Jest 有一个集成的覆盖率报告器,可以很好地与 ES6 配合使用,无需配置。
运行 npm test -- --coverage
(注意中间额外 --
)会显示这样的覆盖率报告:
请注意,测试运行速度要慢得多,因此建议将其与正常工作流分开运行。
配置
可以通过将以下任何受支持的密钥添加到 package.json 中的 Jest 配置来覆盖默认的 Jest 覆盖率报告配置。
支持的覆盖:
示例 package.json:
{
"name": "your-package",
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!<rootDir>/node_modules/",
"!<rootDir>/path/to/dir/"
],
"coverageThreshold": {
"global": {
"branches": 90,
"functions": 90,
"lines": 90,
"statements": 90
}
},
"coverageReporters": ["text"],
"snapshotSerializers": ["my-serializer-module"]
}
}
持续集成
默认情况下,npm test
使用交互式 CLI 运行 watcher 观察程序。但是,你可以强制它运行一次测试并通过设置名为 CI
的环境变量来完成该过程。
在使用 npm run build
linter 创建应用程序的构建时,默认情况下不会检查警告。与 npm test
类似,你可以通过设置环境变量CI
强制构建执行 linter 警告检查。如果遇到任何警告,则构建失败。
流行的 CI 服务器已默认设置环境变量 CI
,但你也可以自己执行此操作:
在 CI servers 上
Travis CI
- 遵循 Travis入门指南 ,将你的 GitHub 存储库与 Travis 同步。你可能需要在 profile(个人资料) 页面中手动初始化某些设置。
- 将
.travis.yml
文件添加到你的 git 仓库。
language: node_js
node_js:
- 8
cache:
directories:
- node_modules
script:
- npm run build
- npm test
- 使用 git push 触发你的第一个构建。
- 如果需要,自定义 Travis CI Build 。
CircleCI
按照 本文 使用 Create React App 项目设置 CircleCI 。
在你自己的环境中
Windows (cmd.exe)
set CI=true&&npm test
set CI=true&&npm run build
(注意:缺少空格是故意的。)
Windows (Powershell)
($env:CI = "true") -and (npm test)
($env:CI = "true") -and (npm run build)
Linux, macOS (Bash)
CI=true npm test
CI=true npm run build
测试命令将强制 Jest 运行一次测试,而不是启动 watcher(观察器)。
如果你发现自己经常在开发中这样做,请 提交一个 issue 告诉我们你的用例,因为我们希望让观察者获得最佳体验,并且愿意改变其工作方式以适应更多工作流程。
构建命令将检查 linter 警告,如果找到则告警失败。
禁用 jsdom
如果你知道你的测试都不依赖于 jsdom ,你可以安全地设置 --env=node
,你的测试会运行得更快:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
- "test": "react-scripts test"
+ "test": "react-scripts test --env=node"
为了帮助你确定,以下是 需要jsdom 的API列表:
- 任何浏览器全局变量,如
window
和document
ReactDOM.render()
TestUtils.renderIntoDocument()
(以上的 捷径 )- Enzyme 中的
mount()
相反,以下 API 不需要jsdom:
TestUtils.createRenderer()
(浅层渲染)- Enzyme 中的
shallow()
最后,快照测试 也不需要 jsdom 。
快照测试
快照测试是 Jest 的一项功能,它可以自动生成组件的文本快照并将其保存在磁盘上,因此如果 UI 输出发生更改,你将收到通知,而无需在组件输出上手动编写任何断言。详细了解快照测试。
编辑器集成
如果你使用 Visual Studio Code ,则可以使用 Jest 扩展 ,该扩展适用于 Create React App 。这在使用文本编辑器时提供了许多类似 IDE 的功能:显示测试运行的状态,其中包含潜在的内联失败消息,自动启动和停止 watcher(观察程序),以及提供一键式快照更新。