You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试嵌套的React Server Components?孤立测试有效但嵌套报错

解决方案:递归解析异步Server Component树

问题根源

单独测试UserData时,await UserData()直接拿到了组件执行后的最终JSX,渲染自然正常。但测试Page时,await Page()仅完成了Page自身的执行,返回的JSX里的<UserData />只是一个未触发执行的React组件元素——测试环境下的React不会自动处理嵌套的异步Server Component,渲染时会把UserData返回的Promise当作React子元素,从而抛出"Objects are not valid as a React child"错误。

实现方案

写一个递归函数,遍历组件树中的所有元素,自动执行并await所有异步组件的结果,把整个组件树解析为纯同步JSX后再渲染。

1. 编写异步组件解析工具函数

import React from 'react';

async function resolveAsyncComponents(element) {
  // 处理异步组件函数
  if (typeof element.type === 'function' && element.type.constructor.name === 'AsyncFunction') {
    const resolvedElement = await element.type(element.props);
    return resolveAsyncComponents(resolvedElement);
  }
  // 处理React元素,递归解析子元素
  if (React.isValidElement(element)) {
    const resolvedChildren = await Promise.all(
      React.Children.map(element.props.children, resolveAsyncComponents)
    );
    return React.cloneElement(element, element.props, resolvedChildren);
  }
  // 处理数组类型的子元素
  if (Array.isArray(element)) {
    return Promise.all(element.map(resolveAsyncComponents));
  }
  // 普通值直接返回
  return element;
}

2. 修改测试代码

用上述工具函数解析Page组件后再渲染:

it('renders a heading', async () => {
  // 递归解析所有异步组件,得到纯同步JSX
  const resolvedJSX = await resolveAsyncComponents(<Page />);
  render(resolvedJSX);

  const heading = screen.getByRole('heading', { level: 1 });
  expect(heading).toBeInTheDocument();
});

原理说明

这个工具函数会递归遍历整个组件树:

  • 识别并执行所有异步组件函数,await其返回的JSX
  • 对每个React元素,递归解析它的所有子元素
  • 最终返回完全解析后的纯同步JSX结构,此时再传入render就不会出现Promise作为子元素的问题

内容的提问来源于stack exchange,提问作者Faust

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 12:25:30