vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.83k stars 26.96k forks source link

Jest config with "next/jest" not picking up "babel-plugin-formatjs" on v. 12.1.6/12.1.7-canary.40 #37771

Open lassegit opened 2 years ago

lassegit commented 2 years ago

Verify canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:29 PDT 2022; root:xnu-8020.121.3~4/RELEASE_ARM64_T8101
Binaries:
  Node: 16.14.2
  npm: 8.5.0
  Yarn: 1.22.11
  pnpm: N/A
Relevant packages:
  next: 12.1.7-canary.40
  react: 18.2.0
  react-dom: 18.2.0

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

Trying to add the babel-plugin-formatjs plugin to Jest testing environment. It automatically injects hash generated IDs for translations. This works on 12.1.0 but with newer releases I only get non-specific error message when I run yarn test:

 FAIL  test/index.test.tsx
  ✕ renders (41 ms)

  ● renders

    [@formatjs/intl] An `id` must be provided to format a message. You can either:
    1. Configure your build toolchain with [babel-plugin-formatjs](https://formatjs.io/docs/tooling/babel-plugin)
    or [@formatjs/ts-transformer](https://formatjs.io/docs/tooling/ts-transformer) OR
    2. Configure your `eslint` config to include [eslint-plugin-formatjs](https://formatjs.io/docs/tooling/linter#enforce-id)
    to autofix this issue

      11 |     <div className={styles.container}>
      12 |       <Head>
    > 13 |         <title>{intl.formatMessage({ defaultMessage: 'Create Next App' })}</title>

My configuration:

.babelrc:

{
  "presets": ["next/babel"],
  "plugins": ["formatjs"]
}

jest.config.js:

const nextJest = require('next/jest');
const createJestConfig = nextJest({ dir: './' });

const customJestConfig = {
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  moduleDirectories: ['node_modules', '<rootDir>/'],
  testEnvironment: 'jest-environment-jsdom',
  moduleNameMapper: {
    '^@components/(.*)$': '<rootDir>/components/$1',
    '^@containers/(.*)$': '<rootDir>/containers/$1',
    '^@lib/(.*)$': '<rootDir>/lib/$1',
  },
  transform: {
    // 
    // THIS WORKS ON NEXT 12.1.0:
    //
    // Use babel-jest to transpile tests with the next/babel preset (ELSE test will FAIL due to missing ID)
    // https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
    '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
  },
};

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);

jest.setup.js:

import '@testing-library/jest-dom/extend-expect';

Installed dependencies:

{
"dependencies": {
    "next": "12.1.7-canary.40",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-intl": "^6.0.4"
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.3.0",
    "@types/node": "18.0.0",
    "@types/react": "18.0.13",
    "@types/react-dom": "18.0.5",
    "babel-jest": "^28.1.1",
    "babel-plugin-formatjs": "^10.3.24",
    "eslint": "8.17.0",
    "eslint-config-next": "12.1.6",
    "git18n": "^1.0.4",
    "jest": "^28.1.1",
    "jest-environment-jsdom": "^28.1.1",
    "typescript": "4.7.3"
  }
}

I am unsure which direction to look in. Has Next changed how it load Jest configuration/Babel plugins?

Expected Behavior

It should load the babel-plugin-formatjs as previously.

To Reproduce

Install the package and run yarn test:

{
  "name": "next-hash-ids",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "yarn git18n && next build",
    "start": "next start",
    "lint": "next lint",
    "translate": "git18n --files '(pages|components)/**/*.{js,jsx,ts,tsx}'",
    "test": "jest",
    "test:staged": "jest --bail --findRelatedTests",
    "test-watch": "jest --watchAll",
    "test-coverage": "jest --coverage"
  },
  "dependencies": {
    "next": "12.1.7-canary.40",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-intl": "^6.0.4"
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.3.0",
    "@types/node": "18.0.0",
    "@types/react": "18.0.13",
    "@types/react-dom": "18.0.5",
    "babel-jest": "^28.1.1",
    "babel-plugin-formatjs": "^10.3.24",
    "eslint": "8.17.0",
    "eslint-config-next": "12.1.6",
    "git18n": "^1.0.4",
    "jest": "^28.1.1",
    "jest-environment-jsdom": "^28.1.1",
    "typescript": "4.7.3"
  }
}
Daavidaviid commented 2 years ago

I too noticed with latest versions from 12.1.5 to 12.2.5 that jest is not picking up babel config

Daavidaviid commented 2 years ago

It works without createJestConfig()

plourenco commented 2 years ago

I can confirm the problem. Related to formatjs/formatjs#3789. I believe it's something related to how Jest transform is set up using the SWC compiler.

I created the following code sandbox: https://codesandbox.io/s/admiring-currying-0phokz

sethbro commented 2 years ago

I am not using Next.js but encountered this problem. I wound up upgrading all @babel packages (including babel-jest & babel-plugin-formatjs), but only after I upgraded to jest 29 did the issue go away.

geir-helleloid commented 1 year ago

For the jest.config.js file in the original issue description:

I found that with Next.js 13.1.0, changing the "transform" line to

"^.+\\.(js|jsx|ts|tsx|mjs)$": ["babel-jest", { presets: ["next/babel"] }],

allowed Babel + plugins to work in my Jest tests. Note, specifically, that the key includes the "mjs" file suffix. This works because the key now matches the one provided by next/js and overrides it, switching the transformer from SWC to Babel.