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 chain —
ts-jest,babel-jest, orjest-preset-angularisn’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.
- Read the first path — Find the first file path shown right after the error and copy it somewhere.
- Check the extension — Note if it ends with
.ts,.mjs,.js, or.cjs. - Run one test file — Use
jest path/to/test.spec.ts -ito reduce noise while you tweak config.
- Print Jest config — Run
jest --showConfigand confirmtransform,preset, andtransformIgnorePatterns. - 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
moduletarget match your Jest mode and your build output style. - package.json — If you set
"type": "module", understand that Node treats.jsas 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.tsand importjest-preset-angular/setup-jestthere.
// 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-envas dev deps. - Create a .babelrc — Add a small config so Babel can parse the syntax your deps ship.
- Re-run coverage — Use
jest --coverageand 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.
- Open tsconfig.spec.json — Check
compilerOptions.moduleandtarget. - 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: trueinside 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.
- Try a JS config — Rename to
jest.config.cjsorjest.config.jsand export a plain object. - 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, andmainfields. - Check the file extension —
.mjsand.jsunder type module often point to ESM. - Confirm the failing import — The first
importline 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, andts-jestin step. - Clear caches after config changes — Run
jest --clearCachewhen a change doesn’t seem to apply.
Add a tiny “config sanity” test
A tiny smoke spec can catch module-mode issues early.
- Create a smoke spec — Add a
smoke.spec.tsfile that imports a simple util and runs one assertion. - 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.
