了解如何设置和配置 jest-expo 包来为项目编写单元测试和快照测试。
Jest 是使用最广泛的 JavaScript 单元测试框架。在本指南中,你将了解如何在项目中设置 Jest、编写单元测试、快照测试,以及在将 Jest 与 React Native 结合使用时构建测试的最佳实践。
¥Jest is the most widely used JavaScript unit testing framework. In this guide, you'll learn how to set up Jest in your project, write a unit test, write a snapshot test, and best practices for structuring your tests when using Jest with React Native.
你还将使用 jest-expo
包,这是一个 Jest 预设,模拟 Expo SDK 的原生部分并处理大部分配置。
¥You'll also use the jest-expo
package, which is a Jest preset and mocks the native part of the Expo SDK and handles most of the configuration.
¥Installation
要在项目中安装 jest-expo
,请运行以下命令:
¥To install jest-expo
in your project, run the following command:
# For all other package managers
-
npx expo install -- --save-dev jest-expo jest
# For yarn
-
yarn add -D jest-expo jest
如果你使用 TypeScript,则还要安装@types/jest
作为开发依赖。
然后,更新 package.json 以添加用于运行测试的脚本,并添加使用 jest-expo
中的基本配置的预设:
¥Then, update package.json to add a script for running tests and add the preset for using the base configuration from jest-expo
:
"scripts": {
%%placeholder-start%%... %%placeholder-end%%
"test": "jest"
},
%%placeholder-start%%... %%placeholder-end%%
"jest": {
"preset": "jest-expo"
}
¥Configuration
你可以使用的起始配置是确保在运行 Jest 时转换你在 node_modules 目录中使用的任何模块。这可以通过包含采用正则表达式模式作为其值的 transformIgnorePatterns
属性来完成:
¥A starting configuration you can use is to make sure any modules you are using within the node_modules directory are transpiled when running Jest. This can be done by including the transformIgnorePatterns
property that takes a regex pattern as its value:
"jest": {
"preset": "jest-expo",
"transformIgnorePatterns": [
"node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg)"
]
}
"jest": {
"preset": "jest-expo",
"transformIgnorePatterns": [
"node_modules/(?!(?:.pnpm/)?((jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg))"
]
}
Jest 有多种配置选项。以上配置可以满足你的大部分需求。但是,你始终可以添加到此模式列表中。详细信息请参见 配置 Jest。
¥Jest has various configuration options. The above configuration covers the majority of your needs. However, you can always add to this pattern list. For more details, see Configuring Jest.
¥Unit test
单元测试用于检查最小的代码单元,通常是一个函数。
¥A unit test is used to check the smallest unit of code, usually a function.
要编写第一个单元测试,请首先为 App.js 编写一个简单的测试。为其创建一个测试文件并将其命名为 App.test.js。Jest 将扩展名为 .test.js 的文件识别为测试并将其包含在测试队列中。还有其他方法可以实现 构建测试。
¥To write your first unit test, start by writing a simple test for App.js. Create a test file for it and call it App.test.js. Jest identifies a file with the .test.js extension as a test and includes it in the tests queue. There are also other ways to structure a test.
该测试预计 <App />
组件的状态有一个子元素:
¥The test will expect the state of the <App />
component to have one child element:
import React from 'react';
import renderer from 'react-test-renderer';
import App from './App';
describe('<App />', () => {
it('has 1 child', () => {
const tree = renderer.create(<App />).toJSON();
expect(tree.children.length).toBe(1);
});
});
如果你使用的是 TypeScript,请使用 .ts 或 .tsx 文件扩展名。
运行测试:
¥To run the test:
-
npm run test
如果一切顺利,你应该会看到一项测试已通过。欲了解更多信息,请参阅 期望和条件匹配器。
¥If everything goes well, you should see the one test passed. For more information, see expect and conditional matchers.
¥Structure your tests
现在,项目目录中有一个测试文件。添加更多测试文件可能会使组织项目目录变得困难。避免这种情况的最简单方法是创建一个 tests 目录并将所有测试放入其中。
¥Right now, you have a single test file in the project directory. Adding more test files can make it hard to organize your project directory. The easiest way to avoid this is to create a tests directory and put all your tests inside it.
示例结构如下所示:
¥An example structure is shown below:
__tests__
components
button.test.js
navigation
mainstack.test.js
screens
home.test.js
src
components
button.js
navigation
mainstack.js
screens
home.js
但是这种方式会导致很多长导入路径,比如 ../../src/components/button
。
¥However, this approach causes a lot of long import paths, such as ../../src/components/button
.
或者,你可以为项目的不同区域设置多个 tests 子目录。例如,为组件、导航等创建单独的测试目录:
¥Alternatively, you can have multiple tests sub-directories for different areas of your project. For example, create a separate test directory for components, navigation, and so on:
src
components
button.js
__tests__
button.test.js
现在,如果将 tests 移动到组件目录中,则 button.test.js 中 <Button>
的导入路径将是 ../button
。
¥Now, if you move tests within the components directory, the import path of <Button>
in the the button.test.js will be ../button
.
测试/文件结构的另一个选项:
¥Another option for test/file structure:
src
components
button.js
button.style.js
button.test.js
这完全取决于偏好,并由你决定如何组织项目目录。
¥It's all about preferences and up to you to decide how you want to organize your project directory.
¥Snapshot test
快照测试用于确保 UI 保持一致,尤其是当项目使用可能跨组件共享的全局样式时。欲了解更多信息,请参阅 快照测试。
¥A snapshot test is used to make sure that UI stays consistent, especially when a project is working with global styles that are potentially shared across components. For more information, see snapshot testing.
要为 <App />
添加快照测试,请在 App.test.js 中的 describe()
中添加以下代码片段:
¥To add a snapshot test for <App />
, add the following code snippet in the describe()
in App.test.js:
it('renders correctly', () => {
const tree = renderer.create(<App />).toJSON();
expect(tree).toMatchSnapshot();
});
运行 npm run test
命令,如果一切顺利,你应该看到创建的快照并通过了两个测试。
¥Run npm run test
command, and if everything goes well, you should see a snapshot created and two tests passed.
¥Code coverage reports
代码覆盖率报告可以帮助你了解有多少代码经过了测试。
¥Code coverage reports can help you understand how much of your code is tested.
如果你想使用 HTML 格式查看项目中的代码覆盖率报告,请将以下内容添加到 package.json 中:
¥If you'd like to see code coverage report in your project using the HTML format, add the following to the package.json:
"jest": {
...
"collectCoverage": true,
"collectCoverageFrom": [
"**/*.{js,jsx}",
"!**/coverage/**",
"!**/node_modules/**",
"!**/babel.config.js",
"!**/jest.setup.js"
]
}
添加上述代码片段允许 Jest 收集不在 coverage 或 node_modules 目录内的所有.js 和.jsx 文件的覆盖范围。它还排除 babel.config.js 和 jest.setup.js 文件。你可以在此列表中添加或删除更多内容以满足你的需求。
¥Adding the above snippet allows Jest to collect coverage of all .js and .jsx files that are not inside the coverage or node_modules directories. It also excludes the babel.config.js and jest.setup.js files. You can add or remove more to this list to match your needs.
运行 npm run test
。你应该会看到在项目中创建了一个覆盖目录。在此目录中找到 index.html 文件,然后双击在浏览器中将其打开以查看覆盖率报告。
¥Run npm run test
. You should see a coverage directory created in your project. Find the index.html file within this directory and double-click to open it up in a browser to see the coverage report.
通常,我们不建议将 index.html 文件上传到 git。为了防止它被跟踪,你可以在 .gitignore 文件中添加
coverage/**/*
。¥Usually, we don't recommend uploading index.html file to git. To prevent it from being tracked, you can add
coverage/**/*
in the .gitignore file.
¥Optional: Jest flows
你还可以使用不同的流程来运行测试。以下是你可以尝试的一些示例脚本:
¥You can also use different flows to run your tests. Below are a few example scripts that you can try:
"scripts": {
...
// active development of tests, watch files for changes and re-runs all tests
"test": "jest --watch --coverage=false --changedSince=origin/main",
// debug, console.logs and only re-runs the file that was changed
"testDebug": "jest -o --watch --coverage=false",
// displays code coverage in cli and updates the code coverage html
"testFinal": "jest",
// when a screen/component is updated, the test snapshots will throw an error, this updates them
"updateSnapshots": "jest -u --coverage=false"
}
有关更多信息,请参阅 Jest 文档中的 CLI 选项。
¥For more information, see CLI Options in Jest documentation.
¥More
你还可以使用 React Native 测试库,它提供鼓励良好测试实践并与 Jest 配合使用的测试实用程序。
了解如何在使用 Expo Router 时为你的应用创建集成测试。