javascriptjestjsbabeljsbabel-jest

Babel isn't transforming imports to require for Jest tests


I have seen this question a lot on GitHub and Stack Overflow, but using all of the answers that I found, none of them have worked. Everything seems to be set up correctly. I have a monorepo that has a packages/package-a, packages/package-b, etc. In the package-a directory I have a Jest test command in the scripts "test": "jest". which I am running like this: npm run test -w packages/package-a. When it starts up, I get the following error details:

Details:

node_modules/components/src/ui/label.js:2
import { jsx as _jsx } from "react/jsx-runtime";

SyntaxError: Cannot use import statement outside a module

    > 1 | import { Label } from '@/ui/label';
        | ^
      2 |
      3 | export function HelloWorld() {
      4 |   return (

The full component that this is looking at looks like this (src/hello-world.tsx):

import { Label } from '@/ui/label';

export function HelloWorld() {
  return (
    <h1>
      <Label>Hello World</Label>
    </h1>
  );
}

I then have a Jest test that looks like this (__tests__/hello-world.test.tsx):

import { render } from '@testing-library/react';
import { HelloWorld } from '../src/hello-world';

describe('Renders the dashboard', () => {
  it('Load Hello World Component', () => {
    const { getByText } = render(<HelloWorld />);
    expect(getByText('Hello World')).toBeInTheDocument();
  });
});

I have two Jest configs, one in packages/project-a that re-exports the base config found in the root. The base config looks like this (minus things that don't seem relevant to the problem):

import path from 'path';
const __dirname = new URL('.', import.meta.url).pathname;

export default {
  moduleFileExtensions: ['tsx', 'ts', 'jsx', 'js', 'json', 'node'],
  testMatch: ['<rootDir>/__test(s)?__/**/*.(spec|test).[jt]s?(x)'],
  setupFilesAfterEnv: [path.join(__dirname, 'jest.setup.ts')],
  rootDir: './',
  testEnvironment: 'jsdom',
  transform: {
    '\\.[jt]sx?$': [
      'babel-jest',
      {
        configFile: path.join(__dirname, 'babel.config.cjs'),
      },
    ],
  },
  transformIgnorePatterns: [
    '/node_modules/(?!next-auth|jose|@panva/hkdf|uuid|preact-render-to-string|preact)',
    '^.+\\.module\\.(css|sass|scss)$',
  ],
};

In the same directory as the root, I have my base babel.config.cjs, which sets up Babel. The configuration looks like this (I have tried both with and without the plugin):

module.exports = {
  presets: [
    // 'next/babel',
    ['@babel/preset-env', { targets: { node: 'current' } }],
    '@babel/preset-react',
    '@babel/preset-typescript',
  ],
  // plugins: [],
  plugins: ['@babel/plugin-transform-modules-commonjs'],
};

Note: it is being used, as when I change a preset/plugin to something that doesn't exist, it throws an error saying it can't find the preset/plugin.

Why is it not transforming the import to something that works with Jest?


Solution

  • I was finally able to get this to work by updating transformIgnorePatterns in the Jest file, and updating my babel presets.

    First, in the Jest file I removed this from the transformIgnorePatterns:

    '/node_modules/(?!next-auth|jose|@panva/hkdf|uuid|preact-render-to-string|preact)',
    

    So now it looks like this:

    export default {
      transformIgnorePatterns: [
        '^.+\\.module\\.(css|sass|scss)$',
      ]
    }
    

    Next, I updated my babel to look like this:

    module.exports = {
      presets: [
        ['@babel/preset-react', { runtime: 'automatic' }],
        ['@babel/preset-typescript', { isTSX: true, allExtensions: true }],
        [
          '@babel/preset-env',
          {
            targets: { node: 'current' },
            modules: 'cjs',
          },
        ],
      ],
      plugins: [
        '@babel/plugin-transform-modules-commonjs', 
        '@babel/plugin-transform-private-methods'
      ],
    };
    

    Now the tests run fine.