Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nextjs with jest example will not work if there is an esm dependency in node_modules #40183

Open
1 task done
wmira opened this issue Sep 2, 2022 · 26 comments
Open
1 task done
Labels
bug Issue was opened via the bug report template.

Comments

@wmira
Copy link

wmira commented Sep 2, 2022

Verify canary release

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

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP Fri Apr 2 22:23:49 UTC 2021
Binaries:
  Node: 16.16.0
  npm: 8.11.0
  Yarn: 1.22.19
  pnpm: N/A
Relevant packages:
  next: 12.2.5
  eslint-config-next: 12.2.5
  react: 18.2.0
  react-dom: 18.2.0

Which example does this report relate to?

https://nextjs.org/docs/testing

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

If you have a project with a dependency that is published as an es modules in node_modules, running jest will not work..even though nextjs works with it e.g. running the project normally with npm run dev.

Test does not run even if ignoring the package. Please check this repo that reproduce the problem:

https://github.com/wmira/banana/

if you run npm run dev here..works fine.. npm run test here does not and this follow the jest example.

Expected Behavior

running test via jest works as per the docs

To Reproduce

repo is below:
https://github.com/wmira/banana/

  1. npm run dev -- nextjs works fine with an es module dependency under node_modules
  2. npm run test -- throws error
@wmira wmira added the bug Issue was opened via the bug report template. label Sep 2, 2022
@bruceharrison1984
Copy link

I ran into this issue once I installed preact in to my project.

@dariolongo
Copy link

Same issue for me.
I've fixed with:

module.exports = async () => ({
  ...(await createJestConfig(customJestConfig)()),
  transformIgnorePatterns: ["node_modules/(?!(package1|package2)/)", "^.+\\.module\\.(css|sass|scss)$"],
});

In my case packages are: swiper|ssr-window|dom7
Any suggestion?

@nora
Copy link

nora commented Sep 16, 2022

I had the same.

The cause of this issue is that I cannot include any module under node_modules in Jest's trasform target.

Specifically,

  • /node_modules/ is defined in transformIgnorePatterns by next/jest.
  • customJestConfig cannot override it and is limited to adding it

This is the relevant part of next/jest.
https://github.com/vercel/next.js/blob/v12.3.0/packages/next/build/jest/jest.ts#L136

The solution offered by @dariolongo is adequate.
However, instead of completely overriding it, a diversion of the standard ignorePatterns might be safer.

const esModules = ['package1', 'package2']
const customConfig = {
  // Dependency packages must also be included in this list
  transformIgnorePatterns: [`/node_modules/(?!(${esModules.join('|')})/)`],
  // And other custom config...
}

module.exports = async () => {
  const jestConfig = await _createJestConfig(customConfig)()
  return {
    ...jestConfig,
    transformIgnorePatterns: jestConfig.transformIgnorePatterns.filter(
      (ptn) => ptn !== '/node_modules/'
    ), // ['^.+\\.module\\.(css|sass|scss)$', '/node_modules/(?!(package1|package2)/']
  }
}

I would like to suggest that the documentation be supplemented with "config cannot be completely overwritten".

@ThisIsMissEm
Copy link

I've been trying to look into the next.js configuration, and from what I can see, node_modules isn't excluded in the standard next.js config when using esm and swc (both defaults as of Next 12), so I'm suspecting that this might just be a left over from a pre-ESM time?

ThisIsMissEm added a commit to ThisIsMissEm/next.js that referenced this issue Oct 12, 2022
This toggles whether or not the `node_modules` directory will be ignored via the `transformIgnorePatterns`, which appears to be all that's required to correctly load ESM dependencies in your app's tests when working with Next.js & Jest when using Typescript.

fixes vercel#38368, vercel#40183
ThisIsMissEm added a commit to ThisIsMissEm/next.js that referenced this issue Oct 12, 2022
This toggles whether or not the `node_modules` directory will be ignored via the `transformIgnorePatterns`, which appears to be all that's required to correctly load ESM dependencies in your app's tests when working with Next.js & Jest when using Typescript.

