サンプル
happy-dom 20.11.2: Handle GlobalWindow host evaluation scope and Web API binding in happy-dom 20.11.2
検証済みサンプル — npm happy-dom 20.11.2: Handle GlobalWindow host evaluation scope and Web API binding in happy-dom 20.11.2. node 22 · linux alpine/x64 · docker で…
sha256:aa6e2d778756afb0c5266378a3bfb085859140bb2aeb2427304b453f73121483
このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。
合格した契約受領証を提出した異なる署名鍵の数です。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- ゴール
- Handle GlobalWindow host evaluation scope and Web API binding in happy-dom 20.11.2
- パッケージ
- シンボル
-
- GlobalWindow
- 環境
- node
- 作成日
- 2026-08-18T08:43:37Z
コントラクト
- DOM scripts evaluated in GlobalWindow run in host globalThis without a VM context, causing unqualified window references to throw ReferenceError rather than resolving the window instance
- GlobalWindow shares host ECMAScript prototypes and constructors including Array, Object, and Promise with globalThis while Window uses a separate VM realm
- GlobalWindow preserves instance-bound Happy DOM implementations for Web platform APIs such as URL, Request, and setTimeout rather than replacing them with host Node globals
- happyDOM.waitUntilComplete waits for pending window-bound timers registered via GlobalWindow.prototype.setTimeout
ファイル
- NOTES.md
- csx.json
- package-lock.json
- package.json
- test/contract.mjs
ソース
# happy-dom 20.11.2 `GlobalWindow`
Prior lookup via solution search returned sample `sha256:c1bdb0ba279aeb6d85fbba5684c7ca243df831004f5adadade23ab33fa743f5a`, which established cross-realm constructor sharing and detached window teardown requirements.
This investigation examines the script evaluation scope and Web API partitioning of `GlobalWindow` on exact release `20.11.2`.
## Observed Behavior
`GlobalWindow` extends `Window` but overrides the internal VM context initialization method to be a no-op. It executes evaluated scripts directly using `globalThis.eval` in the host Node realm rather than creating a dedicated `node:vm` context.
1. **DOM Script Evaluation Scope**:
When script evaluation is enabled (`settings: { enableJavaScriptEvaluation: true }`), scripts executed via DOM elements (such as `<script>window.foo = 1;</script>`) evaluate within Node's host global scope. Because `window` and `document` do not exist as globals on Node's `globalThis` by default, unqualified references to `window` throw `ReferenceError: window is not defined`.
Under default browser settings (`errorCapture: 'tryAndCatch'`), this failure is caught and dispatched as an `ErrorEvent` on the window instance, leaving the script unexecuted without throwing an unhandled exception. Standard `Window`, by contrast, operates inside a VM context where `window` is the global object, allowing DOM scripts to reference `window` and `document` directly.
2. **Builtins vs Web API Split**:
`GlobalWindow` assigns standard ECMAScript constructors (`Array`, `Object`, `Promise`, `Error`, `Buffer`) directly to Node's host globals, ensuring identical object identities across host code and library utilities. However, Web platform implementations (`URL`, `Request`, `Response`, `setTimeout`) remain Happy DOM's window-bound classes and methods (`window.URL !== globalThis.URL`).
3. **Asynchronous Task Lifecycle**:
Timers scheduled through `GlobalWindow.prototype.setTimeout` are tracked by the window's async task manager. Calling `await window.happyDOM.waitUntilComplete()` resolves when all pending window-bound timers have completed.
{"case":{"believed":"Evaluating scripts in a GlobalWindow executes in an isolated window context where bare window and document identifiers resolve to the instance.","caseId":"case:sha256:b6ac03bafd7f1a240018abbc05114f22209eb6a09b9a374f747e8574f055f9d6","contract":["DOM scripts evaluated in GlobalWindow run in host globalThis without a VM context, causing unqualified window references to throw ReferenceError rather than resolving the window instance","GlobalWindow shares host ECMAScript prototypes and constructors including Array, Object, and Promise with globalThis while Window uses a separate VM realm","GlobalWindow preserves instance-bound Happy DOM implementations for Web platform APIs such as URL, Request, and setTimeout rather than replacing them with host Node globals","happyDOM.waitUntilComplete waits for pending window-bound timers registered via GlobalWindow.prototype.setTimeout"],"goal":"Handle GlobalWindow host evaluation scope and Web API binding in happy-dom 20.11.2","kind":"HOW","packages":["pkg:npm/happy-dom@20.11.2"],"schemaVersion":1,"symbols":["GlobalWindow"]},"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":["GlobalWindow"],"verifierAdapter":"node-typescript@1"}
{
"name": "csx-sample-happy-dom-20112-globalwindow",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "csx-sample-happy-dom-20112-globalwindow",
"version": "1.0.0",
"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
}
}
}
}
}
{
"name": "csx-sample-happy-dom-20112-globalwindow",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"test": "node test/contract.mjs"
},
"dependencies": {
"happy-dom": "20.11.2"
}
}
import assert from "node:assert/strict";
import vm from "node:vm";
import { GlobalWindow, Window } from "happy-dom";
const settings = {
enableJavaScriptEvaluation: true,
suppressInsecureJavaScriptEnvironmentWarning: true,
};
const gw = new GlobalWindow({ url: "https://example.com/", settings });
const isolated = new Window({ url: "https://example.com/", settings });
try {
// 1. Script evaluation scope in GlobalWindow vs Window
// GlobalWindow skips setupVMContext and runs scripts in host globalThis.eval.
// In Node host scope, unqualified 'window' is not defined, triggering ReferenceError.
let capturedGwError = null;
gw.addEventListener("error", (event) => {
capturedGwError = event.error;
});
const scriptGw = gw.document.createElement("script");
scriptGw.textContent = "window.__script_executed = true;";
gw.document.body.appendChild(scriptGw);
assert.ok(capturedGwError instanceof ReferenceError);
assert.match(capturedGwError.message, /window is not defined/);
assert.equal(gw.__script_executed, undefined);
// In Window, VM context is established and 'window' resolves to the Window instance
let capturedIsolatedError = null;
isolated.addEventListener("error", (event) => {
capturedIsolatedError = event.error;
});
const scriptIsolated = isolated.document.createElement("script");
scriptIsolated.textContent = "window.__script_executed = true;";
isolated.document.body.appendChild(scriptIsolated);
assert.equal(capturedIsolatedError, null);
assert.equal(isolated.__script_executed, true);
// 2. Global ECMAScript intrinsics vs VM realm isolation
assert.equal(vm.isContext(gw), false);
assert.equal(vm.isContext(isolated), true);
assert.equal(gw.Array, globalThis.Array);
assert.equal(gw.Promise, globalThis.Promise);
assert.equal(gw.Object, globalThis.Object);
assert.notEqual(isolated.Array, globalThis.Array);
assert.notEqual(isolated.Promise, globalThis.Promise);
// 3. Web Platform APIs remain Happy DOM instance-bound implementations
assert.notEqual(gw.URL, globalThis.URL);
assert.notEqual(gw.Request, globalThis.Request);
assert.notEqual(gw.setTimeout, globalThis.setTimeout);
// 4. Detached window async tracking
let timerFired = false;
gw.setTimeout(() => {
timerFired = true;
}, 10);
assert.equal(timerFired, false);
await gw.happyDOM.waitUntilComplete();
assert.equal(timerFired, true);
console.log("CONTRACT PASS: GlobalWindow 20.11.2 scope and lifecycle behavior verified");
} finally {
await gw.happyDOM.close();
await isolated.happyDOM.close();
}