0
# Configuration
1
2
jsdom provides comprehensive configuration options through the JSDOM constructor's `options` parameter. These options control document properties, script execution, resource loading, visual rendering simulation, and more.
3
4
## Capabilities
5
6
### Basic Document Options
7
8
Options that control document properties and metadata.
9
10
#### url
11
12
```javascript { .api }
13
/**
14
* Set the document URL
15
* @default "about:blank"
16
*/
17
url?: string
18
```
19
20
Sets `window.location`, `document.URL`, and `document.documentURI`. Affects relative URL resolution within the document and same-origin restrictions for subresources.
21
22
**Must be a valid absolute URL**. URLs are canonicalized according to the URL Standard.
23
24
**Usage Examples:**
25
26
```javascript
27
const { JSDOM } = require("jsdom");
28
29
const dom = new JSDOM(`<img src="logo.png">`, {
30
url: "https://example.com/page.html"
31
});
32
33
console.log(dom.window.location.href); // "https://example.com/page.html"
34
console.log(dom.window.document.URL); // "https://example.com/page.html"
35
console.log(dom.window.document.querySelector("img").src);
36
// "https://example.com/logo.png" (resolved relative to URL)
37
38
// URL canonicalization
39
const dom2 = new JSDOM(``, { url: "http:example.com" });
40
console.log(dom2.window.location.href); // "http://example.com/"
41
```
42
43
#### referrer
44
45
```javascript { .api }
46
/**
47
* Set the document referrer
48
* @default "" (empty string)
49
*/
50
referrer?: string
51
```
52
53
Sets `document.referrer`. Must be a valid absolute URL if provided. URLs are canonicalized before use.
54
55
**Usage Examples:**
56
57
```javascript
58
const { JSDOM } = require("jsdom");
59
60
const dom = new JSDOM(``, {
61
referrer: "https://google.com/"
62
});
63
64
console.log(dom.window.document.referrer); // "https://google.com/"
65
66
// Default is empty string
67
const dom2 = new JSDOM(``);
68
console.log(dom2.window.document.referrer); // ""
69
```
70
71
#### contentType
72
73
```javascript { .api }
74
/**
75
* Set the content type and parsing mode
76
* @default "text/html"
77
*/
78
contentType?: string
79
```
80
81
Affects `document.contentType` and determines how the document is parsed (HTML vs XML). Must be a valid HTML MIME type or XML MIME type.
82
83
Can include a `charset` parameter for encoding sniffing (though BOM takes precedence).
84
85
**Valid HTML MIME types:** `"text/html"`, `"application/xhtml+xml"`
86
87
**Valid XML MIME types:** `"application/xml"`, `"text/xml"`, `"image/svg+xml"`, etc.
88
89
**Usage Examples:**
90
91
```javascript
92
const { JSDOM } = require("jsdom");
93
94
// HTML parsing (default)
95
const htmlDom = new JSDOM(`<p>test</p>`, {
96
contentType: "text/html"
97
});
98
console.log(htmlDom.window.document.contentType); // "text/html"
99
100
// XML parsing
101
const xmlDom = new JSDOM(`<doc><item/></doc>`, {
102
contentType: "application/xhtml+xml"
103
});
104
console.log(xmlDom.window.document.contentType); // "application/xhtml+xml"
105
106
// With charset parameter
107
const dom = new JSDOM(buffer, {
108
contentType: "text/html; charset=utf-8"
109
});
110
console.log(dom.window.document.contentType); // "text/html" (parameter not shown)
111
112
// Invalid content type throws
113
try {
114
new JSDOM(``, { contentType: "application/json" });
115
} catch (e) {
116
console.error("Not a valid HTML or XML MIME type");
117
}
118
```
119
120
### Parsing Options
121
122
Options that affect how HTML is parsed and tracked.
123
124
#### includeNodeLocations
125
126
```javascript { .api }
127
/**
128
* Preserve source code location information
129
* @default false
130
*/
131
includeNodeLocations?: boolean
132
```
133
134
When `true`, preserves location info produced by the HTML parser, enabling the `nodeLocation()` method. Also ensures correct line numbers in exception stack traces for `<script>` elements.
135
136
**Cannot be used with XML content types** (XML parser doesn't support location info).
137
138
Disabled by default for performance.
139
140
**Usage Examples:**
141
142
```javascript
143
const { JSDOM } = require("jsdom");
144
145
const dom = new JSDOM(`<p>Hello</p>`, {
146
includeNodeLocations: true
147
});
148
149
const p = dom.window.document.querySelector("p");
150
const location = dom.nodeLocation(p);
151
console.log(location);
152
// { startOffset: 0, endOffset: 12, startLine: 1, ... }
153
154
// Without the option, nodeLocation() throws
155
const dom2 = new JSDOM(`<p>Hello</p>`);
156
try {
157
dom2.nodeLocation(dom2.window.document.querySelector("p"));
158
} catch (e) {
159
console.error("Location information was not saved");
160
}
161
162
// Cannot use with XML
163
try {
164
new JSDOM(`<doc/>`, {
165
contentType: "application/xml",
166
includeNodeLocations: true
167
});
168
} catch (e) {
169
console.error("Cannot set includeNodeLocations with XML");
170
}
171
```
172
173
### Script Execution Options
174
175
Options that control script execution behavior and security.
176
177
#### runScripts
178
179
```javascript { .api }
180
/**
181
* Control script execution mode
182
* @default undefined (no script execution)
183
*/
184
runScripts?: "dangerously" | "outside-only"
185
```
186
187
Controls whether and how JavaScript code executes within the jsdom.
188
189
**Values:**
190
191
- **`undefined` (default)**: Scripts don't execute. `<script>` tags are parsed but not run. Event handler attributes don't function. `window.eval` === Node.js `eval`.
192
193
- **`"dangerously"`**: Executes `<script>` tags and event handler attributes. **Security warning**: The sandbox is not foolproof - code can escape to Node.js environment if it tries hard enough. **Only use with trusted content**.
194
195
- **`"outside-only"`**: Provides fresh JavaScript globals (`window.Array`, `window.Promise`, `window.eval`, etc.) for external script execution, but doesn't run inline `<script>` tags or event handler attributes. Safe to enable. Use `window.eval()` or VM module to run code.
196
197
**Usage Examples:**
198
199
```javascript
200
const { JSDOM } = require("jsdom");
201
202
// Default: scripts don't run
203
const dom1 = new JSDOM(`
204
<div id="content"></div>
205
<script>
206
document.getElementById("content").innerHTML = "<p>Added</p>";
207
</script>
208
`);
209
console.log(dom1.window.document.getElementById("content").children.length); // 0
210
211
// "dangerously": scripts run (SECURITY WARNING!)
212
const dom2 = new JSDOM(`
213
<div id="content"></div>
214
<script>
215
document.getElementById("content").innerHTML = "<p>Added</p>";
216
</script>
217
`, { runScripts: "dangerously" });
218
console.log(dom2.window.document.getElementById("content").children.length); // 1
219
220
// "outside-only": run scripts from outside
221
const dom3 = new JSDOM(`
222
<div id="content"></div>
223
<script>
224
// This won't run
225
document.getElementById("content").innerHTML = "<p>From inside</p>";
226
</script>
227
`, { runScripts: "outside-only" });
228
229
// Script didn't run
230
console.log(dom3.window.document.getElementById("content").children.length); // 0
231
232
// But we can run code from outside
233
dom3.window.eval(`
234
document.getElementById("content").innerHTML = "<p>From outside</p>";
235
`);
236
console.log(dom3.window.document.getElementById("content").children.length); // 1
237
238
// Event handler attributes require "dangerously"
239
const dom4 = new JSDOM(`<button onclick="console.log('clicked')">Click</button>`, {
240
runScripts: "dangerously"
241
});
242
// onclick will work
243
244
// But event handler properties work regardless
245
const dom5 = new JSDOM(`<button>Click</button>`);
246
const button = dom5.window.document.querySelector("button");
247
button.onclick = () => console.log("clicked"); // This works
248
```
249
250
### Resource Loading Options
251
252
Options that control loading of external resources.
253
254
#### resources
255
256
```javascript { .api }
257
/**
258
* Configure resource loading
259
* @default undefined (no resources loaded)
260
*/
261
resources?: "usable" | ResourceLoader
262
```
263
264
Controls whether and how jsdom loads subresources (scripts, stylesheets, images, iframes).
265
266
**Values:**
267
268
- **`undefined` (default)**: No subresources loaded
269
270
- **`"usable"`**: Loads all usable resources:
271
- Frames and iframes via `<frame>` and `<iframe>`
272
- Stylesheets via `<link rel="stylesheet">`
273
- Scripts via `<script src="">` (only if `runScripts: "dangerously"`)
274
- Images via `<img>` (only if `canvas` npm package installed)
275
276
- **ResourceLoader instance**: Custom resource loader for advanced control
277
278
**Note:** Default `url` is `"about:blank"`, so relative URLs will fail to load. Set a proper `url` option when using resource loading.
279
280
**Usage Examples:**
281
282
```javascript
283
const { JSDOM, ResourceLoader } = require("jsdom");
284
285
// Load usable resources
286
const dom = new JSDOM(`
287
<!DOCTYPE html>
288
<html>
289
<head>
290
<link rel="stylesheet" href="styles.css">
291
<script src="app.js"></script>
292
</head>
293
<body><img src="logo.png"></body>
294
</html>
295
`, {
296
url: "https://example.com/",
297
resources: "usable",
298
runScripts: "dangerously" // Required for <script> loading
299
});
300
301
// Custom resource loader
302
class MyResourceLoader extends ResourceLoader {
303
fetch(url, options) {
304
if (url.endsWith(".css")) {
305
return Promise.resolve(Buffer.from("body { margin: 0; }"));
306
}
307
return super.fetch(url, options);
308
}
309
}
310
311
const dom2 = new JSDOM(`<link rel="stylesheet" href="custom.css">`, {
312
url: "https://example.com/",
313
resources: new MyResourceLoader()
314
});
315
316
// No resources loaded (default)
317
const dom3 = new JSDOM(`<script src="script.js"></script>`);
318
// script.js won't load
319
```
320
321
### Visual Rendering Options
322
323
Options that simulate visual browser behavior.
324
325
#### pretendToBeVisual
326
327
```javascript { .api }
328
/**
329
* Pretend to be a visual browser
330
* @default false
331
*/
332
pretendToBeVisual?: boolean
333
```
334
335
When `true`, jsdom pretends to render and display content. Does **not** actually implement layout or rendering.
336
337
**Effects:**
338
339
- Sets `document.hidden` to `false` (instead of `true`)
340
- Sets `document.visibilityState` to `"visible"` (instead of `"prerender"`)
341
- Enables `window.requestAnimationFrame()` and `window.cancelAnimationFrame()` methods
342
343
**Usage Examples:**
344
345
```javascript
346
const { JSDOM } = require("jsdom");
347
348
// Default: acts as headless
349
const dom1 = new JSDOM();
350
console.log(dom1.window.document.hidden); // true
351
console.log(dom1.window.document.visibilityState); // "prerender"
352
console.log(typeof dom1.window.requestAnimationFrame); // "undefined"
353
354
// Pretend to be visual
355
const dom2 = new JSDOM(``, { pretendToBeVisual: true });
356
console.log(dom2.window.document.hidden); // false
357
console.log(dom2.window.document.visibilityState); // "visible"
358
console.log(typeof dom2.window.requestAnimationFrame); // "function"
359
360
// Use requestAnimationFrame
361
dom2.window.requestAnimationFrame(timestamp => {
362
console.log("Animation frame:", timestamp);
363
});
364
```
365
366
### Storage Options
367
368
Options that control Web Storage behavior.
369
370
#### storageQuota
371
372
```javascript { .api }
373
/**
374
* Maximum storage size for localStorage and sessionStorage
375
* @default 5000000 (5 million code units per origin)
376
*/
377
storageQuota?: number
378
```
379
380
Maximum size in code units for the separate storage areas used by `localStorage` and `sessionStorage`. Attempting to store data exceeding this limit throws a `DOMException`.
381
382
Default is 5,000,000 code units per origin, as inspired by the HTML specification.
383
384
**Usage Examples:**
385
386
```javascript
387
const { JSDOM } = require("jsdom");
388
389
// Default quota
390
const dom1 = new JSDOM(``, { url: "https://example.com/" });
391
dom1.window.localStorage.setItem("key", "value"); // Works
392
393
// Small quota
394
const dom2 = new JSDOM(``, {
395
url: "https://example.com/",
396
storageQuota: 100
397
});
398
399
try {
400
// Try to store more than 100 code units
401
const largeData = "x".repeat(101);
402
dom2.window.localStorage.setItem("key", largeData);
403
} catch (e) {
404
console.error("QuotaExceededError:", e.name);
405
}
406
```
407
408
### Console and Cookie Options
409
410
Options for console output capture and cookie management.
411
412
#### virtualConsole
413
414
```javascript { .api }
415
/**
416
* Virtual console for capturing output
417
* @default new VirtualConsole().forwardTo(console)
418
*/
419
virtualConsole?: VirtualConsole
420
```
421
422
Provides a VirtualConsole instance for capturing console output from within jsdom. Default forwards all output to Node.js console.
423
424
See [Virtual Console](./virtual-console.md) for detailed documentation.
425
426
**Usage Examples:**
427
428
```javascript
429
const { JSDOM, VirtualConsole } = require("jsdom");
430
431
// Custom virtual console
432
const virtualConsole = new VirtualConsole();
433
virtualConsole.on("log", (message) => {
434
console.log("Page logged:", message);
435
});
436
virtualConsole.on("error", (message) => {
437
console.error("Page error:", message);
438
});
439
440
const dom = new JSDOM(`
441
<script>console.log("Hello from page");</script>
442
`, {
443
runScripts: "dangerously",
444
virtualConsole: virtualConsole
445
});
446
// Logs: "Page logged: Hello from page"
447
```
448
449
#### cookieJar
450
451
```javascript { .api }
452
/**
453
* Cookie jar for HTTP cookie storage
454
* @default new CookieJar()
455
*/
456
cookieJar?: CookieJar
457
```
458
459
Provides a CookieJar instance for cookie storage. Useful for sharing cookies across multiple jsdom instances or priming cookies before creation.
460
461
See [Resources](./resources.md) for detailed documentation.
462
463
**Usage Examples:**
464
465
```javascript
466
const { JSDOM, CookieJar } = require("jsdom");
467
468
// Shared cookie jar
469
const cookieJar = new CookieJar();
470
471
const dom1 = new JSDOM(``, {
472
url: "https://example.com/",
473
cookieJar: cookieJar
474
});
475
476
// Set cookie via document.cookie
477
dom1.window.document.cookie = "session=abc123";
478
479
// Cookie available in another jsdom with same jar
480
const dom2 = new JSDOM(``, {
481
url: "https://example.com/",
482
cookieJar: cookieJar
483
});
484
485
console.log(dom2.window.document.cookie); // "session=abc123"
486
487
// Pre-populate cookies
488
const prePopulatedJar = new CookieJar();
489
prePopulatedJar.setCookieSync("token=xyz789", "https://example.com/");
490
491
const dom3 = new JSDOM(``, {
492
url: "https://example.com/",
493
cookieJar: prePopulatedJar
494
});
495
496
console.log(dom3.window.document.cookie); // "token=xyz789"
497
```
498
499
### Advanced Options
500
501
Options for advanced use cases.
502
503
#### beforeParse
504
505
```javascript { .api }
506
/**
507
* Callback invoked before HTML parsing
508
* @default no-op function
509
*/
510
beforeParse?: (window: Window) => void
511
```
512
513
Callback function invoked after `Window` and `Document` objects are created, but before any HTML is parsed. Useful for modifying the environment, adding shims, or injecting globals before the page loads.
514
515
**Parameters:**
516
517
- `window`: The Window object (global proxy)
518
519
**Usage Examples:**
520
521
```javascript
522
const { JSDOM } = require("jsdom");
523
524
const dom = new JSDOM(`<p>Hello</p>`, {
525
beforeParse(window) {
526
// Window and document exist, but no nodes parsed yet
527
console.log(window.document.childNodes.length); // 0
528
529
// Add custom API
530
window.myCustomAPI = () => {
531
return "Custom functionality";
532
};
533
534
// Add shim for missing API
535
if (!window.someAPI) {
536
window.someAPI = () => {
537
console.log("Shimmed API");
538
};
539
}
540
541
// Modify navigator
542
window.navigator.userAgent = "Custom User Agent";
543
}
544
});
545
546
// Custom API is available
547
console.log(dom.window.myCustomAPI()); // "Custom functionality"
548
549
// HTML has been parsed
550
console.log(dom.window.document.querySelector("p").textContent); // "Hello"
551
```
552
553
## Complete Options Interface
554
555
```javascript { .api }
556
/**
557
* Configuration options for JSDOM constructor
558
*/
559
interface JSDOMOptions {
560
/** Document URL (default: "about:blank") */
561
url?: string;
562
563
/** Document referrer (default: "") */
564
referrer?: string;
565
566
/** Content type for parsing (default: "text/html") */
567
contentType?: string;
568
569
/** Enable node location tracking for source mapping (default: false) */
570
includeNodeLocations?: boolean;
571
572
/** Storage quota for localStorage/sessionStorage in code units (default: 5000000) */
573
storageQuota?: number;
574
575
/** Script execution mode (default: undefined) */
576
runScripts?: "dangerously" | "outside-only";
577
578
/** Resource loading configuration (default: undefined) */
579
resources?: "usable" | ResourceLoader;
580
581
/** Pretend to be a visual browser (default: false) */
582
pretendToBeVisual?: boolean;
583
584
/** Virtual console for output capture (default: new VirtualConsole().forwardTo(console)) */
585
virtualConsole?: VirtualConsole;
586
587
/** Cookie jar for cookie storage (default: new CookieJar()) */
588
cookieJar?: CookieJar;
589
590
/** Callback before HTML parsing (default: no-op) */
591
beforeParse?: (window: Window) => void;
592
}
593
```
594
595
## Common Configuration Patterns
596
597
### Testing Environment
598
599
```javascript
600
const { JSDOM } = require("jsdom");
601
602
const dom = new JSDOM(`<!DOCTYPE html><body></body>`, {
603
url: "https://example.org/",
604
referrer: "https://google.com/",
605
contentType: "text/html",
606
runScripts: "dangerously",
607
resources: "usable",
608
pretendToBeVisual: true
609
});
610
611
// Make available globally for tests
612
global.window = dom.window;
613
global.document = dom.window.document;
614
global.navigator = dom.window.navigator;
615
```
616
617
### Web Scraping
618
619
```javascript
620
const { JSDOM } = require("jsdom");
621
622
JSDOM.fromURL("https://example.com/", {
623
resources: "usable",
624
runScripts: "dangerously"
625
}).then(dom => {
626
const title = dom.window.document.title;
627
const content = dom.window.document.querySelector(".content").textContent;
628
console.log({ title, content });
629
});
630
```
631
632
### Safe Script Execution
633
634
```javascript
635
const { JSDOM } = require("jsdom");
636
637
const dom = new JSDOM(`<!DOCTYPE html><body></body>`, {
638
url: "https://example.org/",
639
runScripts: "outside-only"
640
});
641
642
// Run code safely from outside
643
dom.window.eval(`
644
document.body.innerHTML = '<h1>Safe execution</h1>';
645
`);
646
```
647
648
### Debug Mode
649
650
```javascript
651
const { JSDOM, VirtualConsole } = require("jsdom");
652
653
const virtualConsole = new VirtualConsole();
654
virtualConsole.on("log", msg => console.log("[Page]", msg));
655
virtualConsole.on("error", msg => console.error("[Page Error]", msg));
656
virtualConsole.on("jsdomError", e => console.error("[jsdom Error]", e));
657
658
const dom = new JSDOM(`<!DOCTYPE html><script>console.log("Hi!");</script>`, {
659
runScripts: "dangerously",
660
virtualConsole: virtualConsole,
661
includeNodeLocations: true,
662
resources: "usable"
663
});
664
```
665