diff --git a/src/client/channelOwner.ts b/src/client/channelOwner.ts index be7d84a53f..0df0ebeb67 100644 --- a/src/client/channelOwner.ts +++ b/src/client/channelOwner.ts @@ -19,7 +19,7 @@ import * as channels from '../protocol/channels'; import type { Connection } from './connection'; import type { Logger } from './types'; import { debugLogger } from '../utils/debugLogger'; -import { isUnderTest } from '../utils/utils'; +import { rewriteErrorMessage } from '../utils/stackTrace'; export abstract class ChannelOwner extends EventEmitter { private _connection: Connection; @@ -89,9 +89,6 @@ export abstract class ChannelOwner(apiName: string, func: () => Promise, logger?: Logger): Promise { - const stackObject: any = {}; - Error.captureStackTrace(stackObject); - const stack = stackObject.stack.startsWith('Error') ? stackObject.stack.substring(5) : stackObject.stack; logger = logger || this._logger; try { logApiCall(logger, `=> ${apiName} started`); @@ -100,9 +97,7 @@ export abstract class ChannelOwner { constructor(connection: Connection) { @@ -71,12 +72,22 @@ export class Connection { } async sendMessageToServer(type: string, guid: string, method: string, params: any): Promise { + const stackObject: any = {}; + Error.captureStackTrace(stackObject); + const stack = stackObject.stack.startsWith('Error') ? stackObject.stack.substring(5) : stackObject.stack; const id = ++this._lastId; const validated = method === 'debugScopeState' ? params : validateParams(type, method, params); const converted = { id, guid, method, params: validated }; + // Do not include metadata in debug logs to avoid noise. debugLogger.log('channel:command', converted); - this.onmessage(converted); - return new Promise((resolve, reject) => this._callbacks.set(id, { resolve, reject })); + this.onmessage({ ...converted, metadata: { stack } }); + try { + return await new Promise((resolve, reject) => this._callbacks.set(id, { resolve, reject })); + } catch (e) { + const innerStack = (isUnderTest() && e.stack) ? e.stack.substring(e.stack.indexOf(e.message) + e.message.length) : ''; + e.stack = e.message + innerStack + stack; + throw e; + } } _debugScopeState(): any { diff --git a/src/dispatchers/dispatcher.ts b/src/dispatchers/dispatcher.ts index 7ce5cd2b08..7c752abec0 100644 --- a/src/dispatchers/dispatcher.ts +++ b/src/dispatchers/dispatcher.ts @@ -19,6 +19,7 @@ import * as channels from '../protocol/channels'; import { serializeError } from '../protocol/serializers'; import { createScheme, Validator, ValidationError } from '../protocol/validator'; import { assert, createGuid, debugAssert, isUnderTest } from '../utils/utils'; +import { tOptional } from '../protocol/validatorPrimitives'; export const dispatcherSymbol = Symbol('dispatcher'); @@ -122,6 +123,7 @@ export class DispatcherConnection { private _rootDispatcher: Root; onmessage = (message: object) => {}; private _validateParams: (type: string, method: string, params: any) => any; + private _validateMetadata: (metadata: any) => any; sendMessageToClient(guid: string, method: string, params: any, disallowDispatchers?: boolean) { const allowDispatchers = !disallowDispatchers; @@ -152,6 +154,9 @@ export class DispatcherConnection { throw new ValidationError(`Unknown scheme for ${type}.${method}`); return scheme[name](params, ''); }; + this._validateMetadata = (metadata: any): any => { + return tOptional(scheme['Metadata'])(metadata, ''); + }; } rootDispatcher(): Dispatcher { @@ -159,7 +164,7 @@ export class DispatcherConnection { } async dispatch(message: object) { - const { id, guid, method, params } = message as any; + const { id, guid, method, params, metadata } = message as any; const dispatcher = this._dispatchers.get(guid); if (!dispatcher) { this.onmessage({ id, error: serializeError(new Error('Target browser or context has been closed')) }); @@ -171,7 +176,7 @@ export class DispatcherConnection { } try { const validated = this._validateParams(dispatcher._type, method, params); - const result = await (dispatcher as any)[method](validated); + const result = await (dispatcher as any)[method](validated, this._validateMetadata(metadata)); this.onmessage({ id, result: this._replaceDispatchersWithGuids(result, true) }); } catch (e) { this.onmessage({ id, error: serializeError(e) }); diff --git a/src/protocol/channels.ts b/src/protocol/channels.ts index f4a8052b66..580b77a455 100644 --- a/src/protocol/channels.ts +++ b/src/protocol/channels.ts @@ -23,6 +23,10 @@ export type Binary = string; export interface Channel extends EventEmitter { } +export type Metadata = { + stack?: string, +}; + export type SerializedValue = { n?: number, b?: boolean, @@ -121,7 +125,7 @@ export interface RemoteBrowserChannel extends Channel { // ----------- Selectors ----------- export type SelectorsInitializer = {}; export interface SelectorsChannel extends Channel { - register(params: SelectorsRegisterParams): Promise; + register(params: SelectorsRegisterParams, metadata?: Metadata): Promise; } export type SelectorsRegisterParams = { name: string, @@ -139,8 +143,8 @@ export type BrowserTypeInitializer = { name: string, }; export interface BrowserTypeChannel extends Channel { - launch(params: BrowserTypeLaunchParams): Promise; - launchPersistentContext(params: BrowserTypeLaunchPersistentContextParams): Promise; + launch(params: BrowserTypeLaunchParams, metadata?: Metadata): Promise; + launchPersistentContext(params: BrowserTypeLaunchPersistentContextParams, metadata?: Metadata): Promise; } export type BrowserTypeLaunchParams = { executablePath?: string, @@ -325,11 +329,11 @@ export type BrowserInitializer = { }; export interface BrowserChannel extends Channel { on(event: 'close', callback: (params: BrowserCloseEvent) => void): this; - close(params?: BrowserCloseParams): Promise; - newContext(params: BrowserNewContextParams): Promise; - crNewBrowserCDPSession(params?: BrowserCrNewBrowserCDPSessionParams): Promise; - crStartTracing(params: BrowserCrStartTracingParams): Promise; - crStopTracing(params?: BrowserCrStopTracingParams): Promise; + close(params?: BrowserCloseParams, metadata?: Metadata): Promise; + newContext(params: BrowserNewContextParams, metadata?: Metadata): Promise; + crNewBrowserCDPSession(params?: BrowserCrNewBrowserCDPSessionParams, metadata?: Metadata): Promise; + crStartTracing(params: BrowserCrStartTracingParams, metadata?: Metadata): Promise; + crStopTracing(params?: BrowserCrStopTracingParams, metadata?: Metadata): Promise; } export type BrowserCloseEvent = {}; export type BrowserCloseParams = {}; @@ -447,23 +451,23 @@ export interface BrowserContextChannel extends Channel { on(event: 'route', callback: (params: BrowserContextRouteEvent) => void): this; on(event: 'crBackgroundPage', callback: (params: BrowserContextCrBackgroundPageEvent) => void): this; on(event: 'crServiceWorker', callback: (params: BrowserContextCrServiceWorkerEvent) => void): this; - addCookies(params: BrowserContextAddCookiesParams): Promise; - addInitScript(params: BrowserContextAddInitScriptParams): Promise; - clearCookies(params?: BrowserContextClearCookiesParams): Promise; - clearPermissions(params?: BrowserContextClearPermissionsParams): Promise; - close(params?: BrowserContextCloseParams): Promise; - cookies(params: BrowserContextCookiesParams): Promise; - exposeBinding(params: BrowserContextExposeBindingParams): Promise; - grantPermissions(params: BrowserContextGrantPermissionsParams): Promise; - newPage(params?: BrowserContextNewPageParams): Promise; - setDefaultNavigationTimeoutNoReply(params: BrowserContextSetDefaultNavigationTimeoutNoReplyParams): Promise; - setDefaultTimeoutNoReply(params: BrowserContextSetDefaultTimeoutNoReplyParams): Promise; - setExtraHTTPHeaders(params: BrowserContextSetExtraHTTPHeadersParams): Promise; - setGeolocation(params: BrowserContextSetGeolocationParams): Promise; - setHTTPCredentials(params: BrowserContextSetHTTPCredentialsParams): Promise; - setNetworkInterceptionEnabled(params: BrowserContextSetNetworkInterceptionEnabledParams): Promise; - setOffline(params: BrowserContextSetOfflineParams): Promise; - crNewCDPSession(params: BrowserContextCrNewCDPSessionParams): Promise; + addCookies(params: BrowserContextAddCookiesParams, metadata?: Metadata): Promise; + addInitScript(params: BrowserContextAddInitScriptParams, metadata?: Metadata): Promise; + clearCookies(params?: BrowserContextClearCookiesParams, metadata?: Metadata): Promise; + clearPermissions(params?: BrowserContextClearPermissionsParams, metadata?: Metadata): Promise; + close(params?: BrowserContextCloseParams, metadata?: Metadata): Promise; + cookies(params: BrowserContextCookiesParams, metadata?: Metadata): Promise; + exposeBinding(params: BrowserContextExposeBindingParams, metadata?: Metadata): Promise; + grantPermissions(params: BrowserContextGrantPermissionsParams, metadata?: Metadata): Promise; + newPage(params?: BrowserContextNewPageParams, metadata?: Metadata): Promise; + setDefaultNavigationTimeoutNoReply(params: BrowserContextSetDefaultNavigationTimeoutNoReplyParams, metadata?: Metadata): Promise; + setDefaultTimeoutNoReply(params: BrowserContextSetDefaultTimeoutNoReplyParams, metadata?: Metadata): Promise; + setExtraHTTPHeaders(params: BrowserContextSetExtraHTTPHeadersParams, metadata?: Metadata): Promise; + setGeolocation(params: BrowserContextSetGeolocationParams, metadata?: Metadata): Promise; + setHTTPCredentials(params: BrowserContextSetHTTPCredentialsParams, metadata?: Metadata): Promise; + setNetworkInterceptionEnabled(params: BrowserContextSetNetworkInterceptionEnabledParams, metadata?: Metadata): Promise; + setOffline(params: BrowserContextSetOfflineParams, metadata?: Metadata): Promise; + crNewCDPSession(params: BrowserContextCrNewCDPSessionParams, metadata?: Metadata): Promise; } export type BrowserContextBindingCallEvent = { binding: BindingCallChannel, @@ -659,37 +663,37 @@ export interface PageChannel extends Channel { on(event: 'route', callback: (params: PageRouteEvent) => void): this; on(event: 'videoStarted', callback: (params: PageVideoStartedEvent) => void): this; on(event: 'worker', callback: (params: PageWorkerEvent) => void): this; - setDefaultNavigationTimeoutNoReply(params: PageSetDefaultNavigationTimeoutNoReplyParams): Promise; - setDefaultTimeoutNoReply(params: PageSetDefaultTimeoutNoReplyParams): Promise; - setFileChooserInterceptedNoReply(params: PageSetFileChooserInterceptedNoReplyParams): Promise; - addInitScript(params: PageAddInitScriptParams): Promise; - close(params: PageCloseParams): Promise; - emulateMedia(params: PageEmulateMediaParams): Promise; - exposeBinding(params: PageExposeBindingParams): Promise; - goBack(params: PageGoBackParams): Promise; - goForward(params: PageGoForwardParams): Promise; - opener(params?: PageOpenerParams): Promise; - reload(params: PageReloadParams): Promise; - screenshot(params: PageScreenshotParams): Promise; - setExtraHTTPHeaders(params: PageSetExtraHTTPHeadersParams): Promise; - setNetworkInterceptionEnabled(params: PageSetNetworkInterceptionEnabledParams): Promise; - setViewportSize(params: PageSetViewportSizeParams): Promise; - keyboardDown(params: PageKeyboardDownParams): Promise; - keyboardUp(params: PageKeyboardUpParams): Promise; - keyboardInsertText(params: PageKeyboardInsertTextParams): Promise; - keyboardType(params: PageKeyboardTypeParams): Promise; - keyboardPress(params: PageKeyboardPressParams): Promise; - mouseMove(params: PageMouseMoveParams): Promise; - mouseDown(params: PageMouseDownParams): Promise; - mouseUp(params: PageMouseUpParams): Promise; - mouseClick(params: PageMouseClickParams): Promise; - accessibilitySnapshot(params: PageAccessibilitySnapshotParams): Promise; - pdf(params: PagePdfParams): Promise; - crStartJSCoverage(params: PageCrStartJSCoverageParams): Promise; - crStopJSCoverage(params?: PageCrStopJSCoverageParams): Promise; - crStartCSSCoverage(params: PageCrStartCSSCoverageParams): Promise; - crStopCSSCoverage(params?: PageCrStopCSSCoverageParams): Promise; - bringToFront(params?: PageBringToFrontParams): Promise; + setDefaultNavigationTimeoutNoReply(params: PageSetDefaultNavigationTimeoutNoReplyParams, metadata?: Metadata): Promise; + setDefaultTimeoutNoReply(params: PageSetDefaultTimeoutNoReplyParams, metadata?: Metadata): Promise; + setFileChooserInterceptedNoReply(params: PageSetFileChooserInterceptedNoReplyParams, metadata?: Metadata): Promise; + addInitScript(params: PageAddInitScriptParams, metadata?: Metadata): Promise; + close(params: PageCloseParams, metadata?: Metadata): Promise; + emulateMedia(params: PageEmulateMediaParams, metadata?: Metadata): Promise; + exposeBinding(params: PageExposeBindingParams, metadata?: Metadata): Promise; + goBack(params: PageGoBackParams, metadata?: Metadata): Promise; + goForward(params: PageGoForwardParams, metadata?: Metadata): Promise; + opener(params?: PageOpenerParams, metadata?: Metadata): Promise; + reload(params: PageReloadParams, metadata?: Metadata): Promise; + screenshot(params: PageScreenshotParams, metadata?: Metadata): Promise; + setExtraHTTPHeaders(params: PageSetExtraHTTPHeadersParams, metadata?: Metadata): Promise; + setNetworkInterceptionEnabled(params: PageSetNetworkInterceptionEnabledParams, metadata?: Metadata): Promise; + setViewportSize(params: PageSetViewportSizeParams, metadata?: Metadata): Promise; + keyboardDown(params: PageKeyboardDownParams, metadata?: Metadata): Promise; + keyboardUp(params: PageKeyboardUpParams, metadata?: Metadata): Promise; + keyboardInsertText(params: PageKeyboardInsertTextParams, metadata?: Metadata): Promise; + keyboardType(params: PageKeyboardTypeParams, metadata?: Metadata): Promise; + keyboardPress(params: PageKeyboardPressParams, metadata?: Metadata): Promise; + mouseMove(params: PageMouseMoveParams, metadata?: Metadata): Promise; + mouseDown(params: PageMouseDownParams, metadata?: Metadata): Promise; + mouseUp(params: PageMouseUpParams, metadata?: Metadata): Promise; + mouseClick(params: PageMouseClickParams, metadata?: Metadata): Promise; + accessibilitySnapshot(params: PageAccessibilitySnapshotParams, metadata?: Metadata): Promise; + pdf(params: PagePdfParams, metadata?: Metadata): Promise; + crStartJSCoverage(params: PageCrStartJSCoverageParams, metadata?: Metadata): Promise; + crStopJSCoverage(params?: PageCrStopJSCoverageParams, metadata?: Metadata): Promise; + crStartCSSCoverage(params: PageCrStartCSSCoverageParams, metadata?: Metadata): Promise; + crStopCSSCoverage(params?: PageCrStopCSSCoverageParams, metadata?: Metadata): Promise; + bringToFront(params?: PageBringToFrontParams, metadata?: Metadata): Promise; } export type PageBindingCallEvent = { binding: BindingCallChannel, @@ -1080,38 +1084,38 @@ export type FrameInitializer = { export interface FrameChannel extends Channel { on(event: 'loadstate', callback: (params: FrameLoadstateEvent) => void): this; on(event: 'navigated', callback: (params: FrameNavigatedEvent) => void): this; - evalOnSelector(params: FrameEvalOnSelectorParams): Promise; - evalOnSelectorAll(params: FrameEvalOnSelectorAllParams): Promise; - addScriptTag(params: FrameAddScriptTagParams): Promise; - addStyleTag(params: FrameAddStyleTagParams): Promise; - check(params: FrameCheckParams): Promise; - click(params: FrameClickParams): Promise; - content(params?: FrameContentParams): Promise; - dblclick(params: FrameDblclickParams): Promise; - dispatchEvent(params: FrameDispatchEventParams): Promise; - evaluateExpression(params: FrameEvaluateExpressionParams): Promise; - evaluateExpressionHandle(params: FrameEvaluateExpressionHandleParams): Promise; - fill(params: FrameFillParams): Promise; - focus(params: FrameFocusParams): Promise; - frameElement(params?: FrameFrameElementParams): Promise; - getAttribute(params: FrameGetAttributeParams): Promise; - goto(params: FrameGotoParams): Promise; - hover(params: FrameHoverParams): Promise; - innerHTML(params: FrameInnerHTMLParams): Promise; - innerText(params: FrameInnerTextParams): Promise; - press(params: FramePressParams): Promise; - querySelector(params: FrameQuerySelectorParams): Promise; - querySelectorAll(params: FrameQuerySelectorAllParams): Promise; - selectOption(params: FrameSelectOptionParams): Promise; - setContent(params: FrameSetContentParams): Promise; - setInputFiles(params: FrameSetInputFilesParams): Promise; - textContent(params: FrameTextContentParams): Promise; - title(params?: FrameTitleParams): Promise; - type(params: FrameTypeParams): Promise; - uncheck(params: FrameUncheckParams): Promise; - waitForFunction(params: FrameWaitForFunctionParams): Promise; - waitForSelector(params: FrameWaitForSelectorParams): Promise; - extendInjectedScript(params: FrameExtendInjectedScriptParams): Promise; + evalOnSelector(params: FrameEvalOnSelectorParams, metadata?: Metadata): Promise; + evalOnSelectorAll(params: FrameEvalOnSelectorAllParams, metadata?: Metadata): Promise; + addScriptTag(params: FrameAddScriptTagParams, metadata?: Metadata): Promise; + addStyleTag(params: FrameAddStyleTagParams, metadata?: Metadata): Promise; + check(params: FrameCheckParams, metadata?: Metadata): Promise; + click(params: FrameClickParams, metadata?: Metadata): Promise; + content(params?: FrameContentParams, metadata?: Metadata): Promise; + dblclick(params: FrameDblclickParams, metadata?: Metadata): Promise; + dispatchEvent(params: FrameDispatchEventParams, metadata?: Metadata): Promise; + evaluateExpression(params: FrameEvaluateExpressionParams, metadata?: Metadata): Promise; + evaluateExpressionHandle(params: FrameEvaluateExpressionHandleParams, metadata?: Metadata): Promise; + fill(params: FrameFillParams, metadata?: Metadata): Promise; + focus(params: FrameFocusParams, metadata?: Metadata): Promise; + frameElement(params?: FrameFrameElementParams, metadata?: Metadata): Promise; + getAttribute(params: FrameGetAttributeParams, metadata?: Metadata): Promise; + goto(params: FrameGotoParams, metadata?: Metadata): Promise; + hover(params: FrameHoverParams, metadata?: Metadata): Promise; + innerHTML(params: FrameInnerHTMLParams, metadata?: Metadata): Promise; + innerText(params: FrameInnerTextParams, metadata?: Metadata): Promise; + press(params: FramePressParams, metadata?: Metadata): Promise; + querySelector(params: FrameQuerySelectorParams, metadata?: Metadata): Promise; + querySelectorAll(params: FrameQuerySelectorAllParams, metadata?: Metadata): Promise; + selectOption(params: FrameSelectOptionParams, metadata?: Metadata): Promise; + setContent(params: FrameSetContentParams, metadata?: Metadata): Promise; + setInputFiles(params: FrameSetInputFilesParams, metadata?: Metadata): Promise; + textContent(params: FrameTextContentParams, metadata?: Metadata): Promise; + title(params?: FrameTitleParams, metadata?: Metadata): Promise; + type(params: FrameTypeParams, metadata?: Metadata): Promise; + uncheck(params: FrameUncheckParams, metadata?: Metadata): Promise; + waitForFunction(params: FrameWaitForFunctionParams, metadata?: Metadata): Promise; + waitForSelector(params: FrameWaitForSelectorParams, metadata?: Metadata): Promise; + extendInjectedScript(params: FrameExtendInjectedScriptParams, metadata?: Metadata): Promise; } export type FrameLoadstateEvent = { add?: 'load' | 'domcontentloaded' | 'networkidle', @@ -1528,8 +1532,8 @@ export type WorkerInitializer = { }; export interface WorkerChannel extends Channel { on(event: 'close', callback: (params: WorkerCloseEvent) => void): this; - evaluateExpression(params: WorkerEvaluateExpressionParams): Promise; - evaluateExpressionHandle(params: WorkerEvaluateExpressionHandleParams): Promise; + evaluateExpression(params: WorkerEvaluateExpressionParams, metadata?: Metadata): Promise; + evaluateExpressionHandle(params: WorkerEvaluateExpressionHandleParams, metadata?: Metadata): Promise; } export type WorkerCloseEvent = {}; export type WorkerEvaluateExpressionParams = { @@ -1561,12 +1565,12 @@ export type JSHandleInitializer = { }; export interface JSHandleChannel extends Channel { on(event: 'previewUpdated', callback: (params: JSHandlePreviewUpdatedEvent) => void): this; - dispose(params?: JSHandleDisposeParams): Promise; - evaluateExpression(params: JSHandleEvaluateExpressionParams): Promise; - evaluateExpressionHandle(params: JSHandleEvaluateExpressionHandleParams): Promise; - getPropertyList(params?: JSHandleGetPropertyListParams): Promise; - getProperty(params: JSHandleGetPropertyParams): Promise; - jsonValue(params?: JSHandleJsonValueParams): Promise; + dispose(params?: JSHandleDisposeParams, metadata?: Metadata): Promise; + evaluateExpression(params: JSHandleEvaluateExpressionParams, metadata?: Metadata): Promise; + evaluateExpressionHandle(params: JSHandleEvaluateExpressionHandleParams, metadata?: Metadata): Promise; + getPropertyList(params?: JSHandleGetPropertyListParams, metadata?: Metadata): Promise; + getProperty(params: JSHandleGetPropertyParams, metadata?: Metadata): Promise; + jsonValue(params?: JSHandleJsonValueParams, metadata?: Metadata): Promise; } export type JSHandlePreviewUpdatedEvent = { preview: string, @@ -1622,35 +1626,35 @@ export type JSHandleJsonValueResult = { // ----------- ElementHandle ----------- export type ElementHandleInitializer = {}; export interface ElementHandleChannel extends JSHandleChannel { - evalOnSelector(params: ElementHandleEvalOnSelectorParams): Promise; - evalOnSelectorAll(params: ElementHandleEvalOnSelectorAllParams): Promise; - boundingBox(params?: ElementHandleBoundingBoxParams): Promise; - check(params: ElementHandleCheckParams): Promise; - click(params: ElementHandleClickParams): Promise; - contentFrame(params?: ElementHandleContentFrameParams): Promise; - dblclick(params: ElementHandleDblclickParams): Promise; - dispatchEvent(params: ElementHandleDispatchEventParams): Promise; - fill(params: ElementHandleFillParams): Promise; - focus(params?: ElementHandleFocusParams): Promise; - getAttribute(params: ElementHandleGetAttributeParams): Promise; - hover(params: ElementHandleHoverParams): Promise; - innerHTML(params?: ElementHandleInnerHTMLParams): Promise; - innerText(params?: ElementHandleInnerTextParams): Promise; - ownerFrame(params?: ElementHandleOwnerFrameParams): Promise; - press(params: ElementHandlePressParams): Promise; - querySelector(params: ElementHandleQuerySelectorParams): Promise; - querySelectorAll(params: ElementHandleQuerySelectorAllParams): Promise; - screenshot(params: ElementHandleScreenshotParams): Promise; - scrollIntoViewIfNeeded(params: ElementHandleScrollIntoViewIfNeededParams): Promise; - selectOption(params: ElementHandleSelectOptionParams): Promise; - selectText(params: ElementHandleSelectTextParams): Promise; - setInputFiles(params: ElementHandleSetInputFilesParams): Promise; - textContent(params?: ElementHandleTextContentParams): Promise; - type(params: ElementHandleTypeParams): Promise; - uncheck(params: ElementHandleUncheckParams): Promise; - waitForElementState(params: ElementHandleWaitForElementStateParams): Promise; - waitForSelector(params: ElementHandleWaitForSelectorParams): Promise; - createSelectorForTest(params: ElementHandleCreateSelectorForTestParams): Promise; + evalOnSelector(params: ElementHandleEvalOnSelectorParams, metadata?: Metadata): Promise; + evalOnSelectorAll(params: ElementHandleEvalOnSelectorAllParams, metadata?: Metadata): Promise; + boundingBox(params?: ElementHandleBoundingBoxParams, metadata?: Metadata): Promise; + check(params: ElementHandleCheckParams, metadata?: Metadata): Promise; + click(params: ElementHandleClickParams, metadata?: Metadata): Promise; + contentFrame(params?: ElementHandleContentFrameParams, metadata?: Metadata): Promise; + dblclick(params: ElementHandleDblclickParams, metadata?: Metadata): Promise; + dispatchEvent(params: ElementHandleDispatchEventParams, metadata?: Metadata): Promise; + fill(params: ElementHandleFillParams, metadata?: Metadata): Promise; + focus(params?: ElementHandleFocusParams, metadata?: Metadata): Promise; + getAttribute(params: ElementHandleGetAttributeParams, metadata?: Metadata): Promise; + hover(params: ElementHandleHoverParams, metadata?: Metadata): Promise; + innerHTML(params?: ElementHandleInnerHTMLParams, metadata?: Metadata): Promise; + innerText(params?: ElementHandleInnerTextParams, metadata?: Metadata): Promise; + ownerFrame(params?: ElementHandleOwnerFrameParams, metadata?: Metadata): Promise; + press(params: ElementHandlePressParams, metadata?: Metadata): Promise; + querySelector(params: ElementHandleQuerySelectorParams, metadata?: Metadata): Promise; + querySelectorAll(params: ElementHandleQuerySelectorAllParams, metadata?: Metadata): Promise; + screenshot(params: ElementHandleScreenshotParams, metadata?: Metadata): Promise; + scrollIntoViewIfNeeded(params: ElementHandleScrollIntoViewIfNeededParams, metadata?: Metadata): Promise; + selectOption(params: ElementHandleSelectOptionParams, metadata?: Metadata): Promise; + selectText(params: ElementHandleSelectTextParams, metadata?: Metadata): Promise; + setInputFiles(params: ElementHandleSetInputFilesParams, metadata?: Metadata): Promise; + textContent(params?: ElementHandleTextContentParams, metadata?: Metadata): Promise; + type(params: ElementHandleTypeParams, metadata?: Metadata): Promise; + uncheck(params: ElementHandleUncheckParams, metadata?: Metadata): Promise; + waitForElementState(params: ElementHandleWaitForElementStateParams, metadata?: Metadata): Promise; + waitForSelector(params: ElementHandleWaitForSelectorParams, metadata?: Metadata): Promise; + createSelectorForTest(params: ElementHandleCreateSelectorForTestParams, metadata?: Metadata): Promise; } export type ElementHandleEvalOnSelectorParams = { selector: string, @@ -1987,7 +1991,7 @@ export type RequestInitializer = { redirectedFrom?: RequestChannel, }; export interface RequestChannel extends Channel { - response(params?: RequestResponseParams): Promise; + response(params?: RequestResponseParams, metadata?: Metadata): Promise; } export type RequestResponseParams = {}; export type RequestResponseOptions = {}; @@ -2000,9 +2004,9 @@ export type RouteInitializer = { request: RequestChannel, }; export interface RouteChannel extends Channel { - abort(params: RouteAbortParams): Promise; - continue(params: RouteContinueParams): Promise; - fulfill(params: RouteFulfillParams): Promise; + abort(params: RouteAbortParams, metadata?: Metadata): Promise; + continue(params: RouteContinueParams, metadata?: Metadata): Promise; + fulfill(params: RouteFulfillParams, metadata?: Metadata): Promise; } export type RouteAbortParams = { errorCode?: string, @@ -2060,8 +2064,8 @@ export type ResponseInitializer = { }[], }; export interface ResponseChannel extends Channel { - body(params?: ResponseBodyParams): Promise; - finished(params?: ResponseFinishedParams): Promise; + body(params?: ResponseBodyParams, metadata?: Metadata): Promise; + finished(params?: ResponseFinishedParams, metadata?: Metadata): Promise; } export type ResponseBodyParams = {}; export type ResponseBodyOptions = {}; @@ -2095,8 +2099,8 @@ export type BindingCallInitializer = { args: SerializedValue[], }; export interface BindingCallChannel extends Channel { - reject(params: BindingCallRejectParams): Promise; - resolve(params: BindingCallResolveParams): Promise; + reject(params: BindingCallRejectParams, metadata?: Metadata): Promise; + resolve(params: BindingCallResolveParams, metadata?: Metadata): Promise; } export type BindingCallRejectParams = { error: SerializedError, @@ -2120,8 +2124,8 @@ export type DialogInitializer = { defaultValue: string, }; export interface DialogChannel extends Channel { - accept(params: DialogAcceptParams): Promise; - dismiss(params?: DialogDismissParams): Promise; + accept(params: DialogAcceptParams, metadata?: Metadata): Promise; + dismiss(params?: DialogDismissParams, metadata?: Metadata): Promise; } export type DialogAcceptParams = { promptText?: string, @@ -2137,7 +2141,7 @@ export type DialogDismissResult = void; // ----------- Video ----------- export type VideoInitializer = {}; export interface VideoChannel extends Channel { - path(params?: VideoPathParams): Promise; + path(params?: VideoPathParams, metadata?: Metadata): Promise; } export type VideoPathParams = {}; export type VideoPathOptions = {}; @@ -2151,12 +2155,12 @@ export type DownloadInitializer = { suggestedFilename: string, }; export interface DownloadChannel extends Channel { - path(params?: DownloadPathParams): Promise; - saveAs(params: DownloadSaveAsParams): Promise; - saveAsStream(params?: DownloadSaveAsStreamParams): Promise; - failure(params?: DownloadFailureParams): Promise; - stream(params?: DownloadStreamParams): Promise; - delete(params?: DownloadDeleteParams): Promise; + path(params?: DownloadPathParams, metadata?: Metadata): Promise; + saveAs(params: DownloadSaveAsParams, metadata?: Metadata): Promise; + saveAsStream(params?: DownloadSaveAsStreamParams, metadata?: Metadata): Promise; + failure(params?: DownloadFailureParams, metadata?: Metadata): Promise; + stream(params?: DownloadStreamParams, metadata?: Metadata): Promise; + delete(params?: DownloadDeleteParams, metadata?: Metadata): Promise; } export type DownloadPathParams = {}; export type DownloadPathOptions = {}; @@ -2192,8 +2196,8 @@ export type DownloadDeleteResult = void; // ----------- Stream ----------- export type StreamInitializer = {}; export interface StreamChannel extends Channel { - read(params: StreamReadParams): Promise; - close(params?: StreamCloseParams): Promise; + read(params: StreamReadParams, metadata?: Metadata): Promise; + close(params?: StreamCloseParams, metadata?: Metadata): Promise; } export type StreamReadParams = { size?: number, @@ -2212,8 +2216,8 @@ export type StreamCloseResult = void; export type CDPSessionInitializer = {}; export interface CDPSessionChannel extends Channel { on(event: 'event', callback: (params: CDPSessionEventEvent) => void): this; - send(params: CDPSessionSendParams): Promise; - detach(params?: CDPSessionDetachParams): Promise; + send(params: CDPSessionSendParams, metadata?: Metadata): Promise; + detach(params?: CDPSessionDetachParams, metadata?: Metadata): Promise; } export type CDPSessionEventEvent = { method: string, @@ -2236,7 +2240,7 @@ export type CDPSessionDetachResult = void; // ----------- Electron ----------- export type ElectronInitializer = {}; export interface ElectronChannel extends Channel { - launch(params: ElectronLaunchParams): Promise; + launch(params: ElectronLaunchParams, metadata?: Metadata): Promise; } export type ElectronLaunchParams = { executablePath: string, @@ -2273,10 +2277,10 @@ export interface ElectronApplicationChannel extends Channel { on(event: 'context', callback: (params: ElectronApplicationContextEvent) => void): this; on(event: 'close', callback: (params: ElectronApplicationCloseEvent) => void): this; on(event: 'window', callback: (params: ElectronApplicationWindowEvent) => void): this; - newBrowserWindow(params: ElectronApplicationNewBrowserWindowParams): Promise; - evaluateExpression(params: ElectronApplicationEvaluateExpressionParams): Promise; - evaluateExpressionHandle(params: ElectronApplicationEvaluateExpressionHandleParams): Promise; - close(params?: ElectronApplicationCloseParams): Promise; + newBrowserWindow(params: ElectronApplicationNewBrowserWindowParams, metadata?: Metadata): Promise; + evaluateExpression(params: ElectronApplicationEvaluateExpressionParams, metadata?: Metadata): Promise; + evaluateExpressionHandle(params: ElectronApplicationEvaluateExpressionHandleParams, metadata?: Metadata): Promise; + close(params?: ElectronApplicationCloseParams, metadata?: Metadata): Promise; } export type ElectronApplicationContextEvent = { context: BrowserContextChannel, diff --git a/src/protocol/protocol.yml b/src/protocol/protocol.yml index eb59688f1e..0722f73cdd 100644 --- a/src/protocol/protocol.yml +++ b/src/protocol/protocol.yml @@ -12,6 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. + +# This object can be send with any rpc call in the "metadata" field. +Metadata: + type: object + properties: + stack: string? + + SerializedValue: type: object # Exactly one of the properties must be present. diff --git a/src/protocol/validator.ts b/src/protocol/validator.ts index f6dffa1218..189aa2a34e 100644 --- a/src/protocol/validator.ts +++ b/src/protocol/validator.ts @@ -33,6 +33,9 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { }; }; + scheme.Metadata = tObject({ + stack: tOptional(tString), + }); scheme.SerializedValue = tObject({ n: tOptional(tNumber), b: tOptional(tBoolean), diff --git a/utils/generate_channels.js b/utils/generate_channels.js index 3cb857cb45..23faac7262 100755 --- a/utils/generate_channels.js +++ b/utils/generate_channels.js @@ -212,7 +212,7 @@ for (const [name, item] of Object.entries(protocol)) { const returns = objectType(method.returns || {}, ''); ts_types.set(resultName, method.returns ? returns.ts : 'void'); - channels_ts.push(` ${methodName}(params${method.parameters ? '' : '?'}: ${paramsName}): Promise<${resultName}>;`); + channels_ts.push(` ${methodName}(params${method.parameters ? '' : '?'}: ${paramsName}, metadata?: Metadata): Promise<${resultName}>;`); } channels_ts.push(`}`);