fixes vercel#38368, vercel#40183
@BoilingSoup
Copy link

BoilingSoup commented Jan 15, 2023

Solution from @nora worked perfectly. I believe this is a bug, but at the very least the docs should be updated to show how transformIgnorePatterns can be configured. What's currently implied in the docs is incorrect.

@oosawy
Copy link

oosawy commented Feb 9, 2023

The solution offered by @dariolongo is adequate. However, instead of completely overriding it, a diversion of the standard ignorePatterns might be safer.

const esModules = ['package1', 'package2']
const customConfig = {
  // Dependency packages must also be included in this list
  transformIgnorePatterns: [`/node_modules/(?!(${esModules.join('|')})/)`],
  // And other custom config...
}

module.exports = async () => {
  const jestConfig = await _createJestConfig(customConfig)()
  return {
    ...jestConfig,
    transformIgnorePatterns: jestConfig.transformIgnorePatterns.filter(
      (ptn) => ptn !== '/node_modules/'
    ), // ['^.+\\.module\\.(css|sass|scss)$', '/node_modules/(?!(package1|package2)/']
  }
}

I would like to suggest that the documentation be supplemented with "config cannot be completely overwritten".

When using Next.js 13.1 transpilePackages, this solution seems not working by another regex next/jest added.

But now just put all esModules into transpilePackages in next.config.js works perfectly for me!

module.exports = {
  transpilePackages: ['package1', 'package2'],
}

@sshah98
Copy link

sshah98 commented Apr 7, 2023

fyi i fixed this issue by removing the default paths in tsconfig "paths": {
"": ["./"]
}

@tachun
Copy link

tachun commented Apr 12, 2023

The solution offered by @dariolongo is adequate. However, instead of completely overriding it, a diversion of the standard ignorePatterns might be safer.

const esModules = ['package1', 'package2']
const customConfig = {
  // Dependency packages must also be included in this list
  transformIgnorePatterns: [`/node_modules/(?!(${esModules.join('|')})/)`],
  // And other custom config...
}

module.exports = async () => {
  const jestConfig = await _createJestConfig(customConfig)()
  return {
    ...jestConfig,
    transformIgnorePatterns: jestConfig.transformIgnorePatterns.filter(
      (ptn) => ptn !== '/node_modules/'
    ), // ['^.+\\.module\\.(css|sass|scss)$', '/node_modules/(?!(package1|package2)/']
  }
}

I would like to suggest that the documentation be supplemented with "config cannot be completely overwritten".

When using Next.js 13.1 transpilePackages, this solution seems not working by another regex next/jest added.

But now just put all esModules into transpilePackages in next.config.js works perfectly for me!

module.exports = {
  transpilePackages: ['package1', 'package2'],
}

As mentioned by @oosawy, with the use of Next.js 13.1's transpilePackages, the regex has changed and will generate these transformIgnorePatterns:

module.exports = {
  transpilePackages: ['package1', 'package2'],
}
[
  '/node_modules/(?!.pnpm)(?!(package1|package2)/)',
  '/node_modules/.pnpm/(?!(package1|package2)@)',
  '^.+\\.module\\.(css|sass|scss)$'
]

In this case, we don't need to add transformIgnorePatterns in the custom configuration, but, I need to remove the first element from the generated transformIgnorePatterns array to make it work.

module.exports = async () => {
  const jestConfig = await _createJestConfig(customConfig)()
  return {
    ...jestConfig,
    transformIgnorePatterns: jestConfig.transformIgnorePatterns.filter(
      (ptn) => ptn !== '/node_modules/(?!.pnpm)(?!(package1|package2)/)'
    ),
  }
}

@drewloomer
Copy link

This workaround seems to be broken with the release of 13.4. Has anyone else had luck upgrading to that release?

@jonioni
Copy link

jonioni commented May 10, 2023

Also encountering this issue. Wondering if next jest config could take into account type: "module" of the node_modules dependencies and auto add them into transformIgorePatterns?

@LarsEjaas
Copy link

