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

求助:Next 13中如何用Jest测试异步Server Component

Next.js 13+ 异步Server Component的Jest测试方案

直接用React Testing Library渲染异步Server Component会触发Objects are not valid as a React child (found: [object Promise])错误,本质原因是异步组件返回的是Promise而非React元素,React测试工具默认不支持直接渲染异步根组件。以下是可行的解决方法:

方法一:手动解析异步组件Promise

直接调用异步组件函数,等待其返回JSX后再传入render方法:

it('should render without crashing', async () => {
  // 提前mock好getArtist、getArtistAlbums等异步依赖
  jest.mock('../utils/api', () => ({
    getArtist: () => Promise.resolve({ name: 'Bob Dylan' }),
    getArtistAlbums: () => Promise.resolve([])
  }));

  // 手动调用异步组件,获取JSX
  const jsx = await Page({ params: { username: 'Bob Dylan' } });
  // 渲染拿到的JSX
  const { container } = render(jsx);

  // 执行断言
  expect(container.querySelector('h1')).toHaveTextContent('Bob Dylan');
});

方法二:封装异步渲染工具函数

重复手动解析Promise太繁琐,可以封装一个通用工具函数:

// 测试工具文件中定义
async function renderAsync(Component, props = {}) {
  const jsx = await Component(props);
  return render(jsx);
}

// 测试用例中使用
it('should render artist and their albums', async () => {
  // 配置mock
  jest.mock('../utils/api', () => ({
    getArtist: () => Promise.resolve({ name: 'Bob Dylan' }),
    getArtistAlbums: () => Promise.resolve([
      { title: 'Highway 61 Revisited' },
      { title: 'Blonde on Blonde' }
    ])
  }));

  // 使用封装的工具渲染异步组件
  const { container } = await renderAsync(Page, { params: { username: 'Bob Dylan' } });

  // 验证渲染结果
  expect(container.querySelector('h1')).toHaveTextContent('Bob Dylan');
  expect(container.querySelectorAll('.album-title')).toHaveLength(2);
});

注意事项

  • 必须确保所有异步依赖(如数据请求函数)都被正确mock,避免触发真实网络请求
  • 如果组件内部嵌套了其他异步Server Component,同样需要在测试时手动解析或mock其依赖,因为测试环境不会像Next.js服务端那样自动处理异步组件的嵌套解析

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 04:45:16