了解如何在使用 Expo Router 时为你的应用创建集成测试。
Expo Router 依赖于你的文件系统,这在为集成测试设置模拟时可能会带来挑战。Expo Router 的子模块 expo-router/testing-library
是一组构建在流行的 @testing-library/react-native
之上的测试实用程序,允许你快速创建预先配置用于测试的内存中 Expo Router 应用。
¥Expo Router relies on your file system, which can present challenges when setting up mocks for integration tests. Expo Router's submodule, expo-router/testing-library
, is a set of testing utilities built on top of the popular @testing-library/react-native
and allows you to quickly create in-memory Expo Router apps that are pre-configured for testing.
¥Configuration
在继续之前,请确保你已根据项目中的 使用 Jest 进行单元测试 和 @testing-library/react-native
设置了 jest-expo
。
¥Before you proceed, ensure you have set up jest-expo
according to the Unit testing with Jest and @testing-library/react-native
in your project.
注意:使用 Expo Router 时,请勿将测试文件放在应用目录中。应用文件夹中的所有文件都必须是路由或布局文件。而是使用 tests 目录或单独的目录。这种方法在 使用 Jest 进行单元测试 中进行了解释。
¥Note: When using Expo Router, do not put your test files inside the app directory. All files inside your app folder must be either routes or layout files. Instead, use the tests directory or a separate directory. This approach is explained in Unit testing with Jest.
¥Jest Native Matchers (optional)
@testing-library/jest-native
提供了自定义 Jest 匹配器,可用于扩展 @testing-library/react-native
的功能。如果安装,Expo Router 将自动执行 @testing-library/jest-native
设置。
¥@testing-library/jest-native
provides custom Jest matchers that can be used to extend the functionality of @testing-library/react-native
. If installed, Expo Router will automatically perform the @testing-library/jest-native
setup.
renderRouter
renderRouter
扩展了 render
的功能,以简化 Expo Router 的测试。它返回与 render
相同的查询对象,并且兼容 screen
,允许你使用标准 查询接口 来定位组件。
¥renderRouter
extends the functionality of render
to simplify testing with Expo Router. It returns the same query object as render
, and is compatible with screen
, allowing you to use the standard query API to locate components.
renderRouter
接受与 render
相同的 options,并引入了一个附加选项 initialUrl
,该选项设置用于模拟深度链接的初始路由。
¥renderRouter
accepts the same options as render
and introduces an additional option initialUrl
, which sets an initial route for simulating deep-linking.
Inline file system
renderRouter(mock: Record<string, ReactComponent>, options: RenderOptions)
renderRouter
可以通过将对象作为第一个参数传递给该函数来提供文件系统的内联模拟。该对象的键是模拟文件系统路径。定义这些路径并排除文件扩展名时,请勿使用前导相对 (./
) 或绝对 (/
) 表示法。
¥renderRouter
can provide inline-mocking of a file system by passing an object to this function as the first parameter. The keys of the object are the mock filesystem paths. Do not use leading relative (./
) or absolute (/
) notation when defining these paths and exclude file extension.
import { renderRouter, screen } from 'expo-router/testing-library';
it('my-test', async () => {
const MockComponent = jest.fn(() => <View />);
renderRouter(
{
index: MockComponent,
'directory/a': MockComponent,
'(group)/b': MockComponent,
},
{
initialUrl: '/directory/a',
}
);
expect(screen).toHavePathname('/directory/a');
});
Inline file system with `null` components
renderRouter(mock: string[], options: RenderOptions)
向 renderRouter
提供字符串数组将创建带有 null
组件 ({ default: () => null }
) 的内联模拟文件系统。这对于不需要测试路由输出的测试场景非常有用。
¥Providing an array of strings to renderRouter
will create an inline mock filesystem with null
components ({ default: () => null }
). This is useful for testing scenarios where you do not need to test the output of a route.
import { renderRouter, screen } from 'expo-router/testing-library';
it('my-test', async () => {
renderRouter(['index', 'directory/a', '(group)/b'], {
initialUrl: '/directory/a',
});
expect(screen).toHavePathname('/directory/a');
});
Path to fixture
renderRouter(fixturePath: string, options: RenderOptions)
renderRouter
可以接受目录路径来模拟现有的装置。确保提供的路径相对于当前测试文件。
¥renderRouter
can accept a directory path to mock an existing fixture. Ensure that the provided path is relative to the current test file.
it('my-test', async () => {
const MockComponent = jest.fn(() => <View />);
renderRouter('./my-test-fixture');
});
Path to the fixture with overrides
renderRouter({ appDir: string, overrides: Record<string, ReactComponent>}, options: RenderOptions)
对于更复杂的测试场景,renderRouter
可以同时利用目录路径和内联模拟方法。appDir
参数采用表示目录路径名的字符串。overrides 参数是一个内联模拟,可用于覆盖 appDir
中的特定路径。这种组合允许对模拟环境进行微调控制。
¥For more intricate testing scenarios, renderRouter
can leverage both directory path and inline-mocking methods simultaneously. The appDir
parameter takes a string representing a pathname to a directory. The overrides parameter is an inline mock that can be used to override specific paths within the appDir
. This combination allows for fine-tuned control over the mock environment.
it('my-test', async () => {
const MockAuthLayout = jest.fn(() => <View />);
renderRouter({
appDir: './my-test-fixture',
overrides: {
'directory/(auth)/_layout': MockAuthLayout,
},
});
});
¥Jest matchers
以下匹配已添加到 expect
,可用于在 screen
上声明值。
¥The following matches have been added to expect
and can be used to assert values on screen
.
toHavePathname()
针对给定字符串断言当前路径名。匹配器使用当前 screen
上的 usePathname
钩子的值。
¥Assert the current pathname against a given string. The matcher uses the value of the usePathname
hook on the current screen
.
expect(screen).toHavePathname('/my-router');
toHavePathnameWithParams()
针对给定字符串断言当前路径名,包括 URL 参数。这对于断言 URL 在 Web 浏览器中的出现很有用。
¥Assert the current pathname, including URL parameters, against a given string. This is useful to assert the appearance of URL in a web browser.
expect(screen).toHavePathnameWithParams('/my-router?hello=world');
toHaveSegments()
针对字符串数组断言当前段。匹配器使用当前 screen
上的 useSegments
钩子的值。
¥Assert the current segments against an array of strings. The matcher uses the value of the useSegments
hook on the current screen
.
expect(screen).toHaveSegments(['[id]']);
useLocalSearchParams()
针对对象断言当前本地 URL 参数。匹配器使用当前 screen
上的 useLocalSearchParams
钩子的值。
¥Assert the current local URL parameters against an object. The matcher uses the value of the useLocalSearchParams
hook on the current screen
.
expect(screen).useLocalSearchParams({ first: 'abc' });
useGlobalSearchParams()
断言当前屏幕的路径名与某个值匹配。使用 useGlobalSearchParams
钩子的值进行比较。
¥Assert the current screen's pathname that matches a value. Compares using the value of useGlobalSearchParams
hook.
针对对象断言当前全局 URL 参数。匹配器使用当前 screen
上的 useGlobalSearchParams
钩子的值。
¥Assert the current global URL parameters against an object. The matcher uses the value of the useGlobalSearchParams
hook on the current screen
.
expect(screen).useGlobalSearchParams({ first: 'abc' });
toHaveRouterState()
一种高级匹配器,用于针对对象断言当前路由状态。
¥An advanced matcher that asserts the current router state against an object.
expect(screen).toHaveRouterState({
routes: [{ name: 'index', path: '/' }],
});