diff --git a/src/rpc/channels.ts b/src/rpc/channels.ts index 362843f321..4e592985e2 100644 --- a/src/rpc/channels.ts +++ b/src/rpc/channels.ts @@ -14,33 +14,156 @@ * limitations under the License. */ +// This file is generated by generate_channels.js, do not edit manually. + import { EventEmitter } from 'events'; -import * as types from '../types'; -import { SerializedValue } from '../common/utilityScriptSerializers'; export type Binary = string; -export type SerializedArgument = { value: SerializedValue, handles: Channel[] }; -export type BrowserContextOptions = { - viewport?: types.Size | null, - ignoreHTTPSErrors?: boolean, - javaScriptEnabled?: boolean, - bypassCSP?: boolean, - userAgent?: string, - locale?: string, - timezoneId?: string, - geolocation?: types.Geolocation, - permissions?: string[], - extraHTTPHeaders?: types.HeadersArray, - offline?: boolean, - httpCredentials?: types.Credentials, - deviceScaleFactor?: number, - isMobile?: boolean, - hasTouch?: boolean, - colorScheme?: types.ColorScheme, - acceptDownloads?: boolean, +export interface Channel extends EventEmitter { +} + +export type SerializedValue = undefined | boolean | number | string | ComplexSerializedValue; + +export type ComplexSerializedValue = { + v?: 'null' | 'undefined' | 'NaN' | 'Infinity' | '-Infinity' | '-0', + d?: string, + r?: { + p: string, + f: string, + }, + a?: SerializedValue[], + o?: { + k: string, + v: SerializedValue, + }[], + h?: number, }; -type LaunchOptionsBase = { + +export type SerializedArgument = { + value: SerializedValue, + handles: Channel[], +}; + +export type AXNodeValue = string | number; + +export type AXNodeChecked = boolean | 'mixed'; + +export type AXNodePressed = boolean | 'mixed'; + +export type AXNode = { + role: string, + name: string, + value?: AXNodeValue, + description?: string, + keyshortcuts?: string, + roledescription?: string, + valuetext?: string, + disabled?: boolean, + expanded?: boolean, + focused?: boolean, + modal?: boolean, + multiline?: boolean, + multiselectable?: boolean, + readonly?: boolean, + required?: boolean, + selected?: boolean, + checked?: AXNodeChecked, + pressed?: AXNodePressed, + level?: number, + valuemin?: number, + valuemax?: number, + autocomplete?: string, + haspopup?: string, + invalid?: string, + orientation?: string, + children?: AXNode[], +}; + +export type WaitForFunctionPolling = number | 'raf'; + +export type Viewport = { + width: number, + height: number, +}; + +export type ViewportOrNull = null | Viewport; + +export type SerializedError = { + error?: { + message: string, + name: string, + stack?: string, + }, + value?: SerializedValue, +}; + +// ----------- Playwright ----------- +export type PlaywrightInitializer = { + chromium: BrowserTypeChannel, + firefox: BrowserTypeChannel, + webkit: BrowserTypeChannel, + electron?: ElectronChannel, + deviceDescriptors: { + name: string, + descriptor: { + userAgent: string, + viewport: { + width: number, + height: number, + }, + deviceScaleFactor: number, + isMobile: boolean, + hasTouch: boolean, + }, + }[], + selectors: SelectorsChannel, +}; +export interface PlaywrightChannel extends Channel { +} + +// ----------- Selectors ----------- +export type SelectorsInitializer = {}; +export interface SelectorsChannel extends Channel { + register(params: SelectorsRegisterParams): Promise; + createSelector(params: SelectorsCreateSelectorParams): Promise; +} +export type SelectorsRegisterParams = { + name: string, + source: string, + options: { + contentScript?: boolean, + }, +}; +export type SelectorsRegisterResult = void; +export type SelectorsCreateSelectorParams = { + name: string, + handle: ElementHandleChannel, +}; +export type SelectorsCreateSelectorResult = { + value?: string, +}; + +// ----------- BrowserType ----------- +export type BrowserTypeInitializer = { + executablePath: string, + name: string, +}; +export interface BrowserTypeChannel extends Channel { + connect(params: BrowserTypeConnectParams): Promise; + launch(params: BrowserTypeLaunchParams): Promise; + launchServer(params: BrowserTypeLaunchServerParams): Promise; + launchPersistentContext(params: BrowserTypeLaunchPersistentContextParams): Promise; +} +export type BrowserTypeConnectParams = { + wsEndpoint: string, + slowMo?: number, + timeout?: number, +}; +export type BrowserTypeConnectResult = { + browser: BrowserChannel, +}; +export type BrowserTypeLaunchParams = { executablePath?: string, args?: string[], ignoreAllDefaultArgs?: boolean, @@ -49,369 +172,580 @@ type LaunchOptionsBase = { handleSIGTERM?: boolean, handleSIGHUP?: boolean, timeout?: number, - env?: types.EnvArray, + env?: { + name: string, + value: string, + }[], headless?: boolean, devtools?: boolean, - proxy?: types.ProxySettings, + proxy?: { + server: string, + bypass?: string, + username?: string, + password?: string, + }, downloadsPath?: string, + slowMo?: number, }; -export type LaunchOptions = LaunchOptionsBase & { slowMo?: number }; -export type LaunchServerOptions = LaunchOptionsBase & { port?: number }; -export type LaunchPersistentContextOptions = { userDataDir: string } & LaunchOptions & BrowserContextOptions; - -export interface Channel extends EventEmitter { -} - -export interface PlaywrightChannel extends Channel { -} -export type PlaywrightInitializer = { - chromium: BrowserTypeChannel, - firefox: BrowserTypeChannel, - webkit: BrowserTypeChannel, - electron?: ElectronChannel, - deviceDescriptors: { name: string, descriptor: types.DeviceDescriptor }[], - selectors: SelectorsChannel, +export type BrowserTypeLaunchResult = { + browser: BrowserChannel, +}; +export type BrowserTypeLaunchServerParams = { + executablePath?: string, + args?: string[], + ignoreAllDefaultArgs?: boolean, + ignoreDefaultArgs?: string[], + handleSIGINT?: boolean, + handleSIGTERM?: boolean, + handleSIGHUP?: boolean, + timeout?: number, + env?: { + name: string, + value: string, + }[], + headless?: boolean, + devtools?: boolean, + proxy?: { + server: string, + bypass?: string, + username?: string, + password?: string, + }, + downloadsPath?: string, + port?: number, +}; +export type BrowserTypeLaunchServerResult = { + server: BrowserServerChannel, +}; +export type BrowserTypeLaunchPersistentContextParams = { + userDataDir: string, + executablePath?: string, + args?: string[], + ignoreAllDefaultArgs?: boolean, + ignoreDefaultArgs?: string[], + handleSIGINT?: boolean, + handleSIGTERM?: boolean, + handleSIGHUP?: boolean, + timeout?: number, + env?: { + name: string, + value: string, + }[], + headless?: boolean, + devtools?: boolean, + proxy?: { + server: string, + bypass?: string, + username?: string, + password?: string, + }, + downloadsPath?: string, + slowMo?: number, + viewport?: ViewportOrNull, + ignoreHTTPSErrors?: boolean, + javaScriptEnabled?: boolean, + bypassCSP?: boolean, + userAgent?: string, + locale?: string, + timezoneId?: string, + geolocation?: { + longitude: number, + latitude: number, + accuracy?: number, + }, + permissions?: string[], + extraHTTPHeaders?: { + name: string, + value: string, + }[], + offline?: boolean, + httpCredentials?: { + username: string, + password: string, + }, + deviceScaleFactor?: number, + isMobile?: boolean, + hasTouch?: boolean, + colorScheme?: 'dark' | 'light' | 'no-preference', + acceptDownloads?: boolean, +}; +export type BrowserTypeLaunchPersistentContextResult = { + context: BrowserContextChannel, }; - -export interface SelectorsChannel extends Channel { - register(params: { name: string, source: string, options: { contentScript?: boolean } }): Promise; - createSelector(params: { name: string, handle: ElementHandleChannel }): Promise<{ value?: string }>; -} -export type SelectorsInitializer = {}; - - -export interface BrowserTypeChannel extends Channel { - connect(params: types.ConnectOptions): Promise<{ browser: BrowserChannel }>; - launch(params: LaunchOptions): Promise<{ browser: BrowserChannel }>; - launchServer(params: LaunchServerOptions): Promise<{ server: BrowserServerChannel }>; - launchPersistentContext(params: LaunchPersistentContextOptions): Promise<{ context: BrowserContextChannel }>; -} -export type BrowserTypeInitializer = { - executablePath: string, - name: string -}; - - -export interface BrowserServerChannel extends Channel { - on(event: 'close', callback: () => void): this; - - close(): Promise; - kill(): Promise; -} +// ----------- BrowserServer ----------- export type BrowserServerInitializer = { wsEndpoint: string, - pid: number + pid: number, +}; +export interface BrowserServerChannel extends Channel { + on(event: 'close', callback: (params: BrowserServerCloseEvent) => void): this; + close(params?: BrowserServerCloseParams): Promise; + kill(params?: BrowserServerKillParams): Promise; +} +export type BrowserServerCloseEvent = {}; +export type BrowserServerCloseParams = {}; +export type BrowserServerCloseResult = void; +export type BrowserServerKillParams = {}; +export type BrowserServerKillResult = void; + +// ----------- Browser ----------- +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; +} +export type BrowserCloseEvent = {}; +export type BrowserCloseParams = {}; +export type BrowserCloseResult = void; +export type BrowserNewContextParams = { + viewport?: ViewportOrNull, + ignoreHTTPSErrors?: boolean, + javaScriptEnabled?: boolean, + bypassCSP?: boolean, + userAgent?: string, + locale?: string, + timezoneId?: string, + geolocation?: { + longitude: number, + latitude: number, + accuracy?: number, + }, + permissions?: string[], + extraHTTPHeaders?: { + name: string, + value: string, + }[], + offline?: boolean, + httpCredentials?: { + username: string, + password: string, + }, + deviceScaleFactor?: number, + isMobile?: boolean, + hasTouch?: boolean, + colorScheme?: 'dark' | 'light' | 'no-preference', + acceptDownloads?: boolean, +}; +export type BrowserNewContextResult = { + context: BrowserContextChannel, +}; +export type BrowserCrNewBrowserCDPSessionParams = {}; +export type BrowserCrNewBrowserCDPSessionResult = { + session: CDPSessionChannel, +}; +export type BrowserCrStartTracingParams = { + page?: PageChannel, + path?: string, + screenshots?: boolean, + categories?: string[], +}; +export type BrowserCrStartTracingResult = void; +export type BrowserCrStopTracingParams = {}; +export type BrowserCrStopTracingResult = { + binary: Binary, }; - -export interface BrowserChannel extends Channel { - on(event: 'close', callback: () => void): this; - - close(): Promise; - newContext(params: BrowserContextOptions): Promise<{ context: BrowserContextChannel }>; - - crNewBrowserCDPSession(): Promise<{ session: CDPSessionChannel }>; - crStartTracing(params: { page?: PageChannel, path?: string, screenshots?: boolean, categories?: string[] }): Promise; - crStopTracing(): Promise<{ binary: Binary }>; -} -export type BrowserInitializer = {}; - - -export interface BrowserContextChannel extends Channel { - on(event: 'bindingCall', callback: (params: { binding: BindingCallChannel }) => void): this; - on(event: 'close', callback: () => void): this; - on(event: 'page', callback: (params: { page: PageChannel }) => void): this; - on(event: 'route', callback: (params: { route: RouteChannel, request: RequestChannel }) => void): this; - - addCookies(params: { cookies: types.SetNetworkCookieParam[] }): Promise; - addInitScript(params: { source: string }): Promise; - clearCookies(): Promise; - clearPermissions(): Promise; - close(): Promise; - cookies(params: { urls: string[] }): Promise<{ cookies: types.NetworkCookie[] }>; - exposeBinding(params: { name: string }): Promise; - grantPermissions(params: { permissions: string[], origin?: string }): Promise; - newPage(): Promise<{ page: PageChannel }>; - setDefaultNavigationTimeoutNoReply(params: { timeout: number }): void; - setDefaultTimeoutNoReply(params: { timeout: number }): void; - setExtraHTTPHeaders(params: { headers: types.HeadersArray }): Promise; - setGeolocation(params: { geolocation: types.Geolocation | null }): Promise; - setHTTPCredentials(params: { httpCredentials: types.Credentials | null }): Promise; - setNetworkInterceptionEnabled(params: { enabled: boolean }): Promise; - setOffline(params: { offline: boolean }): Promise; - - on(event: 'crBackgroundPage', callback: (params: { page: PageChannel }) => void): this; - on(event: 'crServiceWorker', callback: (params: { worker: WorkerChannel }) => void): this; - crNewCDPSession(params: { page: PageChannel }): Promise<{ session: CDPSessionChannel }>; -} +// ----------- BrowserContext ----------- export type BrowserContextInitializer = {}; - - -export interface PageChannel extends Channel { - on(event: 'bindingCall', callback: (params: { binding: BindingCallChannel }) => void): this; - on(event: 'close', callback: () => void): this; - on(event: 'console', callback: (params: { message: ConsoleMessageChannel }) => void): this; - on(event: 'crash', callback: () => void): this; - on(event: 'dialog', callback: (params: { dialog: DialogChannel }) => void): this; - on(event: 'download', callback: (params: { download: DownloadChannel }) => void): this; - on(event: 'domcontentloaded', callback: () => void): this; - on(event: 'fileChooser', callback: (params: { element: ElementHandleChannel, isMultiple: boolean }) => void): this; - on(event: 'frameAttached', callback: (params: { frame: FrameChannel }) => void): this; - on(event: 'frameDetached', callback: (params: { frame: FrameChannel }) => void): this; - on(event: 'load', callback: () => void): this; - on(event: 'pageError', callback: (params: { error: types.Error }) => void): this; - on(event: 'popup', callback: (params: { page: PageChannel }) => void): this; - on(event: 'request', callback: (params: { request: RequestChannel }) => void): this; - on(event: 'requestFailed', callback: (params: { request: RequestChannel, failureText: string | null }) => void): this; - on(event: 'requestFinished', callback: (params: { request: RequestChannel }) => void): this; - on(event: 'response', callback: (params: { response: ResponseChannel }) => void): this; - on(event: 'route', callback: (params: { route: RouteChannel, request: RequestChannel }) => void): this; - on(event: 'worker', callback: (params: { worker: WorkerChannel }) => void): this; - - setDefaultNavigationTimeoutNoReply(params: { timeout: number }): void; - setDefaultTimeoutNoReply(params: { timeout: number }): Promise; - setFileChooserInterceptedNoReply(params: { intercepted: boolean }): Promise; - - addInitScript(params: { source: string }): Promise; - close(params: { runBeforeUnload?: boolean }): Promise; - emulateMedia(params: { media?: 'screen' | 'print', colorScheme?: 'dark' | 'light' | 'no-preference' }): Promise; - exposeBinding(params: { name: string }): Promise; - goBack(params: types.NavigateOptions): Promise<{ response: ResponseChannel | null }>; - goForward(params: types.NavigateOptions): Promise<{ response: ResponseChannel | null }>; - opener(): Promise<{ page: PageChannel | null }>; - reload(params: types.NavigateOptions): Promise<{ response: ResponseChannel | null }>; - screenshot(params: types.ScreenshotOptions): Promise<{ binary: Binary }>; - setExtraHTTPHeaders(params: { headers: types.HeadersArray }): Promise; - setNetworkInterceptionEnabled(params: { enabled: boolean }): Promise; - setViewportSize(params: { viewportSize: types.Size }): Promise; - - // Input - keyboardDown(params: { key: string }): Promise; - keyboardUp(params: { key: string }): Promise; - keyboardInsertText(params: { text: string }): Promise; - keyboardType(params: { text: string, delay?: number }): Promise; - keyboardPress(params: { key: string, delay?: number }): Promise; - mouseMove(params: { x: number, y: number, steps?: number }): Promise; - mouseDown(params: { button?: types.MouseButton, clickCount?: number }): Promise; - mouseUp(params: { button?: types.MouseButton, clickCount?: number }): Promise; - mouseClick(params: { x: number, y: number, delay?: number, button?: types.MouseButton, clickCount?: number }): Promise; - - accessibilitySnapshot(params: { interestingOnly?: boolean, root?: ElementHandleChannel }): Promise<{ rootAXNode: types.SerializedAXNode | null }>; - pdf: (params: PDFOptions) => Promise<{ pdf: Binary }>; - - crStartJSCoverage(params: types.JSCoverageOptions): Promise; - crStopJSCoverage(): Promise<{ entries: types.JSCoverageEntry[] }>; - crStartCSSCoverage(params: types.CSSCoverageOptions): Promise; - crStopCSSCoverage(): Promise<{ entries: types.CSSCoverageEntry[] }>; +export interface BrowserContextChannel extends Channel { + on(event: 'bindingCall', callback: (params: BrowserContextBindingCallEvent) => void): this; + on(event: 'close', callback: (params: BrowserContextCloseEvent) => void): this; + on(event: 'page', callback: (params: BrowserContextPageEvent) => void): this; + on(event: 'route', callback: (params: BrowserContextRouteEvent) => 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; + on(event: 'crBackgroundPage', callback: (params: BrowserContextCrBackgroundPageEvent) => void): this; + on(event: 'crServiceWorker', callback: (params: BrowserContextCrServiceWorkerEvent) => void): this; + crNewCDPSession(params: BrowserContextCrNewCDPSessionParams): Promise; } +export type BrowserContextBindingCallEvent = { + binding: BindingCallChannel, +}; +export type BrowserContextCloseEvent = {}; +export type BrowserContextPageEvent = { + page: PageChannel, +}; +export type BrowserContextRouteEvent = { + route: RouteChannel, + request: RequestChannel, +}; +export type BrowserContextAddCookiesParams = { + cookies: { + name: string, + value: string, + url?: string, + domain?: string, + path?: string, + expires?: number, + httpOnly?: boolean, + secure?: boolean, + sameSite?: 'Strict' | 'Lax' | 'None', + }[], +}; +export type BrowserContextAddCookiesResult = void; +export type BrowserContextAddInitScriptParams = { + source: string, +}; +export type BrowserContextAddInitScriptResult = void; +export type BrowserContextClearCookiesParams = {}; +export type BrowserContextClearCookiesResult = void; +export type BrowserContextClearPermissionsParams = {}; +export type BrowserContextClearPermissionsResult = void; +export type BrowserContextCloseParams = {}; +export type BrowserContextCloseResult = void; +export type BrowserContextCookiesParams = { + urls: string[], +}; +export type BrowserContextCookiesResult = { + cookies: { + name: string, + value: string, + domain: string, + path: string, + expires: number, + httpOnly: boolean, + secure: boolean, + sameSite: 'Strict' | 'Lax' | 'None', + }[], +}; +export type BrowserContextExposeBindingParams = { + name: string, +}; +export type BrowserContextExposeBindingResult = void; +export type BrowserContextGrantPermissionsParams = { + permissions: string[], + origin?: string, +}; +export type BrowserContextGrantPermissionsResult = void; +export type BrowserContextNewPageParams = {}; +export type BrowserContextNewPageResult = { + page: PageChannel, +}; +export type BrowserContextSetDefaultNavigationTimeoutNoReplyParams = { + timeout: number, +}; +export type BrowserContextSetDefaultNavigationTimeoutNoReplyResult = void; +export type BrowserContextSetDefaultTimeoutNoReplyParams = { + timeout: number, +}; +export type BrowserContextSetDefaultTimeoutNoReplyResult = void; +export type BrowserContextSetExtraHTTPHeadersParams = { + headers: { + name: string, + value: string, + }[], +}; +export type BrowserContextSetExtraHTTPHeadersResult = void; +export type BrowserContextSetGeolocationParams = { + geolocation?: { + longitude: number, + latitude: number, + accuracy?: number, + }, +}; +export type BrowserContextSetGeolocationResult = void; +export type BrowserContextSetHTTPCredentialsParams = { + httpCredentials?: { + username: string, + password: string, + }, +}; +export type BrowserContextSetHTTPCredentialsResult = void; +export type BrowserContextSetNetworkInterceptionEnabledParams = { + enabled: boolean, +}; +export type BrowserContextSetNetworkInterceptionEnabledResult = void; +export type BrowserContextSetOfflineParams = { + offline: boolean, +}; +export type BrowserContextSetOfflineResult = void; +export type BrowserContextCrBackgroundPageEvent = { + page: PageChannel, +}; +export type BrowserContextCrServiceWorkerEvent = { + worker: WorkerChannel, +}; +export type BrowserContextCrNewCDPSessionParams = { + page: PageChannel, +}; +export type BrowserContextCrNewCDPSessionResult = { + session: CDPSessionChannel, +}; +// ----------- Page ----------- export type PageInitializer = { mainFrame: FrameChannel, - viewportSize: types.Size | null, - isClosed: boolean + viewportSize?: { + width: number, + height: number, + }, + isClosed: boolean, }; - -export type FrameNavigatedEvent = { url: string, name: string, newDocument?: { request?: RequestChannel }, error?: string }; - -export interface FrameChannel extends Channel { - on(event: 'loadstate', callback: (params: { add?: types.LifecycleEvent, remove?: types.LifecycleEvent }) => void): this; - on(event: 'navigated', callback: (params: FrameNavigatedEvent) => void): this; - - evalOnSelector(params: { selector: string; expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ value: SerializedValue }>; - evalOnSelectorAll(params: { selector: string; expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ value: SerializedValue }>; - addScriptTag(params: { url?: string, content?: string, type?: string }): Promise<{ element: ElementHandleChannel }>; - addStyleTag(params: { url?: string, content?: string }): Promise<{ element: ElementHandleChannel }>; - check(params: { selector: string, force?: boolean, noWaitAfter?: boolean } & types.TimeoutOptions): Promise; - click(params: { selector: string, force?: boolean, noWaitAfter?: boolean } & types.PointerActionOptions & types.MouseClickOptions & types.TimeoutOptions): Promise; - content(): Promise<{ value: string }>; - dblclick(params: { selector: string, force?: boolean } & types.PointerActionOptions & types.MouseMultiClickOptions & types.TimeoutOptions): Promise; - dispatchEvent(params: { selector: string, type: string, eventInit: SerializedArgument } & types.TimeoutOptions): Promise; - evaluateExpression(params: { expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ value: SerializedValue }>; - evaluateExpressionHandle(params: { expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ handle: JSHandleChannel }>; - fill(params: { selector: string, value: string } & types.NavigatingActionWaitOptions): Promise; - focus(params: { selector: string } & types.TimeoutOptions): Promise; - frameElement(): Promise<{ element: ElementHandleChannel }>; - getAttribute(params: { selector: string, name: string } & types.TimeoutOptions): Promise<{ value: string | null }>; - goto(params: { url: string } & types.GotoOptions): Promise<{ response: ResponseChannel | null }>; - hover(params: { selector: string, force?: boolean } & types.PointerActionOptions & types.TimeoutOptions): Promise; - innerHTML(params: { selector: string } & types.TimeoutOptions): Promise<{ value: string }>; - innerText(params: { selector: string } & types.TimeoutOptions): Promise<{ value: string }>; - press(params: { selector: string, key: string, delay?: number, noWaitAfter?: boolean } & types.TimeoutOptions): Promise; - querySelector(params: { selector: string}): Promise<{ element: ElementHandleChannel | null }>; - querySelectorAll(params: { selector: string}): Promise<{ elements: ElementHandleChannel[] }>; - selectOption(params: { selector: string, elements?: ElementHandleChannel[], options?: types.SelectOption[] } & types.NavigatingActionWaitOptions): Promise<{ values: string[] }>; - setContent(params: { html: string } & types.NavigateOptions): Promise; - setInputFiles(params: { selector: string, files: { name: string, mimeType: string, buffer: Binary }[] } & types.NavigatingActionWaitOptions): Promise; - textContent(params: { selector: string } & types.TimeoutOptions): Promise<{ value: string | null }>; - title(): Promise<{ value: string }>; - type(params: { selector: string, text: string, delay?: number, noWaitAfter?: boolean } & types.TimeoutOptions): Promise; - uncheck(params: { selector: string, force?: boolean, noWaitAfter?: boolean } & types.TimeoutOptions): Promise; - waitForFunction(params: { expression: string, isFunction: boolean, arg: SerializedArgument } & types.WaitForFunctionOptions): Promise<{ handle: JSHandleChannel }>; - waitForSelector(params: { selector: string } & types.WaitForElementOptions): Promise<{ element: ElementHandleChannel | null }>; +export interface PageChannel extends Channel { + on(event: 'bindingCall', callback: (params: PageBindingCallEvent) => void): this; + on(event: 'close', callback: (params: PageCloseEvent) => void): this; + on(event: 'console', callback: (params: PageConsoleEvent) => void): this; + on(event: 'crash', callback: (params: PageCrashEvent) => void): this; + on(event: 'dialog', callback: (params: PageDialogEvent) => void): this; + on(event: 'download', callback: (params: PageDownloadEvent) => void): this; + on(event: 'domcontentloaded', callback: (params: PageDomcontentloadedEvent) => void): this; + on(event: 'fileChooser', callback: (params: PageFileChooserEvent) => void): this; + on(event: 'frameAttached', callback: (params: PageFrameAttachedEvent) => void): this; + on(event: 'frameDetached', callback: (params: PageFrameDetachedEvent) => void): this; + on(event: 'load', callback: (params: PageLoadEvent) => void): this; + on(event: 'pageError', callback: (params: PagePageErrorEvent) => void): this; + on(event: 'popup', callback: (params: PagePopupEvent) => void): this; + on(event: 'request', callback: (params: PageRequestEvent) => void): this; + on(event: 'requestFailed', callback: (params: PageRequestFailedEvent) => void): this; + on(event: 'requestFinished', callback: (params: PageRequestFinishedEvent) => void): this; + on(event: 'response', callback: (params: PageResponseEvent) => void): this; + on(event: 'route', callback: (params: PageRouteEvent) => 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; } -export type FrameInitializer = { - url: string, - name: string, - parentFrame: FrameChannel | null, - loadStates: types.LifecycleEvent[], +export type PageBindingCallEvent = { + binding: BindingCallChannel, }; - - -export interface WorkerChannel extends Channel { - evaluateExpression(params: { expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ value: SerializedValue }>; - evaluateExpressionHandle(params: { expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ handle: JSHandleChannel }>; -} -export type WorkerInitializer = { - url: string, +export type PageCloseEvent = {}; +export type PageConsoleEvent = { + message: ConsoleMessageChannel, }; - - -export interface JSHandleChannel extends Channel { - on(event: 'previewUpdated', callback: (params: { preview: string }) => void): this; - - dispose(): Promise; - evaluateExpression(params: { expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ value: SerializedValue }>; - evaluateExpressionHandle(params: { expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ handle: JSHandleChannel }>; - getPropertyList(): Promise<{ properties: { name: string, value: JSHandleChannel}[] }>; - getProperty(params: { name: string }): Promise<{ handle: JSHandleChannel }>; - jsonValue(): Promise<{ value: SerializedValue }>; -} -export type JSHandleInitializer = { - preview: string, +export type PageCrashEvent = {}; +export type PageDialogEvent = { + dialog: DialogChannel, }; - - -export interface ElementHandleChannel extends JSHandleChannel { - evalOnSelector(params: { selector: string; expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ value: SerializedValue }>; - evalOnSelectorAll(params: { selector: string; expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ value: SerializedValue }>; - boundingBox(): Promise<{ value: types.Rect | null }>; - check(params: { force?: boolean } & { noWaitAfter?: boolean } & types.TimeoutOptions): Promise; - click(params: { force?: boolean, noWaitAfter?: boolean } & types.PointerActionOptions & types.MouseClickOptions & types.TimeoutOptions): Promise; - contentFrame(): Promise<{ frame: FrameChannel | null }>; - dblclick(params: { force?: boolean, noWaitAfter?: boolean } & types.PointerActionOptions & types.MouseMultiClickOptions & types.TimeoutOptions): Promise; - dispatchEvent(params: { type: string, eventInit: SerializedArgument }): Promise; - fill(params: { value: string } & types.NavigatingActionWaitOptions): Promise; - focus(): Promise; - getAttribute(params: { name: string }): Promise<{ value: string | null }>; - hover(params: { force?: boolean } & types.PointerActionOptions & types.TimeoutOptions): Promise; - innerHTML(): Promise<{ value: string }>; - innerText(): Promise<{ value: string }>; - ownerFrame(): Promise<{ frame: FrameChannel | null }>; - press(params: { key: string, delay?: number } & types.TimeoutOptions & { noWaitAfter?: boolean }): Promise; - querySelector(params: { selector: string }): Promise<{ element: ElementHandleChannel | null }>; - querySelectorAll(params: { selector: string }): Promise<{ elements: ElementHandleChannel[] }>; - screenshot(params: types.ElementScreenshotOptions): Promise<{ binary: Binary }>; - scrollIntoViewIfNeeded(params: types.TimeoutOptions): Promise; - selectOption(params: { elements?: ElementHandleChannel[], options?: types.SelectOption[] } & types.NavigatingActionWaitOptions): Promise<{ values: string[] }>; - selectText(params: types.TimeoutOptions): Promise; - setInputFiles(params: { files: { name: string, mimeType: string, buffer: Binary }[] } & types.NavigatingActionWaitOptions): Promise; - textContent(): Promise<{ value: string | null }>; - type(params: { text: string, delay?: number, noWaitAfter?: boolean } & types.TimeoutOptions): Promise; - uncheck(params: { force?: boolean, noWaitAfter?: boolean } & types.TimeoutOptions): Promise; -} - - -export interface RequestChannel extends Channel { - response(): Promise<{ response: ResponseChannel | null }>; -} -export type RequestInitializer = { +export type PageDownloadEvent = { + download: DownloadChannel, +}; +export type PageDomcontentloadedEvent = {}; +export type PageFileChooserEvent = { + element: ElementHandleChannel, + isMultiple: boolean, +}; +export type PageFrameAttachedEvent = { frame: FrameChannel, - url: string, - resourceType: string, - method: string, - postData: string | null, - headers: types.HeadersArray, - isNavigationRequest: boolean, - redirectedFrom: RequestChannel | null, }; - - -export interface RouteChannel extends Channel { - abort(params: { errorCode: string }): Promise; - continue(params: types.NormalizedContinueOverrides): Promise; - fulfill(params: types.NormalizedFulfillResponse): Promise; -} -export type RouteInitializer = { +export type PageFrameDetachedEvent = { + frame: FrameChannel, +}; +export type PageLoadEvent = {}; +export type PagePageErrorEvent = { + error: SerializedError, +}; +export type PagePopupEvent = { + page: PageChannel, +}; +export type PageRequestEvent = { request: RequestChannel, }; - - -export interface ResponseChannel extends Channel { - body(): Promise<{ binary: Binary }>; - finished(): Promise<{ error: Error | null }>; -} -export type ResponseInitializer = { +export type PageRequestFailedEvent = { request: RequestChannel, - url: string, - status: number, - statusText: string, - headers: types.HeadersArray, + failureText?: string, }; - - -export interface ConsoleMessageChannel extends Channel { -} -export type ConsoleMessageInitializer = { - type: string, +export type PageRequestFinishedEvent = { + request: RequestChannel, +}; +export type PageResponseEvent = { + response: ResponseChannel, +}; +export type PageRouteEvent = { + route: RouteChannel, + request: RequestChannel, +}; +export type PageWorkerEvent = { + worker: WorkerChannel, +}; +export type PageSetDefaultNavigationTimeoutNoReplyParams = { + timeout: number, +}; +export type PageSetDefaultNavigationTimeoutNoReplyResult = void; +export type PageSetDefaultTimeoutNoReplyParams = { + timeout: number, +}; +export type PageSetDefaultTimeoutNoReplyResult = void; +export type PageSetFileChooserInterceptedNoReplyParams = { + intercepted: boolean, +}; +export type PageSetFileChooserInterceptedNoReplyResult = void; +export type PageAddInitScriptParams = { + source: string, +}; +export type PageAddInitScriptResult = void; +export type PageCloseParams = { + runBeforeUnload?: boolean, +}; +export type PageCloseResult = void; +export type PageEmulateMediaParams = { + media?: 'screen' | 'print', + colorScheme?: 'dark' | 'light' | 'no-preference', +}; +export type PageEmulateMediaResult = void; +export type PageExposeBindingParams = { + name: string, +}; +export type PageExposeBindingResult = void; +export type PageGoBackParams = { + timeout?: number, + waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', +}; +export type PageGoBackResult = { + response?: ResponseChannel, +}; +export type PageGoForwardParams = { + timeout?: number, + waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', +}; +export type PageGoForwardResult = { + response?: ResponseChannel, +}; +export type PageOpenerParams = {}; +export type PageOpenerResult = { + page?: PageChannel, +}; +export type PageReloadParams = { + timeout?: number, + waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', +}; +export type PageReloadResult = { + response?: ResponseChannel, +}; +export type PageScreenshotParams = { + timeout?: number, + type?: 'png' | 'jpeg', + path?: string, + quality?: number, + omitBackground?: boolean, + fullPage?: boolean, + clip?: { + width: number, + height: number, + x: number, + y: number, + }, +}; +export type PageScreenshotResult = { + binary: Binary, +}; +export type PageSetExtraHTTPHeadersParams = { + headers: { + name: string, + value: string, + }[], +}; +export type PageSetExtraHTTPHeadersResult = void; +export type PageSetNetworkInterceptionEnabledParams = { + enabled: boolean, +}; +export type PageSetNetworkInterceptionEnabledResult = void; +export type PageSetViewportSizeParams = { + viewportSize: { + width: number, + height: number, + }, +}; +export type PageSetViewportSizeResult = void; +export type PageKeyboardDownParams = { + key: string, +}; +export type PageKeyboardDownResult = void; +export type PageKeyboardUpParams = { + key: string, +}; +export type PageKeyboardUpResult = void; +export type PageKeyboardInsertTextParams = { text: string, - args: JSHandleChannel[], - location: types.ConsoleMessageLocation, }; - - -export interface BindingCallChannel extends Channel { - reject(params: { error: types.Error }): void; - resolve(params: { result: SerializedArgument }): void; -} -export type BindingCallInitializer = { - frame: FrameChannel, - name: string, - args: SerializedValue[], +export type PageKeyboardInsertTextResult = void; +export type PageKeyboardTypeParams = { + text: string, + delay?: number, }; - - -export interface DialogChannel extends Channel { - accept(params: { promptText?: string }): Promise; - dismiss(): Promise; -} -export type DialogInitializer = { - type: string, - message: string, - defaultValue: string, +export type PageKeyboardTypeResult = void; +export type PageKeyboardPressParams = { + key: string, + delay?: number, }; - - -export interface DownloadChannel extends Channel { - path(): Promise<{ value: string | null }>; - failure(): Promise<{ error: string | null }>; - stream(): Promise<{ stream: StreamChannel | null }>; - delete(): Promise; -} -export type DownloadInitializer = { - url: string, - suggestedFilename: string, +export type PageKeyboardPressResult = void; +export type PageMouseMoveParams = { + x: number, + y: number, + steps?: number, }; - - -export interface StreamChannel extends Channel { - read(params: { size?: number }): Promise<{ binary: Binary }>; -} -export type StreamInitializer = { -} - - -// Chromium-specific. -export interface CDPSessionChannel extends Channel { - on(event: 'event', callback: (params: { method: string, params?: Object }) => void): this; - on(event: 'disconnected', callback: () => void): this; - - send(params: { method: string, params?: Object }): Promise<{ result: Object }>; - detach(): Promise; -} -export type CDPSessionInitializer = {}; - -export type PDFOptions = { +export type PageMouseMoveResult = void; +export type PageMouseDownParams = { + button?: 'left' | 'right' | 'middle', + clickCount?: number, +}; +export type PageMouseDownResult = void; +export type PageMouseUpParams = { + button?: 'left' | 'right' | 'middle', + clickCount?: number, +}; +export type PageMouseUpResult = void; +export type PageMouseClickParams = { + x: number, + y: number, + delay?: number, + button?: 'left' | 'right' | 'middle', + clickCount?: number, +}; +export type PageMouseClickResult = void; +export type PageAccessibilitySnapshotParams = { + interestingOnly?: boolean, + root?: ElementHandleChannel, +}; +export type PageAccessibilitySnapshotResult = { + rootAXNode?: AXNode, +}; +export type PagePdfParams = { scale?: number, displayHeaderFooter?: boolean, headerTemplate?: string, @@ -423,34 +757,903 @@ export type PDFOptions = { width?: string, height?: string, preferCSSPageSize?: boolean, - margin?: {top?: string, bottom?: string, left?: string, right?: string}, + margin?: { + top?: string, + bottom?: string, + left?: string, + right?: string, + }, +}; +export type PagePdfResult = { + pdf: Binary, +}; +export type PageCrStartJSCoverageParams = { + resetOnNavigation?: boolean, + reportAnonymousScripts?: boolean, +}; +export type PageCrStartJSCoverageResult = void; +export type PageCrStopJSCoverageParams = {}; +export type PageCrStopJSCoverageResult = { + entries: { + url: string, + scriptId: string, + source?: string, + functions: { + functionName: string, + isBlockCoverage: boolean, + ranges: { + startOffset: number, + endOffset: number, + count: number, + }[], + }[], + }[], +}; +export type PageCrStartCSSCoverageParams = { + resetOnNavigation?: boolean, +}; +export type PageCrStartCSSCoverageResult = void; +export type PageCrStopCSSCoverageParams = {}; +export type PageCrStopCSSCoverageResult = { + entries: { + url: string, + text?: string, + ranges: { + start: number, + end: number, + }[], + }[], }; +// ----------- Frame ----------- +export type FrameInitializer = { + url: string, + name: string, + parentFrame?: FrameChannel, + loadStates: ('load' | 'domcontentloaded' | 'networkidle')[], +}; +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; +} +export type FrameLoadstateEvent = { + add?: 'load' | 'domcontentloaded' | 'networkidle', + remove?: 'load' | 'domcontentloaded' | 'networkidle', +}; +export type FrameNavigatedEvent = { + url: string, + name: string, + newDocument?: { + request?: RequestChannel, + }, + error?: string, +}; +export type FrameEvalOnSelectorParams = { + selector: string, + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type FrameEvalOnSelectorResult = { + value?: SerializedValue, +}; +export type FrameEvalOnSelectorAllParams = { + selector: string, + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type FrameEvalOnSelectorAllResult = { + value?: SerializedValue, +}; +export type FrameAddScriptTagParams = { + url?: string, + content?: string, + type?: string, +}; +export type FrameAddScriptTagResult = { + element: ElementHandleChannel, +}; +export type FrameAddStyleTagParams = { + url?: string, + content?: string, +}; +export type FrameAddStyleTagResult = { + element: ElementHandleChannel, +}; +export type FrameCheckParams = { + selector: string, + force?: boolean, + noWaitAfter?: boolean, + timeout?: number, +}; +export type FrameCheckResult = void; +export type FrameClickParams = { + selector: string, + force?: boolean, + noWaitAfter?: boolean, + modifiers?: ('Alt' | 'Control' | 'Meta' | 'Shift')[], + position?: { + x: number, + y: number, + }, + delay?: number, + button?: 'left' | 'right' | 'middle', + clickCount?: number, + timeout?: number, +}; +export type FrameClickResult = void; +export type FrameContentParams = {}; +export type FrameContentResult = { + value: string, +}; +export type FrameDblclickParams = { + selector: string, + force?: boolean, + modifiers?: ('Alt' | 'Control' | 'Meta' | 'Shift')[], + position?: { + x: number, + y: number, + }, + delay?: number, + button?: 'left' | 'right' | 'middle', + timeout?: number, +}; +export type FrameDblclickResult = void; +export type FrameDispatchEventParams = { + selector: string, + type: string, + eventInit: SerializedArgument, + timeout?: number, +}; +export type FrameDispatchEventResult = void; +export type FrameEvaluateExpressionParams = { + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type FrameEvaluateExpressionResult = { + value?: SerializedValue, +}; +export type FrameEvaluateExpressionHandleParams = { + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type FrameEvaluateExpressionHandleResult = { + handle: JSHandleChannel, +}; +export type FrameFillParams = { + selector: string, + value: string, + timeout?: number, + noWaitAfter?: boolean, +}; +export type FrameFillResult = void; +export type FrameFocusParams = { + selector: string, + timeout?: number, +}; +export type FrameFocusResult = void; +export type FrameFrameElementParams = {}; +export type FrameFrameElementResult = { + element: ElementHandleChannel, +}; +export type FrameGetAttributeParams = { + selector: string, + name: string, + timeout?: number, +}; +export type FrameGetAttributeResult = { + value?: string, +}; +export type FrameGotoParams = { + url: string, + timeout?: number, + waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + referer?: string, +}; +export type FrameGotoResult = { + response?: ResponseChannel, +}; +export type FrameHoverParams = { + selector: string, + force?: boolean, + modifiers?: ('Alt' | 'Control' | 'Meta' | 'Shift')[], + position?: { + x: number, + y: number, + }, + timeout?: number, +}; +export type FrameHoverResult = void; +export type FrameInnerHTMLParams = { + selector: string, + timeout?: number, +}; +export type FrameInnerHTMLResult = { + value: string, +}; +export type FrameInnerTextParams = { + selector: string, + timeout?: number, +}; +export type FrameInnerTextResult = { + value: string, +}; +export type FramePressParams = { + selector: string, + key: string, + delay?: number, + noWaitAfter?: boolean, + timeout?: number, +}; +export type FramePressResult = void; +export type FrameQuerySelectorParams = { + selector: string, +}; +export type FrameQuerySelectorResult = { + element?: ElementHandleChannel, +}; +export type FrameQuerySelectorAllParams = { + selector: string, +}; +export type FrameQuerySelectorAllResult = { + elements: ElementHandleChannel[], +}; +export type FrameSelectOptionParams = { + selector: string, + elements?: ElementHandleChannel[], + options?: { + value?: string, + label?: string, + index?: number, + }[], + timeout?: number, + noWaitAfter?: boolean, +}; +export type FrameSelectOptionResult = { + values: string[], +}; +export type FrameSetContentParams = { + html: string, + timeout?: number, + waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', +}; +export type FrameSetContentResult = void; +export type FrameSetInputFilesParams = { + selector: string, + files: { + name: string, + mimeType: string, + buffer: string, + }[], + timeout?: number, + noWaitAfter?: boolean, +}; +export type FrameSetInputFilesResult = void; +export type FrameTextContentParams = { + selector: string, + timeout?: number, +}; +export type FrameTextContentResult = { + value?: string, +}; +export type FrameTitleParams = {}; +export type FrameTitleResult = { + value: string, +}; +export type FrameTypeParams = { + selector: string, + text: string, + delay?: number, + noWaitAfter?: boolean, + timeout?: number, +}; +export type FrameTypeResult = void; +export type FrameUncheckParams = { + selector: string, + force?: boolean, + noWaitAfter?: boolean, + timeout?: number, +}; +export type FrameUncheckResult = void; +export type FrameWaitForFunctionParams = { + expression: string, + isFunction: boolean, + arg: SerializedArgument, + timeout?: number, + polling?: WaitForFunctionPolling, +}; +export type FrameWaitForFunctionResult = { + handle: JSHandleChannel, +}; +export type FrameWaitForSelectorParams = { + selector: string, + timeout?: number, + state?: 'attached' | 'detached' | 'visible' | 'hidden', +}; +export type FrameWaitForSelectorResult = { + element?: ElementHandleChannel, +}; -export type ElectronLaunchOptions = { +// ----------- Worker ----------- +export type WorkerInitializer = { + url: string, +}; +export interface WorkerChannel extends Channel { + evaluateExpression(params: WorkerEvaluateExpressionParams): Promise; + evaluateExpressionHandle(params: WorkerEvaluateExpressionHandleParams): Promise; +} +export type WorkerEvaluateExpressionParams = { + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type WorkerEvaluateExpressionResult = { + value?: SerializedValue, +}; +export type WorkerEvaluateExpressionHandleParams = { + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type WorkerEvaluateExpressionHandleResult = { + handle: JSHandleChannel, +}; + +// ----------- JSHandle ----------- +export type JSHandleInitializer = { + preview: string, +}; +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; +} +export type JSHandlePreviewUpdatedEvent = { + preview: string, +}; +export type JSHandleDisposeParams = {}; +export type JSHandleDisposeResult = void; +export type JSHandleEvaluateExpressionParams = { + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type JSHandleEvaluateExpressionResult = { + value?: SerializedValue, +}; +export type JSHandleEvaluateExpressionHandleParams = { + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type JSHandleEvaluateExpressionHandleResult = { + handle: JSHandleChannel, +}; +export type JSHandleGetPropertyListParams = {}; +export type JSHandleGetPropertyListResult = { + properties: { + name: string, + value: JSHandleChannel, + }[], +}; +export type JSHandleGetPropertyParams = { + name: string, +}; +export type JSHandleGetPropertyResult = { + handle: JSHandleChannel, +}; +export type JSHandleJsonValueParams = {}; +export type JSHandleJsonValueResult = { + value?: SerializedValue, +}; + +// ----------- 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; +} +export type ElementHandleEvalOnSelectorParams = { + selector: string, + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type ElementHandleEvalOnSelectorResult = { + value?: SerializedValue, +}; +export type ElementHandleEvalOnSelectorAllParams = { + selector: string, + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type ElementHandleEvalOnSelectorAllResult = { + value?: SerializedValue, +}; +export type ElementHandleBoundingBoxParams = {}; +export type ElementHandleBoundingBoxResult = { + value?: { + width: number, + height: number, + x: number, + y: number, + }, +}; +export type ElementHandleCheckParams = { + force?: boolean, + noWaitAfter?: boolean, + timeout?: number, +}; +export type ElementHandleCheckResult = void; +export type ElementHandleClickParams = { + force?: boolean, + noWaitAfter?: boolean, + modifiers?: ('Alt' | 'Control' | 'Meta' | 'Shift')[], + position?: { + x: number, + y: number, + }, + delay?: number, + button?: 'left' | 'right' | 'middle', + clickCount?: number, + timeout?: number, +}; +export type ElementHandleClickResult = void; +export type ElementHandleContentFrameParams = {}; +export type ElementHandleContentFrameResult = { + frame?: FrameChannel, +}; +export type ElementHandleDblclickParams = { + force?: boolean, + noWaitAfter?: boolean, + modifiers?: ('Alt' | 'Control' | 'Meta' | 'Shift')[], + position?: { + x: number, + y: number, + }, + delay?: number, + button?: 'left' | 'right' | 'middle', + timeout?: number, +}; +export type ElementHandleDblclickResult = void; +export type ElementHandleDispatchEventParams = { + type: string, + eventInit: SerializedArgument, +}; +export type ElementHandleDispatchEventResult = void; +export type ElementHandleFillParams = { + value: string, + timeout?: number, + noWaitAfter?: boolean, +}; +export type ElementHandleFillResult = void; +export type ElementHandleFocusParams = {}; +export type ElementHandleFocusResult = void; +export type ElementHandleGetAttributeParams = { + name: string, +}; +export type ElementHandleGetAttributeResult = { + value?: string, +}; +export type ElementHandleHoverParams = { + force?: boolean, + modifiers?: ('Alt' | 'Control' | 'Meta' | 'Shift')[], + position?: { + x: number, + y: number, + }, + timeout?: number, +}; +export type ElementHandleHoverResult = void; +export type ElementHandleInnerHTMLParams = {}; +export type ElementHandleInnerHTMLResult = { + value: string, +}; +export type ElementHandleInnerTextParams = {}; +export type ElementHandleInnerTextResult = { + value: string, +}; +export type ElementHandleOwnerFrameParams = {}; +export type ElementHandleOwnerFrameResult = { + frame?: FrameChannel, +}; +export type ElementHandlePressParams = { + key: string, + delay?: number, + timeout?: number, + noWaitAfter?: boolean, +}; +export type ElementHandlePressResult = void; +export type ElementHandleQuerySelectorParams = { + selector: string, +}; +export type ElementHandleQuerySelectorResult = { + element?: ElementHandleChannel, +}; +export type ElementHandleQuerySelectorAllParams = { + selector: string, +}; +export type ElementHandleQuerySelectorAllResult = { + elements: ElementHandleChannel[], +}; +export type ElementHandleScreenshotParams = { + timeout?: number, + type?: 'png' | 'jpeg', + path?: string, + quality?: number, + omitBackground?: boolean, +}; +export type ElementHandleScreenshotResult = { + binary: Binary, +}; +export type ElementHandleScrollIntoViewIfNeededParams = { + timeout?: number, +}; +export type ElementHandleScrollIntoViewIfNeededResult = void; +export type ElementHandleSelectOptionParams = { + elements?: ElementHandleChannel[], + options?: { + value?: string, + label?: string, + index?: number, + }[], + timeout?: number, + noWaitAfter?: boolean, +}; +export type ElementHandleSelectOptionResult = { + values: string[], +}; +export type ElementHandleSelectTextParams = { + timeout?: number, +}; +export type ElementHandleSelectTextResult = void; +export type ElementHandleSetInputFilesParams = { + files: { + name: string, + mimeType: string, + buffer: string, + }[], + timeout?: number, + noWaitAfter?: boolean, +}; +export type ElementHandleSetInputFilesResult = void; +export type ElementHandleTextContentParams = {}; +export type ElementHandleTextContentResult = { + value?: string, +}; +export type ElementHandleTypeParams = { + text: string, + delay?: number, + noWaitAfter?: boolean, + timeout?: number, +}; +export type ElementHandleTypeResult = void; +export type ElementHandleUncheckParams = { + force?: boolean, + noWaitAfter?: boolean, + timeout?: number, +}; +export type ElementHandleUncheckResult = void; + +// ----------- Request ----------- +export type RequestInitializer = { + frame: FrameChannel, + url: string, + resourceType: string, + method: string, + postData?: string, + headers: { + name: string, + value: string, + }[], + isNavigationRequest: boolean, + redirectedFrom?: RequestChannel, +}; +export interface RequestChannel extends Channel { + response(params?: RequestResponseParams): Promise; +} +export type RequestResponseParams = {}; +export type RequestResponseResult = { + response?: ResponseChannel, +}; + +// ----------- Route ----------- +export type RouteInitializer = { + request: RequestChannel, +}; +export interface RouteChannel extends Channel { + abort(params: RouteAbortParams): Promise; + continue(params: RouteContinueParams): Promise; + fulfill(params: RouteFulfillParams): Promise; +} +export type RouteAbortParams = { + errorCode: string, +}; +export type RouteAbortResult = void; +export type RouteContinueParams = { + method?: string, + headers?: { + name: string, + value: string, + }[], + postData?: string, +}; +export type RouteContinueResult = void; +export type RouteFulfillParams = { + status: number, + headers: { + name: string, + value: string, + }[], + body: string, + isBase64: boolean, +}; +export type RouteFulfillResult = void; + +// ----------- Response ----------- +export type ResponseInitializer = { + request: RequestChannel, + url: string, + status: number, + statusText: string, + headers: { + name: string, + value: string, + }[], +}; +export interface ResponseChannel extends Channel { + body(params?: ResponseBodyParams): Promise; + finished(params?: ResponseFinishedParams): Promise; +} +export type ResponseBodyParams = {}; +export type ResponseBodyResult = { + binary: Binary, +}; +export type ResponseFinishedParams = {}; +export type ResponseFinishedResult = { + error?: SerializedError, +}; + +// ----------- ConsoleMessage ----------- +export type ConsoleMessageInitializer = { + type: string, + text: string, + args: JSHandleChannel[], + location: { + url?: string, + lineNumber?: number, + columnNumber?: number, + }, +}; +export interface ConsoleMessageChannel extends Channel { +} + +// ----------- BindingCall ----------- +export type BindingCallInitializer = { + frame: FrameChannel, + name: string, + args: SerializedValue[], +}; +export interface BindingCallChannel extends Channel { + reject(params: BindingCallRejectParams): Promise; + resolve(params: BindingCallResolveParams): Promise; +} +export type BindingCallRejectParams = { + error: SerializedError, +}; +export type BindingCallRejectResult = void; +export type BindingCallResolveParams = { + result: SerializedArgument, +}; +export type BindingCallResolveResult = void; + +// ----------- Dialog ----------- +export type DialogInitializer = { + type: string, + message: string, + defaultValue: string, +}; +export interface DialogChannel extends Channel { + accept(params: DialogAcceptParams): Promise; + dismiss(params?: DialogDismissParams): Promise; +} +export type DialogAcceptParams = { + promptText?: string, +}; +export type DialogAcceptResult = void; +export type DialogDismissParams = {}; +export type DialogDismissResult = void; + +// ----------- Download ----------- +export type DownloadInitializer = { + url: string, + suggestedFilename: string, +}; +export interface DownloadChannel extends Channel { + path(params?: DownloadPathParams): Promise; + failure(params?: DownloadFailureParams): Promise; + stream(params?: DownloadStreamParams): Promise; + delete(params?: DownloadDeleteParams): Promise; +} +export type DownloadPathParams = {}; +export type DownloadPathResult = { + value?: string, +}; +export type DownloadFailureParams = {}; +export type DownloadFailureResult = { + error?: string, +}; +export type DownloadStreamParams = {}; +export type DownloadStreamResult = { + stream?: StreamChannel, +}; +export type DownloadDeleteParams = {}; +export type DownloadDeleteResult = void; + +// ----------- Stream ----------- +export type StreamInitializer = {}; +export interface StreamChannel extends Channel { + read(params: StreamReadParams): Promise; +} +export type StreamReadParams = { + size?: number, +}; +export type StreamReadResult = { + binary: Binary, +}; + +// ----------- CDPSession ----------- +export type CDPSessionInitializer = {}; +export interface CDPSessionChannel extends Channel { + on(event: 'event', callback: (params: CDPSessionEventEvent) => void): this; + on(event: 'disconnected', callback: (params: CDPSessionDisconnectedEvent) => void): this; + send(params: CDPSessionSendParams): Promise; + detach(params?: CDPSessionDetachParams): Promise; +} +export type CDPSessionEventEvent = { + method: string, + params?: { + + }, +}; +export type CDPSessionDisconnectedEvent = {}; +export type CDPSessionSendParams = { + method: string, + params?: { + + }, +}; +export type CDPSessionSendResult = { + result: { + + }, +}; +export type CDPSessionDetachParams = {}; +export type CDPSessionDetachResult = void; + +// ----------- Electron ----------- +export type ElectronInitializer = {}; +export interface ElectronChannel extends Channel { + launch(params: ElectronLaunchParams): Promise; +} +export type ElectronLaunchParams = { + executablePath: string, args?: string[], cwd?: string, - env?: {[key: string]: string|number|boolean}, + env?: { + name: string, + value: string, + }[], handleSIGINT?: boolean, handleSIGTERM?: boolean, handleSIGHUP?: boolean, timeout?: number, }; -export interface ElectronChannel extends Channel { - launch(params: { executablePath: string } & ElectronLaunchOptions): Promise<{ electronApplication: ElectronApplicationChannel }>; -} -export type ElectronInitializer = {}; +export type ElectronLaunchResult = { + electronApplication: ElectronApplicationChannel, +}; - -export interface ElectronApplicationChannel extends Channel { - on(event: 'close', callback: () => void): this; - on(event: 'window', callback: (params: { page: PageChannel, browserWindow: JSHandleChannel }) => void): this; - - newBrowserWindow(params: { arg: SerializedArgument }): Promise<{ page: PageChannel }>; - evaluateExpression(params: { expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ value: SerializedValue }>; - evaluateExpressionHandle(params: { expression: string, isFunction: boolean, arg: SerializedArgument }): Promise<{ handle: JSHandleChannel }>; - close(): Promise; -} +// ----------- ElectronApplication ----------- export type ElectronApplicationInitializer = { context: BrowserContextChannel, }; +export interface ElectronApplicationChannel extends Channel { + 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; +} +export type ElectronApplicationCloseEvent = {}; +export type ElectronApplicationWindowEvent = { + page: PageChannel, + browserWindow: JSHandleChannel, +}; +export type ElectronApplicationNewBrowserWindowParams = { + arg: SerializedArgument, +}; +export type ElectronApplicationNewBrowserWindowResult = { + page: PageChannel, +}; +export type ElectronApplicationEvaluateExpressionParams = { + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type ElectronApplicationEvaluateExpressionResult = { + value?: SerializedValue, +}; +export type ElectronApplicationEvaluateExpressionHandleParams = { + expression: string, + isFunction: boolean, + arg: SerializedArgument, +}; +export type ElectronApplicationEvaluateExpressionHandleResult = { + handle: JSHandleChannel, +}; +export type ElectronApplicationCloseParams = {}; +export type ElectronApplicationCloseResult = void; diff --git a/src/rpc/client/accessibility.ts b/src/rpc/client/accessibility.ts index b95c51b900..ad69d46aec 100644 --- a/src/rpc/client/accessibility.ts +++ b/src/rpc/client/accessibility.ts @@ -29,6 +29,6 @@ export class Accessibility { async snapshot(options: { interestingOnly?: boolean; root?: ElementHandle } = {}): Promise { const root = options.root ? options.root._elementChannel : undefined; const result = await this._channel.accessibilitySnapshot({ interestingOnly: options.interestingOnly, root }); - return result.rootAXNode; + return result.rootAXNode || null; } } diff --git a/src/rpc/client/browser.ts b/src/rpc/client/browser.ts index 6b93b6bb4f..6f6decf484 100644 --- a/src/rpc/client/browser.ts +++ b/src/rpc/client/browser.ts @@ -15,7 +15,7 @@ */ import * as types from '../../types'; -import { BrowserChannel, BrowserInitializer, BrowserContextOptions } from '../channels'; +import { BrowserChannel, BrowserInitializer, BrowserNewContextParams } from '../channels'; import { BrowserContext } from './browserContext'; import { Page } from './page'; import { ChannelOwner } from './channelOwner'; @@ -55,7 +55,7 @@ export class Browser extends ChannelOwner { const logger = options.logger; options = { ...options, logger: undefined }; return this._wrapApiCall('browser.newContext', async () => { - const contextOptions: BrowserContextOptions = { + const contextOptions: BrowserNewContextParams = { ...options, extraHTTPHeaders: options.extraHTTPHeaders ? headersObjectToArray(options.extraHTTPHeaders) : undefined, }; diff --git a/src/rpc/client/browserContext.ts b/src/rpc/client/browserContext.ts index d8e6e087fa..e433bfb59c 100644 --- a/src/rpc/client/browserContext.ts +++ b/src/rpc/client/browserContext.ts @@ -141,7 +141,7 @@ export class BrowserContext extends ChannelOwner { return this._wrapApiCall('browserContext.setGeolocation', async () => { - await this._channel.setGeolocation({ geolocation }); + await this._channel.setGeolocation({ geolocation: geolocation || undefined }); }); } @@ -159,7 +159,7 @@ export class BrowserContext extends ChannelOwner { return this._wrapApiCall('browserContext.setHTTPCredentials', async () => { - await this._channel.setHTTPCredentials({ httpCredentials }); + await this._channel.setHTTPCredentials({ httpCredentials: httpCredentials || undefined }); }); } diff --git a/src/rpc/client/browserType.ts b/src/rpc/client/browserType.ts index d43a36a976..caa3198980 100644 --- a/src/rpc/client/browserType.ts +++ b/src/rpc/client/browserType.ts @@ -15,7 +15,7 @@ */ import * as types from '../../types'; -import { BrowserTypeChannel, BrowserTypeInitializer, LaunchPersistentContextOptions, LaunchOptions, LaunchServerOptions } from '../channels'; +import { BrowserTypeChannel, BrowserTypeInitializer, BrowserTypeLaunchParams, BrowserTypeLaunchServerParams, BrowserTypeLaunchPersistentContextParams } from '../channels'; import { Browser } from './browser'; import { BrowserContext } from './browserContext'; import { ChannelOwner } from './channelOwner'; @@ -45,7 +45,7 @@ export class BrowserType extends ChannelOwner { - const launchOptions: LaunchOptions = { + const launchOptions: BrowserTypeLaunchParams = { ...options, ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined, ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs), @@ -61,7 +61,7 @@ export class BrowserType extends ChannelOwner { - const launchServerOptions: LaunchServerOptions = { + const launchServerOptions: BrowserTypeLaunchServerParams = { ...options, ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined, ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs), @@ -75,7 +75,7 @@ export class BrowserType extends ChannelOwner { - const persistentOptions: LaunchPersistentContextOptions = { + const persistentOptions: BrowserTypeLaunchPersistentContextParams = { ...options, ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined, ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs), diff --git a/src/rpc/client/download.ts b/src/rpc/client/download.ts index 7e567b0f0c..648954d1a3 100644 --- a/src/rpc/client/download.ts +++ b/src/rpc/client/download.ts @@ -37,11 +37,11 @@ export class Download extends ChannelOwner } async path(): Promise { - return (await this._channel.path()).value; + return (await this._channel.path()).value || null; } async failure(): Promise { - return (await this._channel.failure()).error; + return (await this._channel.failure()).error || null; } async createReadStream(): Promise { diff --git a/src/rpc/client/electron.ts b/src/rpc/client/electron.ts index 541e84b316..5216a83c58 100644 --- a/src/rpc/client/electron.ts +++ b/src/rpc/client/electron.ts @@ -15,17 +15,18 @@ */ import * as types from '../../types'; -import { ElectronChannel, ElectronInitializer, ElectronLaunchOptions, ElectronApplicationChannel, ElectronApplicationInitializer } from '../channels'; +import { ElectronChannel, ElectronInitializer, ElectronApplicationChannel, ElectronApplicationInitializer, ElectronLaunchParams } from '../channels'; import { BrowserContext } from './browserContext'; import { ChannelOwner } from './channelOwner'; import { Page } from './page'; import { serializeArgument, FuncOn, parseResult, SmartHandle, JSHandle } from './jsHandle'; -import { ElectronEvents } from '../../server/electron'; +import { ElectronEvents, ElectronLaunchOptionsBase } from '../../server/electron'; import { TimeoutSettings } from '../../timeoutSettings'; import { Waiter } from './waiter'; import { TimeoutError } from '../../errors'; import { Events } from '../../events'; import { LoggerSink } from '../../loggerSink'; +import { envObjectToArray } from '../serializers'; export class Electron extends ChannelOwner { static from(electron: ElectronChannel): Electron { @@ -36,11 +37,16 @@ export class Electron extends ChannelOwner super(parent, type, guid, initializer, true); } - async launch(executablePath: string, options: ElectronLaunchOptions & { logger?: LoggerSink } = {}): Promise { + async launch(executablePath: string, options: ElectronLaunchOptionsBase & { logger?: LoggerSink } = {}): Promise { const logger = options.logger; options = { ...options, logger: undefined }; return this._wrapApiCall('electron.launch', async () => { - return ElectronApplication.from((await this._channel.launch({ executablePath, ...options })).electronApplication); + const params: ElectronLaunchParams = { + ...options, + env: options.env ? envObjectToArray(options.env) : undefined, + executablePath, + }; + return ElectronApplication.from((await this._channel.launch(params)).electronApplication); }, logger); } } diff --git a/src/rpc/client/elementHandle.ts b/src/rpc/client/elementHandle.ts index 0f2cb5ce54..9b6c5755fc 100644 --- a/src/rpc/client/elementHandle.ts +++ b/src/rpc/client/elementHandle.ts @@ -29,7 +29,7 @@ export class ElementHandle extends JSHandle { return (handle as any)._object; } - static fromNullable(handle: ElementHandleChannel | null): ElementHandle | null { + static fromNullable(handle: ElementHandleChannel | undefined): ElementHandle | null { return handle ? ElementHandle.from(handle) : null; } @@ -56,13 +56,15 @@ export class ElementHandle extends JSHandle { async getAttribute(name: string): Promise { return this._wrapApiCall('elementHandle.getAttribute', async () => { - return (await this._elementChannel.getAttribute({ name })).value; + const value = (await this._elementChannel.getAttribute({ name })).value; + return value === undefined ? null : value; }); } async textContent(): Promise { return this._wrapApiCall('elementHandle.textContent', async () => { - return (await this._elementChannel.textContent()).value; + const value = (await this._elementChannel.textContent()).value; + return value === undefined ? null : value; }); } @@ -165,7 +167,8 @@ export class ElementHandle extends JSHandle { async boundingBox(): Promise { return this._wrapApiCall('elementHandle.boundingBox', async () => { - return (await this._elementChannel.boundingBox()).value; + const value = (await this._elementChannel.boundingBox()).value; + return value === undefined ? null : value; }); } diff --git a/src/rpc/client/frame.ts b/src/rpc/client/frame.ts index 5c29ee1a33..ea1792b56f 100644 --- a/src/rpc/client/frame.ts +++ b/src/rpc/client/frame.ts @@ -53,7 +53,7 @@ export class Frame extends ChannelOwner { return (frame as any)._object; } - static fromNullable(frame: FrameChannel | null): Frame | null { + static fromNullable(frame: FrameChannel | undefined): Frame | null { return frame ? Frame.from(frame) : null; } @@ -132,7 +132,7 @@ export class Frame extends ChannelOwner { }); } - const request = navigatedEvent.newDocument ? network.Request.fromNullable(navigatedEvent.newDocument.request || null) : null; + const request = navigatedEvent.newDocument ? network.Request.fromNullable(navigatedEvent.newDocument.request) : null; const response = request ? await waiter.waitForPromise(request._finalRequest().response()) : null; waiter.dispose(); return response; @@ -306,7 +306,8 @@ export class Frame extends ChannelOwner { async textContent(selector: string, options: types.TimeoutOptions = {}): Promise { return this._wrapApiCall(this._apiName('textContent'), async () => { - return (await this._channel.textContent({ selector, ...options })).value; + const value = (await this._channel.textContent({ selector, ...options })).value; + return value === undefined ? null : value; }); } @@ -324,7 +325,8 @@ export class Frame extends ChannelOwner { async getAttribute(selector: string, name: string, options: types.TimeoutOptions = {}): Promise { return this._wrapApiCall(this._apiName('getAttribute'), async () => { - return (await this._channel.getAttribute({ selector, name, ...options })).value; + const value = (await this._channel.getAttribute({ selector, name, ...options })).value; + return value === undefined ? null : value; }); } diff --git a/src/rpc/client/jsHandle.ts b/src/rpc/client/jsHandle.ts index ec1a133eaa..312c2079f9 100644 --- a/src/rpc/client/jsHandle.ts +++ b/src/rpc/client/jsHandle.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { JSHandleChannel, JSHandleInitializer, SerializedArgument, Channel } from '../channels'; +import { JSHandleChannel, JSHandleInitializer, SerializedArgument, SerializedValue, Channel } from '../channels'; import { ElementHandle } from './elementHandle'; import { ChannelOwner } from './channelOwner'; -import { serializeAsCallArgument, parseEvaluationResultValue, SerializedValue } from '../../common/utilityScriptSerializers'; +import { serializeAsCallArgument, parseEvaluationResultValue } from '../../common/utilityScriptSerializers'; type NoHandles = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles } : Arg); type Unboxed = @@ -42,10 +42,6 @@ export class JSHandle extends ChannelOwner { return (request as any)._object; } - static fromNullable(request: RequestChannel | null): Request | null { + static fromNullable(request: RequestChannel | undefined): Request | null { return request ? Request.from(request) : null; } @@ -79,7 +79,7 @@ export class Request extends ChannelOwner { } postData(): string | null { - return this._initializer.postData; + return this._initializer.postData || null; } postDataJSON(): Object | null { @@ -174,7 +174,7 @@ export class Response extends ChannelOwner return (response as any)._object; } - static fromNullable(response: ResponseChannel | null): Response | null { + static fromNullable(response: ResponseChannel | undefined): Response | null { return response ? Response.from(response) : null; } @@ -204,7 +204,10 @@ export class Response extends ChannelOwner } async finished(): Promise { - return (await this._channel.finished()).error; + const result = await this._channel.finished(); + if (result.error) + return parseError(result.error); + return null; } async body(): Promise { diff --git a/src/rpc/client/page.ts b/src/rpc/client/page.ts index 16c223d971..4ac3ac35e1 100644 --- a/src/rpc/client/page.ts +++ b/src/rpc/client/page.ts @@ -20,8 +20,8 @@ import { Events } from '../../events'; import { assert, assertMaxArguments, helper, Listener } from '../../helper'; import { TimeoutSettings } from '../../timeoutSettings'; import * as types from '../../types'; -import { BindingCallChannel, BindingCallInitializer, PageChannel, PageInitializer, PDFOptions } from '../channels'; -import { parseError, serializeError, headersObjectToArray } from '../serializers'; +import { BindingCallChannel, BindingCallInitializer, PageChannel, PageInitializer, PagePdfParams } from '../channels'; +import { parseError, headersObjectToArray, serializeError } from '../serializers'; import { Accessibility } from './accessibility'; import { BrowserContext } from './browserContext'; import { ChannelOwner } from './channelOwner'; @@ -69,7 +69,7 @@ export class Page extends ChannelOwner { return (page as any)._object; } - static fromNullable(page: PageChannel | null): Page | null { + static fromNullable(page: PageChannel | undefined): Page | null { return page ? Page.from(page) : null; } @@ -86,7 +86,7 @@ export class Page extends ChannelOwner { this._mainFrame = Frame.from(initializer.mainFrame); this._mainFrame._page = this; this._frames.add(this._mainFrame); - this._viewportSize = initializer.viewportSize; + this._viewportSize = initializer.viewportSize || null; this._closed = initializer.isClosed; this._channel.on('bindingCall', ({ binding }) => this._onBinding(BindingCall.from(binding))); @@ -115,8 +115,8 @@ export class Page extends ChannelOwner { } } - private _onRequestFailed(request: Request, failureText: string | null) { - request._failureText = failureText; + private _onRequestFailed(request: Request, failureText: string | undefined) { + request._failureText = failureText || null; this.emit(Events.Page.RequestFailed, request); } @@ -518,7 +518,7 @@ export class Page extends ChannelOwner { async _pdf(options: types.PDFOptions = {}): Promise { const path = options.path; - const transportOptions: PDFOptions = { ...options } as PDFOptions; + const transportOptions: PagePdfParams = { ...options } as PagePdfParams; if (path) delete (transportOptions as any).path; if (transportOptions.margin) diff --git a/src/rpc/protocol.pdl b/src/rpc/protocol.pdl new file mode 100644 index 0000000000..13b95a107a --- /dev/null +++ b/src/rpc/protocol.pdl @@ -0,0 +1,1483 @@ +# Copyright (c) Microsoft Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +union SerializedValue + undefined + boolean + number + string + ComplexSerializedValue + +type ComplexSerializedValue + v?: enum + null + undefined + NaN + Infinity + -Infinity + -0 + d?: string + r?: object + p: string + f: string + a?: SerializedValue[] + o?: object[] + k: string + v: SerializedValue + h?: number + +type SerializedArgument + value: SerializedValue + handles: Channel[] + +union AXNodeValue + string + number + +union AXNodeChecked + boolean + enum + mixed + +union AXNodePressed + boolean + enum + mixed + +type AXNode + role: string + name: string + value?: AXNodeValue + description?: string + keyshortcuts?: string + roledescription?: string + valuetext?: string + disabled?: boolean + expanded?: boolean + focused?: boolean + modal?: boolean + multiline?: boolean + multiselectable?: boolean + readonly?: boolean + required?: boolean + selected?: boolean + checked?: AXNodeChecked + pressed?: AXNodePressed + level?: number + valuemin?: number + valuemax?: number + autocomplete?: string + haspopup?: string + invalid?: string + orientation?: string + children?: AXNode[] + +union WaitForFunctionPolling + number + enum + raf + +type Viewport + width: number + height: number + +union ViewportOrNull + null + Viewport + +type SerializedError + error?: object + message: string + name: string + stack?: string + value?: SerializedValue + +interface Playwright + initializer + chromium: BrowserType + firefox: BrowserType + webkit: BrowserType + electron?: Electron + deviceDescriptors: object[] + name: string + descriptor: object + userAgent: string + viewport: object + width: number + height: number + deviceScaleFactor: number + isMobile: boolean + hasTouch: boolean + selectors: Selectors + +interface Selectors + command register + parameters + name: string + source: string + options: object + contentScript?: boolean + + command createSelector + parameters + name: string + handle: ElementHandle + returns + value?: string + +interface BrowserType + initializer + executablePath: string + name: string + + command connect + parameters + wsEndpoint: string + slowMo?: number + timeout?: number + returns + browser: Browser + + command launch + parameters + executablePath?: string + args?: string[] + ignoreAllDefaultArgs?: boolean + ignoreDefaultArgs?: string[] + handleSIGINT?: boolean + handleSIGTERM?: boolean + handleSIGHUP?: boolean + timeout?: number + env?: object[] + name: string + value: string + headless?: boolean + devtools?: boolean + proxy?: object + server: string + bypass?: string + username?: string + password?: string + downloadsPath?: string + slowMo?: number + returns + browser: Browser + + command launchServer + parameters + executablePath?: string + args?: string[] + ignoreAllDefaultArgs?: boolean + ignoreDefaultArgs?: string[] + handleSIGINT?: boolean + handleSIGTERM?: boolean + handleSIGHUP?: boolean + timeout?: number + env?: object[] + name: string + value: string + headless?: boolean + devtools?: boolean + proxy?: object + server: string + bypass?: string + username?: string + password?: string + downloadsPath?: string + port?: number + returns + server: BrowserServer + + command launchPersistentContext + parameters + userDataDir: string + executablePath?: string + args?: string[] + ignoreAllDefaultArgs?: boolean + ignoreDefaultArgs?: string[] + handleSIGINT?: boolean + handleSIGTERM?: boolean + handleSIGHUP?: boolean + timeout?: number + env?: object[] + name: string + value: string + headless?: boolean + devtools?: boolean + proxy?: object + server: string + bypass?: string + username?: string + password?: string + downloadsPath?: string + slowMo?: number + viewport?: ViewportOrNull + ignoreHTTPSErrors?: boolean + javaScriptEnabled?: boolean + bypassCSP?: boolean + userAgent?: string + locale?: string + timezoneId?: string + geolocation?: object + longitude: number + latitude: number + accuracy?: number + permissions?: string[] + extraHTTPHeaders?: object[] + name: string + value: string + offline?: boolean + httpCredentials?: object + username: string + password: string + deviceScaleFactor?: number + isMobile?: boolean + hasTouch?: boolean + colorScheme?: enum + dark + light + no-preference + acceptDownloads?: boolean + returns + context: BrowserContext + +interface BrowserServer + initializer + wsEndpoint: string + pid: number + + event close + + command close + + command kill + +interface Browser + event close + + command close + + command newContext + parameters + viewport?: ViewportOrNull + ignoreHTTPSErrors?: boolean + javaScriptEnabled?: boolean + bypassCSP?: boolean + userAgent?: string + locale?: string + timezoneId?: string + geolocation?: object + longitude: number + latitude: number + accuracy?: number + permissions?: string[] + extraHTTPHeaders?: object[] + name: string + value: string + offline?: boolean + httpCredentials?: object + username: string + password: string + deviceScaleFactor?: number + isMobile?: boolean + hasTouch?: boolean + colorScheme?: enum + dark + light + no-preference + acceptDownloads?: boolean + returns + context: BrowserContext + + command crNewBrowserCDPSession + returns + session: CDPSession + + command crStartTracing + parameters + page?: Page + path?: string + screenshots?: boolean + categories?: string[] + + command crStopTracing + returns + binary: binary + +interface BrowserContext + event bindingCall + parameters + binding: BindingCall + + event close + + event page + parameters + page: Page + + event route + parameters + route: Route + request: Request + + command addCookies + parameters + cookies: object[] + name: string + value: string + url?: string + domain?: string + path?: string + expires?: number + httpOnly?: boolean + secure?: boolean + sameSite?: enum + Strict + Lax + None + + command addInitScript + parameters + source: string + + command clearCookies + + command clearPermissions + + command close + + command cookies + parameters + urls: string[] + returns + cookies: object[] + name: string + value: string + domain: string + path: string + expires: number + httpOnly: boolean + secure: boolean + sameSite: enum + Strict + Lax + None + + command exposeBinding + parameters + name: string + + command grantPermissions + parameters + permissions: string[] + origin?: string + + command newPage + returns + page: Page + + command setDefaultNavigationTimeoutNoReply + parameters + timeout: number + + command setDefaultTimeoutNoReply + parameters + timeout: number + + command setExtraHTTPHeaders + parameters + headers: object[] + name: string + value: string + + command setGeolocation + parameters + geolocation?: object + longitude: number + latitude: number + accuracy?: number + + command setHTTPCredentials + parameters + httpCredentials?: object + username: string + password: string + + command setNetworkInterceptionEnabled + parameters + enabled: boolean + + command setOffline + parameters + offline: boolean + + event crBackgroundPage + parameters + page: Page + + event crServiceWorker + parameters + worker: Worker + + command crNewCDPSession + parameters + page: Page + returns + session: CDPSession + +interface Page + initializer + mainFrame: Frame + viewportSize?: object + width: number + height: number + isClosed: boolean + + event bindingCall + parameters + binding: BindingCall + + event close + + event console + parameters + message: ConsoleMessage + + event crash + + event dialog + parameters + dialog: Dialog + + event download + parameters + download: Download + + event domcontentloaded + + event fileChooser + parameters + element: ElementHandle + isMultiple: boolean + + event frameAttached + parameters + frame: Frame + + event frameDetached + parameters + frame: Frame + + event load + + event pageError + parameters + error: SerializedError + + event popup + parameters + page: Page + + event request + parameters + request: Request + + event requestFailed + parameters + request: Request + failureText?: string + + event requestFinished + parameters + request: Request + + event response + parameters + response: Response + + event route + parameters + route: Route + request: Request + + event worker + parameters + worker: Worker + + command setDefaultNavigationTimeoutNoReply + parameters + timeout: number + + command setDefaultTimeoutNoReply + parameters + timeout: number + + command setFileChooserInterceptedNoReply + parameters + intercepted: boolean + + command addInitScript + parameters + source: string + + command close + parameters + runBeforeUnload?: boolean + + command emulateMedia + parameters + media?: enum + screen + print + colorScheme?: enum + dark + light + no-preference + + command exposeBinding + parameters + name: string + + command goBack + parameters + timeout?: number + waitUntil?: enum + load + domcontentloaded + networkidle + returns + response?: Response + + command goForward + parameters + timeout?: number + waitUntil?: enum + load + domcontentloaded + networkidle + returns + response?: Response + + command opener + returns + page?: Page + + command reload + parameters + timeout?: number + waitUntil?: enum + load + domcontentloaded + networkidle + returns + response?: Response + + command screenshot + parameters + timeout?: number + type?: enum + png + jpeg + path?: string + quality?: number + omitBackground?: boolean + fullPage?: boolean + clip?: object + width: number + height: number + x: number + y: number + returns + binary: binary + + command setExtraHTTPHeaders + parameters + headers: object[] + name: string + value: string + + command setNetworkInterceptionEnabled + parameters + enabled: boolean + + command setViewportSize + parameters + viewportSize: object + width: number + height: number + + command keyboardDown + parameters + key: string + + command keyboardUp + parameters + key: string + + command keyboardInsertText + parameters + text: string + + command keyboardType + parameters + text: string + delay?: number + + command keyboardPress + parameters + key: string + delay?: number + + command mouseMove + parameters + x: number + y: number + steps?: number + + command mouseDown + parameters + button?: enum + left + right + middle + clickCount?: number + + command mouseUp + parameters + button?: enum + left + right + middle + clickCount?: number + + command mouseClick + parameters + x: number + y: number + delay?: number + button?: enum + left + right + middle + clickCount?: number + + command accessibilitySnapshot + parameters + interestingOnly?: boolean + root?: ElementHandle + returns + rootAXNode?: AXNode + + command pdf + parameters + scale?: number + displayHeaderFooter?: boolean + headerTemplate?: string + footerTemplate?: string + printBackground?: boolean + landscape?: boolean + pageRanges?: string + format?: string + width?: string + height?: string + preferCSSPageSize?: boolean + margin?: object + top?: string + bottom?: string + left?: string + right?: string + returns + pdf: binary + + command crStartJSCoverage + parameters + resetOnNavigation?: boolean + reportAnonymousScripts?: boolean + + command crStopJSCoverage + returns + entries: object[] + url: string + scriptId: string + source?: string + functions: object[] + functionName: string + isBlockCoverage: boolean + ranges: object[] + startOffset: number + endOffset: number + count: number + + command crStartCSSCoverage + parameters + resetOnNavigation?: boolean + + command crStopCSSCoverage + returns + entries: object[] + url: string + text?: string + ranges: object[] + start: number + end: number + +interface Frame + initializer + url: string + name: string + parentFrame?: Frame + loadStates: enum[] + load + domcontentloaded + networkidle + + event loadstate + parameters + add?: enum + load + domcontentloaded + networkidle + remove?: enum + load + domcontentloaded + networkidle + + event navigated + parameters + url: string + name: string + newDocument?: object + request?: Request + error?: string + + command evalOnSelector + parameters + selector: string + expression: string + isFunction: boolean + arg: SerializedArgument + returns + value?: SerializedValue + + command evalOnSelectorAll + parameters + selector: string + expression: string + isFunction: boolean + arg: SerializedArgument + returns + value?: SerializedValue + + command addScriptTag + parameters + url?: string + content?: string + type?: string + returns + element: ElementHandle + + command addStyleTag + parameters + url?: string + content?: string + returns + element: ElementHandle + + command check + parameters + selector: string + force?: boolean + noWaitAfter?: boolean + timeout?: number + + command click + parameters + selector: string + force?: boolean + noWaitAfter?: boolean + modifiers?: enum[] + Alt + Control + Meta + Shift + position?: object + x: number + y: number + delay?: number + button?: enum + left + right + middle + clickCount?: number + timeout?: number + + command content + returns + value: string + + command dblclick + parameters + selector: string + force?: boolean + modifiers?: enum[] + Alt + Control + Meta + Shift + position?: object + x: number + y: number + delay?: number + button?: enum + left + right + middle + timeout?: number + + command dispatchEvent + parameters + selector: string + type: string + eventInit: SerializedArgument + timeout?: number + + command evaluateExpression + parameters + expression: string + isFunction: boolean + arg: SerializedArgument + returns + value?: SerializedValue + + command evaluateExpressionHandle + parameters + expression: string + isFunction: boolean + arg: SerializedArgument + returns + handle: JSHandle + + command fill + parameters + selector: string + value: string + timeout?: number + noWaitAfter?: boolean + + command focus + parameters + selector: string + timeout?: number + + command frameElement + returns + element: ElementHandle + + command getAttribute + parameters + selector: string + name: string + timeout?: number + returns + value?: string + + command goto + parameters + url: string + timeout?: number + waitUntil?: enum + load + domcontentloaded + networkidle + referer?: string + returns + response?: Response + + command hover + parameters + selector: string + force?: boolean + modifiers?: enum[] + Alt + Control + Meta + Shift + position?: object + x: number + y: number + timeout?: number + + command innerHTML + parameters + selector: string + timeout?: number + returns + value: string + + command innerText + parameters + selector: string + timeout?: number + returns + value: string + + command press + parameters + selector: string + key: string + delay?: number + noWaitAfter?: boolean + timeout?: number + + command querySelector + parameters + selector: string + returns + element?: ElementHandle + + command querySelectorAll + parameters + selector: string + returns + elements: ElementHandle[] + + command selectOption + parameters + selector: string + elements?: ElementHandle[] + options?: object[] + value?: string + label?: string + index?: number + timeout?: number + noWaitAfter?: boolean + returns + values: string[] + + command setContent + parameters + html: string + timeout?: number + waitUntil?: enum + load + domcontentloaded + networkidle + + command setInputFiles + parameters + selector: string + files: object[] + name: string + mimeType: string + buffer: string + timeout?: number + noWaitAfter?: boolean + + command textContent + parameters + selector: string + timeout?: number + returns + value?: string + + command title + returns + value: string + + command type + parameters + selector: string + text: string + delay?: number + noWaitAfter?: boolean + timeout?: number + + command uncheck + parameters + selector: string + force?: boolean + noWaitAfter?: boolean + timeout?: number + + command waitForFunction + parameters + expression: string + isFunction: boolean + arg: SerializedArgument + timeout?: number + polling?: WaitForFunctionPolling + returns + handle: JSHandle + + command waitForSelector + parameters + selector: string + timeout?: number + state?: enum + attached + detached + visible + hidden + returns + element?: ElementHandle + +interface Worker + initializer + url: string + + command evaluateExpression + parameters + expression: string + isFunction: boolean + arg: SerializedArgument + returns + value?: SerializedValue + + command evaluateExpressionHandle + parameters + expression: string + isFunction: boolean + arg: SerializedArgument + returns + handle: JSHandle + +interface JSHandle + initializer + preview: string + + event previewUpdated + parameters + preview: string + + command dispose + + command evaluateExpression + parameters + expression: string + isFunction: boolean + arg: SerializedArgument + returns + value?: SerializedValue + + command evaluateExpressionHandle + parameters + expression: string + isFunction: boolean + arg: SerializedArgument + returns + handle: JSHandle + + command getPropertyList + returns + properties: object[] + name: string + value: JSHandle + + command getProperty + parameters + name: string + returns + handle: JSHandle + + command jsonValue + returns + value?: SerializedValue + +interface ElementHandle extends JSHandle + command evalOnSelector + parameters + selector: string + expression: string + isFunction: boolean + arg: SerializedArgument + returns + value?: SerializedValue + + command evalOnSelectorAll + parameters + selector: string + expression: string + isFunction: boolean + arg: SerializedArgument + returns + value?: SerializedValue + + command boundingBox + returns + value?: object + width: number + height: number + x: number + y: number + + command check + parameters + force?: boolean + noWaitAfter?: boolean + timeout?: number + + command click + parameters + force?: boolean + noWaitAfter?: boolean + modifiers?: enum[] + Alt + Control + Meta + Shift + position?: object + x: number + y: number + delay?: number + button?: enum + left + right + middle + clickCount?: number + timeout?: number + + command contentFrame + returns + frame?: Frame + + command dblclick + parameters + force?: boolean + noWaitAfter?: boolean + modifiers?: enum[] + Alt + Control + Meta + Shift + position?: object + x: number + y: number + delay?: number + button?: enum + left + right + middle + timeout?: number + + command dispatchEvent + parameters + type: string + eventInit: SerializedArgument + + command fill + parameters + value: string + timeout?: number + noWaitAfter?: boolean + + command focus + + command getAttribute + parameters + name: string + returns + value?: string + + command hover + parameters + force?: boolean + modifiers?: enum[] + Alt + Control + Meta + Shift + position?: object + x: number + y: number + timeout?: number + + command innerHTML + returns + value: string + + command innerText + returns + value: string + + command ownerFrame + returns + frame?: Frame + + command press + parameters + key: string + delay?: number + timeout?: number + noWaitAfter?: boolean + + command querySelector + parameters + selector: string + returns + element?: ElementHandle + + command querySelectorAll + parameters + selector: string + returns + elements: ElementHandle[] + + command screenshot + parameters + timeout?: number + type?: enum + png + jpeg + path?: string + quality?: number + omitBackground?: boolean + returns + binary: binary + + command scrollIntoViewIfNeeded + parameters + timeout?: number + + command selectOption + parameters + elements?: ElementHandle[] + options?: object[] + value?: string + label?: string + index?: number + timeout?: number + noWaitAfter?: boolean + returns + values: string[] + + command selectText + parameters + timeout?: number + + command setInputFiles + parameters + files: object[] + name: string + mimeType: string + buffer: string + timeout?: number + noWaitAfter?: boolean + + command textContent + returns + value?: string + + command type + parameters + text: string + delay?: number + noWaitAfter?: boolean + timeout?: number + + command uncheck + parameters + force?: boolean + noWaitAfter?: boolean + timeout?: number + +interface Request + initializer + frame: Frame + url: string + resourceType: string + method: string + postData?: string + headers: object[] + name: string + value: string + isNavigationRequest: boolean + redirectedFrom?: Request + + command response + returns + response?: Response + +interface Route + initializer + request: Request + + command abort + parameters + errorCode: string + + command continue + parameters + method?: string + headers?: object[] + name: string + value: string + postData?: string + + command fulfill + parameters + status: number + headers: object[] + name: string + value: string + body: string + isBase64: boolean + +interface Response + initializer + request: Request + url: string + status: number + statusText: string + headers: object[] + name: string + value: string + + command body + returns + binary: binary + + command finished + returns + error?: SerializedError + +interface ConsoleMessage + initializer + type: string + text: string + args: JSHandle[] + location: object + url?: string + lineNumber?: number + columnNumber?: number + +interface BindingCall + initializer + frame: Frame + name: string + args: SerializedValue[] + + command reject + parameters + error: SerializedError + + command resolve + parameters + result: SerializedArgument + +interface Dialog + initializer + type: string + message: string + defaultValue: string + + command accept + parameters + promptText?: string + + command dismiss + +interface Download + initializer + url: string + suggestedFilename: string + + command path + returns + value?: string + + command failure + returns + error?: string + + command stream + returns + stream?: Stream + + command delete + +interface Stream + command read + parameters + size?: number + returns + binary: binary + +interface CDPSession + event event + parameters + method: string + params?: object + + event disconnected + + command send + parameters + method: string + params?: object + returns + result: object + + command detach + +interface Electron + command launch + parameters + executablePath: string + args?: string[] + cwd?: string + env?: object[] + name: string + value: string + handleSIGINT?: boolean + handleSIGTERM?: boolean + handleSIGHUP?: boolean + timeout?: number + returns + electronApplication: ElectronApplication + +interface ElectronApplication + initializer + context: BrowserContext + + event close + + event window + parameters + page: Page + browserWindow: JSHandle + + command newBrowserWindow + parameters + arg: SerializedArgument + returns + page: Page + + command evaluateExpression + parameters + expression: string + isFunction: boolean + arg: SerializedArgument + returns + value?: SerializedValue + + command evaluateExpressionHandle + parameters + expression: string + isFunction: boolean + arg: SerializedArgument + returns + handle: JSHandle + + command close + diff --git a/src/rpc/serializers.ts b/src/rpc/serializers.ts index df153f651a..6e738c2845 100644 --- a/src/rpc/serializers.ts +++ b/src/rpc/serializers.ts @@ -21,24 +21,25 @@ import * as util from 'util'; import { TimeoutError } from '../errors'; import * as types from '../types'; import { helper, assert } from '../helper'; +import { SerializedError } from './channels'; +import { serializeAsCallArgument, parseEvaluationResultValue } from '../common/utilityScriptSerializers'; - -export function serializeError(e: any): types.Error { +export function serializeError(e: any): SerializedError { if (helper.isError(e)) - return { message: e.message, stack: e.stack, name: e.name }; - return { value: e }; + return { error: { message: e.message, stack: e.stack, name: e.name } }; + return { value: serializeAsCallArgument(e, value => ({ fallThrough: value })) }; } -export function parseError(error: types.Error): any { - if (error.message === undefined) - return error.value; - if (error.name === 'TimeoutError') { - const e = new TimeoutError(error.message); - e.stack = error.stack; +export function parseError(error: SerializedError): Error { + if (!error.error) + return parseEvaluationResultValue(error.value as any, []); + if (error.error.name === 'TimeoutError') { + const e = new TimeoutError(error.error.message); + e.stack = error.error.stack || ''; return e; } - const e = new Error(error.message); - e.stack = error.stack; + const e = new Error(error.error.message); + e.stack = error.error.stack || ''; return e; } diff --git a/src/rpc/server/browserContextDispatcher.ts b/src/rpc/server/browserContextDispatcher.ts index a535a7e016..24f16e0f11 100644 --- a/src/rpc/server/browserContextDispatcher.ts +++ b/src/rpc/server/browserContextDispatcher.ts @@ -19,7 +19,7 @@ import { BrowserContextBase, BrowserContext } from '../../browserContext'; import { Events } from '../../events'; import { Dispatcher, DispatcherScope, lookupDispatcher } from './dispatcher'; import { PageDispatcher, BindingCallDispatcher, WorkerDispatcher } from './pageDispatcher'; -import { PageChannel, BrowserContextChannel, BrowserContextInitializer, CDPSessionChannel } from '../channels'; +import { PageChannel, BrowserContextChannel, BrowserContextInitializer, CDPSessionChannel, BrowserContextSetGeolocationParams, BrowserContextSetHTTPCredentialsParams } from '../channels'; import { RouteDispatcher, RequestDispatcher } from './networkDispatchers'; import { CRBrowserContext } from '../../chromium/crBrowser'; import { CDPSessionDispatcher } from './cdpSessionDispatcher'; @@ -91,8 +91,8 @@ export class BrowserContextDispatcher extends Dispatcher { - await this._context.setGeolocation(params.geolocation); + async setGeolocation(params: BrowserContextSetGeolocationParams): Promise { + await this._context.setGeolocation(params.geolocation || null); } async setExtraHTTPHeaders(params: { headers: types.HeadersArray }): Promise { @@ -103,8 +103,8 @@ export class BrowserContextDispatcher extends Dispatcher { - await this._context.setHTTPCredentials(params.httpCredentials); + async setHTTPCredentials(params: BrowserContextSetHTTPCredentialsParams): Promise { + await this._context.setHTTPCredentials(params.httpCredentials || null); } async addInitScript(params: { source: string }): Promise { diff --git a/src/rpc/server/browserDispatcher.ts b/src/rpc/server/browserDispatcher.ts index f8cfa1b3a0..a5f8aeb06a 100644 --- a/src/rpc/server/browserDispatcher.ts +++ b/src/rpc/server/browserDispatcher.ts @@ -17,7 +17,7 @@ import { Browser, BrowserBase } from '../../browser'; import { BrowserContextBase } from '../../browserContext'; import { Events } from '../../events'; -import { BrowserChannel, BrowserContextChannel, BrowserInitializer, CDPSessionChannel, Binary, BrowserContextOptions } from '../channels'; +import { BrowserChannel, BrowserContextChannel, BrowserInitializer, CDPSessionChannel, Binary, BrowserNewContextParams } from '../channels'; import { BrowserContextDispatcher } from './browserContextDispatcher'; import { CDPSessionDispatcher } from './cdpSessionDispatcher'; import { Dispatcher, DispatcherScope } from './dispatcher'; @@ -34,7 +34,7 @@ export class BrowserDispatcher extends Dispatcher i }); } - async newContext(params: BrowserContextOptions): Promise<{ context: BrowserContextChannel }> { + async newContext(params: BrowserNewContextParams): Promise<{ context: BrowserContextChannel }> { const options = { ...params, extraHTTPHeaders: params.extraHTTPHeaders ? headersArrayToObject(params.extraHTTPHeaders) : undefined, diff --git a/src/rpc/server/browserTypeDispatcher.ts b/src/rpc/server/browserTypeDispatcher.ts index ba781ea0fa..849183c1ad 100644 --- a/src/rpc/server/browserTypeDispatcher.ts +++ b/src/rpc/server/browserTypeDispatcher.ts @@ -18,7 +18,7 @@ import { BrowserBase } from '../../browser'; import { BrowserTypeBase, BrowserType } from '../../server/browserType'; import * as types from '../../types'; import { BrowserDispatcher } from './browserDispatcher'; -import { BrowserChannel, BrowserTypeChannel, BrowserContextChannel, BrowserTypeInitializer, BrowserServerChannel, LaunchPersistentContextOptions, LaunchOptions, LaunchServerOptions } from '../channels'; +import { BrowserChannel, BrowserTypeChannel, BrowserContextChannel, BrowserTypeInitializer, BrowserServerChannel, BrowserTypeLaunchParams, BrowserTypeLaunchPersistentContextParams, BrowserTypeLaunchServerParams } from '../channels'; import { Dispatcher, DispatcherScope } from './dispatcher'; import { BrowserContextBase } from '../../browserContext'; import { BrowserContextDispatcher } from './browserContextDispatcher'; @@ -33,7 +33,7 @@ export class BrowserTypeDispatcher extends Dispatcher { + async launch(params: BrowserTypeLaunchParams): Promise<{ browser: BrowserChannel }> { const options = { ...params, ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs, @@ -43,7 +43,7 @@ export class BrowserTypeDispatcher extends Dispatcher { + async launchPersistentContext(params: BrowserTypeLaunchPersistentContextParams): Promise<{ context: BrowserContextChannel }> { const options = { ...params, ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs, @@ -54,7 +54,7 @@ export class BrowserTypeDispatcher extends Dispatcher { + async launchServer(params: BrowserTypeLaunchServerParams): Promise<{ server: BrowserServerChannel }> { const options = { ...params, ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs, diff --git a/src/rpc/server/dispatcher.ts b/src/rpc/server/dispatcher.ts index 1ffb71373e..2931259182 100644 --- a/src/rpc/server/dispatcher.ts +++ b/src/rpc/server/dispatcher.ts @@ -31,8 +31,8 @@ export function existingDispatcher(object: any): DispatcherType return object[dispatcherSymbol]; } -export function lookupNullableDispatcher(object: any | null): DispatcherType | null { - return object ? lookupDispatcher(object) : null; +export function lookupNullableDispatcher(object: any | null): DispatcherType | undefined { + return object ? lookupDispatcher(object) : undefined; } export class Dispatcher extends EventEmitter implements Channel { diff --git a/src/rpc/server/downloadDispatcher.ts b/src/rpc/server/downloadDispatcher.ts index 9fe59c976b..881ca8b1cd 100644 --- a/src/rpc/server/downloadDispatcher.ts +++ b/src/rpc/server/downloadDispatcher.ts @@ -27,20 +27,22 @@ export class DownloadDispatcher extends Dispatcher { - return { value: await this._object.path() }; + async path(): Promise<{ value?: string }> { + const path = await this._object.path(); + return { value: path || undefined }; } - async stream(): Promise<{ stream: StreamChannel | null }> { + async stream(): Promise<{ stream?: StreamChannel }> { const stream = await this._object.createReadStream(); if (!stream) - return { stream: null }; + return {}; await new Promise(f => stream.on('readable', f)); return { stream: new StreamDispatcher(this._scope, stream) }; } - async failure(): Promise<{ error: string | null }> { - return { error: await this._object.failure() }; + async failure(): Promise<{ error?: string }> { + const error = await this._object.failure(); + return { error: error || undefined }; } async delete(): Promise { diff --git a/src/rpc/server/electronDispatcher.ts b/src/rpc/server/electronDispatcher.ts index 551e0aaaba..0192b563c5 100644 --- a/src/rpc/server/electronDispatcher.ts +++ b/src/rpc/server/electronDispatcher.ts @@ -16,21 +16,26 @@ import { Dispatcher, DispatcherScope, lookupDispatcher } from './dispatcher'; import { Electron, ElectronApplication, ElectronEvents, ElectronPage } from '../../server/electron'; -import { ElectronApplicationChannel, ElectronApplicationInitializer, PageChannel, JSHandleChannel, ElectronInitializer, ElectronChannel, ElectronLaunchOptions, SerializedArgument } from '../channels'; +import { ElectronApplicationChannel, ElectronApplicationInitializer, PageChannel, JSHandleChannel, ElectronInitializer, ElectronChannel, SerializedArgument, ElectronLaunchParams } from '../channels'; import { BrowserContextDispatcher } from './browserContextDispatcher'; import { BrowserContextBase } from '../../browserContext'; import { PageDispatcher } from './pageDispatcher'; import { parseArgument, serializeResult } from './jsHandleDispatcher'; import { createHandle } from './elementHandlerDispatcher'; import { SerializedValue } from '../../common/utilityScriptSerializers'; +import { envArrayToObject } from '../serializers'; export class ElectronDispatcher extends Dispatcher implements ElectronChannel { constructor(scope: DispatcherScope, electron: Electron) { super(scope, electron, 'electron', {}, true); } - async launch(params: { executablePath: string } & ElectronLaunchOptions): Promise<{ electronApplication: ElectronApplicationChannel }> { - const electronApplication = await this._object.launch(params.executablePath, params); + async launch(params: ElectronLaunchParams): Promise<{ electronApplication: ElectronApplicationChannel }> { + const options = { + ...params, + env: params.env ? envArrayToObject(params.env) : undefined, + }; + const electronApplication = await this._object.launch(params.executablePath, options); return { electronApplication: new ElectronApplicationDispatcher(this._scope, electronApplication) }; } } diff --git a/src/rpc/server/elementHandlerDispatcher.ts b/src/rpc/server/elementHandlerDispatcher.ts index 383dfdd9fb..9b88d7c919 100644 --- a/src/rpc/server/elementHandlerDispatcher.ts +++ b/src/rpc/server/elementHandlerDispatcher.ts @@ -30,9 +30,9 @@ export function createHandle(scope: DispatcherScope, handle: js.JSHandle): JSHan export class ElementHandleDispatcher extends JSHandleDispatcher implements ElementHandleChannel { readonly _elementHandle: ElementHandle; - static createNullable(scope: DispatcherScope, handle: ElementHandle | null): ElementHandleDispatcher | null { + static createNullable(scope: DispatcherScope, handle: ElementHandle | null): ElementHandleDispatcher | undefined { if (!handle) - return null; + return undefined; return new ElementHandleDispatcher(scope, handle); } @@ -41,20 +41,22 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements Eleme this._elementHandle = elementHandle; } - async ownerFrame(): Promise<{ frame: FrameChannel | null }> { + async ownerFrame(): Promise<{ frame?: FrameChannel }> { return { frame: lookupNullableDispatcher(await this._elementHandle.ownerFrame()) }; } - async contentFrame(): Promise<{ frame: FrameChannel | null }> { + async contentFrame(): Promise<{ frame?: FrameChannel }> { return { frame: lookupNullableDispatcher(await this._elementHandle.contentFrame()) }; } - async getAttribute(params: { name: string }): Promise<{ value: string | null }> { - return { value: await this._elementHandle.getAttribute(params.name) }; + async getAttribute(params: { name: string }): Promise<{ value?: string }> { + const value = await this._elementHandle.getAttribute(params.name); + return { value: value === null ? undefined : value }; } - async textContent(): Promise<{ value: string | null }> { - return { value: await this._elementHandle.textContent() }; + async textContent(): Promise<{ value?: string }> { + const value = await this._elementHandle.textContent(); + return { value: value === null ? undefined : value }; } async innerText(): Promise<{ value: string }> { @@ -121,17 +123,18 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements Eleme await this._elementHandle.uncheck(params); } - async boundingBox(): Promise<{ value: types.Rect | null }> { - return { value: await this._elementHandle.boundingBox() }; + async boundingBox(): Promise<{ value?: types.Rect }> { + const value = await this._elementHandle.boundingBox(); + return { value: value || undefined }; } async screenshot(params: types.ElementScreenshotOptions): Promise<{ binary: Binary }> { return { binary: (await this._elementHandle.screenshot(params)).toString('base64') }; } - async querySelector(params: { selector: string }): Promise<{ element: ElementHandleChannel | null }> { + async querySelector(params: { selector: string }): Promise<{ element?: ElementHandleChannel }> { const handle = await this._elementHandle.$(params.selector); - return { element: handle ? new ElementHandleDispatcher(this._scope, handle) : null }; + return { element: handle ? new ElementHandleDispatcher(this._scope, handle) : undefined }; } async querySelectorAll(params: { selector: string }): Promise<{ elements: ElementHandleChannel[] }> { diff --git a/src/rpc/server/frameDispatcher.ts b/src/rpc/server/frameDispatcher.ts index 526d986519..601eb1997e 100644 --- a/src/rpc/server/frameDispatcher.ts +++ b/src/rpc/server/frameDispatcher.ts @@ -53,11 +53,11 @@ export class FrameDispatcher extends Dispatcher impleme }); } - async goto(params: { url: string } & types.GotoOptions): Promise<{ response: ResponseChannel | null }> { + async goto(params: { url: string } & types.GotoOptions): Promise<{ response?: ResponseChannel }> { return { response: lookupNullableDispatcher(await this._frame.goto(params.url, params)) }; } - async waitForNavigation(params: types.WaitForNavigationOptions): Promise<{ response: ResponseChannel | null }> { + async waitForNavigation(params: types.WaitForNavigationOptions): Promise<{ response?: ResponseChannel }> { return { response: lookupNullableDispatcher(await this._frame.waitForNavigation(params)) }; } @@ -73,7 +73,7 @@ export class FrameDispatcher extends Dispatcher impleme return { handle: createHandle(this._scope, await this._frame._evaluateExpressionHandle(params.expression, params.isFunction, parseArgument(params.arg))) }; } - async waitForSelector(params: { selector: string } & types.WaitForElementOptions): Promise<{ element: ElementHandleChannel | null }> { + async waitForSelector(params: { selector: string } & types.WaitForElementOptions): Promise<{ element?: ElementHandleChannel }> { return { element: ElementHandleDispatcher.createNullable(this._scope, await this._frame.waitForSelector(params.selector, params)) }; } @@ -89,7 +89,7 @@ export class FrameDispatcher extends Dispatcher impleme return { value: serializeResult(await this._frame._$$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg))) }; } - async querySelector(params: { selector: string }): Promise<{ element: ElementHandleChannel | null }> { + async querySelector(params: { selector: string }): Promise<{ element?: ElementHandleChannel }> { return { element: ElementHandleDispatcher.createNullable(this._scope, await this._frame.$(params.selector)) }; } @@ -130,8 +130,9 @@ export class FrameDispatcher extends Dispatcher impleme await this._frame.focus(params.selector, params); } - async textContent(params: { selector: string } & types.TimeoutOptions): Promise<{ value: string | null }> { - return { value: await this._frame.textContent(params.selector, params) }; + async textContent(params: { selector: string } & types.TimeoutOptions): Promise<{ value?: string }> { + const value = await this._frame.textContent(params.selector, params); + return { value: value === null ? undefined : value }; } async innerText(params: { selector: string } & types.TimeoutOptions): Promise<{ value: string }> { @@ -142,8 +143,9 @@ export class FrameDispatcher extends Dispatcher impleme return { value: await this._frame.innerHTML(params.selector, params) }; } - async getAttribute(params: { selector: string, name: string } & types.TimeoutOptions): Promise<{ value: string | null }> { - return { value: await this._frame.getAttribute(params.selector, params.name, params) }; + async getAttribute(params: { selector: string, name: string } & types.TimeoutOptions): Promise<{ value?: string }> { + const value = await this._frame.getAttribute(params.selector, params.name, params); + return { value: value === null ? undefined : value }; } async hover(params: { selector: string } & types.PointerActionOptions & types.TimeoutOptions & { force?: boolean }): Promise { diff --git a/src/rpc/server/jsHandleDispatcher.ts b/src/rpc/server/jsHandleDispatcher.ts index f63f40c8b9..e82141b483 100644 --- a/src/rpc/server/jsHandleDispatcher.ts +++ b/src/rpc/server/jsHandleDispatcher.ts @@ -63,7 +63,7 @@ export class JSHandleDispatcher extends Dispatcher (arg as JSHandleDispatcher)._object)); + return parseEvaluationResultValue(arg.value as any, arg.handles.map(arg => (arg as JSHandleDispatcher)._object)); } export function serializeResult(arg: any): SerializedValue { diff --git a/src/rpc/server/networkDispatchers.ts b/src/rpc/server/networkDispatchers.ts index 91163cc6f1..a8b07d2ac0 100644 --- a/src/rpc/server/networkDispatchers.ts +++ b/src/rpc/server/networkDispatchers.ts @@ -15,10 +15,10 @@ */ import { Request, Response, Route } from '../../network'; -import { RequestChannel, ResponseChannel, RouteChannel, ResponseInitializer, RequestInitializer, RouteInitializer, Binary } from '../channels'; +import { RequestChannel, ResponseChannel, RouteChannel, ResponseInitializer, RequestInitializer, RouteInitializer, Binary, SerializedError } from '../channels'; import { Dispatcher, DispatcherScope, lookupNullableDispatcher, existingDispatcher } from './dispatcher'; import { FrameDispatcher } from './frameDispatcher'; -import { headersObjectToArray, headersArrayToObject } from '../serializers'; +import { headersObjectToArray, headersArrayToObject, serializeError } from '../serializers'; import * as types from '../../types'; export class RequestDispatcher extends Dispatcher implements RequestChannel { @@ -28,24 +28,25 @@ export class RequestDispatcher extends Dispatcher i return result || new RequestDispatcher(scope, request); } - static fromNullable(scope: DispatcherScope, request: Request | null): RequestDispatcher | null { - return request ? RequestDispatcher.from(scope, request) : null; + static fromNullable(scope: DispatcherScope, request: Request | null): RequestDispatcher | undefined { + return request ? RequestDispatcher.from(scope, request) : undefined; } private constructor(scope: DispatcherScope, request: Request) { + const postData = request.postData(); super(scope, request, 'request', { frame: FrameDispatcher.from(scope, request.frame()), url: request.url(), resourceType: request.resourceType(), method: request.method(), - postData: request.postData(), + postData: postData === null ? undefined : postData, headers: headersObjectToArray(request.headers()), isNavigationRequest: request.isNavigationRequest(), redirectedFrom: RequestDispatcher.fromNullable(scope, request.redirectedFrom()), }); } - async response(): Promise<{ response: ResponseChannel | null }> { + async response(): Promise<{ response?: ResponseChannel }> { return { response: lookupNullableDispatcher(await this._object.response()) }; } } @@ -63,8 +64,9 @@ export class ResponseDispatcher extends Dispatcher { - return { error: await this._object.finished() }; + async finished(): Promise<{ error?: SerializedError }> { + const error = await this._object.finished(); + return { error: error ? serializeError(error) : undefined }; } async body(): Promise<{ binary: Binary }> { diff --git a/src/rpc/server/pageDispatcher.ts b/src/rpc/server/pageDispatcher.ts index 19e3de6089..186c16b146 100644 --- a/src/rpc/server/pageDispatcher.ts +++ b/src/rpc/server/pageDispatcher.ts @@ -20,7 +20,7 @@ import { Frame } from '../../frames'; import { Request } from '../../network'; import { Page, Worker } from '../../page'; import * as types from '../../types'; -import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel, WorkerInitializer, WorkerChannel, JSHandleChannel, Binary, PDFOptions, SerializedArgument } from '../channels'; +import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel, WorkerInitializer, WorkerChannel, JSHandleChannel, Binary, SerializedArgument, PagePdfParams, SerializedError } from '../channels'; import { Dispatcher, DispatcherScope, lookupDispatcher, lookupNullableDispatcher } from './dispatcher'; import { parseError, serializeError, headersArrayToObject } from '../serializers'; import { ConsoleMessageDispatcher } from './consoleMessageDispatcher'; @@ -42,7 +42,7 @@ export class PageDispatcher extends Dispatcher implements // If we split pageCreated and pageReady, there should be no main frame during pageCreated. super(scope, page, 'page', { mainFrame: FrameDispatcher.from(scope, page.mainFrame()), - viewportSize: page.viewportSize(), + viewportSize: page.viewportSize() || undefined, isClosed: page.isClosed() }); this._page = page; @@ -79,7 +79,7 @@ export class PageDispatcher extends Dispatcher implements this._page.setDefaultTimeout(params.timeout); } - async opener(): Promise<{ page: PageChannel | null }> { + async opener(): Promise<{ page?: PageChannel }> { return { page: lookupNullableDispatcher(await this._page.opener()) }; } @@ -95,15 +95,15 @@ export class PageDispatcher extends Dispatcher implements await this._page.setExtraHTTPHeaders(headersArrayToObject(params.headers)); } - async reload(params: types.NavigateOptions): Promise<{ response: ResponseChannel | null }> { + async reload(params: types.NavigateOptions): Promise<{ response?: ResponseChannel }> { return { response: lookupNullableDispatcher(await this._page.reload(params)) }; } - async goBack(params: types.NavigateOptions): Promise<{ response: ResponseChannel | null }> { + async goBack(params: types.NavigateOptions): Promise<{ response?: ResponseChannel }> { return { response: lookupNullableDispatcher(await this._page.goBack(params)) }; } - async goForward(params: types.NavigateOptions): Promise<{ response: ResponseChannel | null }> { + async goForward(params: types.NavigateOptions): Promise<{ response?: ResponseChannel }> { return { response: lookupNullableDispatcher(await this._page.goForward(params)) }; } @@ -180,15 +180,15 @@ export class PageDispatcher extends Dispatcher implements await this._page.mouse.click(params.x, params.y, params); } - async accessibilitySnapshot(params: { interestingOnly?: boolean, root?: ElementHandleChannel }): Promise<{ rootAXNode: types.SerializedAXNode | null }> { + async accessibilitySnapshot(params: { interestingOnly?: boolean, root?: ElementHandleChannel }): Promise<{ rootAXNode?: types.SerializedAXNode }> { const rootAXNode = await this._page.accessibility.snapshot({ interestingOnly: params.interestingOnly, root: params.root ? (params.root as ElementHandleDispatcher)._elementHandle : undefined }); - return { rootAXNode }; + return { rootAXNode: rootAXNode || undefined }; } - async pdf(params: PDFOptions): Promise<{ pdf: Binary }> { + async pdf(params: PagePdfParams): Promise<{ pdf: Binary }> { if (!this._page.pdf) throw new Error('PDF generation is only supported for Headless Chromium'); const buffer = await this._page.pdf(params); @@ -263,11 +263,11 @@ export class BindingCallDispatcher extends Dispatcher<{}, BindingCallInitializer return this._promise; } - resolve(params: { result: SerializedArgument }) { + async resolve(params: { result: SerializedArgument }) { this._resolve!(parseArgument(params.result)); } - reject(params: { error: types.Error }) { + async reject(params: { error: SerializedError }) { this._reject!(parseError(params.error)); } } diff --git a/src/server/electron.ts b/src/server/electron.ts index fb03e13f28..df0b35bbce 100644 --- a/src/server/electron.ts +++ b/src/server/electron.ts @@ -34,15 +34,14 @@ import { EventEmitter } from 'events'; import { helper } from '../helper'; import { LoggerSink } from '../loggerSink'; -type ElectronLaunchOptions = { +export type ElectronLaunchOptionsBase = { args?: string[], cwd?: string, - env?: {[key: string]: string|number|boolean}, + env?: types.Env, handleSIGINT?: boolean, handleSIGTERM?: boolean, handleSIGHUP?: boolean, timeout?: number, - logger?: LoggerSink, }; export const ElectronEvents = { @@ -165,7 +164,7 @@ export class ElectronApplication extends EventEmitter { } export class Electron { - async launch(executablePath: string, options: ElectronLaunchOptions = {}): Promise { + async launch(executablePath: string, options: ElectronLaunchOptionsBase & { logger?: LoggerSink } = {}): Promise { const { args = [], env = process.env, diff --git a/src/types.ts b/src/types.ts index 7086250c1e..28c29a16f7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -348,8 +348,7 @@ export type ConsoleMessageLocation = { }; export type Error = { - message?: string, - name?: string, + message: string, + name: string, stack?: string, - value?: any }; diff --git a/utils/generate_channels.js b/utils/generate_channels.js new file mode 100755 index 0000000000..e769d29584 --- /dev/null +++ b/utils/generate_channels.js @@ -0,0 +1,217 @@ +#!/usr/bin/env node +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const fs = require('fs'); +const path = require('path'); + +const channels = new Set(); + +function tokenize(source) { + const lines = source.split('\n').filter(line => { + const trimmed = line.trim(); + return !!trimmed && trimmed[0] != '#'; + }); + + const stack = [{ indent: -1, list: [], words: '' }]; + for (const line of lines) { + const indent = line.length - line.trimLeft().length; + const o = { indent, list: [], words: line.split(' ').filter(word => !!word) }; + + let current = stack[stack.length - 1]; + while (indent <= current.indent) { + stack.pop(); + current = stack[stack.length - 1]; + } + + current.list.push(o); + stack.push(o); + } + return stack[0].list; +} + +function raise(item) { + throw new Error(item.words.join(' ')); +} + +function titleCase(name) { + return name[0].toUpperCase() + name.substring(1); +} + +function inlineType(type, item, indent) { + const array = type.endsWith('[]'); + if (array) + type = type.substring(0, type.length - 2); + let inner = ''; + if (type === 'enum') { + const literals = item.list.map(literal => { + if (literal.words.length > 1 || literal.list.length) + raise(literal); + return literal.words[0]; + }); + inner = literals.map(literal => `'${literal}'`).join(' | '); + if (array) + inner = `(${inner})`; + } else if (['string', 'boolean', 'number', 'undefined'].includes(type)) { + inner = type; + } else if (type === 'object') { + inner = `{\n${properties(item, indent + ' ')}\n${indent}}`; + } else if (type === 'binary') { + inner = 'Binary'; + } else if (type === 'Error') { + inner = 'SerializedError'; + } else if (channels.has(type)) { + inner = type + 'Channel'; + } else { + inner = type; + } + return inner + (array ? '[]' : ''); +} + +function properties(item, indent) { + const result = []; + for (const prop of item.list) { + if (prop.words.length !== 2) + raise(prop); + let name = prop.words[0]; + if (!name.endsWith(':')) + raise(item); + name = name.substring(0, name.length - 1); + const optional = name.endsWith('?'); + if (optional) + name = name.substring(0, name.length - 1); + result.push(`${indent}${name}${optional ? '?' : ''}: ${inlineType(prop.words[1], prop, indent)},`); + } + return result.join('\n'); +} + +function objectType(name, item, indent) { + if (!item.list.length) + return `export type ${name} = {};`; + return `export type ${name} = {\n${properties(item, indent)}\n};` +} + +const result = [ +`/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file is generated by ${path.basename(__filename)}, do not edit manually. + +import { EventEmitter } from 'events'; + +export type Binary = string; + +export interface Channel extends EventEmitter { +} +`]; + +const pdl = fs.readFileSync(path.join(__dirname, '..', 'src', 'rpc', 'protocol.pdl'), 'utf-8'); +const list = tokenize(pdl); + +for (const item of list) { + if (item.words[0] === 'interface') + channels.add(item.words[1]); +} + +for (const item of list) { + if (item.words[0] === 'union') { + if (item.words.length !== 2) + raise(item); + result.push(`export type ${item.words[1]} = ${item.list.map(clause => { + if (clause.words.length !== 1) + raise(clause); + return inlineType(clause.words[0], clause, ' '); + }).join(' | ')};`); + } else if (item.words[0] === 'type') { + if (item.words.length !== 2) + raise(item); + result.push(`export type ${item.words[1]} = {`); + result.push(properties(item, ' ')); + result.push(`};`); + } else if (item.words[0] === 'interface') { + const channelName = item.words[1]; + result.push(`// ----------- ${channelName} -----------`); + const init = item.list.find(i => i.words[0] === 'initializer'); + if (init && init.words.length > 1) + raise(init); + result.push(objectType(channelName + 'Initializer', init || { list: [] }, ' ')); + + let extendsName = 'Channel'; + if (item.words.length === 4 && item.words[2] === 'extends') + extendsName = item.words[3] + 'Channel'; + else if (item.words.length !== 2) + raise(item); + result.push(`export interface ${channelName}Channel extends ${extendsName} {`); + + const types = new Map(); + for (const method of item.list) { + if (method === init) + continue; + if (method.words[0] === 'command') { + if (method.words.length !== 2) + raise(method); + const methodName = method.words[1]; + + const parameters = method.list.find(i => i.words[0] === 'parameters'); + const paramsName = `${channelName}${titleCase(methodName)}Params`; + types.set(paramsName, parameters || { list: [] }); + + const returns = method.list.find(i => i.words[0] === 'returns'); + const resultName = `${channelName}${titleCase(methodName)}Result`; + types.set(resultName, returns); + + result.push(` ${methodName}(params${parameters ? '' : '?'}: ${paramsName}): Promise<${resultName}>;`); + } else if (method.words[0] === 'event') { + if (method.words.length !== 2) + raise(method); + const eventName = method.words[1]; + + const parameters = method.list.find(i => i.words[0] === 'parameters'); + const paramsName = `${channelName}${titleCase(eventName)}Event`; + types.set(paramsName, parameters || { list: [] }); + + result.push(` on(event: '${eventName}', callback: (params: ${paramsName}) => void): this;`); + } else { + raise(method); + } + } + result.push(`}`); + for (const [name, item] of types) { + if (!item) + result.push(`export type ${name} = void;`); + else + result.push(objectType(name, item, ' ')); + } + } else { + raise(item); + } + result.push(``); +} + +fs.writeFileSync(path.join(__dirname, '..', 'src', 'rpc', 'channels.ts'), result.join('\n'), 'utf-8');