CodeSampleX

サンプル

happy-dom 20.11.2: VirtualConsolePrinter buffers console logs, destructively drains on read/readAsString calls, filters by log level, formats group indentation and collapsed group suppression, dispatches lifecycle events, and is exposed on Window via happyDOM.virtualConsolePrinter.

検証済みサンプル — npm happy-dom 20.11.2: VirtualConsolePrinter buffers console logs, destructively drains on read/readAsString calls, filters by log level, formats…

sha256:d441e94a7c6bb72eecdd1deff6dfec2ade1724d7325ec0c3ff65739e39d46a7e

このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。 合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。 MIT-0

実行証拠

宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。

証拠の基準
署名済みコントラクト合格
検証レシート
3
ビルドした署名鍵
3
宣言された環境 node linux x64 node node npm

検証実行環境

環境 コントラクト ステージ 実行日
node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-18
node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-18
node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5…
2026-09-07

ケース

HOW
ゴール
VirtualConsolePrinter buffers console logs, destructively drains on read/readAsString calls, filters by log level, formats group indentation and collapsed group suppression, dispatches lifecycle events, and is exposed on Window via happyDOM.virtualConsolePrinter.
パッケージ
シンボル
  • happy-dom.VirtualConsolePrinter
環境
node
作成日
2026-08-18T03:38:20Z

コントラクト

  1. VirtualConsolePrinter.read() and readAsString() destructively drain the internal log buffer upon invocation, causing subsequent immediate reads to return empty results.
  2. readAsString(minLogLevel) filters formatted output by severity while draining all log entries from the buffer regardless of level.
  3. console.group() indents log entries by two spaces with a ▼ prefix, whereas console.groupCollapsed() suppresses nested entries from readAsString() with a ▶ prefix.
  4. addEventListener dispatches synchronous 'print' and 'clear' events on log and clear operations, rejecting unsupported event names.
  5. close() marks the printer as closed, flushes buffered entries and listeners, and causes subsequent print and event calls to be ignored.
  6. Window instances expose the page VirtualConsolePrinter through window.happyDOM.virtualConsolePrinter.

ファイル

  • NOTES.md
  • csx.json
  • package-lock.json
  • package.json
  • test/contract.mjs

ソースアーティファクトをダウンロード (tar.gz)

ソース

NOTES.md
# happy-dom VirtualConsolePrinter

## Discovery
The solution search returned `NO_SAFE_MATCH` for `happy-dom.VirtualConsolePrinter` on `happy-dom@20.11.2`.

## Pinned Release
- `happy-dom`: `20.11.2`

## Observed Behavior
`VirtualConsolePrinter` manages captured virtual console logs in Happy-DOM:

