测试 React 服务器组件

了解如何在 Expo 中为 React 服务器组件编写单元测试。

Android
iOS
Web

本指南涉及仍在开发中的实验性功能 React Server Components。

React 服务器组件 (RSC) 是 React 中的一项新功能,允许你构建在服务器上渲染并可在客户端上水化的组件。本指南详细介绍了如何在你的项目中为 RSC 编写单元测试。

¥React Server Components (RSC) is a new feature in React that allows you to build components that render on the server and can be hydrated on the client. This guide provides details on how to write unit tests for RSC in your project.

Jest 测试

¥Jest testing

React 服务器组件在 Node.js 上运行。这意味着 Jest 本身可以紧密模拟服务器端渲染环境,而基于客户端的测试则需要 Jest 预设才能在 Node.js 和 Web 浏览器之间进行通信。

¥React Server Components run on Node.js. This means Jest on its own can closely emulate the server-side rendering environment, in contrast with client-based tests that require a Jest preset to communicate between Node.js and a web browser.

设置

¥Setup

虽然标准服务器渲染仅适用于 Web,但 Expo 的通用 RSC 为每个平台打包了自定义服务器渲染器。这意味着支持特定于平台的文件扩展名。例如,在为 iOS 应用编写服务器组件时,将解析特定于平台的扩展,例如 *.ios.js 和 *.native.ts。

¥While standard server rendering is web-only, Expo's universal RSC bundles custom server renderers for each platform. This means platform-specific file extensions are supported. For example, when writing Server Components for an iOS app, platform-specific extensions such as *.ios.js and *.native.ts will be resolved.

jest-expo 提供了几个不同的预设来测试服务器组件:

¥jest-expo provides a couple different presets for testing Server Components:

Runner描述
jest-expo/rsc/androidRSC 的 Android 专用运行器。使用 .android.js、.native.js 和 *.js 文件。
jest-expo/rsc/iosRSC 的 iOS 专用运行器。使用 .ios.js、.native.js 和 *.js 文件。
jest-expo/rsc/webRSC 的 Web 专用运行器。使用 *.web.js 和 *.js 文件。
jest-expo/rsc结合上述运行器的多运行器。

要为 RSC 配置 Jest,请在项目的根目录中创建一个 jest-rsc.config.js 文件:

¥To configure Jest for RSC, create a jest-rsc.config.js file in your project's root:

jest-rsc.config.js
module.exports = require('jest-expo/rsc/jest-preset');

然后,你可以将脚本(例如 test:rsc)添加到 package.json:

¥Then, you can add a script such as test:rsc to your package.json:

package.json
{
  "scripts": {
    "test:rsc": "jest --config jest-rsc.config.js"
  }
}

编写测试

¥Writing tests

测试应该写在 rsc_tests 目录中,以防止 Jest 在服务器上运行客户端测试。

¥Tests should be written in a rsc_tests directory to prevent Jest from running your client tests on the server.

__rsc_tests__/my-component.test.ts
/// <reference types="jest-expo/rsc/expect" />

import { LinearGradient } from 'expo-linear-gradient';

it(`renders to RSC`, async () => {
  const jsx = (
    <LinearGradient
      colors={['cyan', '#ff00ff', 'rgba(0,0,0,0)', 'rgba(0,255,255,0.5)']}
      testID="gradient"
    />
  );

  await expect(jsx).toMatchFlight(`1:I["src/LinearGradient.tsx",[],"LinearGradient"]
0:["$","$L1",null,{"colors":["cyan","#ff00ff","rgba(0,0,0,0)","rgba(0,255,255,0.5)"],"testID":"gradient"},null]`);
});

你在测试文件中导入的任何代码都将在服务器环境中运行。你可以导入仅限服务器的模块,如 react-serverserver-only。这对于确定库是否与 RSC 兼容很有用。

¥Any code you import in your test files will run in the server environment. You can import server-only modules like react-server and server-only. This is useful for determining if a library is compatible with RSC.

自定义期望匹配器

¥Custom expect matchers

RSC 的 jest-expo 为 Jest 的 expect 添加了几个自定义匹配器:

¥jest-expo for RSC adds a couple of custom matchers to Jest's expect:

  • toMatchFlight:使用 Expo CLI 中渲染的伪实现渲染 JSX 元素并与航班字符串进行比较。

    ¥toMatchFlight: Render a JSX element using a pseudo-implementation of the render in Expo CLI and compare to a flight string.

  • toMatchFlightSnapshot:与 toMatchFlight 相同,但将航班字符串保存到快照文件。

    ¥toMatchFlightSnapshot: Same as toMatchFlight but saves the flight string to a snapshot file.

在幕后,这些方法处理渲染 RSC 所需的部分框架操作。组件的渲染流被缓冲到字符串并一次性进行比较。你也可以手动流式传输它以观察渲染进度。

¥Behind the scenes, these methods handle a part of the framework operation needed to render RSC. The component's render stream is buffered to a string and compared all at once. You can alternatively stream it manually to observe the rendering progress.

如果组件无法渲染,匹配器将抛出错误以使测试失败。实际上,服务器渲染器将生成一个 E: 行,该行将发送到客户端,以便在本地为用户抛出。

¥If a component fails to render, the matcher will throw an error to fail the test. In practice, the server renderer will generate an E: line, which will sent to the client to be thrown locally for the user.

运行测试

¥Running tests

你可以使用 test:rsc 脚本运行测试:

¥You can run your tests with the test:rsc script:

Terminal
yarn test:rsc --watch

如果你使用的是多运行器,则可以使用 --selectProjects 标志选择特定项目。以下示例仅运行 Web 平台:

¥If you're using the multi-runner, you can select a specific project using the --selectProjects flag. The following example only runs the web platform:

Terminal
yarn test:rsc --watch --selectProjects rsc/web

环境

¥Environments

在 RSC 打包环境中,你可以导入以下文件:

¥In an RSC bundling environment, you can import files like

提示

¥Tips

使用 server-onlyclient-only 模块断言不应在客户端或服务器上导入模块:

¥Use the server-only and client-only modules to assert that a module should not be imported on the client or server:

my-module.js
import 'server-only';

RSC 默认支持包导出。你可以使用 react-server 条件来更改从模块导入的文件:

¥RSC supports package exports by default. You can use the react-server condition to change what file is imported from a module:

package.json
{
  "exports": {
    ".": {
      "react-server": "./index.react-server.js",
      "default": "./index.js"
    }
  }
}

当为 RSC 打包时,所有模块都以 React Server 模式打包,你可以使用 "use client" 指令选择退出。找到 "use client" 后,模块将成为对客户端模块的异步引用。

¥When bundling for RSC, all modules are bundled in React Server mode and you can opt out with the "use client" directive. When "use client" is found, the module becomes an async reference to the client module.

"use server" 不是 "use client" 的对立面。它用于定义 React 服务器函数文件。

¥"use server" is not the opposite of "use client". It is instead used to define a React Server Functions file.