javascripttestingnext.jsjestjsbabeljs

Facing issue while migrating Jest@26 to Jest@27


I'm trying to migrate Jest from version 26 to 27 in my Next.js 13 project but facing the following error while running test after updating to Jest 27 version -

 FAIL  src/__tests__/app.test.tsx
  ● Test suite failed to run

    Cannot combine importAssertions and importAttributes plugins.

      at validatePlugins (node_modules/@babel/parser/src/plugin-utils.ts:130:11)
      at getParser (node_modules/@babel/parser/src/index.ts:106:5)
      at parse (node_modules/@babel/parser/src/index.ts:32:22)
      at parser (node_modules/@babel/core/src/parser/index.ts:28:19)
          at parser.next (<anonymous>)
      at normalizeFile (node_modules/@babel/core/src/transformation/normalize-file.ts:51:24)
          at normalizeFile.next (<anonymous>)
      at run (node_modules/@babel/core/src/transformation/index.ts:38:36)
          at run.next (<anonymous>)
      at transform (node_modules/@babel/core/src/transform.ts:29:20)
          at transform.next (<anonymous>)
      at evaluateSync (node_modules/gensync/index.js:251:28)
      at fn (node_modules/gensync/index.js:89:14)
      at stopHiding - secret - don't use this - v1 (node_modules/@babel/core/src/errors/rewrite-stack-trace.ts:97:14)
      at transformSync (node_modules/@babel/core/src/transform.ts:66:52)
      at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
      at runJest (node_modules/@jest/core/build/runJest.js:404:19)
      at _run10000 (node_modules/@jest/core/build/cli/index.js:320:7)
      at runCLI (node_modules/@jest/core/build/cli/index.js:173:3)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.683 s

before updating the Jest, the test was passing so it's not related to my code. My jest.config.js looks like this -

module.exports = {
  collectCoverage: true,
  coverageProvider: 'babel',
  collectCoverageFrom: [
    '**/*.{js,jsx,ts,tsx}',
    '!**/*.d.ts',
    '!**/node_modules/**',
    '!<rootDir>/out/**',
    '!<rootDir>/.next/**',
    '!<rootDir>/*.config.js',
    '!<rootDir>/coverage/**',
  ],
  moduleNameMapper: {
    '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
 
    '^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
 
    '^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i': `<rootDir>/__mocks__/fileMock.js`,
 
    '^@/components/(.*)$': '<rootDir>/components/$1',
 
    '@next/font/(.*)': `<rootDir>/__mocks__/nextFontMock.js`,
    'next/font/(.*)': `<rootDir>/__mocks__/nextFontMock.js`,
    'server-only': `<rootDir>/__mocks__/empty.js`,
  },
  testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
  testEnvironment: 'jsdom',
  transform: {
    // Use babel-jest to transpile tests with the next/babel preset
    // https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
    '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
  },
  transformIgnorePatterns: [
    '/node_modules/',
    '^.+\\.module\\.(css|sass|scss)$',
  ],
}

and babel.config.js -

module.exports = {
  presets: ["next/babel"],
  plugins: [
    [
      'react-css-modules',
      {
        autoResolveMultipleImports: true,
        generateScopedName: '[name]__[local]__[hash:base64:5]',
        handleMissingStyleName: 'throw',
        webpackHotModuleReloading: true,
      },
    ],
  ],
};

my package.json snapshot is here:

 {
    "dependencies": {
    "abortcontroller-polyfill": "^1.7.5",
    "babel-plugin-react-css-modules": "^5.2.6",
    "next": "13.1.0"
  },
  "devDependencies": {
    "@babel/core": "^7.22.0",
    "@testing-library/dom": "^10.4.0",
    "@testing-library/jest-dom": "^6.4.8",
    "@testing-library/react": "^16.0.0",
    "@types/jest": "^29.5.12",
    "babel-loader": "^8.2.2",
    "css-loader": "^3.4.2",
    "jest": "27.0.0",
    "jest-environment-jsdom": "^29.7.0",
    "node-fetch": "^2.6.1",
    "nodemon": "^2.0.7",
    "webpack": "^5.75.0"
  }
}

Please help me resolve this !


Solution

  • For me, this error was due to the fact that we were using next/babel in our babel config for jest tests and nextjs 14 uses @babel/plugin-syntax-import-assertions while jest uses the plugin "babel-preset-current-node-syntax": "1.1.0" which uses @babel/plugin-syntax-import-assertions.

    Import assertions have been proposed to be replaced by import attributes which is more flexible: https://github.com/tc39/proposal-import-attributes

    However, you can get the old + the new syntax with https://babeljs.io/docs/babel-plugin-syntax-import-attributes#deprecatedassertsyntax

    Nextjs 14 uses import assertions, which is a problem when we use the next/babel preset in babel.config.js and jest-babel is applied on top of that, applying import attributes via the dependency module "babel-preset-current-node-syntax": "1.1.0".

    However, the use of import assertions was replaced with babel-plugin-syntax-import-attributes with deprecatedassertsyntax and merged into next canary: https://github.com/vercel/next.js/pull/65749

    Finally, the resolutions property in the yarn's package.json did not affect the installed @jest/core/node_modules/babel-preset-current-node-syntax version.

    Thus we did this:

    yarn install babel-preset-current-node-syntax@1.0.0

    Remove the caret operator, so it's pinned like so: "babel-preset-current-node-syntax": "1.0.0",

    Then, we did this:

    
    import { exec } from '@utils/scripting';
    import { existsSync } from 'node:fs';
    
    const JEST_BABEL_PRESET_CURRENT_NODE_SYNTAX_LOC = 'node_modules/@jest/core/node_modules/babel-preset-current-node-syntax';
    const VERSION_ONE_BABEL_PRESET_CURRENT_NODE_SYNTAX_LOC = 'node_modules/babel-preset-current-node-syntax';
    export const run = (): void => {
      if (!existsSync(`${process.cwd()}/${JEST_BABEL_PRESET_CURRENT_NODE_SYNTAX_LOC}`)) {
        throw new Error(`The file ${JEST_BABEL_PRESET_CURRENT_NODE_SYNTAX_LOC} does not exist.
            You probably upgraded jest and now you have to downgrade or read the comments in deploy/bin/patch-jest-import-assertions.ts`);
      }
      exec(`rm -rf ${JEST_BABEL_PRESET_CURRENT_NODE_SYNTAX_LOC}`);
      exec(`cp -R ${VERSION_ONE_BABEL_PRESET_CURRENT_NODE_SYNTAX_LOC} ${JEST_BABEL_PRESET_CURRENT_NODE_SYNTAX_LOC}`);
    };
    

    Now, next/babel will be in charge of adding either import attributes or import assertions, and we don't use either syntax so we don't care.