Angular Jest SyntaxError Cannot Use Import Statement Outside A Module | Fix ESM Tests

This Angular Jest error means Jest is reading ESM import syntax as plain JS; your transforms and module settings don’t match.

If you’re seeing SyntaxError: Cannot use import statement outside a module while running Jest in an Angular project, you’re not alone. The message looks scary, but it’s often one small mismatch between what Node, TypeScript, and Jest think your files are.

This guide walks you through checks that catch the cause fast, then shows fixes you can keep.

Why This Error Shows Up In Angular Jest Runs

Jest runs your test files inside Node. Node can run CommonJS (require()) and it can run ESM (import), but it needs a clear signal for which mode a file belongs to. Jest adds one more layer because it transforms your TypeScript and Angular templates before Node sees them.

This error appears when a file that still contains an import statement reaches the runtime step without being transformed in the way Jest expects. That file might be your test, your app code, or a dependency inside node_modules.

In Angular projects, the trigger is often one of these:

  • Mixed module mode — Your project outputs ESM, but Jest is set up for CommonJS transforms.
  • Untransformed dependency — A package ships ESM-only entry points and Jest skips it by default.
  • Wrong transformer chaints-jest, babel-jest, or jest-preset-angular isn’t being applied to the file that failed.

Quick Triage Before You Touch Config Files

Start by spotting which file is actually blowing up. The stack trace often points at the first file that Jest tried to execute without transforming.

  1. Read the first path — Find the first file path shown right after the error and copy it somewhere.
  2. Check the extension — Note if it ends with .ts, .mjs, .js, or .cjs.
  3. Run one test file — Use jest path/to/test.spec.ts -i to reduce noise while you tweak config.
  • Print Jest config — Run jest --showConfig and confirm transform, preset, and transformIgnorePatterns.
  • Check config file type — If you use jest.config.ts, make sure your project can load TS config files during test runs.

Angular Jest SyntaxError Cannot Use Import Statement Outside A Module Fix Checklist

Most Angular + Jest setups land in two camps. Run tests in CommonJS mode, or run them in ESM mode. Pick one and stick to it.

Pick a direction and align these three files

  • Jest config — Decide whether Jest should treat TypeScript as ESM and set transforms to match.
  • tsconfig.spec.json — Make the module target match your Jest mode and your build output style.
  • package.json — If you set "type": "module", understand that Node treats .js as ESM by default.

This table maps common failure lines to the fastest fix area.

Symptom In Output Likely Cause Where To Fix
import … from … in a TS test TS not transformed for Jest jest transform / preset
import … in node_modules ESM package skipped transformIgnorePatterns
.mjs file fails Jest mode mismatch ESM config or CJS transform

Fixes By Root Cause

Once you know which file caused the crash, you can match it to one of the patterns below. Apply one fix at a time, then rerun a single test file.

Root cause 1: Jest is not using the Angular preset

If you set up Jest long ago, you may have a plain TypeScript config and no Angular preset. Angular templates, style URLs, and zone setup need the preset wiring.

  • Use the preset — Set preset: 'jest-preset-angular' in your Jest config.
  • Load setup file — Add a setup file like setup-jest.ts and import jest-preset-angular/setup-jest there.
// jest.config.js
module.exports = {
  preset: 'jest-preset-angular',
  setupFilesAfterEnv: ['/setup-jest.ts'],
  testMatch: ['**/*.spec.ts'],
};
// setup-jest.ts
import 'jest-preset-angular/setup-jest';

Root cause 2: Coverage works differently than plain test runs

Some teams fix the import error and then hit a new failure only when they run coverage. That happens because Jest can use a Babel step while producing coverage output, even if your normal transform path is TypeScript-first. Keep it small, then commit the file.

  • Add babel-jest — Install babel-jest, @babel/core, and @babel/preset-env as dev deps.
  • Create a .babelrc — Add a small config so Babel can parse the syntax your deps ship.
  • Re-run coverage — Use jest --coverage and confirm the same spec file passes.
