首页指南参考教程

测试 Expo Router 的配置

了解如何在使用 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 匹配器(可选)

¥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.

app.test.tsx
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.

app.test.tsx
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.

app.test.js
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.

app.test.js
it('my-test', async () => {
  const MockAuthLayout = jest.fn(() => <View />);
  renderRouter({
    appDir: './my-test-fixture',
    overrides: {
      'directory/(auth)/_layout': MockAuthLayout,
    },
  });
});

Jest 匹配器

¥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.

app.test.ts
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.

app.test.ts
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.

app.test.ts
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.

app.test.ts
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.

app.test.ts
expect(screen).useGlobalSearchParams({ first: 'abc' });

toHaveRouterState()

一种高级匹配器,用于针对对象断言当前路由状态。

¥An advanced matcher that asserts the current router state against an object.

app.test.ts
expect(screen).toHaveRouterState({
  routes: [{ name: 'index', path: '/' }],
});
Expo 中文网 - 粤ICP备13048890号