Fix: ReferenceError: jest is not defined (ESM tests)
Access Jest's mocking object in native ESM tests without confusing it with the test, expect and global names that remain available by default.
TL;DR#
ReferenceError: jest is not defined on jest.fn() almost always means your
project runs Jest under native ES modules ("type": "module" in
package.json, tests started with --experimental-vm-modules) — and native
ESM requires explicit access to the jest object. Add
import {jest} from '@jest/globals' to the top of the file, or expose it
globally once from a setup file.
The error#
A test that mocks fetch throws before it gets anywhere near an assertion:
ReferenceError: jest is not defined
at Object.<anonymous> (app.test.js:7:20)The line it points at is a completely ordinary mock:
test("Get total number of people", async () => {
global.fetch = jest.fn(() => Promise.resolve({
json: () => Promise.resolve({count: 15})
})
)
expect(await getTotalNumPeople()).toBe(15);
});This exact symptom was reported on Stack Overflow
by a developer who had just switched a plain Node project to ES modules,
adding "type": "module" to package.json and following the usual guide
for running Jest under --experimental-vm-modules. The test worked with
CommonJS the day before; nothing in the test file itself changed, only the
module system around it. The question also notes a second, related symptom:
commenting out the jest.fn() mock doesn't make the test pass — it just
trades one ReferenceError for another, this time complaining that global
itself is not defined, since the mock also reaches for global.fetch.
That reported symptom needs a separate environment diagnosis: native ESM
alone does not remove Node's global object.
Why it happens#
With the default injectGlobals setting, Jest exposes test, describe
and expect globally. In CommonJS test files, Jest also supplies the jest
object through its module wrapper.
Native ES modules don't go through that wrapper. When package.json has
"type": "module" and Jest runs the file as a real ES module (via Node's
--experimental-vm-modules flag), Jest's own documentation is explicit that
the jest object needs explicit access in ESM — import it from
@jest/globals or use import.meta.jest. This does not remove test,
describe or expect when Jest's default injectGlobals setting is enabled.
Node's global remains available too; it is distinct from the CommonJS
module-local names such as require and module. If global is missing,
inspect the actual execution environment instead of treating it as an
automatic consequence of ESM.
Fix#
1. Import jest explicitly in the test file#
The minimal fix, and the one Jest's own ESM guide recommends first, is a single import at the top of the affected file:
import { jest } from '@jest/globals';
import { getTotalNumPeople } from './app.js';
test('Get total number of people', async () => {
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ count: 15 }),
})
);
expect(await getTotalNumPeople()).toBe(15);
});If your linter needs explicit names, use
import { jest, expect, test } from '@jest/globals'.
Importing jest alone does not also import the other names.
2. Or expose jest globally once, for every test file#
If you don't want the import at the top of every file, add a setup file that
runs before your suite and attaches jest to global:
import { jest } from '@jest/globals';
global.jest = jest;{
"jest": {
"setupFiles": ["<rootDir>/test-setup.js"]
}
}Every test file in the project can then use jest.fn() without its own
import, the same way it worked before switching to ESM.
3. Confirm the ESM run itself is configured#
ReferenceError: jest is not defined only appears once the file is actually
running as an ES module — if Jest instead fails immediately with
SyntaxError: Cannot use import statement outside a module, the ESM runner
isn't wired up yet. Jest needs Node started with the experimental VM modules
flag: A Vite project that leaves Jest on CommonJS fails differently, with SyntaxError: Cannot use 'import.meta' outside a module wherever the source reads import.meta.env, and the import.meta fix for Jest in a Vite project covers mapping those reads to one stand-in module or testing with Vitest instead.
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"or, equivalently, NODE_OPTIONS=--experimental-vm-modules npx jest. On
Windows, set the variable with
cross-env rather than inline,
since NODE_OPTIONS=... command isn't valid syntax in cmd.exe or
PowerShell.
Check your own module error#
ReferenceError: jest is not defined is one specific symptom of a broader
family of ESM/CommonJS mismatches — require() of ES Module not supported,
exports is not defined in ES module scope, and a handful of others all
trace back to the same root cause: some part of the toolchain expected
CommonJS and got an ES module, or vice versa. If you're not sure which of
those you're actually looking at, paste the exact error below:
Runs entirely in your browser — nothing you paste is sent anywhere. Tokens and passwords that appear in paths or URLs are masked in the output.
Optional: package.json, file extension, Node.js version (sharper advice)
Verify the fix#
Re-run the failing test file:
npm testjest.fn() should now return a mock function instead of throwing, and the
assertion runs normally through to completion. If you added the global
setup file instead of the per-file import, check a different test file
that never imports jest directly — it should also see jest.fn without a
ReferenceError, which confirms the setup file actually loaded before the
suite rather than the fix only working by coincidence in the one file you
edited.
Also re-run your full suite, not just the one file you edited. If some test
files still throw ReferenceError: jest is not defined while others don't,
double-check that every affected file is actually covered by the same Jest
configuration — a monorepo with more than one jest.config.js, or a
testPathIgnorePatterns override in one workspace, can leave the setup file
wired to only part of the project.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
The import.meta.jest alternative#
Jest also exposes the same object through import.meta.jest inside an ESM
test file, without any import statement:
import.meta.jest.useFakeTimers();It's equivalent to importing from @jest/globals — jest === import.meta.jest
is true in a Jest ESM run — so which one you use is a style choice, not a
functional difference. The explicit import tends to read better in a file
that also imports expect and describe the same way.
If your ESM migration instead trips on the bundler side — Vite or Rollup
rejecting an import rather than Jest rejecting a global — the failure mode
and the fix are different; see
Fix Cannot find module '@vitejs/plugin-react' in Vite
for that class of error, and
Fix ESLint 'import/extensions' Definition Not Found
if the complaint is coming from your linter instead of your test runner. And
if TypeScript itself is the one complaining — a red squiggle under jest in
your editor even after the import compiles and runs — that's a missing
@types/jest or a tsconfig.json types array that doesn't list it, a
separate class of error covered in
Fix TS7016: Could Not Find Declaration File for Module.
This flag is still labelled experimental in Jest's own docs years after ESM support landed — expect the odd rough edge like this one until Jest ships first-class ESM support without the flag.
Further reading: Cannot access 'Player' before initialization: ESM cycle.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix: Jest SyntaxError Unexpected token export (uuid library)
The fix depends on whether the stale uuid build is yours or a transitive dependency's — here is how to tell, and the exact config for each case.
Cannot access 'Player' before initialization: ESM cycle
Find the import loop behind the ReferenceError with madge, then cut the one edge that points from the base class back to its subclasses.
Fix ESLint: Module.createRequire is not a function
Reproduced on Node 10 vs Node 18 with the same node_modules: the crash is the Node runtime executing ESLint, not Parcel or a broken module resolution.