1. **Destructive Buffer Reads**: Both `.read()` and `.readAsString()` empty the internal buffer (`#logEntries = []`) when called. A developer expecting `.read()` or `.readAsString()` to be non-destructive inspection calls will find subsequent reads returning empty arrays `[]` or empty strings `""`.
2. **Log Level Filtering Drains Buffer**: `.readAsString(minLogLevel)` filters output to include only entries whose level is greater than or equal to `minLogLevel` (using `VirtualConsoleLogLevelEnum`), but because it delegates to `.read()`, all buffered entries are drained, discarding lower-severity entries from the buffer as well.
3. **Group Formatting & Collapsed Suppression**: Log entries within a `console.group()` are indented with two spaces per level and prefixed with `▼ `. Entries within a `console.groupCollapsed()` are prefixed with `▶ ` for the group header, but any messages logged inside the collapsed group return empty strings and are suppressed from `.readAsString()`.
4. **Lifecycle & Events**: Dispatches synchronous DOM `Event` objects (`'print'` on `print()`, `'clear'` on `clear()`). Unsupported event names throw an error. Calling `.close()` sets `.closed` to `true`, clears all listeners and buffered entries, and causes subsequent calls to `.print()`, `.clear()`, and listener additions to be ignored.
5. **Window Integration**: Each `BrowserPage` creates a default `VirtualConsolePrinter`, accessible on detached `Window` instances via `window.happyDOM.virtualConsolePrinter`.
csx.json
{"case":{"believed":"readAsString() and read() inspect captured virtual console logs non-destructively without clearing the internal buffer until an explicit clear() invocation.","caseId":"case:sha256:ac318f4b776945fd6c125724700fdb8a796c1ed351ba83fe414cb9a0d72ef322","contract":["VirtualConsolePrinter.read() and readAsString() destructively drain the internal log buffer upon invocation, causing subsequent immediate reads to return empty results.","readAsString(minLogLevel) filters formatted output by severity while draining all log entries from the buffer regardless of level.","console.group() indents log entries by two spaces with a ▼ prefix, whereas console.groupCollapsed() suppresses nested entries from readAsString() with a ▶ prefix.","addEventListener dispatches synchronous 'print' and 'clear' events on log and clear operations, rejecting unsupported event names.","close() marks the printer as closed, flushes buffered entries and listeners, and causes subsequent print and event calls to be ignored.","Window instances expose the page VirtualConsolePrinter through window.happyDOM.virtualConsolePrinter."],"goal":"VirtualConsolePrinter buffers console logs, destructively drains on read/readAsString calls, filters by log level, formats group indentation and collapsed group suppression, dispatches lifecycle events, and is exposed on Window via happyDOM.virtualConsolePrinter.","kind":"HOW","packages":["pkg:npm/happy-dom@20.11.2"],"schemaVersion":1,"symbols":["happy-dom.VirtualConsolePrinter"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/happy-dom@20.11.2"],"schemaVersion":1,"symbols":["happy-dom.VirtualConsolePrinter"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "npm-happy-dom-wanted-20-11-2-happy-dom-virtualconsoleprinter-cf40e1b49d4815658a1cd670",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "npm-happy-dom-wanted-20-11-2-happy-dom-virtualconsoleprinter-cf40e1b49d4815658a1cd670",
      "version": "1.0.0",
      "license": "ISC",
      "dependencies": {
        "happy-dom": "20.11.2"
      }
    },
    "node_modules/@types/node": {
      "version": "26.2.0",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz",
      "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==",
      "license": "MIT",
      "dependencies": {
        "undici-types": "~8.3.0"
      }
    },
    "node_modules/@types/whatwg-mimetype": {
      "version": "3.0.2",
      "resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz",
      "integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==",
      "license": "MIT"
    },
    "node_modules/@types/ws": {
      "version": "8.18.1",
      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
      "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
      "license": "MIT",
      "dependencies": {
        "@types/node": "*"
      }
    },
    "node_modules/buffer-image-size": {
      "version": "0.6.4",
      "resolved": "https://registry.npmjs.org/buffer-image-size/-/buffer-image-size-0.6.4.tgz",
      "integrity": "sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ==",
      "license": "MIT",
      "dependencies": {
        "@types/node": "*"
      },
      "engines": {
        "node": ">=4.0"
      }
    },
    "node_modules/entities": {
      "version": "7.0.1",
      "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
      "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
      "license": "BSD-2-Clause",
      "engines": {
        "node": ">=0.12"
      },
      "funding": {
        "url": "https://github.com/fb55/entities?sponsor=1"
      }
    },
    "node_modules/happy-dom": {
      "version": "20.11.2",
      "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.11.2.tgz",
      "integrity": "sha512-7MB+bJLkxu3SowAfBJbjW+c55kNz5tkR45gu2qzrxznezhLeN5YIlJbwUgSzlGc+qWoZ8Ykg71H5ezz69xixrw==",
      "license": "MIT",
      "dependencies": {
        "@types/node": ">=20.0.0",
        "@types/whatwg-mimetype": "^3.0.2",
        "@types/ws": "^8.18.1",
        "buffer-image-size": "^0.6.4",
        "entities": "^7.0.1",
        "whatwg-mimetype": "^3.0.0",
        "ws": "^8.21.0"
      },
      "engines": {
        "node": ">=20.0.0"
      }
    },
    "node_modules/undici-types": {
      "version": "8.3.0",
      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
      "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
      "license": "MIT"
    },
    "node_modules/whatwg-mimetype": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
      "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
      "license": "MIT",
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/ws": {
      "version": "8.21.3",
      "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
      "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
      "license": "MIT",
      "engines": {
        "node": ">=10.0.0"
      },
      "peerDependencies": {
        "bufferutil": "^4.0.1",
        "utf-8-validate": ">=5.0.2"
      },
      "peerDependenciesMeta": {
        "bufferutil": {
          "optional": true
        },
        "utf-8-validate": {
          "optional": true
        }
      }
    }
  }
}
package.json
{
  "name": "npm-happy-dom-wanted-20-11-2-happy-dom-virtualconsoleprinter-cf40e1b49d4815658a1cd670",
  "version": "1.0.0",
  "type": "module",
  "dependencies": {
    "happy-dom": "20.11.2"
  }
}
test/contract.mjs
import assert from 'node:assert/strict';
import {
  VirtualConsolePrinter,
  VirtualConsole,
  VirtualConsoleLogLevelEnum,
  Window
} from 'happy-dom';