// .babelrc
{
  "presets": ["@babel/preset-env"]
}

Root cause 3: TypeScript module output and Jest mode don’t match

If tsconfig.spec.json emits ESM but Jest runs CommonJS, imports may never be rewritten.

  1. Open tsconfig.spec.json — Check compilerOptions.module and target.
  2. Match Jest mode — If you want CommonJS tests, set module to CommonJS. If you want ESM tests, keep an ES module target and configure Jest for ESM.

Root cause 4: You are in ESM mode but ts-jest is not

If your project uses "type": "module" or NodeNext-style TypeScript, Jest may run ESM, but ts-jest still needs ESM output.

  • Enable ESM in ts-jest — Set useESM: true inside your ts-jest transform config.
  • Treat TS as ESM — Add extensionsToTreatAsEsm: ['.ts'] in Jest config.
// jest.config.ts
import type { Config } from 'jest';

const config: Config = {
  preset: 'jest-preset-angular',
  extensionsToTreatAsEsm: ['.ts'],
  transform: {
    '^.+\\\\.(ts|mjs|js|html)$': [
      'ts-jest',
      { useESM: true },
    ],
  },
};

export default config;

Root cause 5: An ESM-only dependency is skipped by default

Jest skips transforming most files inside node_modules. That’s fine for packages that ship CommonJS, but it breaks when a dependency ships ESM that Node can’t run under your current Jest setup.

The fix is to allowlist the package (or a small set of packages) in transformIgnorePatterns so Jest transforms them too.

// jest.config.js
module.exports = {
  preset: 'jest-preset-angular',
  transformIgnorePatterns: [
    'node_modules/(?!(@scope/esm-lib|another-esm-lib)/)',
  ],
};
  • Start with one package — Add only the package from the failing stack trace, then rerun tests.

Root cause 6: Your Jest config file can’t be loaded

If you use jest.config.ts and Jest can’t load it, it may fall back to defaults or mask the real issue.

  1. Try a JS config — Rename to jest.config.cjs or jest.config.js and export a plain object.
  2. Keep TS types optional — TS typing is nice, but getting tests green matters more.

Node Modules Checks That Save Hours

When the failing file lives under node_modules, the root cause is rarely Angular itself. It’s almost always a package that shipped ESM and expects tooling to transform it.

Spot what entry point Jest picked

Many packages publish multiple entry points. Your resolver choice decides which one you get.

  • Open the package.json — Look for exports, module, and main fields.
  • Check the file extension.mjs and .js under type module often point to ESM.
  • Confirm the failing import — The first import line in that file is the line Node couldn’t execute.

Keep transformIgnorePatterns readable

A messy regex becomes a trap later. Keep a short allowlist and add a comment so the next person knows why it exists.

// jest.config.js
module.exports = {
  preset: 'jest-preset-angular',
  transformIgnorePatterns: [
    'node_modules/(?!(@scope/esm-lib)/)', // ESM-only dependency
  ],
};

Make The Fix Stick Across Upgrades

Once tests run, take a few minutes to prevent the same error on the next dependency bump.

Keep versions in a compatible range

Angular, Jest, and your transformer packages should be upgraded as a set. When you update Jest, check your preset and transformer docs and bump them too.

  • Pin Jest and preset together — Keep jest, jest-preset-angular, and ts-jest in step.
  • Clear caches after config changes — Run jest --clearCache when a change doesn’t seem to apply.

Add a tiny “config sanity” test

A tiny smoke spec can catch module-mode issues early.

  1. Create a smoke spec — Add a smoke.spec.ts file that imports a simple util and runs one assertion.
  2. Run it in CI — Keep it in your normal test run so it fails fast when module wiring breaks.

When you see this error again, don’t guess. angular jest syntaxerror cannot use import statement outside a module. Follow this path: find the failing file, decide if it’s yours, then fix transforms.

For reference, the exact error name you’re fixing is angular jest syntaxerror cannot use import statement outside a module, and it almost always traces back to one mismatch you can pin down in a few minutes.