Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Nested Server Components

I've successfully tested one isolated server component by using an async it and awaiting the output of a call to the component as a plain function to pass into render:

  it('renders the user data when user is authenticated', async () => {

    render(await UserData())

    expect(screen.getByTestId('user-data')).toBeInTheDocument();
  });

^ That works and passes.

But I also have a page.tsx server component that renders another server component -- <UserData /> -- nested within it:

'use server'

import styles from './page.module.css';
import LogInOut from "./LogInOut/LogInOut";
import UserData from "./UserData";

export default async function Page() {
  return (
    <main className={styles.main}>
      <h1>Title</h1>
      <LogInOut/>
      <UserData />
    </main>
  );
}

// Note: LogInOut is a client component, removing it doesn't help the problem.

... and if I try the same technique to test this component, i.e.:

  it('renders a heading', async () => {

    render(await Page());

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

    expect(heading).toBeInTheDocument();
  });

^ ...this does not work -- I get an error that reads:

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

How can we test nested server components? I want a solution that allows me to render both the parent and descendent server component in a unit test, without mocking one or the other.

like image 226
Faust Avatar asked Aug 15 '26 22:08

Faust


2 Answers

It seems like there's not much support for react-testing-library, see here. What about using Suspense, have you tried that?

import { render, screen } from "@testing-library/react";
import { Suspense } from "react";

it('renders a heading', async () => {
  render(
    <Suspense>
      <Page />
    </Suspense>
  );

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

  expect(heading).toBeInTheDocument();
});
like image 65
alextrastero Avatar answered Aug 17 '26 11:08

alextrastero


The discussion is still ongoing on Issue 1209 of React Testing Library :

  • For nested async components, you will indeed face an error of trying to render a promise, because the current workaround is to render Server Components in the client, which do not support async Components.
    This custom render function hacks React internals to render server components in tests. It works by taking async children one by one, and prerendering them manually.

  • For simpler cases (no nesting), you should simply using Suspense.

like image 28
jillro Avatar answered Aug 17 '26 11:08

jillro



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!