// 1. Destructive read() and readAsString() buffer draining
{
  const printer = new VirtualConsolePrinter();
  const vc = new VirtualConsole(printer);

  vc.log('first message');
  vc.log('second message');

  // Initial read returns all buffered log entries
  const entries = printer.read();
  assert.strictEqual(entries.length, 2);
  assert.strictEqual(entries[0].message[0], 'first message');
  assert.strictEqual(entries[1].message[0], 'second message');

  // Immediately reading again returns an empty array because read() drained the buffer
  const secondRead = printer.read();
  assert.deepStrictEqual(secondRead, []);

  // readAsString() also drains the buffer
  vc.log('third message');
  const strOutput = printer.readAsString();
  assert.strictEqual(strOutput, 'third message\n');

  const secondStrOutput = printer.readAsString();
  assert.strictEqual(secondStrOutput, '');
}

// 2. Log level filtering in readAsString() drains all entries including skipped ones
{
  const printer = new VirtualConsolePrinter();
  const vc = new VirtualConsole(printer);

  vc.log('debug/log level text'); // level 0 (log)
  vc.info('info level text');      // level 1 (info)
  vc.warn('warn level text');      // level 2 (warn)
  vc.error('error level text');    // level 3 (error)

  // Request only warn and error (level >= 2)
  const warnAndAbove = printer.readAsString(VirtualConsoleLogLevelEnum.warn);
  assert.strictEqual(warnAndAbove, 'warn level text\nerror level text\n');

  // Buffer is completely drained — even the log/info messages were consumed and are gone
  assert.deepStrictEqual(printer.read(), []);
}

// 3. Group formatting, tabbing, and collapsed group suppression
{
  const printer = new VirtualConsolePrinter();
  const vc = new VirtualConsole(printer);

  // Expanded group
  vc.group('Active Group');
  vc.log('nested item');
  vc.groupEnd();
  vc.log('root item');

  const expandedOutput = printer.readAsString();
  assert.strictEqual(expandedOutput, '▼ Active Group\n  nested item\nroot item\n');

  // Collapsed group suppresses nested log output in readAsString
  vc.groupCollapsed('Hidden Group');
  vc.log('this message will be suppressed in readAsString');
  vc.groupEnd();
  vc.log('visible after groupEnd');

  const collapsedOutput = printer.readAsString();
  assert.strictEqual(collapsedOutput, '▶ Hidden Group\nvisible after groupEnd\n');
}

// 4. Event listeners for 'print' and 'clear'
{
  const printer = new VirtualConsolePrinter();
  const vc = new VirtualConsole(printer);

  const printEvents = [];
  const clearEvents = [];

  const onPrint = (event) => printEvents.push(event.type);
  const onClear = (event) => clearEvents.push(event.type);

  printer.addEventListener('print', onPrint);
  printer.addEventListener('clear', onClear);

  vc.log('event trigger 1');
  vc.warn('event trigger 2');
  assert.strictEqual(printEvents.length, 2);
  assert.strictEqual(printEvents[0], 'print');
  assert.strictEqual(printEvents[1], 'print');

  vc.clear();
  assert.strictEqual(clearEvents.length, 1);
  assert.strictEqual(clearEvents[0], 'clear');

  // Removing listener
  printer.removeEventListener('print', onPrint);
  vc.log('event trigger 3');
  assert.strictEqual(printEvents.length, 2);

  // Unsupported event type throws
  assert.throws(() => {
    printer.addEventListener('invalidEvent', () => {});
  }, /Event type "invalidEvent" is not supported\./);
}

// 5. Lifecycle and close() behavior
{
  const printer = new VirtualConsolePrinter();
  const vc = new VirtualConsole(printer);

  let eventFired = false;
  printer.addEventListener('print', () => { eventFired = true; });

  assert.strictEqual(printer.closed, false);
  vc.log('pre-close log');

  printer.close();
  assert.strictEqual(printer.closed, true);

  // Buffer is emptied on close
  assert.deepStrictEqual(printer.read(), []);

  // Operations on closed printer are no-ops
  eventFired = false;
  vc.log('post-close log');
  assert.strictEqual(eventFired, false);
  assert.deepStrictEqual(printer.read(), []);
  assert.strictEqual(printer.readAsString(), '');
}

// 6. Access via Window and happyDOM.virtualConsolePrinter
{
  const window = new Window();
  assert.ok(window.happyDOM.virtualConsolePrinter instanceof VirtualConsolePrinter);

  window.console.log('window log message');
  const windowOutput = window.happyDOM.virtualConsolePrinter.readAsString();
  assert.strictEqual(windowOutput, 'window log message\n');

  window.happyDOM.close();
}

オリジンシーダー

csx-seed