jest: [Bug]: Jest ESM (ts-jest) can't find import from CJS module

Version

27.4.3

Steps to reproduce

Minimal repro: https://github.com/themaskedavenger/jest-esm-apollo-client

run yarn and then yarn test:jest

also to see the original issue replace the imports (lines 4-10) with:

import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider,
  useQuery,
  gql
} from '@apollo/client';

Expected behavior

Would expect to have Jest be able to properly import those components and see the tests run (and hopefully pass!).

Actual behavior

When using these imports:

import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider,
  useQuery,
  gql
} from '@apollo/client';

Each of the imports gives an error like SyntaxError: The requested module '@apollo/client' does not provide an export named 'ApolloProvider'. Looking at the @apollo/client’s package.json, the "main" key is set to "./main.cjs", which is re-exporting things in cjs style:

var core = require('./core');
var react = require('./react');

for (var k in core) {
	if (k !== 'default' && !exports.hasOwnProperty(k)) exports[k] = core[k];
}
for (var k in react) {
	if (k !== 'default' && !exports.hasOwnProperty(k)) exports[k] = react[k];
}

For some reason I guess this cjs is not recognized with the recommended jest config. To get around it, can directly import the specific exports directly from esm files in the @apollo/client package like this:

import {
  ApolloClient,
  InMemoryCache,
} from '@apollo/client/core';
import { ApolloProvider } from '@apollo/client/react/context/ApolloProvider';
import { useQuery } from '@apollo/client/react/hooks';
import { gql } from 'graphql-tag';

Then there’s a new error for a dependency:

/path/to/project/node_modules/ts-invariant/process/index.js:15
    export function install() {
    ^^^^^^

    SyntaxError: Unexpected token 'export'

Adding transformIgnorePatterns to jest config doesn’t seem to help:

    "transformIgnorePatterns": [
      "node_modules/(?!(ts-invariant)/)"
    ],

Any thoughts on how to fix?

Full jest config:

  "jest": {
    "resetMocks": true,
    "testEnvironment": "node",
    "testMatch": [
      "**/src/**/*.(spec|test).[tj]s?(x)"
    ],
    "preset": "ts-jest/presets/default-esm",
    "transform": {},
    "transformIgnorePatterns": [
      "node_modules/(?!(ts-invariant)/)"
    ],
    "extensionsToTreatAsEsm": [
      ".ts",
      ".tsx"
    ],
    "globals": {
      "ts-jest": {
        "useESM": true
      }
    },
    "moduleNameMapper": {
      "^(\\.{1,2}/.*)\\.js$": "$1"
    }
  }

and tsconfig:

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "declaration": true,
    "downlevelIteration": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "jsx": "react",
    "outDir": "build",
    "sourceMap": true,
    "strictNullChecks": true,
    "baseUrl": ".",
    "lib": [
      "ESNext",
      "dom"
    ],
    "moduleResolution": "Node",
    "target": "ESNext",
    "module": "ESNext"
  },
  "include": [
    "src/**/*"
  ]
}

Additional context

Also tried using this jest resolver suggested in the docs:

module.exports = (request, options) => {
  // Call the defaultResolver, so we leverage its cache, error handling, etc.
  return options.defaultResolver(request, {
    ...options,
    // Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
    packageFilter: (pkg) => {
      return {
        ...pkg,
        // Alter the value of `main` before resolving the package
        main: pkg.module || pkg.main,
      };
    },
  });
};

I notice that the @apollo/client package has both "module" and "main" keys. But using this resolver it errors for other modules:

/Users/justin/dev/sandbox/jest-esm-apollo-client/node_modules/@testing-library/react/dist/@testing-library/react.esm.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import _extends from '@babel/runtime/helpers/esm/extends';
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

Is it possible to utilize the esm "module" field in package.json with jest ESM? Seemed like the obvious choice for ESM jest but it creates all kinds of errors like this. Is it because cjs modules in node_modules are trying to load the ESM exports?

Environment

npx: installed 1 in 1.509s

  System:
    OS: macOS 11.6
    CPU: (8) x64 Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
  Binaries:
    Node: 14.17.6 - /usr/local/bin/node
    Yarn: 1.22.0 - /usr/local/bin/yarn
    npm: 6.14.15 - /usr/local/bin/npm
  npmPackages:
    jest: ^27.4.3 => 27.4.3 


npx envinfo@latest --preset apollo --clipboard
npx: installed 1 in 1.563s

  System:
    OS: macOS 11.6
  Binaries:
    Node: 14.17.6 - /usr/local/bin/node
    Yarn: 1.22.0 - /usr/local/bin/yarn
    npm: 6.14.15 - /usr/local/bin/npm
  Browsers:
    Chrome: 96.0.4664.55
    Edge: 80.0.361.54
    Firefox: 89.0.2
    Safari: 14.1.2
  npmPackages:
    @apollo/client: ^3.5.5 => 3.5.5

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 22
  • Comments: 15 (4 by maintainers)

Most upvoted comments

I’m having a similar issue, I think it fits in here.

My problem is that, even though the packages from node_modules being imported have both CJS and ESM modules, and that in “my” (well, my company’s) package.json and tsconfig.files we have it to work with CJS… When Jest runs, it tries to load the ESM variants instead, and then it complains about the export keyword because it does not understand it.

Of course I could try to apply some of the transformations referred in this thread, but what confuses me is why is it even trying to load the ESM files when we have CJS ones available (and they are properly declared in the respective package.json files of the packages we have in node_modules, via the "exports" section).

I’m having a similar issue, I think it fits in here.

My problem is that, even though the packages from node_modules being imported have both CJS and ESM modules, and that in “my” (well, my company’s) package.json and tsconfig.files we have it to work with CJS… When Jest runs, it tries to load the ESM variants instead, and then it complains about the export keyword because it does not understand it.

Of course I could try to apply some of the transformations referred in this thread, but what confuses me is why is it even trying to load the ESM files when we have CJS ones available (and they are properly declared in the respective package.json files of the packages we have in node_modules, via the "exports" section).

I’m also experiencing this issue, did you create an issue or managed to resolve it?

I’m also experiencing this issue, did you create an issue or managed to resolve it?

@NiklasPor I didn’t had time to prepare a minimum reproducible example for this problem and to write a detailed issue yet. Will do.

Better open new issue with minimal reproduction. It is impossible to guess what is going on from your description.

Hi, I had the same issue, spent a lot time on it but eventually fixed by changing jest config like described here https://github.com/facebook/jest/issues/11783#issuecomment-1107861603