From ce30547af39f692bef777591bdb329a7fa00e86e Mon Sep 17 00:00:00 2001 From: amankumarsingh77 Date: Tue, 28 Jul 2026 19:42:25 +0530 Subject: fix(cdp): re-enable domains when re-attaching to a known tab Every Target.attachToTarget mints a new sessionId and CDP domain enablement is per-session, but switchTo only enabled domains on a tab's first visit. Switching away and back left the refreshed session with Page, Network, Runtime and Log disabled, so that tab silently stopped collecting console and network records and stopped reporting dialogs and load events for the rest of the session. Report: docs/superpowers/reports/2026-07-26-bug-audit.md#f3 Co-Authored-By: Claude Opus 5 (1M context) --- test/cdp/session-switch-test.ts | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 test/cdp/session-switch-test.ts (limited to 'test') diff --git a/test/cdp/session-switch-test.ts b/test/cdp/session-switch-test.ts new file mode 100644 index 0000000..f09d26c --- /dev/null +++ b/test/cdp/session-switch-test.ts @@ -0,0 +1,66 @@ +import { test, describe } from "node:test"; +import assert from "node:assert/strict"; +import { createCdpSession } from "../../src/cdp/session"; +import { createOwnershipRegistry } from "../../src/cdp/ownership"; +import { createStubTransport } from "../domains/fake-client"; +import { ok } from "../../src/util/result"; + +const ENABLED_DOMAINS = ["Page", "DOM", "Runtime", "Network", "Accessibility", "Log"]; + +const twoTabSession = async () => { + const stub = createStubTransport({ + "Target.setDiscoverTargets": ok({}), + "Target.getTargets": ok({ + targetInfos: [ + { targetId: "t1", type: "page", title: "One", url: "https://one.test/" }, + { targetId: "t2", type: "page", title: "Two", url: "https://two.test/" }, + ], + }), + "Target.attachToTarget": [ok({ sessionId: "s1" }), ok({ sessionId: "s2" }), ok({ sessionId: "s3" })], + "Browser.getWindowForTarget": ok({ windowId: 7 }), + "Target.activateTarget": ok({}), + }); + const ownership = createOwnershipRegistry({ ownedTargetIds: ["t1", "t2"] }); + const session = createCdpSession(stub.transport, ownership); + const attached = await session.attachFirstPage(); + assert.equal(attached.success, true); + return { stub, session }; +}; + +const enablesFor = (stub: { calls: ReadonlyArray<{ method: string; sessionId: string | null | undefined }> }, sessionId: string): string[] => + stub.calls.filter((c) => c.sessionId === sessionId && c.method.endsWith(".enable")).map((c) => c.method); + +describe("CdpSession.switchTo domain enablement", () => { + test("a first visit enables every domain on the new session", async () => { + const { stub, session } = await twoTabSession(); + const switched = await session.switchTo("t2"); + assert.equal(switched.success, true); + assert.deepEqual( + enablesFor(stub, "s2").sort(), + ENABLED_DOMAINS.map((d) => `${d}.enable`).sort(), + ); + }); + + test("returning to a known tab re-enables domains on its new session", async () => { + const { stub, session } = await twoTabSession(); + await session.switchTo("t2"); + const back = await session.switchTo("t1"); + assert.equal(back.success, true); + assert.equal(session.current()?.sessionId, "s3"); + assert.deepEqual( + enablesFor(stub, "s3").sort(), + ENABLED_DOMAINS.map((d) => `${d}.enable`).sort(), + ); + }); + + test("calls on the returned-to tab are routed to its refreshed session id", async () => { + const { stub, session } = await twoTabSession(); + await session.switchTo("t2"); + await session.switchTo("t1"); + const r = await session.call("Page.bringToFront", {}); + assert.equal(r.success, true); + const last = stub.calls.at(-1); + assert.equal(last?.method, "Page.bringToFront"); + assert.equal(last?.sessionId, "s3"); + }); +}); -- cgit v1.2.3