next.js: [NEXT-863] Unable to test page components using metadata API with Jest

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.3.0: Mon Jan 30 20:38:37 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T6000
    Binaries:
      Node: 18.12.1
      npm: 8.19.2
      Yarn: 1.22.19
      pnpm: N/A
    Relevant packages:
      next: 13.2.5-canary.8
      eslint-config-next: N/A
      react: 18.2.0
      react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true), Jest (next/jest)

Link to the code that reproduces this issue

https://github.com/andremendonca/metadata-jest-error

To Reproduce

git clone https://github.com/andremendonca/metadata-jest-error.git npm i npm test

Describe the Bug

in NextJs 13+ using the experimental App folder, I cannot test any server component that exports metadata or generateMetadata from https://beta.nextjs.org/docs/api-reference/metadata

Resulting in the following error:

 × NEXT_RSC_ERR_CLIENT_METADATA_EXPORT: metadata
       ╭─[/metadata-jest-bug/app/page.tsx:1:1]
     1 │ export const metadata = {
       ·              ────────
     2 │   title: 'My jest sample'
     3 │ }
       ╰────

Expected Behavior

I expected to be able to test Server Components present on app directory

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

From SyncLinear.com | NEXT-863

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 25
  • Comments: 43 (10 by maintainers)

Commits related to this issue

Most upvoted comments

Also having this issue

Same issue.

Hey everyone, we have a fix landed on the latest canary (v13.4.20-canary.16). Please let us know if it’s working for y’all 🙏 Appreciate your patience.

Hi, the issue is that @testing-library/react simulates a browser environment, while metadata is intended to run on the server only.

I will discuss with the team what we should recommend in this case, but if you want to test a page, you could likely use Playwright or a similar tool to spin up a server where metadata can run correctly.

Another solution could be to extract the Page component into a non-page file and import it into Jest from there, and re-export it in your page file.

same issue

Same issue.

Using RTL for integration testing is very common. Having to use Cypress as a workaround is a real shame

Not sure how my comment is spam, lol. No sense of humor? Also, not sure why people are downvoting the “same” comments. What do people expect them to say?? We are consumers of this, not the maintainers. This issue is more complex than a simple typo fix in the docs or something I feel. I would think it will require intimate knowledge of the internals of the framework even. It has now been four months with no real response from the team. Not even a “Hey we see this and will try to slate for fixing” or “This issue is more complex than a simple typo fix in the docs.” This issue clearly affects many people, now even at the enterprise level. Rip…

same issue

It’s really dissapointing that this bug is still on after 4 months. generateMetadata is a built in feature from Nextjs, and using jest for testing components is really basic. The fact that the app directory was put on stable and there are bugs like this (alongside i18n support breaking draft mode and other things) puzzles me.

We’re also updating examples here: https://github.com/vercel/next.js/pull/54989

v13.4.20-canary.16

it works! thank you so much

I was trying to write my first test in a brand new repository and it’s a pretty sour taste in the mouth and frustrating when the first test you write blows up and SWC gives you no useful message to go off of. I also don’t understand why the arrows for the error messages seem to point to nothing useful or relevant. Am I doing something wrong to get such an ugly useless stack trace, or is this just how SWC works; are people fine with this useless ugliness?¿¿ I love the speed that SWC seems to bring, but if it creates useless errors, it makes me not want it in my tooling if it’s providing a bad DX.

Minimum Reproduction

Config

This seems to be irrelevant, but here’s what I’ve got going on. I did this so that I could have the test next to the source file/page.

/** @type {import('next').NextConfig} */
const nextConfig = {
  pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js'],
}

module.exports = nextConfig

Directory Structure

./src/app/social/[userHandle]
├── page.test.tsx
└── page.tsx

page.test.tsx

Just an irrelevant test. It seems to get angry that the generateMetadata exists as an export from the imported file.

import { add } from './page'

describe('Page', () => {
  describe('#add', () => {
    it('adds two numbers', () => {
      expect(add(1, 3)).toEqual(4)
    })
  })
})

page.tsx

Note: This is just a minimal reproduction but the real code has some async work going on here.

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  return {
    title: 'title',
    description: 'description',
  }
}

export default function SocialPage({ params }: Props) {
  return <h1>Hello Worlds</h1>
}

export function add(num1: number, num2: number) {
  return num1 + num2
}

I am writing the tests as follows: creating a wrapper server component for the Page component and writing Jest tests for it.

// app/products/[id]/product-page.tsx

import type { Product } from '@/lib/api/interfaces/product';

interface Props {
  product: Product;
}

export default function ProductPage({ product }: Props) {
  return (
    <div>{product.name}</div>
  );
}

// app/products/[id]/page.tsx

import ProductPage from './product-page';

interface Params {
  params: {
    id: string;
  };
}

export async function generateMetadata({ params }: Params) {
  const product = await fetch('https://api.example.com/...');
  const title = product.name;
  return { title };
}

export default async function Page({ params }: Params) {
  const product = await fetch('https://api.example.com/...');

  return <ProductPage product={product} />;
}
// __tests__/app/products/[id]/product-page.test.tsx

import { render, screen } from '@testing-library/react';
import ProductPage from '@/app/products/[id]/product-page';

describe('ProductPage', () => {
  const product = { id: 1, name: 'product name' };

  test('renders props', () => {
    render(<ProductPage product={product} />);

    expect(screen.getByText(product.name)).toBeInTheDocument();
  });
});

Same problem here. Waiting for a solution 😞

It’s really dissapointing that this bug is still on after 4 months. generateMetadata is a built in feature from Nextjs, and using jest for testing components is really basic. The fact that the app directory was put on stable and there are bugs like this (alongside i18n support breaking draft mode and other things) puzzles me.

I 100% agree here. I only considered version 13 for use on client work because the app directory was marked as stable. Being able to write tests isn’t something I consider optional, and I have a hard enough time getting other developers to get on board with testing without having to have a workaround for this. The “… just use Playwrite” response is not sufficient. I REALLY like this framework, but it’s difficult for me to promote it to my client with this issue unresolved.

Same here 👋🏼

same issue