The VirtualConsole class captures both in-page window.console calls and jsdom implementation messages. It provides event-based access to all console output and jsdom-specific error reporting.
Creates a new virtual console with no default behavior.
/**
* Creates a virtual console instance
* By default, does nothing - must add event listeners or use forwardTo()
*/
constructor();Usage Example:
const { JSDOM, VirtualConsole } = require("jsdom");
const virtualConsole = new VirtualConsole();
const dom = new JSDOM(``, { virtualConsole });
// Without listeners or forwardTo(), console output is silentForwards all console output to another console object.
/**
* Forwards virtual console output to another console
* @param console - Target console (e.g., Node.js console)
* @param options - Filtering options for jsdomError events
* @returns this (for chaining)
* @throws TypeError if jsdomErrors is not undefined, "none", or an array
*/
forwardTo(console: Console, options?: ForwardOptions): this;
interface ForwardOptions {
/**
* Controls which jsdomError events are forwarded
* - undefined: All jsdomErrors forwarded (default)
* - "none": No jsdomErrors forwarded
* - string[]: Only specified error types forwarded
* @throws TypeError if value is not undefined, "none", or an array
*/
jsdomErrors?: "none" | Array<"unhandled-exception" | "css-parsing" | "not-implemented" | "resource-loading">;
}Usage Examples:
const { JSDOM, VirtualConsole } = require("jsdom");
// Forward everything to Node.js console
const virtualConsole = new VirtualConsole();
virtualConsole.forwardTo(console);
const dom = new JSDOM(`
<script>
console.log("Hello from the page!");
console.error("An error occurred");
</script>
`, {
runScripts: "dangerously",
virtualConsole
});
// Output: Hello from the page!
// Output: An error occurred
// Forward console output but suppress jsdom errors
const vc = new VirtualConsole();
vc.forwardTo(console, { jsdomErrors: "none" });
// Forward only specific jsdom error types
const vc2 = new VirtualConsole();
vc2.forwardTo(console, {
jsdomErrors: ["unhandled-exception", "not-implemented"]
});
// CSS parsing and resource loading errors will not be forwardedThe VirtualConsole is an EventEmitter that emits events for all console methods.
/**
* Listen for console method calls
* @param event - Console method name
* @param listener - Event handler receiving console arguments
*/
on(event: ConsoleMethod, listener: (...args: any[]) => void): this;
type ConsoleMethod =
| "assert"
| "clear"
| "count"
| "countReset"
| "debug"
| "dir"
| "dirxml"
| "error"
| "group"
| "groupCollapsed"
| "groupEnd"
| "info"
| "log"
| "table"
| "time"
| "timeEnd"
| "timeLog"
| "trace"
| "warn";Usage Example:
const { JSDOM, VirtualConsole } = require("jsdom");
const virtualConsole = new VirtualConsole();
// Listen for specific console methods
virtualConsole.on("error", (...args) => {
console.error("Page error:", ...args);
});
virtualConsole.on("warn", (...args) => {
console.warn("Page warning:", ...args);
});
virtualConsole.on("info", (...args) => {
console.info("Page info:", ...args);
});
virtualConsole.on("log", (...args) => {
console.log("Page log:", ...args);
});
virtualConsole.on("dir", (obj) => {
console.log("Page dir:", obj);
});
const dom = new JSDOM(`
<script>
console.log("Message", 123);
console.error("Error message");
console.warn("Warning");
console.info("Info");
console.dir({ foo: "bar" });
</script>
`, {
runScripts: "dangerously",
virtualConsole
});Special event for jsdom implementation errors and warnings.
/**
* Listen for jsdom-specific errors
* @param event - Always "jsdomError"
* @param listener - Error handler
*/
on(event: "jsdomError", listener: (error: JSDOMError) => void): this;
interface JSDOMError {
/**
* Type of jsdom error
*/
type: "css-parsing" | "not-implemented" | "resource-loading" | "unhandled-exception";
/**
* Error message
*/
message: string;
/**
* Original exception (for certain error types)
*/
cause?: Error;
/**
* URL of resource (for resource-loading errors)
*/
url?: string;
/**
* CSS stylesheet text (for css-parsing errors)
*/
sheetText?: string;
}Error Types:
CSS parsing errors from the CSSOM parser.
{
type: "css-parsing",
message: string,
cause: Error, // Exception from rrweb-cssom parser
sheetText: string // Full text of stylesheet that failed to parse
}Called when unimplemented web platform methods are invoked.
{
type: "not-implemented",
message: string
}Resource loading failures (network errors, bad response codes).
{
type: "resource-loading",
message: string,
cause: Error, // Network error from Node.js or custom ResourceLoader
url: string // URL that failed to load
}Script execution errors not handled by Window error event listeners.
{
type: "unhandled-exception",
message: string,
cause: Error // Original exception thrown by script
}Usage Example:
const { JSDOM, VirtualConsole } = require("jsdom");
const virtualConsole = new VirtualConsole();
// Handle all jsdom errors
virtualConsole.on("jsdomError", (error) => {
switch (error.type) {
case "unhandled-exception":
console.error("Unhandled exception:", error.cause?.stack || error.message);
break;
case "css-parsing":
console.error("CSS parse error:", error.message);
console.error("CSS content:", error.sheetText);
break;
case "resource-loading":
console.error("Failed to load resource:", error.url);
console.error("Cause:", error.cause?.message);
break;
case "not-implemented":
console.warn("Not implemented:", error.message);
break;
}
});
const dom = new JSDOM(`
<html>
<head>
<style>
/* Invalid CSS */
.class {
color: #invalid-color;
}
</style>
<script src="https://nonexistent.example.com/script.js"></script>
</head>
<body>
<script>
throw new Error("Unhandled error in script");
</script>
</body>
</html>
`, {
runScripts: "dangerously",
resources: "usable",
virtualConsole
});You can use both forwardTo() and custom event listeners together.
Usage Example:
const { JSDOM, VirtualConsole } = require("jsdom");
const virtualConsole = new VirtualConsole();
// Forward regular console output to Node.js console
virtualConsole.forwardTo(console, { jsdomErrors: "none" });
// But handle jsdom errors specially
virtualConsole.on("jsdomError", (error) => {
if (error.type === "unhandled-exception") {
// Log to error tracking service
errorTracker.captureException(error.cause);
}
});
// And capture specific console methods for analysis
const errorLogs = [];
virtualConsole.on("error", (...args) => {
errorLogs.push({ timestamp: Date.now(), args });
});
const dom = new JSDOM(html, {
runScripts: "dangerously",
virtualConsole
});If no virtual console is provided to the JSDOM constructor, a default one is created that forwards everything to the Node.js console:
// These are equivalent:
const dom1 = new JSDOM(html);
const virtualConsole = new VirtualConsole();
virtualConsole.forwardTo(console);
const dom2 = new JSDOM(html, { virtualConsole });Set up event listeners before creating the JSDOM instance to capture errors that occur during parsing:
const { JSDOM, VirtualConsole } = require("jsdom");
// GOOD: Listeners set up before JSDOM creation
const virtualConsole = new VirtualConsole();
virtualConsole.on("jsdomError", (error) => {
console.error("Error:", error);
});
const dom = new JSDOM(html, { virtualConsole });
// BAD: Listeners set up after - may miss parsing errors
const dom2 = new JSDOM(html, { virtualConsole: new VirtualConsole() });
dom2.virtualConsole.on("jsdomError", (error) => {
// May miss errors that occurred during parsing
console.error("Error:", error);
});