Exploring the functionality of an asynchronous server component using Jest within Next 13

When working with NextJs 13+ and the experimental App folder, it is possible to write async server components according to the documentation:

export default async function Page({ params: { username } }) {
  // Initiate both requests in parallel
  const artistData = getArtist(username);
  const albumsData = getArtistAlbums(username);

  // Wait for the promises to resolve
  const [artist, albums] = await Promise.all([artistData, albumsData]);

  return (
    <>
      <h1>{artist.name}</h1>
      <Albums list={albums}></Albums>
    </>
  );
}

I have found this to be a valuable technique that I have applied in multiple areas of my application. However, when attempting to write tests using jest, I encounter difficulties rendering the default export:

it('should render without crashing', async () => {
  ...(set up mocks)
  const { container } = await waitFor(() => render(<Page params={{ username: 'Bob Dylan' }} />));
});

Every effort to render the component manually or through a test results in the error message:

Uncaught [Error: Objects are not valid as a React child (found: [object Promise])

Has anyone successfully managed to write a Jest test for an async server component?

Answer №1

Currently, there is no official method for achieving this task. However, you can employ the following workaround:

it('should render without crashing', async () => {
  // ...(setup mocks)
  render(await Page({params: {username: 'Bob Dylan' }}))
});

Although not ideal, this workaround serves as the current solution. For additional information, refer to this issue.

Answer №2

To test asynchronous components that do not rely on other React Suspense Components or application routing features in React 18.3 (canary), follow these steps:

import { render, screen } from '@testing-library/react';
import { Suspense } from 'react';
import Page from './page';

it('should render without any issues', async () => {
  render(
    <Suspense>
      <Page params={{ username: 'Bob Dylan' }} />
    </Suspense>
  );
  await screen.findByRole('heading');
  expect(screen.getByRole('listitem')).toBeInTheDocument();
});

If your test suite heavily relies on asynchronous components, consider using a custom render function to streamline the setup process.

For scenarios where you require other React Suspense Components (such as server actions) or application routing features (like layouts), utilize hard coding, mocks, or an end-to-end testing framework until native RSC rendering is supported in #1209.

Answer №3

Search for the specific github issue

const asyncLoadComponent = async function loadResolvedComponent(component: any, props?: any) {
const resolvedComponent = await component(props);
return () => resolvedComponent;
}
describe("AboutUs component test", () => {
it("Should render content in French", async () => {
const AboutUsResolved = await asyncLoadComponent(AboutUs, {
  parameters: { language: "fr" },
});

const BackToResolved = await asyncLoadComponent(Backto, { customStyles: "" });
render(<AboutUsResolved />);
render(<BackToResolved />);
// Wait for all promises to resolve
await screen.getByTestId("about_us_first_p");

const firstParagraph = screen.getByTestId("about_us_first_p");

// Check if the displayed text content matches the expected value
expect(firstParagraph.textContent).toContain("Example");
 });
 });

Answer №4

I patiently awaited the transformation of the async component into a React Node. Here's how I did it:

render(
        await (async () => await AsyncComponent())()
    )

The ongoing conversation regarding this issue can be found on the discussion thread on Github. The developers at NextJS even suggest using @//ts-expect-error, arguing that the TypeScript team needs to address this immediately.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Explore the titles provided by Wikipedia

Hi there, I'm fairly new to Angular and trying to work with the Wikipedia API. However, I seem to be having trouble getting 4 titles from the API. Here's an example URL for one of the titles: https://en.wikipedia.org/w/api.php?action=query&pr ...

A beginner's guide to integrating ChartJS with React

Trying to incorporate ChartJS into a React component but unsure of how to proceed. First step is to create a canvas element following the instructions found at https://www.chartjs.org/docs/latest/getting-started/usage.html#creating-a-chart. Next, need to ...

Troubleshooting the Hide/Show feature in React Native

As a newcomer to React Native development, I am attempting something simple. Within a React Class extending Component, I have 4 components <TouchableOpacity>. In the render function, my goal is to hide three of these components while pressing on one ...

What could be causing the delay in the execution of Redux dispatch?

When I open a file and parse it, the dispatch into redux state takes longer than anticipated. It seems like the dispatch itself is taking several hundred milliseconds more than the reducer. After opening and parsing the file, the following dispatch is mad ...

When adding a string to an array, the " " tag is automatically included

Within my program, there is a loop that looks like the following- this.storeData.StudentList.forEach(pStudent => { studentName += pStudent.Name + '\n' }); console.log(studentName); array.push(studentName); console.log(array); When I p ...

Error in Next.js: Trying to access undefined properties while reading 'shallow'

In my attempt to intercept route changes based on a boolean value indicating unsaved changes, I encountered difficulties. Despite referencing discussions on the topic and trying to implement solutions from relevant sources, I faced issues where the 'C ...

Selecting an object dynamically to add a new property in JavaScript

I am faced with a scenario where I have two objects and I need to add new properties to them. The challenge is that I want to be able to choose which object to work with first before adding the new properties. Here's the proposed logic : let customiz ...

Retrieve the API Url within an Angular application built with .Net Core

My current setup includes an API project and an Angular Project within the same .NetCore solution. The Angular Project makes API calls to the API project using a baseurl specified in the Environment.ts and Environment.prod.ts files. However, upon publish ...

There was a module parsing error that occurred due to an unexpected token being found while the 'use client' statement was present

Currently, I am in the process of creating an npm package specifically designed for nextjs projects. Everything has been going smoothly so far. However, my package includes multiple server components and one client component. This particular file contains ...

TS2339: The object does not have a property named 'users'

Transitioning from JavaScript to TypeScript while learning React has presented me with a new challenge. The initial state for my context is blank, which is causing issues with accessing the properties. If you prefer, here is the repository link: https:// ...

Creating a personalized React date selection tool using TypeScript

After following the instructions in the documentation for creating a custom datepicker, I finally managed to build one. However, I encountered an error stating "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean ...

Checking nested arrays recursively in Typescript

I'm facing difficulty in traversing through a nested array which may contain arrays of itself, representing a dynamic menu structure. Below is how the objects are structured: This is the Interface IMenuNode: Interface IMenuNode: export interface IM ...

Warning TS2352: There could be a potential mistake in converting a type 'Session | null' to type '{ x: string; y: string; }'

At first, I encountered the following errors: server.ts:30:12 - error TS2339: Property 'shop' does not exist on type 'Session | null'. 30 const {shop, accessToken} = ctx.session; ~~~~ server.ts:30:18 - error TS2339: ...

Receiving JSX from deeply nested dynamic imports in the latest version of NextJS 12 triggers an error message stating that [object Promise] is

There have been numerous proposed solutions for this particular issue on Stackoverflow, but none of them seem to work for my specific code. It appears that my situation is somewhat unique due to the nested dynamic imports involved: In a NextJS component, ...

On IOS, the internal links within my PWA app are unexpectedly opening as external links

Manifest File (manifest.json): { "theme_color": "#202020", "background_color": "#ffffff", "display": "standalone", "orientation": "portrait", &quo ...

The value of a checkbox in Ionic 2

I have implemented the code for reading checkbox values in Ionic 2 following the answer provided. However, I encountered an error message in the console: Cannot read property 'indexOf' of undefined Here is my home.html code: <form #leadsF ...

Populate List Items until Maximum Capacity is Reached and Increase the

Is there a way to make a ListItem fill the list vertically while also being able to overflow it if needed? I'm looking for a solution that would allow me to access the height of the empty space in the list, which I believe would be the minHeight. Som ...

Resetting matChipList input field in Angular along with Google Recaptcha

In my form, I have an input field where candidates must enter their skills. To achieve this, I implemented a chip input field. However, I encountered an issue when resetting the form - the value from the chip gets cleared, but the chip view remains. I trie ...

Step-by-step guide for resetting imported module between tests

Imagine I have a component that must be initialized once at the beginning of the application to pass on configuration. The module structure would look something like this: MyComponent.js let isInitialized; const myComponent = { init: function() { ...

Typescript enhances React Native's Pressable component with a pressed property

I'm currently diving into the world of typescript with React, and I've encountered an issue where I can't utilize the pressed prop from Pressable in a React Native app while using typescript. To work around this, I am leveraging styled comp ...