| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | import { JSDOM } from "jsdom"; |
| 4 | import { scriptCall } from "./pageScripts.js"; |
| 5 | |
| 6 | test("production input preparation observes painted geometry and cleans up every exit", async () => { |
| 7 | for (const change of ["stable", "moved", "replaced", "detached", "unpainted"] as const) { |
| 8 | const dom = new JSDOM("<button>Target</button><div>Other</div>", { runScripts: "outside-only" }); |
| 9 | const { window } = dom; |
| 10 | const target = window.document.querySelector("button")!; |
| 11 | let current: Element = target, x = 10, frameCallback: FrameRequestCallback | undefined, timeoutCallback: (() => void) | undefined; |
| 12 | window.document.elementFromPoint = () => current as unknown as HTMLElement; |
| 13 | target.getBoundingClientRect = () => ({ x, y: 20, width: 40, height: 20 }) as DOMRect; |
| 14 | window.requestAnimationFrame = callback => { frameCallback = callback; return 1; }; |
| 15 | window.cancelAnimationFrame = () => { frameCallback = undefined; }; |
| 16 | window.setTimeout = ((callback: () => void) => { timeoutCallback = callback; return 1; }) as typeof window.setTimeout; |
| 17 | window.clearTimeout = () => { timeoutCallback = undefined; }; |
| 18 | try { |
| 19 | const result = window.eval(scriptCall("pageInputReady", { x: 20, y: 25 })) as Promise<boolean>; |
| 20 | let settled = false; |
| 21 | void result.then(() => { settled = true; }); |
| 22 | frameCallback!(1); |
| 23 | await Promise.resolve(); |
| 24 | assert.equal(settled, false, "one layout sample is not a rendered-frame boundary"); |
| 25 | if (change === "moved") x++; |
| 26 | if (change === "replaced") current = window.document.querySelector("div")!; |
| 27 | if (change === "detached") target.remove(); |
| 28 | if (change === "unpainted") timeoutCallback!(); else frameCallback!(2); |
| 29 | assert.equal(await result, change === "stable", change); |
| 30 | assert.equal(frameCallback, undefined); |
| 31 | assert.equal(timeoutCallback, undefined); |
| 32 | } finally { window.close(); } |
| 33 | } |
| 34 | }); |
| 35 |