diff --git a/packages/playwright-cloudflare/index.d.ts b/packages/playwright-cloudflare/index.d.ts index 35f8ddd97..bc7691f07 100644 --- a/packages/playwright-cloudflare/index.d.ts +++ b/packages/playwright-cloudflare/index.d.ts @@ -3,6 +3,17 @@ import { Playwright, Browser } from './types/types'; export * from './types/types'; +declare module './types/types' { + interface Browser { + /** + * Get the BISO session ID associated with this browser + * + * @public + */ + sessionId(): string; + } +} + /** * @public */ diff --git a/packages/playwright-cloudflare/src/cloudflare/webSocketTransport.ts b/packages/playwright-cloudflare/src/cloudflare/webSocketTransport.ts index bedfc584e..a4daf13d8 100644 --- a/packages/playwright-cloudflare/src/cloudflare/webSocketTransport.ts +++ b/packages/playwright-cloudflare/src/cloudflare/webSocketTransport.ts @@ -7,13 +7,13 @@ import { AsyncLocalStorage } from 'async_hooks'; export const transportZone = new AsyncLocalStorage(); export class WebSocketTransport implements ConnectionTransport { - ws: WebSocket; - pingInterval: NodeJS.Timer; - chunks: Uint8Array[] = []; + private _ws: WebSocket; + private _pingInterval: NodeJS.Timer; + private _chunks: Uint8Array[] = []; onmessage?: (message: ProtocolResponse) => void; onclose?: () => void; - sessionId: string; - + readonly sessionId: string; + static async connect(): Promise { // read the endpoint and options injected in cliend side const transport = transportZone.getStore(); @@ -23,42 +23,42 @@ export class WebSocketTransport implements ConnectionTransport { } constructor(ws: WebSocket, sessionId: string) { - this.pingInterval = setInterval(() => { - return this.ws.send('ping'); + this._pingInterval = setInterval(() => { + return this._ws.send('ping'); }, 1000); // TODO more investigation - this.ws = ws; + this._ws = ws; this.sessionId = sessionId; - this.ws.addEventListener('message', event => { - this.chunks.push(new Uint8Array(event.data as ArrayBuffer)); - const message = chunksToMessage(this.chunks, sessionId); + this._ws.addEventListener('message', event => { + this._chunks.push(new Uint8Array(event.data as ArrayBuffer)); + const message = chunksToMessage(this._chunks, sessionId); if (message && this.onmessage) this.onmessage!(JSON.parse(message) as ProtocolResponse); }); - this.ws.addEventListener('close', () => { - clearInterval(this.pingInterval as NodeJS.Timeout); + this._ws.addEventListener('close', () => { + clearInterval(this._pingInterval as NodeJS.Timeout); if (this.onclose) this.onclose(); }); - this.ws.addEventListener('error', e => { + this._ws.addEventListener('error', e => { // eslint-disable-next-line no-console console.error(`Websocket error: SessionID: ${sessionId}`, e); - clearInterval(this.pingInterval as NodeJS.Timeout); + clearInterval(this._pingInterval as NodeJS.Timeout); }); } send(message: ProtocolRequest): void { for (const chunk of messageToChunks(JSON.stringify(message))) - this.ws.send(chunk); + this._ws.send(chunk); } close(): void { - clearInterval(this.pingInterval as NodeJS.Timeout); - this.ws.close(); + clearInterval(this._pingInterval as NodeJS.Timeout); + this._ws.close(); this.onclose?.(); } async closeAndWait() { - if (this.ws.readyState === WebSocket.CLOSED) + if (this._ws.readyState === WebSocket.CLOSED) return; this.close(); // TODO wait for close event diff --git a/packages/playwright-cloudflare/src/index.ts b/packages/playwright-cloudflare/src/index.ts index e75bab977..c7d57974a 100644 --- a/packages/playwright-cloudflare/src/index.ts +++ b/packages/playwright-cloudflare/src/index.ts @@ -8,7 +8,6 @@ import type { AcquireResponse, ActiveSession, Browser, BrowserWorker, ClosedSess import { transportZone, WebSocketTransport } from './cloudflare/webSocketTransport'; import { wrapClientApis } from './cloudflare/wrapClientApis'; import { kBrowserCloseMessageId } from 'playwright-core/lib/server/chromium/crConnection'; -import { isUnderTest } from 'playwright-core/lib/utils'; const playwright = createInProcessPlaywright(); wrapClientApis(); @@ -17,7 +16,11 @@ const HTTP_FAKE_HOST = 'http://fake.host'; const WS_FAKE_HOST = 'ws://fake.host'; async function createBrowser(transport: WebSocketTransport): Promise { - return await transportZone.run(transport, async () => await playwright.chromium.connectOverCDP(WS_FAKE_HOST) as Browser); + return await transportZone.run(transport, async () => { + const browser = await playwright.chromium.connectOverCDP(WS_FAKE_HOST) as Browser; + browser.sessionId = () => transport.sessionId; + return browser; + }); } export async function connect(endpoint: BrowserWorker, sessionId: string): Promise { @@ -34,9 +37,6 @@ export async function launch(endpoint: BrowserWorker, options?: WorkersLaunchOpt // keeps the endpoint and options for client -> server async communication const browser = await createBrowser(transport) as Browser; - if (isUnderTest()) - (browser as any).__sessionIdForTest = sessionId; - const browserImpl = (browser as any)._toImpl() as CRBrowser; // ensure we actually close the browser const doClose = async () => { diff --git a/packages/playwright-cloudflare/tests/src/browser-rendering/api.spec.ts b/packages/playwright-cloudflare/tests/src/browser-rendering/api.spec.ts index f7f8eb344..ee6e060af 100644 --- a/packages/playwright-cloudflare/tests/src/browser-rendering/api.spec.ts +++ b/packages/playwright-cloudflare/tests/src/browser-rendering/api.spec.ts @@ -3,7 +3,7 @@ import { launch, connect, sessions, BrowserWorker, Browser, history, acquire } f async function launchAndGetSession(endpoint: BrowserWorker): Promise<[Browser, string]> { const browser = await launch(endpoint); - const sessionId = (browser as any).__sessionIdForTest; + const sessionId = browser.sessionId(); expect(sessionId).toBeDefined(); return [browser, sessionId]; }