Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/playwright-cloudflare/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
38 changes: 19 additions & 19 deletions packages/playwright-cloudflare/src/cloudflare/webSocketTransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import { AsyncLocalStorage } from 'async_hooks';
export const transportZone = new AsyncLocalStorage<WebSocketTransport>();

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<WebSocketTransport> {
// read the endpoint and options injected in cliend side
const transport = transportZone.getStore();
Expand All @@ -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
Expand Down
10 changes: 5 additions & 5 deletions packages/playwright-cloudflare/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -17,7 +16,11 @@ const HTTP_FAKE_HOST = 'http://fake.host';
const WS_FAKE_HOST = 'ws://fake.host';

async function createBrowser(transport: WebSocketTransport): Promise<Browser> {
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<Browser> {
Expand All @@ -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 () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}
Expand Down