I am experiencing the same issue with an ESM node_module causing Jest errors in v.13.4.1 and ended up downgrading to v.13.2.3. Tried different combinations of transpilePackages in next.config.mjs and transformIgnorePatterns in jest.config.mjs but finally gave up and downgraded the version.

@brett-minca
Copy link

brett-minca commented Jun 1, 2023

I just ran into this bug for the query-string module. I found that adding query-string and all of it's dependencies to transpilePackages worked.

  transpilePackages: [
    "query-string",
    "decode-uri-component",
    "filter-obj",
    "split-on-first",
  ],

Then I didn't need to modify transformIgnorePatterns at all. The default:

["/node_modules/(?!.pnpm)(?!(query-string|decode-uri-component|filter-obj|split-on-first)/)","/node_modules/.pnpm/(?!(query-string|decode-uri-component|filter-obj|split-on-first)@)","^.+\\.module\\.(css|sass|scss)$"]

was correct. This might just be the way it has to be if using npm. Switching to pnpm might allow you to only include the top-level package, query-string, in my case, to transpilePackages because of the different way that pnpm bundles packages. It looks like that's what the second generated pattern is for, but I haven't tested that.

@AlfredMadere
Copy link

Has this been resolved? I am still unable to use Jest with nextjs in 13.4 due to esm issues in node_modules.

@paulhchoi
Copy link

Dittoing @AlfredMadere, I'm also still unable to use Jest with Next.JS in 13.5.4 due to esm issues.

@leandroruel
Copy link

