From 85e2db2416896072d9de73bd16a5f8b2bf1b97b3 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Tue, 20 Apr 2021 23:03:56 -0700 Subject: [PATCH] chore: push dispatcher guid into object, reuse it in trace (#6250) --- src/dispatchers/browserContextDispatcher.ts | 2 +- src/dispatchers/consoleMessageDispatcher.ts | 4 +- src/dispatchers/dispatcher.ts | 15 ++-- src/dispatchers/electronDispatcher.ts | 6 +- src/dispatchers/elementHandlerDispatcher.ts | 33 ++++--- src/dispatchers/frameDispatcher.ts | 18 ++-- src/dispatchers/jsHandleDispatcher.ts | 10 +-- src/dispatchers/networkDispatchers.ts | 22 ++++- src/dispatchers/pageDispatcher.ts | 17 ++-- src/dispatchers/playwrightDispatcher.ts | 2 +- src/dispatchers/streamDispatcher.ts | 9 +- src/server/android/android.ts | 5 +- src/server/android/backendAdb.ts | 6 +- src/server/artifact.ts | 6 +- src/server/browser.ts | 4 +- src/server/browserContext.ts | 2 +- src/server/browserType.ts | 2 +- src/server/chromium/crConnection.ts | 2 + src/server/chromium/crPage.ts | 2 +- src/server/console.ts | 6 +- src/server/dialog.ts | 2 +- src/server/download.ts | 2 +- src/server/electron/electron.ts | 4 +- src/server/frames.ts | 6 +- src/server/instrumentation.ts | 5 +- src/server/javascript.ts | 4 +- src/server/network.ts | 8 +- src/server/page.ts | 10 +-- src/server/playwright.ts | 2 +- src/server/selectors.ts | 2 + src/server/snapshot/snapshotServer.ts | 5 +- src/server/snapshot/snapshotStorage.ts | 19 ++-- src/server/snapshot/snapshotTypes.ts | 1 + src/server/snapshot/snapshotter.ts | 11 +-- src/server/trace/recorder/tracer.ts | 4 +- tests/channels.spec.ts | 96 ++++++++++----------- 36 files changed, 193 insertions(+), 161 deletions(-) diff --git a/src/dispatchers/browserContextDispatcher.ts b/src/dispatchers/browserContextDispatcher.ts index 15a7667a83..bb8e1f7af2 100644 --- a/src/dispatchers/browserContextDispatcher.ts +++ b/src/dispatchers/browserContextDispatcher.ts @@ -131,7 +131,7 @@ export class BrowserContextDispatcher extends Dispatcher { - this._dispatchEvent('route', { route: new RouteDispatcher(this._scope, route), request: RequestDispatcher.from(this._scope, request) }); + this._dispatchEvent('route', { route: RouteDispatcher.from(this._scope, route), request: RequestDispatcher.from(this._scope, request) }); }); } diff --git a/src/dispatchers/consoleMessageDispatcher.ts b/src/dispatchers/consoleMessageDispatcher.ts index 3960d84af4..ee18aab305 100644 --- a/src/dispatchers/consoleMessageDispatcher.ts +++ b/src/dispatchers/consoleMessageDispatcher.ts @@ -17,14 +17,14 @@ import { ConsoleMessage } from '../server/console'; import * as channels from '../protocol/channels'; import { Dispatcher, DispatcherScope } from './dispatcher'; -import { createHandle } from './elementHandlerDispatcher'; +import { ElementHandleDispatcher } from './elementHandlerDispatcher'; export class ConsoleMessageDispatcher extends Dispatcher implements channels.ConsoleMessageChannel { constructor(scope: DispatcherScope, message: ConsoleMessage) { super(scope, message, 'ConsoleMessage', { type: message.type(), text: message.text(), - args: message.args().map(a => createHandle(scope, a)), + args: message.args().map(a => ElementHandleDispatcher.fromJSHandle(scope, a)), location: message.location(), }); } diff --git a/src/dispatchers/dispatcher.ts b/src/dispatchers/dispatcher.ts index b80b70785d..0fc525791a 100644 --- a/src/dispatchers/dispatcher.ts +++ b/src/dispatchers/dispatcher.ts @@ -18,7 +18,7 @@ import { EventEmitter } from 'events'; import * as channels from '../protocol/channels'; import { serializeError } from '../protocol/serializers'; import { createScheme, Validator, ValidationError } from '../protocol/validator'; -import { assert, createGuid, debugAssert, isUnderTest, monotonicTime } from '../utils/utils'; +import { assert, debugAssert, isUnderTest, monotonicTime } from '../utils/utils'; import { tOptional } from '../protocol/validatorPrimitives'; import { kBrowserOrContextClosedError } from '../utils/errors'; import { CallMetadata, SdkObject } from '../server/instrumentation'; @@ -41,7 +41,7 @@ export function lookupNullableDispatcher(object: any | null): Di return object ? lookupDispatcher(object) : undefined; } -export class Dispatcher extends EventEmitter implements channels.Channel { +export class Dispatcher extends EventEmitter implements channels.Channel { private _connection: DispatcherConnection; private _isScope: boolean; // Parent is always "isScope". @@ -55,7 +55,7 @@ export class Dispatcher extends EventEmitter implements chann readonly _scope: Dispatcher; _object: Type; - constructor(parent: Dispatcher | DispatcherConnection, object: Type, type: string, initializer: Initializer, isScope?: boolean, guid = type + '@' + createGuid()) { + constructor(parent: Dispatcher | DispatcherConnection, object: Type, type: string, initializer: Initializer, isScope?: boolean) { super(); this._connection = parent instanceof DispatcherConnection ? parent : parent._connection; @@ -63,6 +63,7 @@ export class Dispatcher extends EventEmitter implements chann this._parent = parent instanceof DispatcherConnection ? undefined : parent; this._scope = isScope ? this : this._parent!; + const guid = object.guid; assert(!this._connection._dispatchers.has(guid)); this._connection._dispatchers.set(guid, this); if (this._parent) { @@ -120,9 +121,9 @@ export class Dispatcher extends EventEmitter implements chann } export type DispatcherScope = Dispatcher; -class Root extends Dispatcher<{}, {}> { +class Root extends Dispatcher<{ guid: '' }, {}> { constructor(connection: DispatcherConnection) { - super(connection, {}, '', {}, true, ''); + super(connection, { guid: '' }, '', {}, true); } } @@ -201,8 +202,8 @@ export class DispatcherConnection { let callMetadata: CallMetadata = { id, ...validMetadata, - pageId: sdkObject?.attribution.page?.uniqueId, - frameId: sdkObject?.attribution.frame?.uniqueId, + pageId: sdkObject?.attribution.page?.guid, + frameId: sdkObject?.attribution.frame?.guid, startTime: monotonicTime(), endTime: 0, type: dispatcher._type, diff --git a/src/dispatchers/electronDispatcher.ts b/src/dispatchers/electronDispatcher.ts index 3bec8a756e..010601c6cc 100644 --- a/src/dispatchers/electronDispatcher.ts +++ b/src/dispatchers/electronDispatcher.ts @@ -20,7 +20,7 @@ import * as channels from '../protocol/channels'; import { BrowserContextDispatcher } from './browserContextDispatcher'; import { PageDispatcher } from './pageDispatcher'; import { parseArgument, serializeResult } from './jsHandleDispatcher'; -import { createHandle } from './elementHandlerDispatcher'; +import { ElementHandleDispatcher } from './elementHandlerDispatcher'; export class ElectronDispatcher extends Dispatcher implements channels.ElectronChannel { constructor(scope: DispatcherScope, electron: Electron) { @@ -44,7 +44,7 @@ export class ElectronApplicationDispatcher extends Dispatcher { this._dispatchEvent('window', { page: lookupDispatcher(page), - browserWindow: createHandle(this._scope, page.browserWindow), + browserWindow: ElementHandleDispatcher.fromJSHandle(this._scope, page.browserWindow), }); }); } @@ -57,7 +57,7 @@ export class ElectronApplicationDispatcher extends Dispatcher { const handle = this._object._nodeElectronHandle!; const result = await handle.evaluateExpressionAndWaitForSignals(params.expression, params.isFunction, false /* returnByValue */, parseArgument(params.arg)); - return { handle: createHandle(this._scope, result) }; + return { handle: ElementHandleDispatcher.fromJSHandle(this._scope, result) }; } async close(): Promise { diff --git a/src/dispatchers/elementHandlerDispatcher.ts b/src/dispatchers/elementHandlerDispatcher.ts index 946c100a37..0a6a40634a 100644 --- a/src/dispatchers/elementHandlerDispatcher.ts +++ b/src/dispatchers/elementHandlerDispatcher.ts @@ -17,25 +17,32 @@ import { ElementHandle } from '../server/dom'; import * as js from '../server/javascript'; import * as channels from '../protocol/channels'; -import { DispatcherScope, lookupNullableDispatcher } from './dispatcher'; +import { DispatcherScope, existingDispatcher, lookupNullableDispatcher } from './dispatcher'; import { JSHandleDispatcher, serializeResult, parseArgument } from './jsHandleDispatcher'; import { FrameDispatcher } from './frameDispatcher'; import { CallMetadata } from '../server/instrumentation'; -export function createHandle(scope: DispatcherScope, handle: js.JSHandle): JSHandleDispatcher { - return handle.asElement() ? new ElementHandleDispatcher(scope, handle.asElement()!) : new JSHandleDispatcher(scope, handle); -} - export class ElementHandleDispatcher extends JSHandleDispatcher implements channels.ElementHandleChannel { readonly _elementHandle: ElementHandle; - static createNullable(scope: DispatcherScope, handle: ElementHandle | null): ElementHandleDispatcher | undefined { - if (!handle) - return undefined; - return new ElementHandleDispatcher(scope, handle); + static from(scope: DispatcherScope, handle: ElementHandle): ElementHandleDispatcher { + return existingDispatcher(handle) || new ElementHandleDispatcher(scope, handle); } - constructor(scope: DispatcherScope, elementHandle: ElementHandle) { + static fromNullable(scope: DispatcherScope, handle: ElementHandle | null): ElementHandleDispatcher | undefined { + if (!handle) + return undefined; + return existingDispatcher(handle) || new ElementHandleDispatcher(scope, handle); + } + + static fromJSHandle(scope: DispatcherScope, handle: js.JSHandle): JSHandleDispatcher { + const result = existingDispatcher(handle); + if (result) + return result; + return handle.asElement() ? new ElementHandleDispatcher(scope, handle.asElement()!) : new JSHandleDispatcher(scope, handle); + } + + private constructor(scope: DispatcherScope, elementHandle: ElementHandle) { super(scope, elementHandle); this._elementHandle = elementHandle; } @@ -162,12 +169,12 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements chann async querySelector(params: channels.ElementHandleQuerySelectorParams, metadata: CallMetadata): Promise { const handle = await this._elementHandle.$(params.selector); - return { element: handle ? new ElementHandleDispatcher(this._scope, handle) : undefined }; + return { element: ElementHandleDispatcher.fromNullable(this._scope, handle) }; } async querySelectorAll(params: channels.ElementHandleQuerySelectorAllParams, metadata: CallMetadata): Promise { const elements = await this._elementHandle.$$(params.selector); - return { elements: elements.map(e => new ElementHandleDispatcher(this._scope, e)) }; + return { elements: elements.map(e => ElementHandleDispatcher.from(this._scope, e)) }; } async evalOnSelector(params: channels.ElementHandleEvalOnSelectorParams, metadata: CallMetadata): Promise { @@ -183,6 +190,6 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements chann } async waitForSelector(params: channels.ElementHandleWaitForSelectorParams, metadata: CallMetadata): Promise { - return { element: ElementHandleDispatcher.createNullable(this._scope, await this._elementHandle.waitForSelector(metadata, params.selector, params)) }; + return { element: ElementHandleDispatcher.fromNullable(this._scope, await this._elementHandle.waitForSelector(metadata, params.selector, params)) }; } } diff --git a/src/dispatchers/frameDispatcher.ts b/src/dispatchers/frameDispatcher.ts index 048645c0d9..b68ad1edfa 100644 --- a/src/dispatchers/frameDispatcher.ts +++ b/src/dispatchers/frameDispatcher.ts @@ -17,7 +17,7 @@ import { Frame, NavigationEvent } from '../server/frames'; import * as channels from '../protocol/channels'; import { Dispatcher, DispatcherScope, lookupNullableDispatcher, existingDispatcher } from './dispatcher'; -import { ElementHandleDispatcher, createHandle } from './elementHandlerDispatcher'; +import { ElementHandleDispatcher } from './elementHandlerDispatcher'; import { parseArgument, serializeResult } from './jsHandleDispatcher'; import { ResponseDispatcher, RequestDispatcher } from './networkDispatchers'; import { CallMetadata } from '../server/instrumentation'; @@ -57,7 +57,7 @@ export class FrameDispatcher extends Dispatcher { - return { element: new ElementHandleDispatcher(this._scope, await this._frame.frameElement()) }; + return { element: ElementHandleDispatcher.from(this._scope, await this._frame.frameElement()) }; } async evaluateExpression(params: channels.FrameEvaluateExpressionParams, metadata: CallMetadata): Promise { @@ -65,11 +65,11 @@ export class FrameDispatcher extends Dispatcher { - return { handle: createHandle(this._scope, await this._frame.evaluateExpressionHandleAndWaitForSignals(params.expression, params.isFunction, parseArgument(params.arg), params.world)) }; + return { handle: ElementHandleDispatcher.fromJSHandle(this._scope, await this._frame.evaluateExpressionHandleAndWaitForSignals(params.expression, params.isFunction, parseArgument(params.arg), params.world)) }; } async waitForSelector(params: channels.FrameWaitForSelectorParams, metadata: CallMetadata): Promise { - return { element: ElementHandleDispatcher.createNullable(this._scope, await this._frame.waitForSelector(metadata, params.selector, params)) }; + return { element: ElementHandleDispatcher.fromNullable(this._scope, await this._frame.waitForSelector(metadata, params.selector, params)) }; } async dispatchEvent(params: channels.FrameDispatchEventParams, metadata: CallMetadata): Promise { @@ -85,12 +85,12 @@ export class FrameDispatcher extends Dispatcher { - return { element: ElementHandleDispatcher.createNullable(this._scope, await this._frame.$(params.selector)) }; + return { element: ElementHandleDispatcher.fromNullable(this._scope, await this._frame.$(params.selector)) }; } async querySelectorAll(params: channels.FrameQuerySelectorAllParams, metadata: CallMetadata): Promise { const elements = await this._frame.$$(params.selector); - return { elements: elements.map(e => new ElementHandleDispatcher(this._scope, e)) }; + return { elements: elements.map(e => ElementHandleDispatcher.from(this._scope, e)) }; } async content(): Promise { @@ -102,11 +102,11 @@ export class FrameDispatcher extends Dispatcher { - return { element: new ElementHandleDispatcher(this._scope, await this._frame.addScriptTag(params)) }; + return { element: ElementHandleDispatcher.from(this._scope, await this._frame.addScriptTag(params)) }; } async addStyleTag(params: channels.FrameAddStyleTagParams, metadata: CallMetadata): Promise { - return { element: new ElementHandleDispatcher(this._scope, await this._frame.addStyleTag(params)) }; + return { element: ElementHandleDispatcher.from(this._scope, await this._frame.addStyleTag(params)) }; } async click(params: channels.FrameClickParams, metadata: CallMetadata): Promise { @@ -201,7 +201,7 @@ export class FrameDispatcher extends Dispatcher { - return { handle: createHandle(this._scope, await this._frame._waitForFunctionExpression(metadata, params.expression, params.isFunction, parseArgument(params.arg), params)) }; + return { handle: ElementHandleDispatcher.fromJSHandle(this._scope, await this._frame._waitForFunctionExpression(metadata, params.expression, params.isFunction, parseArgument(params.arg), params)) }; } async title(params: channels.FrameTitleParams, metadata: CallMetadata): Promise { diff --git a/src/dispatchers/jsHandleDispatcher.ts b/src/dispatchers/jsHandleDispatcher.ts index 9c78bc7791..81724369c9 100644 --- a/src/dispatchers/jsHandleDispatcher.ts +++ b/src/dispatchers/jsHandleDispatcher.ts @@ -17,12 +17,12 @@ import * as js from '../server/javascript'; import * as channels from '../protocol/channels'; import { Dispatcher, DispatcherScope } from './dispatcher'; -import { createHandle } from './elementHandlerDispatcher'; +import { ElementHandleDispatcher } from './elementHandlerDispatcher'; import { parseSerializedValue, serializeValue } from '../protocol/serializers'; export class JSHandleDispatcher extends Dispatcher implements channels.JSHandleChannel { - constructor(scope: DispatcherScope, jsHandle: js.JSHandle) { + protected constructor(scope: DispatcherScope, jsHandle: js.JSHandle) { // Do not call this directly, use createHandle() instead. super(scope, jsHandle, jsHandle.asElement() ? 'ElementHandle' : 'JSHandle', { preview: jsHandle.toString(), @@ -36,19 +36,19 @@ export class JSHandleDispatcher extends Dispatcher { const jsHandle = await this._object.evaluateExpressionAndWaitForSignals(params.expression, params.isFunction, false /* returnByValue */, parseArgument(params.arg)); - return { handle: createHandle(this._scope, jsHandle) }; + return { handle: ElementHandleDispatcher.fromJSHandle(this._scope, jsHandle) }; } async getProperty(params: channels.JSHandleGetPropertyParams): Promise { const jsHandle = await this._object.getProperty(params.name); - return { handle: createHandle(this._scope, jsHandle) }; + return { handle: ElementHandleDispatcher.fromJSHandle(this._scope, jsHandle) }; } async getPropertyList(): Promise { const map = await this._object.getProperties(); const properties = []; for (const [name, value] of map) - properties.push({ name, value: createHandle(this._scope, value) }); + properties.push({ name, value: ElementHandleDispatcher.fromJSHandle(this._scope, value) }); return { properties }; } diff --git a/src/dispatchers/networkDispatchers.ts b/src/dispatchers/networkDispatchers.ts index 06215b3640..4441ba7aad 100644 --- a/src/dispatchers/networkDispatchers.ts +++ b/src/dispatchers/networkDispatchers.ts @@ -51,7 +51,16 @@ export class RequestDispatcher extends Dispatcher implements channels.ResponseChannel { - constructor(scope: DispatcherScope, response: Response) { + static from(scope: DispatcherScope, response: Response): ResponseDispatcher { + const result = existingDispatcher(response); + return result || new ResponseDispatcher(scope, response); + } + + static fromNullable(scope: DispatcherScope, response: Response | null): ResponseDispatcher | undefined { + return response ? ResponseDispatcher.from(scope, response) : undefined; + } + + private constructor(scope: DispatcherScope, response: Response) { super(scope, response, 'Response', { // TODO: responses in popups can point to non-reported requests. request: RequestDispatcher.from(scope, response.request()), @@ -75,7 +84,16 @@ export class ResponseDispatcher extends Dispatcher implements channels.RouteChannel { - constructor(scope: DispatcherScope, route: Route) { + static from(scope: DispatcherScope, route: Route): RouteDispatcher { + const result = existingDispatcher(route); + return result || new RouteDispatcher(scope, route); + } + + static fromNullable(scope: DispatcherScope, route: Route | null): RouteDispatcher | undefined { + return route ? RouteDispatcher.from(scope, route) : undefined; + } + + private constructor(scope: DispatcherScope, route: Route) { super(scope, route, 'Route', { // Context route can point to a non-reported request. request: RequestDispatcher.from(scope, route.request()) diff --git a/src/dispatchers/pageDispatcher.ts b/src/dispatchers/pageDispatcher.ts index 7c4c4c51af..883594612b 100644 --- a/src/dispatchers/pageDispatcher.ts +++ b/src/dispatchers/pageDispatcher.ts @@ -26,7 +26,7 @@ import { DialogDispatcher } from './dialogDispatcher'; import { FrameDispatcher } from './frameDispatcher'; import { RequestDispatcher, ResponseDispatcher, RouteDispatcher, WebSocketDispatcher } from './networkDispatchers'; import { serializeResult, parseArgument } from './jsHandleDispatcher'; -import { ElementHandleDispatcher, createHandle } from './elementHandlerDispatcher'; +import { ElementHandleDispatcher } from './elementHandlerDispatcher'; import { FileChooser } from '../server/fileChooser'; import { CRCoverage } from '../server/chromium/crCoverage'; import { JSHandle } from '../server/javascript'; @@ -34,6 +34,7 @@ import { CallMetadata } from '../server/instrumentation'; import { Artifact } from '../server/artifact'; import { ArtifactDispatcher } from './artifactDispatcher'; import { Download } from '../server/download'; +import { createGuid } from '../utils/utils'; export class PageDispatcher extends Dispatcher implements channels.PageChannel { private _page: Page; @@ -67,7 +68,7 @@ export class PageDispatcher extends Dispatcher i this._dispatchEvent('download', { url: download.url, suggestedFilename: download.suggestedFilename(), artifact: new ArtifactDispatcher(scope, download.artifact) }); }); this._page.on(Page.Events.FileChooser, (fileChooser: FileChooser) => this._dispatchEvent('fileChooser', { - element: new ElementHandleDispatcher(this._scope, fileChooser.element()), + element: ElementHandleDispatcher.from(this._scope, fileChooser.element()), isMultiple: fileChooser.isMultiple() })); page.on(Page.Events.FrameAttached, frame => this._onFrameAttached(frame)); @@ -84,7 +85,7 @@ export class PageDispatcher extends Dispatcher i request: RequestDispatcher.from(scope, request), responseEndTiming: request._responseEndTiming })); - page.on(Page.Events.Response, response => this._dispatchEvent('response', { response: new ResponseDispatcher(this._scope, response) })); + page.on(Page.Events.Response, response => this._dispatchEvent('response', { response: ResponseDispatcher.from(this._scope, response) })); page.on(Page.Events.WebSocket, webSocket => this._dispatchEvent('webSocket', { webSocket: new WebSocketDispatcher(this._scope, webSocket) })); page.on(Page.Events.Worker, worker => this._dispatchEvent('worker', { worker: new WorkerDispatcher(this._scope, worker) })); page.on(Page.Events.Video, (artifact: Artifact) => this._dispatchEvent('video', { artifact: existingDispatcher(artifact) })); @@ -145,7 +146,7 @@ export class PageDispatcher extends Dispatcher i return; } await this._page._setClientRequestInterceptor((route, request) => { - this._dispatchEvent('route', { route: new RouteDispatcher(this._scope, route), request: RequestDispatcher.from(this._scope, request) }); + this._dispatchEvent('route', { route: RouteDispatcher.from(this._scope, route), request: RequestDispatcher.from(this._scope, request) }); }); } @@ -263,21 +264,21 @@ export class WorkerDispatcher extends Dispatcher { - return { handle: createHandle(this._scope, await this._object.evaluateExpressionHandle(params.expression, params.isFunction, parseArgument(params.arg))) }; + return { handle: ElementHandleDispatcher.fromJSHandle(this._scope, await this._object.evaluateExpressionHandle(params.expression, params.isFunction, parseArgument(params.arg))) }; } } -export class BindingCallDispatcher extends Dispatcher<{}, channels.BindingCallInitializer> implements channels.BindingCallChannel { +export class BindingCallDispatcher extends Dispatcher<{ guid: string }, channels.BindingCallInitializer> implements channels.BindingCallChannel { private _resolve: ((arg: any) => void) | undefined; private _reject: ((error: any) => void) | undefined; private _promise: Promise; constructor(scope: DispatcherScope, name: string, needsHandle: boolean, source: { context: BrowserContext, page: Page, frame: Frame }, args: any[]) { - super(scope, {}, 'BindingCall', { + super(scope, { guid: createGuid() }, 'BindingCall', { frame: lookupDispatcher(source.frame), name, args: needsHandle ? undefined : args.map(serializeResult), - handle: needsHandle ? createHandle(scope, args[0] as JSHandle) : undefined, + handle: needsHandle ? ElementHandleDispatcher.fromJSHandle(scope, args[0] as JSHandle) : undefined, }); this._promise = new Promise((resolve, reject) => { this._resolve = resolve; diff --git a/src/dispatchers/playwrightDispatcher.ts b/src/dispatchers/playwrightDispatcher.ts index 0e04958389..92c8c9aebb 100644 --- a/src/dispatchers/playwrightDispatcher.ts +++ b/src/dispatchers/playwrightDispatcher.ts @@ -38,6 +38,6 @@ export class PlaywrightDispatcher extends Dispatcher implements channels.StreamChannel { +export class StreamDispatcher extends Dispatcher<{ guid: string, stream: stream.Readable }, channels.StreamInitializer> implements channels.StreamChannel { constructor(scope: DispatcherScope, stream: stream.Readable) { - super(scope, stream, 'Stream', {}); + super(scope, { guid: createGuid(), stream }, 'Stream', {}); } async read(params: channels.StreamReadParams): Promise { - const buffer = this._object.read(Math.min(this._object.readableLength, params.size || this._object.readableLength)); + const buffer = this._object.stream.read(Math.min(this._object.stream.readableLength, params.size || this._object.stream.readableLength)); return { binary: buffer ? buffer.toString('base64') : '' }; } async close() { - this._object.destroy(); + this._object.stream.destroy(); } } diff --git a/src/server/android/android.ts b/src/server/android/android.ts index b477470ab7..6645aaed87 100644 --- a/src/server/android/android.ts +++ b/src/server/android/android.ts @@ -50,6 +50,7 @@ export interface DeviceBackend { } export interface SocketBackend extends EventEmitter { + guid: string; write(data: Buffer): Promise; close(): void; } @@ -61,7 +62,7 @@ export class Android extends SdkObject { readonly _playwrightOptions: PlaywrightOptions; constructor(backend: Backend, playwrightOptions: PlaywrightOptions) { - super(playwrightOptions.rootSdkObject); + super(playwrightOptions.rootSdkObject, 'android'); this._backend = backend; this._playwrightOptions = playwrightOptions; this._timeoutSettings = new TimeoutSettings(); @@ -115,7 +116,7 @@ export class AndroidDevice extends SdkObject { private _isClosed = false; constructor(android: Android, backend: DeviceBackend, model: string) { - super(android); + super(android, 'android-device'); this._android = android; this._backend = backend; this.model = model; diff --git a/src/server/android/backendAdb.ts b/src/server/android/backendAdb.ts index 1927994b51..168850f04a 100644 --- a/src/server/android/backendAdb.ts +++ b/src/server/android/backendAdb.ts @@ -19,6 +19,7 @@ import debug from 'debug'; import * as net from 'net'; import { EventEmitter } from 'events'; import { Backend, DeviceBackend, SocketBackend } from './android'; +import { createGuid } from '../../utils/utils'; export class AdbBackend implements Backend { async devices(): Promise { @@ -99,6 +100,7 @@ function encodeMessage(message: string): Buffer { } class BufferedSocketWrapper extends EventEmitter implements SocketBackend { + readonly guid = createGuid(); private _socket: net.Socket; private _buffer = Buffer.from([]); private _isSocket = false; @@ -149,7 +151,7 @@ class BufferedSocketWrapper extends EventEmitter implements SocketBackend { await this._connectPromise; assert(!this._isSocket, 'Can not read by length in socket mode'); while (this._buffer.length < length) - await new Promise(f => this._notifyReader = f); + await new Promise(f => this._notifyReader = f); const result = this._buffer.slice(0, length); this._buffer = this._buffer.slice(length); debug('pw:adb:recv')(result.toString().substring(0, 100) + '...'); @@ -158,7 +160,7 @@ class BufferedSocketWrapper extends EventEmitter implements SocketBackend { async readAll(): Promise { while (!this._isClosed) - await new Promise(f => this._notifyReader = f); + await new Promise(f => this._notifyReader = f); return this._buffer; } diff --git a/src/server/artifact.ts b/src/server/artifact.ts index 5750b53740..d5fe84bbc0 100644 --- a/src/server/artifact.ts +++ b/src/server/artifact.ts @@ -16,10 +16,11 @@ import fs from 'fs'; import * as util from 'util'; +import { SdkObject } from './instrumentation'; type SaveCallback = (localPath: string, error?: string) => Promise; -export class Artifact { +export class Artifact extends SdkObject { private _localPath: string; private _unaccessibleErrorMessage: string | undefined; private _finishedCallback: () => void; @@ -29,7 +30,8 @@ export class Artifact { private _deleted = false; private _failureError: string | null = null; - constructor(localPath: string, unaccessibleErrorMessage?: string) { + constructor(parent: SdkObject, localPath: string, unaccessibleErrorMessage?: string) { + super(parent, 'artifact'); this._localPath = localPath; this._unaccessibleErrorMessage = unaccessibleErrorMessage; this._finishedCallback = () => {}; diff --git a/src/server/browser.ts b/src/server/browser.ts index 0cfd567800..b07bd3c372 100644 --- a/src/server/browser.ts +++ b/src/server/browser.ts @@ -66,7 +66,7 @@ export abstract class Browser extends SdkObject { readonly _idToVideo = new Map(); constructor(options: BrowserOptions) { - super(options.rootSdkObject); + super(options.rootSdkObject, 'browser'); this.attribution.browser = this; this.options = options; } @@ -97,7 +97,7 @@ export abstract class Browser extends SdkObject { } _videoStarted(context: BrowserContext, videoId: string, path: string, pageOrError: Promise) { - const artifact = new Artifact(path); + const artifact = new Artifact(context, path); this._idToVideo.set(videoId, { context, artifact }); context.emit(BrowserContext.Events.VideoStarted, artifact); pageOrError.then(page => { diff --git a/src/server/browserContext.ts b/src/server/browserContext.ts index 7482ea35f6..3068b9d443 100644 --- a/src/server/browserContext.ts +++ b/src/server/browserContext.ts @@ -53,7 +53,7 @@ export abstract class BrowserContext extends SdkObject { private _origins = new Set(); constructor(browser: Browser, options: types.BrowserContextOptions, browserContextId: string | undefined) { - super(browser); + super(browser, 'browser-context'); this.attribution.context = this; this._browser = browser; this._options = options; diff --git a/src/server/browserType.ts b/src/server/browserType.ts index 75bb40dd6f..1e18336aff 100644 --- a/src/server/browserType.ts +++ b/src/server/browserType.ts @@ -44,7 +44,7 @@ export abstract class BrowserType extends SdkObject { readonly _playwrightOptions: PlaywrightOptions; constructor(browserName: registry.BrowserName, playwrightOptions: PlaywrightOptions) { - super(playwrightOptions.rootSdkObject); + super(playwrightOptions.rootSdkObject, 'browser-type'); this.attribution.browserType = this; this._playwrightOptions = playwrightOptions; this._name = browserName; diff --git a/src/server/chromium/crConnection.ts b/src/server/chromium/crConnection.ts index c590a3acce..5e8b1369ca 100644 --- a/src/server/chromium/crConnection.ts +++ b/src/server/chromium/crConnection.ts @@ -137,9 +137,11 @@ export class CRSession extends EventEmitter { off: (event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this; removeListener: (event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this; once: (event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this; + readonly guid: string; constructor(connection: CRConnection, rootSessionId: string, targetType: string, sessionId: string) { super(); + this.guid = `cdp-session@${sessionId}`; this.setMaxListeners(0); this._connection = connection; this._rootSessionId = rootSessionId; diff --git a/src/server/chromium/crPage.ts b/src/server/chromium/crPage.ts index 08f9b644c8..d90d438075 100644 --- a/src/server/chromium/crPage.ts +++ b/src/server/chromium/crPage.ts @@ -799,7 +799,7 @@ class FrameSession { lineNumber: lineNumber || 0, columnNumber: 0, }; - this._page.emit(Page.Events.Console, new ConsoleMessage(level, text, [], location)); + this._page.emit(Page.Events.Console, new ConsoleMessage(this._page, level, text, [], location)); } } diff --git a/src/server/console.ts b/src/server/console.ts index 08b8367df9..95f4791224 100644 --- a/src/server/console.ts +++ b/src/server/console.ts @@ -14,16 +14,18 @@ * limitations under the License. */ +import { SdkObject } from './instrumentation'; import * as js from './javascript'; import { ConsoleMessageLocation } from './types'; -export class ConsoleMessage { +export class ConsoleMessage extends SdkObject { private _type: string; private _text?: string; private _args: js.JSHandle[]; private _location: ConsoleMessageLocation; - constructor(type: string, text: string | undefined, args: js.JSHandle[], location?: ConsoleMessageLocation) { + constructor(parent: SdkObject, type: string, text: string | undefined, args: js.JSHandle[], location?: ConsoleMessageLocation) { + super(parent, 'console-message'); this._type = type; this._text = text; this._args = args; diff --git a/src/server/dialog.ts b/src/server/dialog.ts index c0dd4755b2..a50b9dd763 100644 --- a/src/server/dialog.ts +++ b/src/server/dialog.ts @@ -32,7 +32,7 @@ export class Dialog extends SdkObject { private _defaultValue: string; constructor(page: Page, type: string, message: string, onHandle: OnHandle, defaultValue?: string) { - super(page); + super(page, 'dialog'); this._page = page; this._type = type; this._message = message; diff --git a/src/server/download.ts b/src/server/download.ts index 138c024f1c..2e80a6402f 100644 --- a/src/server/download.ts +++ b/src/server/download.ts @@ -27,7 +27,7 @@ export class Download { constructor(page: Page, downloadsPath: string, uuid: string, url: string, suggestedFilename?: string) { const unaccessibleErrorMessage = !page._browserContext._options.acceptDownloads ? 'Pass { acceptDownloads: true } when you are creating your browser context.' : undefined; - this.artifact = new Artifact(path.join(downloadsPath, uuid), unaccessibleErrorMessage); + this.artifact = new Artifact(page, path.join(downloadsPath, uuid), unaccessibleErrorMessage); this._page = page; this.url = url; this._suggestedFilename = suggestedFilename; diff --git a/src/server/electron/electron.ts b/src/server/electron/electron.ts index e3cec71ab7..5a609f0c84 100644 --- a/src/server/electron/electron.ts +++ b/src/server/electron/electron.ts @@ -64,7 +64,7 @@ export class ElectronApplication extends SdkObject { readonly _timeoutSettings = new TimeoutSettings(); constructor(parent: SdkObject, browser: CRBrowser, nodeConnection: CRConnection) { - super(parent); + super(parent, 'electron-app'); this._browserContext = browser._defaultContext as CRBrowserContext; this._browserContext.on(BrowserContext.Events.Close, () => { // Emit application closed after context closed. @@ -122,7 +122,7 @@ export class Electron extends SdkObject { private _playwrightOptions: PlaywrightOptions; constructor(playwrightOptions: PlaywrightOptions) { - super(playwrightOptions.rootSdkObject); + super(playwrightOptions.rootSdkObject, 'electron'); this._playwrightOptions = playwrightOptions; } diff --git a/src/server/frames.ts b/src/server/frames.ts index c6eb7c2d10..d132e679be 100644 --- a/src/server/frames.ts +++ b/src/server/frames.ts @@ -24,7 +24,7 @@ import { Page } from './page'; import * as types from './types'; import { BrowserContext } from './browserContext'; import { Progress, ProgressController } from './progress'; -import { assert, createGuid, makeWaitForNextTask } from '../utils/utils'; +import { assert, makeWaitForNextTask } from '../utils/utils'; import { debugLogger } from '../utils/debugLogger'; import { CallMetadata, internalCallMetadata, SdkObject } from './instrumentation'; import { ElementStateWithoutStable } from './injected/injectedScript'; @@ -411,11 +411,9 @@ export class Frame extends SdkObject { private _setContentCounter = 0; readonly _detachedPromise: Promise; private _detachedCallback = () => {}; - readonly uniqueId: string; constructor(page: Page, id: string, parentFrame: Frame | null) { - super(page); - this.uniqueId = parentFrame ? `frame@${createGuid()}` : page.uniqueId; + super(page, 'frame'); this.attribution.frame = this; this._id = id; this._page = page; diff --git a/src/server/instrumentation.ts b/src/server/instrumentation.ts index 445a2c1b97..5c4df3c3a9 100644 --- a/src/server/instrumentation.ts +++ b/src/server/instrumentation.ts @@ -16,6 +16,7 @@ import { EventEmitter } from 'events'; import { Point, StackFrame } from '../common/types'; +import { createGuid } from '../utils/utils'; import type { Browser } from './browser'; import type { BrowserContext } from './browserContext'; import type { BrowserType } from './browserType'; @@ -50,11 +51,13 @@ export type CallMetadata = { }; export class SdkObject extends EventEmitter { + guid: string; attribution: Attribution; instrumentation: Instrumentation; - protected constructor(parent: SdkObject) { + protected constructor(parent: SdkObject, guidPrefix?: string, guid?: string) { super(); + this.guid = guid || `${guidPrefix || ''}@${createGuid()}`; this.setMaxListeners(0); this.attribution = { ...parent.attribution }; this.instrumentation = parent.instrumentation; diff --git a/src/server/javascript.ts b/src/server/javascript.ts index a4a5aa4a55..46ac390f4d 100644 --- a/src/server/javascript.ts +++ b/src/server/javascript.ts @@ -56,7 +56,7 @@ export class ExecutionContext extends SdkObject { private _utilityScriptPromise: Promise | undefined; constructor(parent: SdkObject, delegate: ExecutionContextDelegate) { - super(parent); + super(parent, 'execution-context'); this._delegate = delegate; } @@ -104,7 +104,7 @@ export class JSHandle extends SdkObject { private _previewCallback: ((preview: string) => void) | undefined; constructor(context: ExecutionContext, type: string, objectId?: ObjectId, value?: any) { - super(context); + super(context, 'handle'); this._context = context; this._objectId = objectId; this._value = value; diff --git a/src/server/network.ts b/src/server/network.ts index f76670f9a5..b66a7aac79 100644 --- a/src/server/network.ts +++ b/src/server/network.ts @@ -99,7 +99,7 @@ export class Request extends SdkObject { constructor(routeDelegate: RouteDelegate | null, frame: frames.Frame, redirectedFrom: Request | null, documentId: string | undefined, url: string, resourceType: string, method: string, postData: Buffer | null, headers: types.HeadersArray) { - super(frame); + super(frame, 'request'); assert(!url.startsWith('data:'), 'Data urls should not fire requests'); assert(!(routeDelegate && redirectedFrom), 'Should not be able to intercept redirects'); this._routeDelegate = routeDelegate; @@ -210,7 +210,7 @@ export class Route extends SdkObject { private _handled = false; constructor(request: Request, delegate: RouteDelegate) { - super(request.frame()); + super(request.frame(), 'route'); this._request = request; this._delegate = delegate; } @@ -277,7 +277,7 @@ export class Response extends SdkObject { private _timing: ResourceTiming; constructor(request: Request, status: number, statusText: string, headers: types.HeadersArray, timing: ResourceTiming, getResponseBodyCallback: GetResponseBodyCallback) { - super(request.frame()); + super(request.frame(), 'response'); this._request = request; this._timing = timing; this._status = status; @@ -357,7 +357,7 @@ export class WebSocket extends SdkObject { }; constructor(parent: SdkObject, url: string) { - super(parent); + super(parent, 'ws'); this._url = url; } diff --git a/src/server/page.ts b/src/server/page.ts index 9ef7c45a16..fef96e2021 100644 --- a/src/server/page.ts +++ b/src/server/page.ts @@ -28,7 +28,7 @@ import { ConsoleMessage } from './console'; import * as accessibility from './accessibility'; import { FileChooser } from './fileChooser'; import { Progress, ProgressController } from './progress'; -import { assert, createGuid, isError } from '../utils/utils'; +import { assert, isError } from '../utils/utils'; import { debugLogger } from '../utils/debugLogger'; import { Selectors } from './selectors'; import { CallMetadata, SdkObject } from './instrumentation'; @@ -145,14 +145,12 @@ export class Page extends SdkObject { private _serverRequestInterceptor: network.RouteHandler | undefined; _ownedContext: BrowserContext | undefined; readonly selectors: Selectors; - readonly uniqueId: string; _pageIsError: Error | undefined; _video: Artifact | null = null; _opener: Page | undefined; constructor(delegate: PageDelegate, browserContext: BrowserContext) { - super(browserContext); - this.uniqueId = 'page@' + createGuid(); + super(browserContext, 'page'); this.attribution.page = this; this._delegate = delegate; this._closedCallback = () => {}; @@ -296,7 +294,7 @@ export class Page extends SdkObject { } _addConsoleMessage(type: string, args: js.JSHandle[], location: types.ConsoleMessageLocation, text?: string) { - const message = new ConsoleMessage(type, text, args, location); + const message = new ConsoleMessage(this, type, text, args, location); const intercepted = this._frameManager.interceptConsoleMessage(message); if (intercepted || !this.listenerCount(Page.Events.Console)) args.forEach(arg => arg.dispose()); @@ -519,7 +517,7 @@ export class Worker extends SdkObject { _existingExecutionContext: js.ExecutionContext | null = null; constructor(parent: SdkObject, url: string) { - super(parent); + super(parent, 'worker'); this._url = url; this._executionContextCallback = () => {}; this._executionContextPromise = new Promise(x => this._executionContextCallback = x); diff --git a/src/server/playwright.ts b/src/server/playwright.ts index cb9533737b..8e8205ab7b 100644 --- a/src/server/playwright.ts +++ b/src/server/playwright.ts @@ -46,7 +46,7 @@ export class Playwright extends SdkObject { listeners.push(new InspectorController()); } const instrumentation = multiplexInstrumentation(listeners); - super({ attribution: {}, instrumentation } as any); + super({ attribution: {}, instrumentation } as any, undefined, 'Playwright'); this.options = { registry: new Registry(path.join(__dirname, '..', '..')), rootSdkObject: this, diff --git a/src/server/selectors.ts b/src/server/selectors.ts index ce65805ae9..716ee0521c 100644 --- a/src/server/selectors.ts +++ b/src/server/selectors.ts @@ -19,6 +19,7 @@ import * as frames from './frames'; import * as js from './javascript'; import * as types from './types'; import { ParsedSelector, parseSelector } from './common/selectorParser'; +import { createGuid } from '../utils/utils'; export type SelectorInfo = { parsed: ParsedSelector, @@ -29,6 +30,7 @@ export type SelectorInfo = { export class Selectors { readonly _builtinEngines: Set; readonly _engines: Map; + readonly guid = `selectors@${createGuid()}`; constructor() { // Note: keep in sync with InjectedScript class. diff --git a/src/server/snapshot/snapshotServer.ts b/src/server/snapshot/snapshotServer.ts index 57e8d02747..4c9bb31f64 100644 --- a/src/server/snapshot/snapshotServer.ts +++ b/src/server/snapshot/snapshotServer.ts @@ -156,10 +156,9 @@ export class SnapshotServer { response.statusCode = 200; response.setHeader('Cache-Control', 'public, max-age=31536000'); response.setHeader('Content-Type', 'application/json'); - const [ pageId, query ] = request.url!.substring('/snapshot/'.length).split('?'); + const [ pageOrFrameId, query ] = request.url!.substring('/snapshot/'.length).split('?'); const parsed: any = querystring.parse(query); - - const snapshot = parsed.name ? this._snapshotStorage.snapshotByName(pageId, parsed.name) : this._snapshotStorage.snapshotByTime(pageId, parsed.time); + const snapshot = this._snapshotStorage.snapshotByName(pageOrFrameId, parsed.name); const snapshotData: any = snapshot ? snapshot.render() : { html: '' }; response.end(JSON.stringify(snapshotData)); return true; diff --git a/src/server/snapshot/snapshotStorage.ts b/src/server/snapshot/snapshotStorage.ts index ded0e57957..66523342a3 100644 --- a/src/server/snapshot/snapshotStorage.ts +++ b/src/server/snapshot/snapshotStorage.ts @@ -25,8 +25,7 @@ export interface SnapshotStorage { resources(): ResourceSnapshot[]; resourceContent(sha1: string): Buffer | undefined; resourceById(resourceId: string): ResourceSnapshot | undefined; - snapshotByName(frameId: string, snapshotName: string): SnapshotRenderer | undefined; - snapshotByTime(frameId: string, timestamp: number): SnapshotRenderer | undefined; + snapshotByName(pageOrFrameId: string, snapshotName: string): SnapshotRenderer | undefined; } export abstract class BaseSnapshotStorage extends EventEmitter implements SnapshotStorage { @@ -64,6 +63,8 @@ export abstract class BaseSnapshotStorage extends EventEmitter implements Snapsh renderer: [], }; this._frameSnapshots.set(snapshot.frameId, frameSnapshots); + if (snapshot.isMainFrame) + this._frameSnapshots.set(snapshot.pageId, frameSnapshots); } frameSnapshots.raw.push(snapshot); const renderer = new SnapshotRenderer(new Map(this._contextResources), frameSnapshots.raw, frameSnapshots.raw.length - 1); @@ -81,17 +82,9 @@ export abstract class BaseSnapshotStorage extends EventEmitter implements Snapsh return this._resources.slice(); } - snapshotByName(frameId: string, snapshotName: string): SnapshotRenderer | undefined { - return this._frameSnapshots.get(frameId)?.renderer.find(r => r.snapshotName === snapshotName); - } - - snapshotByTime(frameId: string, timestamp: number): SnapshotRenderer | undefined { - let result: SnapshotRenderer | undefined = undefined; - for (const snapshot of this._frameSnapshots.get(frameId)?.renderer.values() || []) { - if (timestamp && snapshot.snapshot().timestamp <= timestamp) - result = snapshot; - } - return result; + snapshotByName(pageOrFrameId: string, snapshotName: string): SnapshotRenderer | undefined { + const snapshot = this._frameSnapshots.get(pageOrFrameId); + return snapshot?.renderer.find(r => r.snapshotName === snapshotName); } } diff --git a/src/server/snapshot/snapshotTypes.ts b/src/server/snapshot/snapshotTypes.ts index 85928f5e7a..9abeac0469 100644 --- a/src/server/snapshot/snapshotTypes.ts +++ b/src/server/snapshot/snapshotTypes.ts @@ -60,6 +60,7 @@ export type FrameSnapshot = { html: NodeSnapshot, resourceOverrides: ResourceOverride[], viewport: { width: number, height: number }, + isMainFrame: boolean, }; export type ContextResources = Map; diff --git a/src/server/snapshot/snapshotter.ts b/src/server/snapshot/snapshotter.ts index ebc8fb491a..371a59d4c9 100644 --- a/src/server/snapshot/snapshotter.ts +++ b/src/server/snapshot/snapshotter.ts @@ -61,8 +61,8 @@ export class Snapshotter { await this._context.exposeBinding(this._snapshotBinding, false, (source, data: SnapshotData) => { const snapshot: FrameSnapshot = { snapshotName: data.snapshotName, - pageId: source.page.uniqueId, - frameId: source.frame.uniqueId, + pageId: source.page.guid, + frameId: source.frame.guid, frameUrl: data.url, doctype: data.doctype, html: data.html, @@ -71,6 +71,7 @@ export class Snapshotter { pageTimestamp: data.timestamp, collectionTime: data.collectionTime, resourceOverrides: [], + isMainFrame: source.page.mainFrame() === source.frame }; for (const { url, content } of data.resourceOverrides) { if (typeof content === 'string') { @@ -167,8 +168,8 @@ export class Snapshotter { const body = await response.body().catch(e => debugLogger.log('error', e)); const responseSha1 = body ? calculateSha1(body) : 'none'; const resource: ResourceSnapshot = { - pageId: page.uniqueId, - frameId: response.frame().uniqueId, + pageId: page.guid, + frameId: response.frame().guid, resourceId: 'resource@' + createGuid(), url, contentType, @@ -203,7 +204,7 @@ export class Snapshotter { const context = await parent._mainContext(); await context?.evaluate(({ snapshotStreamer, frameElement, frameId }) => { (window as any)[snapshotStreamer].markIframe(frameElement, frameId); - }, { snapshotStreamer: this._snapshotStreamer, frameElement, frameId: frame.uniqueId }); + }, { snapshotStreamer: this._snapshotStreamer, frameElement, frameId: frame.guid }); frameElement.dispose(); } catch (e) { } diff --git a/src/server/trace/recorder/tracer.ts b/src/server/trace/recorder/tracer.ts index 42b9a9f4a8..eedf5be152 100644 --- a/src/server/trace/recorder/tracer.ts +++ b/src/server/trace/recorder/tracer.ts @@ -130,7 +130,7 @@ class ContextTracer { } private _onPage(page: Page) { - const pageId = page.uniqueId; + const pageId = page.guid; const event: trace.PageCreatedTraceEvent = { timestamp: monotonicTime(), @@ -197,7 +197,7 @@ class ContextTracer { const sha1 = calculateSha1(params.buffer); const event: trace.ScreencastFrameTraceEvent = { type: 'page-screencast-frame', - pageId: page.uniqueId, + pageId: page.guid, contextId: this._contextId, sha1, pageTimestamp: params.timestamp, diff --git a/tests/channels.spec.ts b/tests/channels.spec.ts index 0d6baa9976..89e086d083 100644 --- a/tests/channels.spec.ts +++ b/tests/channels.spec.ts @@ -23,15 +23,15 @@ it('should scope context handles', async ({browserType, browserOptions, server}) const GOLDEN_PRECONDITION = { _guid: '', objects: [ - { _guid: 'Android', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [ - { _guid: 'Browser', objects: [] } + { _guid: 'android', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [ + { _guid: 'browser', objects: [] } ] }, - { _guid: 'Electron', objects: [] }, + { _guid: 'electron', objects: [] }, { _guid: 'Playwright', objects: [] }, - { _guid: 'Selectors', objects: [] }, + { _guid: 'selectors', objects: [] }, ] }; await expectScopeState(browser, GOLDEN_PRECONDITION); @@ -42,23 +42,23 @@ it('should scope context handles', async ({browserType, browserOptions, server}) await expectScopeState(browser, { _guid: '', objects: [ - { _guid: 'Android', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [ - { _guid: 'Browser', objects: [ - { _guid: 'BrowserContext', objects: [ - { _guid: 'Frame', objects: [] }, - { _guid: 'Page', objects: [ - { _guid: 'Request', objects: [] }, - { _guid: 'Response', objects: [] }, + { _guid: 'android', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [ + { _guid: 'browser', objects: [ + { _guid: 'browser-context', objects: [ + { _guid: 'frame', objects: [] }, + { _guid: 'page', objects: [ + { _guid: 'request', objects: [] }, + { _guid: 'response', objects: [] }, ]}, ]}, ] }, ] }, - { _guid: 'Electron', objects: [] }, + { _guid: 'electron', objects: [] }, { _guid: 'Playwright', objects: [] }, - { _guid: 'Selectors', objects: [] }, + { _guid: 'selectors', objects: [] }, ] }); @@ -74,15 +74,15 @@ it('should scope CDPSession handles', async ({browserType, browserOptions, brows const GOLDEN_PRECONDITION = { _guid: '', objects: [ - { _guid: 'Android', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [ - { _guid: 'Browser', objects: [] } + { _guid: 'android', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [ + { _guid: 'browser', objects: [] } ] }, - { _guid: 'Electron', objects: [] }, + { _guid: 'electron', objects: [] }, { _guid: 'Playwright', objects: [] }, - { _guid: 'Selectors', objects: [] }, + { _guid: 'selectors', objects: [] }, ] }; await expectScopeState(browserType, GOLDEN_PRECONDITION); @@ -91,17 +91,17 @@ it('should scope CDPSession handles', async ({browserType, browserOptions, brows await expectScopeState(browserType, { _guid: '', objects: [ - { _guid: 'Android', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [ - { _guid: 'Browser', objects: [ - { _guid: 'CDPSession', objects: [] }, + { _guid: 'android', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [ + { _guid: 'browser', objects: [ + { _guid: 'cdp-session', objects: [] }, ] }, ] }, - { _guid: 'Electron', objects: [] }, + { _guid: 'electron', objects: [] }, { _guid: 'Playwright', objects: [] }, - { _guid: 'Selectors', objects: [] }, + { _guid: 'selectors', objects: [] }, ] }); @@ -115,13 +115,13 @@ it('should scope browser handles', async ({browserType, browserOptions}) => { const GOLDEN_PRECONDITION = { _guid: '', objects: [ - { _guid: 'Android', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'Electron', objects: [] }, + { _guid: 'android', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'electron', objects: [] }, { _guid: 'Playwright', objects: [] }, - { _guid: 'Selectors', objects: [] }, + { _guid: 'selectors', objects: [] }, ] }; await expectScopeState(browserType, GOLDEN_PRECONDITION); @@ -131,20 +131,20 @@ it('should scope browser handles', async ({browserType, browserOptions}) => { await expectScopeState(browserType, { _guid: '', objects: [ - { _guid: 'Android', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [] }, - { _guid: 'BrowserType', objects: [ + { _guid: 'android', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [] }, + { _guid: 'browser-type', objects: [ { - _guid: 'Browser', objects: [ - { _guid: 'BrowserContext', objects: [] } + _guid: 'browser', objects: [ + { _guid: 'browser-context', objects: [] } ] }, ] }, - { _guid: 'Electron', objects: [] }, + { _guid: 'electron', objects: [] }, { _guid: 'Playwright', objects: [] }, - { _guid: 'Selectors', objects: [] }, + { _guid: 'selectors', objects: [] }, ] });