yukey

testkit: js() rejects when the expression throws in the page

commit 63181701b89fa31dc55802578151f560170b97b9 · parent 1cd98c6430 · browse this tree
Ximianth, 2026-10-10 05:47:24 UTC

Runtime.evaluate reports a thrown expression as exceptionDetails beside an
error-typed result, and js() returned undefined for it.  A broken probe then
looked like a false check, or like a page that never became ready.  Now it
rejects with the exception text and description.  Test watched failing
(resolved undefined) before the fix.
diff --git a/packages/yukey-testkit/src/cdp.test.ts b/packages/yukey-testkit/src/cdp.test.ts
index 5ae07a4..9eb2b2f 100644
--- a/packages/yukey-testkit/src/cdp.test.ts
+++ b/packages/yukey-testkit/src/cdp.test.ts
@@ -138,4 +138,18 @@ describe("Cdp.js", () => {
 		sock.reply = () => ({ result: { result: { type: "number", value: 2 } } });
 		expect(await Cdp.fromSocket(sock).js("1+1")).toBe(2);
 	});
+
+	it("rejects when the expression throws in the page, with the exception text", async () => {
+		const sock = new FakeSocket();
+		sock.reply = () => ({
+			result: {
+				result: { type: "object", subtype: "error", description: "ReferenceError: nosuchvar is not defined" },
+				exceptionDetails: {
+					text: "Uncaught",
+					exception: { description: "ReferenceError: nosuchvar is not defined\n    at <anonymous>:1:1" },
+				},
+			},
+		});
+		await expect(Cdp.fromSocket(sock).js("nosuchvar.x")).rejects.toThrow(/nosuchvar is not defined/);
+	});
 });
diff --git a/packages/yukey-testkit/src/cdp.ts b/packages/yukey-testkit/src/cdp.ts
index 47e1a2a..4f00277 100644
--- a/packages/yukey-testkit/src/cdp.ts
+++ b/packages/yukey-testkit/src/cdp.ts
@@ -217,12 +217,20 @@ export class Cdp {
 	}
 
 	// Evaluate an expression in the page, returning its value by JSON.
+	// Rejects if the expression throws, carrying the page-side exception text.
 	// awaitPromise resolves a returned promise first (needed by probes that
 	// measure over a time window).
 	async js(expr: string, opts: { awaitPromise?: boolean } = {}): Promise<unknown> {
 		const params: Record<string, unknown> = { expression: expr, returnByValue: true };
 		if (opts.awaitPromise === true) params.awaitPromise = true;
-		const r = (await this.cmd("Runtime.evaluate", params)) as { result?: { value?: unknown } };
+		const r = (await this.cmd("Runtime.evaluate", params)) as {
+			result?: { value?: unknown };
+			exceptionDetails?: { text: string; exception?: { description?: string } };
+		};
+		if (r.exceptionDetails !== undefined) {
+			const detail = r.exceptionDetails.exception?.description ?? "";
+			throw new Error(`page exception in js(${JSON.stringify(expr)}): ${r.exceptionDetails.text} ${detail}`);
+		}
 		return r.result?.value;
 	}