i tried everything in this issue and i`m stuck forever here

@twobit
Copy link

twobit commented Nov 1, 2023

@leandroruel try converting your ESM dependencies to CJS for Jest:

npx esbuild [YOUR_DEP] --bundle --platform=node --outfile=vendor/[YOUR_DEP].js

Then update your jest.config.js:

moduleNameMapper: {
    '^[YOUR_DEP]$': '<rootDir>/vendor/[YOUR_DEP]',
    ...
}

@atstoyanov
Copy link

atstoyanov commented Nov 6, 2023

I think I'll stick with babel until this one is resolved - https://nextjs.org/docs/pages/building-your-application/optimizing/testing#setting-up-jest-with-babel
The babel example was removed from the documentation.

@vicasas
Copy link

vicasas commented Dec 4, 2023

This works for me! using next.js 13.5.6

module.exports = {
  transpilePackages: ['package1', 'package2'],
}

But the error a changed to:

@font-face {
    ^

    SyntaxError: Invalid or unexpected token

@ankita-khandelwal
Copy link

The solution offered by @dariolongo is adequate. However, instead of completely overriding it, a diversion of the standard ignorePatterns might be safer.

const esModules = ['package1', 'package2']
const customConfig = {
  // Dependency packages must also be included in this list
  transformIgnorePatterns: [`/node_modules/(?!(${esModules.join('|')})/)`],
  // And other custom config...
}

module.exports = async () => {
  const jestConfig = await _createJestConfig(customConfig)()
  return {
    ...jestConfig,
    transformIgnorePatterns: jestConfig.transformIgnorePatterns.filter(
      (ptn) => ptn !== '/node_modules/'
    ), // ['^.+\\.module\\.(css|sass|scss)$', '/node_modules/(?!(package1|package2)/']
  }
}

I would like to suggest that the documentation be supplemented with "config cannot be completely overwritten".

When using Next.js 13.1 transpilePackages, this solution seems not working by another regex next/jest added.

But now just put all esModules into transpilePackages in next.config.js works perfectly for me!

module.exports = {
  transpilePackages: ['package1', 'package2'],
}

Above suggestion worked for me with Nextjs 14.0.3.

@esantosrvolvo
Copy link

esantosrvolvo commented Dec 12, 2023

I am on NextJS 14.0.3 and the transpilePackages solution did not work for me for package next-image-export-optimizer.
I got it working by switching back to babel as indicated by @atstoyanov. nvm, it didn't work with babel either.

@atstoyanov
Copy link

It work in 14.0.3 using transpilePackages and without the need of overriding the transformIgnorePatterns. Here is my configuration.

// next.config.js
{
  transpilePackages: [
    'axios',
    'react-dnd-html5-backend',
    'supports-webp',
    'ramda',
    'react-firebase-hooks/auth',
  ]
}

// jest.config.ts
import type { Config } from 'jest';
import nextJest from 'next/jest.js';

const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: './',
});

// Add any custom config to be passed to Jest
const config: Config = {
  coverageProvider: 'v8',
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  moduleNameMapper: {
    'react-markdown': '<rootDir>/node_modules/react-markdown/react-markdown.min.js',
    '^@/(.*)$': '<rootDir>/$1',
  },
  testPathIgnorePatterns: ['/tests/'],
  resetMocks: false,
  clearMocks: true,
};

export default createJestConfig(config);

and here is the produced config:

{
  coverageProvider: 'v8',
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: [ '<rootDir>/jest.setup.js' ],
  moduleNameMapper: {
    '^.+\\.module\\.(css|sass|scss)$': '/Users/user/src/demo-app/node_modules/next/dist/build/jest/object-proxy.js',
    '^.+\\.(css|sass|scss)$': '/Users/user/src/demo-app/node_modules/next/dist/build/jest/__mocks__/styleMock.js',
    '^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp)$': '/Users/user/src/demo-app/node_modules/next/dist/build/jest/__mocks__/fileMock.js',
    '^.+\\.(svg)$': '/Users/user/src/demo-app/node_modules/next/dist/build/jest/__mocks__/fileMock.js',
    '@next/font/(.*)': '/Users/user/src/demo-app/node_modules/next/dist/build/jest/__mocks__/nextFontMock.js',
    'next/font/(.*)': '/Users/user/src/demo-app/node_modules/next/dist/build/jest/__mocks__/nextFontMock.js',
    'server-only': '/Users/user/src/demo-app/node_modules/next/dist/build/jest/__mocks__/empty.js',
    'react-markdown': '<rootDir>/node_modules/react-markdown/react-markdown.min.js',
    '^@/(.*)$': '<rootDir>/$1'
  },
  testPathIgnorePatterns: [ '/node_modules/', '/.next/', '/tests/' ],
  resetMocks: false,
  clearMocks: true,
  transform: {
    '^.+\\.(js|jsx|ts|tsx|mjs)$': [
      '/Users/user/src/demo-app/node_modules/next/dist/build/swc/jest-transformer.js',
      [Object]
    ]
  },
  transformIgnorePatterns: [
    '/node_modules/(?!.pnpm)(?!(axios|react-dnd-html5-backend|supports-webp|ramda|react-firebase-hooks/auth)/)',
    '/node_modules/.pnpm/(?!(axios|react-dnd-html5-backend|supports-webp|ramda|react-firebase-hooks\\+auth)@)',
    '^.+\\.module\\.(css|sass|scss)$'
  ],
  watchPathIgnorePatterns: [ '/.next/' ]
}

sabertazimi added a commit to sabertazimi/blog that referenced this issue Jan 20, 2024
* fix(deps): update dependency next to v14

* fix(nextjs): rectify antd-related modularize imports

See vercel/next.js#40183 and vercel/next.js#58817.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: sabertazimi <sabertazimi@gmail.com>
@YousefMohsen
Copy link

I have similar issue. I just upgraded to nextjs 14 from nextjs 12. And i get the following error:

Cannot find module '../components/base/animation/animations' from 'src/lib/utils.js'

Inside my jsconfig.js i have "css/animations": ["./src/components/base/animation/animations.module.css"], and I use it like import animations from "css/animations";

It works fine when i run the app, but jest throws errors when i run the test.

@RobsonAraujo
Copy link

I'm getting this issue with Next 14.1.0, even when using create-next-app. It looks like ESLINT and JEST/Cypress are not working together.

It is possible to quickly reproduce it following the steps below:

Run npx create-next-app@latest (Choose the option to include Eslint on the config)

Then, follow the step to add config Jest
https://nextjs.org/docs/app/building-your-application/testing/jest

Then, try to run the yarn test command. The following bug will be shown
image

I have tried to use transpilePackages as mentioned above but without success. Any idea?

@leandroruel
Copy link

leandroruel commented Mar 5, 2024

if it helps someone here's my config file:

const nextJest = require('next/jest')
const swiperMocks = require('./src/__mocks__/misc/swiper.ts')

const createJestConfig = nextJest({
  // Path to Next.js app to load next.config.js
  dir: './',
})

/** @type {import('@jest/types').Config.InitialOptions} */
const customJestConfig = {
  testEnvironment: 'jest-environment-jsdom',
  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
  maxWorkers: 4,
  /**
   * Custom config goes here, I am not adding it to keep this example simple.
   * See next/jest examples for more information.
   */
  moduleNameMapper: {
    '^@/components/(.*)$': '<rootDir>/components/$1',
    '^components/(.*)$': '<rootDir>/src/components/$1',
    '^helpers/(.*)$': '<rootDir>/src/helpers/$1',
    '^generated/(.*)$': '<rootDir>/src/generated/$1',
    '^mixins/(.*)$': '<rootDir>/src/mixins/$1',
    '^hooks/(.*)$': '<rootDir>/src/hooks/$1',
    '^mocks/(.*)$': '<rootDir>/src/__mocks__/$1',
    ...swiperMocks.moduleNameMapper,
  },
  transform: {
    ...swiperMocks.transform,
  },
  modulePaths: ['<rootDir>/src/'],
  collectCoverage: true,
  collectCoverageFrom: [
    '<rootDir>/src/components/**/*.tsx', 
    '!<rootDir>/src/pages/**',
    '!<rootDir>/src/components/**/stories.tsx', 
    '!<rootDir>/src/components/**/index.ts',
  ],
  coveragePathIgnorePatterns: ['.*__snapshots__/.*'],
}

const esModules = [
  'ccount',
  'react-markdown',
  'vfile',
  'unist-.+',
  'unified',
  'bail',
  'is-plain-obj',
  'trough',
  'remark',
  'remark-.+',
  'mdast-util-.+',
  'micromark',
  'parse-entities',
  'character-entities',
  'property-information',
  'comma-separated-tokens',
  'hast-util-whitespace',
  'hast-util-to-html',
  'hast-util-sanitize',
  'html-void-elements',
  'space-separated-tokens',
  'decode-named-character-reference',
  'zwitch',
  'longest-streak',
  'stringify-entities',
  'trim-lines',
  'swiper',
  'swiper/react',
  'ssr-window',
  'dom7',
].join('|')

module.exports = async () => ({
  /**
   * Using ...(await createJestConfig(customJestConfig)()) to override transformIgnorePatterns
   * provided byt next/jest.
   *
   * @link https://github.com/vercel/next.js/issues/36077#issuecomment-1096635363
   */
  ...(await createJestConfig(customJestConfig)()),
  /**
   * Swiper uses ECMAScript Modules (ESM) and Jest provides some experimental support for it
   * but "node_modules" are not transpiled by next/jest yet.
   *
   * @link https://github.com/vercel/next.js/issues/36077#issuecomment-1096698456
   * @link https://jestjs.io/docs/ecmascript-modules
   */
  transformIgnorePatterns: [`<rootDir>/node_modules/(?!${esModules})/`],
})

@AtanasChachev
Copy link

I'm getting this issue with Next 14.1.0, even when using create-next-app. It looks like ESLINT and JEST/Cypress are not working together.

It is possible to quickly reproduce it following the steps below:

Run npx create-next-app@latest (Choose the option to include Eslint on the config)

Then, follow the step to add config Jest https://nextjs.org/docs/app/building-your-application/testing/jest

Then, try to run the yarn test command. The following bug will be shown image

I have tried to use transpilePackages as mentioned above but without success. Any idea?

I was able to fix that by adding

"resolutions": {
    "string-width": "4.2.3",
    "wrap-ansi": "7.0.0"
  }

in my package.json.
Not quite sure if it's the best solution but it fixed the problem :)

Make sure you do rm -rf node_modules and then re-run yarn.

@RobsonAraujo
Copy link

@AtanasChachev That works; thanks for sharing this alternative solution 💯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests