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

如何在Jest中测试Next.js 13异步Page组件?

Next.js 13 异步Page组件的Jest单元测试问题解决

我编写了一个Next.js 13的异步Page组件,内部调用API获取数据并传递给子组件。使用Jest进行单元测试时,无法渲染该异步函数组件,报错提示“Objects are not valid as a React child (found: [object Promise])”。尝试异步渲染无效,且不想将组件改为客户端组件(通过useEffect调用API),询问如何在Jest中渲染该异步组件。

组件代码

export default async function Home() {
  const participantsData: ParticipantInfo[] = await getParticipantsInfo();

  return (
    <div data-testid="home-page">
        <ParticipantsTable participantsInfo={participantsData} />
    </div>
  );
}

测试代码

const getRender = (): RenderResult => {
  return render(<Home />);
};

global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () => Promise.resolve(participantsMockData),
  }),
) as jest.Mock;

describe("Home Page Tests", () => {
  it("renders Home Page Component", async () => {
    getRender();

    expect(screen.getByTestId("home-page")).toBeDefined();
  });
});

报错信息

console.error
    Error: Uncaught [Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.]
        at reportException (C:\git\axo-auth-ui\node_modules\jsdom\lib\jsdom\living\helpers\runtime-script-errors.js:66:24)
        at innerInvokeEventListeners (C:\git\axo-auth-ui\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:353:9)
        at invokeEventListeners (C:\git\axo-auth-ui\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:286:3)
        at HTMLUnknownElementImpl._dispatch (C:\git\axo-auth-ui\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:233:9)
        at HTMLUnknownElementImpl.dispatchEvent (C:\git\axo-auth-ui\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:104:17)
        at HTMLUnknownElement.dispatchEvent (C:\git\axo-auth-ui\node_modules\jsdom\lib\jsdom\living\generated\EventTarget.js:241:34)
        at Object.invokeGuardedCallbackDev (C:\git\axo-auth-ui\node_modules\react-dom\cjs\react-dom.development.js:4213:16)
        at invokeGuardedCallback (C:\git\axo-auth-ui\node_modules\react-dom\cjs\react-dom.development.js:4277:31)
        at beginWork$1 (C:\git\axo-auth-ui\node_modules\react-dom\cjs\react-dom.development.js:27451:7)
        at performUnitOfWork (C:\git\axo-auth-ui\node_modules\react-dom\cjs\react-dom.development.js:26560:12)
        at workLoopSync (C:\git\axo-auth-ui\node_modules\react-dom\cjs\react-dom.development.js:26466:5)
        at renderRootSync (C:\git\axo-auth-ui\node_modules\react-dom\cjs\react-dom.development.js:26434:7)
        at performConcurrentWorkOnRoot (C:\git\axo-auth-ui\node_modules\react-dom\cjs\react-dom.development.js:25738:74)

解决方案

原因

Next.js 13的异步Page属于Server Components,直接在Jest中渲染时会返回Promise对象,而React无法直接渲染Promise,因此抛出错误。

方法1:用Suspense包裹组件并等待渲染

在测试代码中用React的Suspense组件包裹异步Page,同时使用waitFor等待组件加载完成:

import { Suspense } from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import Home from '../app/page'; // 请根据实际路径调整

global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () => Promise.resolve(participantsMockData),
  }),
) as jest.Mock;

describe("Home Page Tests", () => {
  it("renders Home Page Component", async () => {
    render(
      <Suspense fallback={<div>Loading...</div>}>
        <Home />
      </Suspense>
    );

    await waitFor(() => {
      expect(screen.getByTestId("home-page")).toBeInTheDocument();
    });
  });
});

方法2:直接await异步组件的返回结果

异步组件本质是返回Promise,因此可以先等待组件执行完成,再渲染其返回的JSX:

import { render, screen } from '@testing-library/react';
import Home from '../app/page'; // 请根据实际路径调整

global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () => Promise.resolve(participantsMockData),
  }),
) as jest.Mock;

describe("Home Page Tests", () => {
  it("renders Home Page Component", async () => {
    const homeJSX = await Home();
    render(homeJSX);

    expect(screen.getByTestId("home-page")).toBeInTheDocument();
  });
});

注意事项

  • 确保getParticipantsInfo内部使用的是你mock的global.fetch,否则mock不会生效;如果用的是Next.js自带的fetch,需要改为mocknext/fetch模块。
  • 测试中尽量使用toBeInTheDocument()替代toBeDefined(),更符合React Testing Library的最佳实践。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 04:57:07