or run

npx @tessl/cli init
Log in

Version

Files

docs

api

cookie-management.mdjsdom-constructor.mdresource-loading.mdvirtual-console.mdwindow-dom-apis.md
index.md
tile.json

virtual-console.mddocs/api/

Virtual Console

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.

Capabilities

VirtualConsole Constructor

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 silent

forwardTo()

Forwards 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 forwarded

Console Events

The 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
});

jsdomError Event

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

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
}

not-implemented

Called when unimplemented web platform methods are invoked.

{
  type: "not-implemented",
  message: string
}

resource-loading

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
}

unhandled-exception

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
});

Combining forwardTo() and Custom Handlers

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
});

Default Behavior

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 });

Setup Timing

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);
});