运行测试
注意:
react-scripts@0.3.0
及更高版本提供此功能。¥Note: this feature is available with
react-scripts@0.3.0
and higher.
¥Read the migration guide to learn how to enable it in older projects!
Create React App 使用 Jest 作为其测试运行器。为了准备这个集成,我们做了 Jest 的 重大改造,所以如果你几年前听说过它的坏消息,再试一次。
¥Create React App uses Jest as its test runner. To prepare for this integration, we did a major revamp of Jest so if you heard bad things about it years ago, give it another try.
Jest 是一个基于节点的运行器。这意味着测试总是在 Node 环境中运行,而不是在真实的浏览器中运行。这使我们能够实现快速迭代速度并防止片状。
¥Jest is a Node-based runner. This means that the tests always run in a Node environment and not in a real browser. This lets us enable fast iteration speed and prevent flakiness.
虽然由于 jsdom,Jest 提供了诸如 window
之类的浏览器全局变量,但它们只是真实浏览器行为的近似值。Jest 旨在用于逻辑和组件的单元测试,而不是 DOM 怪癖。
¥While Jest provides browser globals such as window
thanks to jsdom, they are only approximations of the real browser behavior. Jest is intended to be used for unit tests of your logic and your components rather than the DOM quirks.
如果需要,我们建议你使用单独的工具进行浏览器端到端测试。它们超出了 Create React App 的范围。
¥We recommend that you use a separate tool for browser end-to-end tests if you need them. They are beyond the scope of Create React App.
文件名约定
¥Filename Conventions
Jest 将查找具有以下任何流行命名约定的测试文件:
¥Jest will look for test files with any of the following popular naming conventions:
__tests__
文件夹中带有.js
后缀的文件。¥Files with
.js
suffix in__tests__
folders..test.js
后缀的文件。¥Files with
.test.js
suffix..spec.js
后缀的文件。¥Files with
.spec.js
suffix.
.test.js
/ .spec.js
文件(或 __tests__
文件夹)可以位于 src
顶层文件夹下的任何深度。
¥The .test.js
/ .spec.js
files (or the __tests__
folders) can be located at any depth under the src
top level folder.
我们建议将测试文件(或 __tests__
文件夹)放在他们正在测试的代码旁边,以便相对导入看起来更短。比如 App.test.js
和 App.js
在同一个文件夹下,测试只需要 import App from './App'
就可以了,不需要很长的相对路径。搭配还有助于在较大的项目中更快地找到测试。
¥We recommend to put the test files (or __tests__
folders) next to the code they are testing so that relative imports appear shorter. For example, if App.test.js
and App.js
are in the same folder, the test only needs to import App from './App'
instead of a long relative path. Collocation also helps find tests more quickly in larger projects.
命令行接口
¥Command Line Interface
当你运行 npm test
时,Jest 将以监视模式启动*。每次保存文件时,它都会重新运行测试,就像 npm start
如何重新编译代码一样。
¥When you run npm test
, Jest will launch in watch mode*. Every time you save a file, it will re-run the tests, like how 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:
*虽然我们建议在开发期间以监视模式运行测试,但你可以通过传入
--watchAll=false
标志来禁用此行为。在大多数 CI 环境中,这是为你处理的(请参阅 在 CI 服务器上)。¥*Although we recommend running your tests in watch mode during development, you can disable this behavior by passing in the
--watchAll=false
flag. In most CI environments, this is handled for you (see On CI servers).
版本控制集成
¥Version Control Integration
默认情况下,当你运行 npm test
时,Jest 将只运行与自上次提交以来更改的文件相关的测试。这是一项优化,旨在让你的测试快速运行,而不管你有多少测试。但是,它假设你不经常提交未通过测试的代码。
¥By default, when you run npm test
, Jest will only run the tests related to files changed since the last commit. This is an optimization designed to make your tests run fast regardless of how many tests you have. However it assumes that you don’t often commit the code that doesn’t pass the tests.
Jest 总是会明确提到它只运行与自上次提交以来更改的文件相关的测试。你还可以在监视模式下按 a
以强制 Jest 运行所有测试。
¥Jest will always explicitly mention that it only ran tests related to the files changed since the last commit. You can also press a
in the watch mode to force Jest to run all tests.
Jest 将始终在 持续集成 服务器上运行所有测试,或者如果项目不在 Git 或 Mercurial 存储库中。
¥Jest will always run all tests on a continuous integration server or if the project is not inside a Git or Mercurial repository.
编写测试
¥Writing Tests
要创建测试,请添加带有测试名称及其代码的 it()
(或 test()
)块。你可以选择将它们封装在 describe()
块中以进行逻辑分组,但这既不是必需的也不推荐。
¥To create tests, add it()
(or test()
) blocks with the name of the test and its code. You may optionally wrap them in describe()
blocks for logical grouping but this is neither required nor recommended.
Jest 提供了一个内置的 expect()
全局函数来进行断言。基本测试可能如下所示:
¥Jest provides a built-in expect()
global function for making assertions. A basic test could look like this:
import sum from './sum';
it('sums numbers', () => {
expect(sum(1, 2)).toEqual(3);
expect(sum(2, 2)).toEqual(4);
});
Jest 支持的所有 expect()
匹配器都是 在这里广泛记录。
¥All expect()
matchers supported by Jest are extensively documented here.
你还可以使用 jest.fn()
and expect(fn).toBeCalled()
创建“spies”或模拟函数。
¥You can also use jest.fn()
and expect(fn).toBeCalled()
to create “spies” or mock functions.
测试组件
¥Testing Components
组件测试技术范围很广。它们的范围从验证组件渲染是否不会抛出的“冒烟测试”,到浅层渲染和测试某些输出,再到完整渲染和测试组件生命周期和状态更改。
¥There is a broad spectrum of component testing techniques. They range from a “smoke test” verifying that a component renders without throwing, to shallow rendering and testing some of the output, to full rendering and testing component lifecycle and state changes.
不同的项目根据组件更改的频率以及它们包含的逻辑量来选择不同的测试权衡。如果你还没有决定测试策略,我们建议你从为你的组件创建基本的冒烟测试开始:
¥Different projects choose different testing tradeoffs based on how often components change, and how much logic they contain. If you haven’t decided on a testing strategy yet, we recommend that you start with creating basic smoke tests for your components:
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
中找到的测试。
¥This test mounts a component and makes sure that it didn’t throw during rendering. Tests like this provide a lot of value with very little effort so they are great as a starting point, and this is the test you will find in src/App.test.js
.
当你遇到由更改组件引起的错误时,你将更深入地了解它们的哪些部分值得在你的应用中进行测试。这可能是引入更具体的测试断言特定预期输出或行为的好时机。
¥When you encounter bugs caused by changing components, you will gain a deeper insight into which parts of them are worth testing in your application. This might be a good time to introduce more specific tests asserting specific expected output or behavior.
React 测试库
¥React Testing Library
如果你想独立于它们渲染的子组件来测试组件,我们建议使用 react-testing-library
。react-testing-library
是一个用于以类似于终端用户使用组件的方式测试 React 组件的库。它非常适合 React 组件和应用的单元、集成和端到端测试。它更直接地与 DOM 节点一起工作,因此建议与 jest-dom
一起使用以改进断言。
¥If you’d like to test components in isolation from the child components they render, we recommend using react-testing-library
. react-testing-library
is a library for testing React components in a way that resembles the way the components are used by end users. It is well suited for unit, integration, and end-to-end testing of React components and applications. It works more directly with DOM nodes, and therefore it's recommended to use with jest-dom
for improved assertions.
要安装 react-testing-library
和 jest-dom
,你可以运行:
¥To install react-testing-library
and jest-dom
, you can run:
npm install --save @testing-library/react @testing-library/jest-dom
或者你可以使用 yarn
:
¥Alternatively you may use yarn
:
yarn add @testing-library/react @testing-library/jest-dom
如果你想避免测试文件中的样板文件,你可以创建一个 src/setupTests.js
文件:
¥If you want to avoid boilerplate in your test files, you can create a src/setupTests.js
file:
// react-testing-library renders your components to document.body,
// this adds jest-dom's custom assertions
import '@testing-library/jest-dom';
下面是使用 react-testing-library
和 jest-dom
测试 <App />
组件渲染 "学习 React" 的示例。
¥Here's an example of using react-testing-library
and jest-dom
for testing that the <App />
component renders "Learn React".
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
it('renders welcome message', () => {
render(<App />);
expect(screen.getByText('Learn React')).toBeInTheDocument();
});
详细了解 react-testing-library
提供的实用程序,以方便测试异步交互以及从 react-testing-library
文档 和 examples 选择表单元素。
¥Learn more about the utilities provided by react-testing-library
to facilitate testing asynchronous interactions as well as selecting form elements from the react-testing-library
documentation and examples.
使用第三方断言库
¥Using Third Party Assertion Libraries
我们建议你将 expect()
用于断言,将 jest.fn()
用于间谍。如果你遇到问题,请 对 Jest 提起诉讼,我们会解决它们。我们打算继续让它们更好地用于 React,例如支持 将 React 元素漂亮地打印为 JSX。
¥We recommend that you use expect()
for assertions and jest.fn()
for spies. If you are having issues with them please file those against Jest, and we’ll fix them. We intend to keep making them better for React, supporting, for example, pretty-printing React elements as JSX.
但是,如果你习惯了其他库,例如 Chai 和 Sinon,或者如果你有使用它们的现有代码并希望移植过来,则可以像这样正常导入它们:
¥However, if you are used to other libraries, such as Chai and Sinon, or if you have existing code using them that you’d like to port over, you can import them normally like this:
import sinon from 'sinon';
import { expect } from 'chai';
然后像往常一样在测试中使用它们。
¥and then use them in your tests like you normally do.
初始化测试环境
¥Initializing Test Environment
注意:
react-scripts@0.4.0
及更高版本提供此功能。¥Note: this feature is available with
react-scripts@0.4.0
and higher.
如果你的应用使用你需要在测试中模拟的浏览器 API,或者如果你需要在运行测试之前进行全局设置,请将 src/setupTests.js
添加到你的项目中。它将在运行测试之前自动执行。
¥If your app uses a browser API that you need to mock in your tests or if you need a global setup before running your tests, add a src/setupTests.js
to your project. It will be automatically executed before running your tests.
例如:
¥For example:
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 的配置中手动创建属性setupFilesAfterEnv
,如下所示:¥Note: Keep in mind that if you decide to "eject" before creating
src/setupTests.js
, the resultingpackage.json
file won't contain any reference to it, so you should manually create the propertysetupFilesAfterEnv
in the configuration for Jest, something like the following:
"jest": {
// ...
"setupFilesAfterEnv": ["<rootDir>/src/setupTests.js"]
}
聚焦和排除测试
¥Focusing and Excluding Tests
你可以将 it()
替换为 xit()
以暂时排除正在执行的测试。
¥You can replace it()
with xit()
to temporarily exclude a test from being executed.
同样,fit()
可让你专注于特定测试,而无需运行任何其他测试。
¥Similarly, fit()
lets you focus on a specific test without running any other tests.
覆盖率报告
¥Coverage Reporting
Jest 有一个集成的覆盖率报告器,可以很好地与 ES6 配合使用并且不需要配置。
¥Jest has an integrated coverage reporter that works well with ES6 and requires no configuration.
运行 npm test -- --coverage
(注意中间有额外的 --
)以包含如下覆盖率报告:
¥Run npm test -- --coverage
(note extra --
in the middle) to include a coverage report like this:
请注意,覆盖范围内的测试运行速度要慢得多,因此建议将其与正常工作流程分开运行。
¥Note that tests run much slower with coverage so it is recommended to run it separately from your normal workflow.
配置
¥Configuration
可以通过将以下任何受支持的键添加到 package.json 中的 Jest 配置来覆盖 Create React App 用于 Jest 的 默认配置。
¥The default configuration that Create React App uses for Jest can be overridden by adding any of the following supported keys to a Jest config in your package.json.
支持的覆盖:
¥Supported overrides:
示例 package.json:
¥Example 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"]
}
}
持续集成
¥Continuous Integration
默认情况下,npm test
使用交互式 CLI 运行监视器。但是,你可以强制它运行一次测试并通过设置一个名为 CI
的环境变量来完成该过程。
¥By default npm test
runs the watcher with interactive CLI. However, you can force it to run tests once and finish the process by setting an environment variable called CI
.
使用 npm run build
linter 创建应用构建时,默认情况下不会检查警告。和 npm test
一样,可以通过设置环境变量 CI
强制构建执行 linter 警告检查。如果遇到任何警告,则构建失败。
¥When creating a build of your application with npm run build
linter warnings are not checked by default. Like npm test
, you can force the build to perform a linter warning check by setting the environment variable CI
. If any warnings are encountered then the build fails.
流行的 CI 服务器已经默认设置了环境变量 CI
,但你也可以自己设置:
¥Popular CI servers already set the environment variable CI
by default but you can do this yourself too:
在 CI 服务器上
¥On CI servers
Travis CI
按照 Travis 入门 指南将你的 GitHub 存储库与 Travis 同步。你可能需要在 profile 页面中手动初始化一些设置。
¥Following the Travis Getting started guide for syncing your GitHub repository with Travis. You may need to initialize some settings manually in your profile page.
将
.travis.yml
文件添加到你的 git 存储库。¥Add a
.travis.yml
file to your git repository.
language: node_js
node_js:
- 8
cache:
directories:
- node_modules
script:
- npm run build
- npm test
使用 git push 触发你的第一个构建。
¥Trigger your first build with a git push.
自定义你的 Travis CI 构建 如果需要的话。
¥Customize your Travis CI Build if needed.
CircleCI
按照 本文 使用 Create React App 项目设置 CircleCI。
¥Follow this article to set up CircleCI with a Create React App project.
在你自己的环境中
¥On your own environment
Windows (cmd.exe)
set CI=true&&npm test
set CI=true&&npm run build
(注意:缺少空格是有意的。)
¥(Note: the lack of whitespace is intentional.)
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
test 命令将强制 Jest 在 CI 模式下运行,并且测试将只运行一次而不是启动 watcher。
¥The test command will force Jest to run in CI-mode, and tests will only run once instead of launching the watcher.
对于非 CI 环境,你可以传递 --watchAll=false
标志来禁用测试监视。
¥For non-CI environments, you can pass the --watchAll=false
flag to disable test-watching.
build 命令将检查 linter 警告,如果发现则失败。
¥The build command will check for linter warnings and fail if any are found.
禁用 jsdom
¥Disabling jsdom
如果你知道你的所有测试都不依赖于 jsdom,你可以安全地设置 --env=node
,并且你的测试将运行得更快:
¥If you know that none of your tests depend on jsdom, you can safely set --env=node
, and your tests will run faster:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
- "test": "react-scripts test"
+ "test": "react-scripts test --env=node"
为了帮助你做出决定,这里列出了需要 jsdom 的 API:
¥To help you make up your mind, here is a list of APIs that need jsdom:
任何浏览器全局变量,如
window
和document
¥Any browser globals like
window
anddocument
TestUtils.renderIntoDocument()
(以上为 捷径)¥
TestUtils.renderIntoDocument()
(a shortcut for the above)
相反,以下 API 不需要 jsdom:
¥In contrast, jsdom is not needed for the following APIs:
TestUtils.createRenderer()
(浅渲染)¥
TestUtils.createRenderer()
(shallow rendering)
最后,快照测试 也不需要 jsdom。
¥Finally, jsdom is also not needed for snapshot testing.
快照测试
¥Snapshot Testing
快照测试是 Jest 的一项功能,它会自动生成组件的文本快照并将它们保存在磁盘上,因此如果 UI 输出发生变化,你会收到通知,而无需在组件输出上手动编写任何断言。阅读有关快照测试的更多信息。
¥Snapshot testing is a feature of Jest that automatically generates text snapshots of your components and saves them on the disk so if the UI output changes, you get notified without manually writing any assertions on the component output. Read more about snapshot testing.
编辑器集成
¥Editor Integration
如果你使用 Visual Studio Code,则有一个 Jest 扩展 可以开箱即用地与 Create React App 配合使用。这在使用文本编辑器时提供了许多类似 IDE 的功能:显示带有内联潜在失败消息的测试运行状态,自动启动和停止监视器,并提供一键式快照更新。
¥If you use Visual Studio Code, there is a Jest extension which works with Create React App out of the box. This provides a lot of IDE-like features while using a text editor: showing the status of a test run with potential fail messages inline, starting and stopping the watcher automatically, and offering one-click snapshot updates.