apollo-client-nextjs icon indicating copy to clipboard operation
apollo-client-nextjs copied to clipboard

Jest registerApolloClient is not a function

Open levchenkod opened this issue 1 year ago • 10 comments

I've followed the recommendations from the README, but I get this error during tests:

 TypeError: (0 , _experimentalnextjsappsupport.registerApolloClient) is not a function

       9 |
      10 |
    > 11 | const { getClient: graphClient } = registerApolloClient(() => {

Apart from jest the code works fine.

Repo to reproduce: https://github.com/levchenkod/next-apolo-jest-basic-setup

levchenkod avatar Aug 24 '24 03:08 levchenkod

Jest simulates a browser environment, so it uses the wrong version of Apollo Client for this - registerApolloClient is only available in React Server Components, not in the browser.

You can do

/** @type {import('jest').Config} */
const config = {
  testEnvironment: 'jsdom',
  testEnvironmentOptions: {
    customExportConditions: ['react-server'],
  },
};

in your jest config, which will instead load the "server component" code of @apollo/experimental-nextjs-app-support, but keep in mind that this will change resolution for all your dependencies to "server component" - you'll also get a different build of react, react-dom etc. If you want to test server components, this is probably a good thing, but I don't know for sure if jest actually works nicely with that.

phryneas avatar Aug 26 '24 07:08 phryneas

Jest simulates a browser environment, so it uses the wrong version of Apollo Client for this - registerApolloClient is only available in React Server Components, not in the browser.

You can do

/** @type {import('jest').Config} */
const config = {
  testEnvironment: 'jsdom',
  testEnvironmentOptions: {
    customExportConditions: ['react-server'],
  },
};

in your jest config, which will instead load the "server component" code of @apollo/experimental-nextjs-app-support, but keep in mind that this will change resolution for all your dependencies to "server component" - you'll also get a different build of react, react-dom etc. If you want to test server components, this is probably a good thing, but I don't know for sure if jest actually works nicely with that.

@phryneas I'm getting the same error using Vitest, and I've been trying to replicate the provided Jest config without luck. Any pointers?

marjorg avatar Aug 26 '24 11:08 marjorg

Vitest also doesn't simulate a react-server environment by default. This is really a specific runtime environment where libraries load differently than they would in the RSC run or in the browser.

For vitest, you would have to specify

export default defineConfig({
  plugins: [react()],
  resolve: {
    conditions: ["react-server"],
  },
});

phryneas avatar Aug 26 '24 11:08 phryneas

Vitest also doesn't simulate a react-server environment by default. This is really a specific runtime environment where libraries load differently than they would in the RSC run or in the browser.

For vitest, you would have to specify

export default defineConfig({
  plugins: [react()],
  resolve: {
    conditions: ["react-server"],
  },
});

Thanks for helping, but adding that line to the config seems to break all tests with the following error:

Error: This entry point is not yet supported outside of experimental channels
 ❯ ../../node_modules/.pnpm/[email protected]/node_modules/react/cjs/react.shared-subset.development.js:18:7
 ❯ Object.<anonymous> ../../node_modules/.pnpm/[email protected]/node_modules/react/cjs/react.shared-subset.development.js:19:5
 ❯ Object.<anonymous> ../../node_modules/.pnpm/[email protected]/node_modules/react/react.shared-subset.js:6:2

marjorg avatar Aug 26 '24 11:08 marjorg

Yes, you are running your tests with React 18.3.1, while Next.js is using a Canary build of React. You will have to find out which React build your Next.js installation uses and use that same build for your tests.

Next.js ignores your node_modules and brings it's own dependencies. I know it's insane but that's what we all have to deal with 😢

Look in node_modules/next/dist/compiled/react/cjs/react.development.js for the string ReactVersion, you'll find something like '18.3.0-canary-14898b6a9-20240318'

phryneas avatar Aug 26 '24 11:08 phryneas

That is quite insane indeed, I gave the last suggestion a shot but no luck. I think I'll wait with adding tests for the few pages I've migrated to app router until Next 15 to see if they make this more manageable.

Thanks for your help!

marjorg avatar Aug 26 '24 12:08 marjorg

Has anyone got a working setup for tests with vitest?

I'm using Next.js 15.1.6 with the included React 19.

My vitest.config.mts-file looks like this:

import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
import { defineConfig } from "vitest/config";

export default defineConfig({
  plugins: [tsconfigPaths(), react()],

  resolve: {
    conditions: ["react-server"],
  },
  test: {
    environment: "jsdom",
  },
});

When I try to execute a test case that uses react-testing-library for rendering a "regular" react component (no RSC), it throws the error Error: The "react" package in this environment is not configured correctly. The "react-server" condition must be enabled in any environment that runs React Server Components.. (This error is not happening when I remove the conditions setting)

Running a test file that tries to import client from registerApolloClient gives this error:

The requested module '@apollo/client-react-streaming' does not provide an export named 'registerApolloClient'
file:///XXXXXXXXXXXXX/frontend/node_modules/.pnpm/@[email protected]_@[email protected]_@[email protected]_grap_5ivqx5qy54kclbtftp6n2stzdu/node_modules/@apollo/experimental-nextjs-app-support/dist/index.rsc.js:2
export { DebounceMultipartResponsesLink, RemoveMultipartDirectivesLink, SSRMultipartLink, registerApolloClient } from '@apollo/client-react-streaming';
                                                                                          ^^^^^^^^^^^^^^^^^^^^
SyntaxError: The requested module '@apollo/client-react-streaming' does not provide an export named 'registerApolloClient'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:146:21)
    at ModuleJob.run (node:internal/modules/esm/module_job:229:5)
    at ModuleLoader.import (node:internal/modules/esm/loader:473:24)

My goal is to test functions that use the client from registerApolloClient, like this without React (server) Components:

// queries.ts
import { query } from "@/app/graphql-client";

export function fetchUserData() {
   return client.query(/* ... */);
}

nilshartmann avatar Feb 06 '25 17:02 nilshartmann

@nilshartmann you will probably need two separate test suites, one that runs with the browser build of React and one that runs with the RSC build.

phryneas avatar Feb 06 '25 17:02 phryneas

Thanks, @phryneas! Seems to be a little more effort than I thought 😉

nilshartmann avatar Feb 06 '25 18:02 nilshartmann

@nilshartmann Yeah, unfortunately there's no official way of testing React Server Components or code that should run in that context - with current solutions that can only emulate one environment at a time, you won't get around creating one test suite per environment :/

phryneas avatar Feb 07 '25 10:02 phryneas