jestjs/jest · error · Error
JSDOM did not return a Window object
Error message
JSDOM did not return a Window object
What it means
After constructing a JSDOM instance the environment assigns `this.global = this.dom.window`. If `dom.window` is null/undefined (jsdom failed to build a Window), the environment cannot install globals and throws at index.ts:98. This guards every subsequent global assignment from a null dereference.
Source
Thrown at packages/jest-environment-jsdom-abstract/src/index.ts:98
: '<!DOCTYPE html>',
{
pretendToBeVisual: true,
resources:
typeof projectConfig.testEnvironmentOptions.userAgent === 'string'
? new ResourceLoader({
userAgent: projectConfig.testEnvironmentOptions.userAgent,
})
: undefined,
runScripts: 'dangerously',
url: 'http://localhost/',
virtualConsole,
...projectConfig.testEnvironmentOptions,
},
);
const global = (this.global = this.dom.window as unknown as Win);
if (global == null) {
throw new Error('JSDOM did not return a Window object');
}
// TODO: remove at some point - for "universal" code (code should use `globalThis`)
global.global = global;
// Node's error-message stack size is limited at 10, but it's pretty useful
// to see more than that when a test fails.
this.global.Error.stackTraceLimit = 100;
installCommonGlobals(global, projectConfig.globals);
// TODO: remove this ASAP, but it currently causes tests to run really slow
global.Buffer = Buffer;
// Report uncaught errors.
this.errorEventListener = event => {
if (userErrorListenerCount === 0 && event.error != null) {
process.emit('uncaughtException', event.error);
}View on GitHub (pinned to f49721c78e)
Solutions
- Simplify testEnvironmentOptions to defaults and re-add options one at a time to find the trigger.
- Upgrade/downgrade jsdom to a known-good version matching the adapter.
- Run a minimal JSDOM script in isolation to confirm jsdom itself produces a window.
- Check for native dependency issues (canvas) and install the prebuilt binaries if needed.
Example fix
// before (jest.config)
testEnvironmentOptions: {
html: complexBrokenHtmlString,
resources: new (require('jsdom').ResourceLoader)({ strictSSL: 'maybe' }),
}
// after
testEnvironmentOptions: {
html: '<!DOCTYPE html>',
} Defensive patterns
Strategy: try-catch
Validate before calling
// sanity-check jsdom in isolation before running the suite
const {JSDOM} = require('jsdom');
const dom = new JSDOM('<!DOCTYPE html>');
if (dom.window == null) throw new Error('jsdom produced no window'); Type guard
const hasWindow = (dom: { window: unknown | null }): dom is { window: Window } => dom.window != null; Try / catch
try {
testEnvironmentOptions = { html };
} catch (e) {
// fall back to defaults if a custom html/resource breaks window creation
testEnvironmentOptions = {};
} Prevention
- Start from default testEnvironmentOptions and add fields incrementally.
- Pin a known-good jsdom version.
- Isolate jsdom in a scratch script when debugging.
When it happens
Trigger: JSDOM internally fails to produce a window — e.g. an unrecoverable parse error on the provided `testEnvironmentOptions.html`, a jsdom build that is corrupted, or a VirtualConsole/ResourceLoader misconfiguration that short-circuits window creation.
Common situations: Passing invalid `testEnvironmentOptions.html` (non-string handled, but a bad ResourceLoader/userAgent object can throw inside jsdom); an incompatible jsdom version that changed constructor semantics; a native module load failure in jsdom on a restricted CI image.
Related errors
- Custom export conditions specified but they are not an array
- Jest: Got error running ${moduleName} - ${modulePath}, reaso
- Unable to forward JSDOM console output - neither sendTo nor
- Custom export conditions specified but they are not an array
- The --config option requires a JSON string literal, or a fil
AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03).
Data as JSON: /data/errors/46eeb94265b2c432.json.
Report an issue: GitHub.