2020-06-26 02:05:36 +03:00
|
|
|
/**
|
|
|
|
* Copyright 2017 Google Inc. All rights reserved.
|
|
|
|
* Modifications 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.
|
|
|
|
*/
|
|
|
|
|
2020-07-30 03:26:59 +03:00
|
|
|
import { Events } from './events';
|
2020-08-23 01:13:51 +03:00
|
|
|
import { assert } from '../utils/utils';
|
|
|
|
import { TimeoutSettings } from '../utils/timeoutSettings';
|
2020-08-25 03:05:16 +03:00
|
|
|
import * as channels from '../protocol/channels';
|
2020-08-23 01:13:51 +03:00
|
|
|
import { parseError, serializeError } from '../protocol/serializers';
|
2020-06-26 04:01:18 +03:00
|
|
|
import { Accessibility } from './accessibility';
|
2020-06-30 20:55:11 +03:00
|
|
|
import { BrowserContext } from './browserContext';
|
|
|
|
import { ChannelOwner } from './channelOwner';
|
2020-06-26 22:28:27 +03:00
|
|
|
import { ConsoleMessage } from './consoleMessage';
|
2020-06-27 03:24:21 +03:00
|
|
|
import { Dialog } from './dialog';
|
|
|
|
import { Download } from './download';
|
2020-08-19 04:46:56 +03:00
|
|
|
import { ElementHandle, determineScreenshotType } from './elementHandle';
|
2020-06-30 20:55:11 +03:00
|
|
|
import { Worker } from './worker';
|
2020-10-02 08:47:31 +03:00
|
|
|
import { Frame, verifyLoadState, WaitForNavigationOptions } from './frame';
|
2020-10-19 20:07:33 +03:00
|
|
|
import { Keyboard, Mouse, Touchscreen } from './input';
|
2020-12-27 04:05:57 +03:00
|
|
|
import { assertMaxArguments, serializeArgument, parseResult, JSHandle } from './jsHandle';
|
2020-10-27 08:20:43 +03:00
|
|
|
import { Request, Response, Route, RouteHandler, WebSocket, validateHeaders } from './network';
|
2020-06-30 20:55:11 +03:00
|
|
|
import { FileChooser } from './fileChooser';
|
|
|
|
import { Buffer } from 'buffer';
|
2021-04-02 04:47:14 +03:00
|
|
|
import { Coverage } from './coverage';
|
2020-07-14 02:03:24 +03:00
|
|
|
import { Waiter } from './waiter';
|
2020-12-27 04:05:57 +03:00
|
|
|
import * as api from '../../types/types';
|
|
|
|
import * as structs from '../../types/structs';
|
2021-02-11 17:36:15 +03:00
|
|
|
import fs from 'fs';
|
|
|
|
import path from 'path';
|
2020-07-30 03:26:59 +03:00
|
|
|
import { Size, URLMatch, Headers, LifecycleEvent, WaitForEventOptions, SelectOption, SelectOptionOptions, FilePayload, WaitForFunctionOptions } from './types';
|
2020-08-19 23:27:58 +03:00
|
|
|
import { evaluationScript, urlMatches } from './clientHelper';
|
2020-08-23 01:13:51 +03:00
|
|
|
import { isString, isRegExp, isObject, mkdirIfNeeded, headersObjectToArray } from '../utils/utils';
|
2020-10-01 07:17:30 +03:00
|
|
|
import { isSafeCloseError } from '../utils/errors';
|
2020-10-14 08:15:51 +03:00
|
|
|
import { Video } from './video';
|
2021-03-31 20:38:05 +03:00
|
|
|
import { Artifact } from './artifact';
|
2020-07-30 03:26:59 +03:00
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
type PDFOptions = Omit<channels.PagePdfParams, 'width' | 'height' | 'margin'> & {
|
2020-07-30 03:26:59 +03:00
|
|
|
width?: string | number,
|
|
|
|
height?: string | number,
|
|
|
|
margin?: {
|
|
|
|
top?: string | number,
|
|
|
|
bottom?: string | number,
|
|
|
|
left?: string | number,
|
|
|
|
right?: string | number
|
|
|
|
},
|
|
|
|
path?: string,
|
|
|
|
};
|
2020-08-22 17:07:13 +03:00
|
|
|
type Listener = (...args: any[]) => void;
|
2020-07-14 20:51:37 +03:00
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitializer> implements api.Page {
|
2020-07-14 01:26:09 +03:00
|
|
|
private _browserContext: BrowserContext;
|
2020-06-27 03:24:21 +03:00
|
|
|
_ownedContext: BrowserContext | undefined;
|
|
|
|
|
2020-06-26 22:28:27 +03:00
|
|
|
private _mainFrame: Frame;
|
2020-06-26 02:05:36 +03:00
|
|
|
private _frames = new Set<Frame>();
|
2020-06-30 20:55:11 +03:00
|
|
|
_workers = new Set<Worker>();
|
2020-06-26 02:05:36 +03:00
|
|
|
private _closed = false;
|
2021-03-31 20:38:05 +03:00
|
|
|
_closedOrCrashedPromise: Promise<void>;
|
2020-07-30 03:26:59 +03:00
|
|
|
private _viewportSize: Size | null;
|
|
|
|
private _routes: { url: URLMatch, handler: RouteHandler }[] = [];
|
2020-06-26 02:05:36 +03:00
|
|
|
|
2020-06-26 04:01:18 +03:00
|
|
|
readonly accessibility: Accessibility;
|
2021-04-02 04:47:14 +03:00
|
|
|
readonly coverage: Coverage;
|
2020-06-26 04:01:18 +03:00
|
|
|
readonly keyboard: Keyboard;
|
|
|
|
readonly mouse: Mouse;
|
2020-10-19 20:07:33 +03:00
|
|
|
readonly touchscreen: Touchscreen;
|
2020-07-14 01:26:09 +03:00
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
readonly _bindings = new Map<string, (source: structs.BindingSource, ...args: any[]) => any>();
|
2020-07-14 02:03:24 +03:00
|
|
|
readonly _timeoutSettings: TimeoutSettings;
|
2020-06-30 04:58:09 +03:00
|
|
|
_isPageCall = false;
|
2020-10-14 08:15:51 +03:00
|
|
|
private _video: Video | null = null;
|
2021-04-02 21:15:07 +03:00
|
|
|
readonly _opener: Page | null;
|
2020-06-26 04:01:18 +03:00
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
static from(page: channels.PageChannel): Page {
|
2020-07-02 04:36:09 +03:00
|
|
|
return (page as any)._object;
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
static fromNullable(page: channels.PageChannel | undefined): Page | null {
|
2020-06-26 02:05:36 +03:00
|
|
|
return page ? Page.from(page) : null;
|
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.PageInitializer) {
|
2020-07-11 04:00:10 +03:00
|
|
|
super(parent, type, guid, initializer);
|
2020-07-14 01:26:09 +03:00
|
|
|
this._browserContext = parent as BrowserContext;
|
|
|
|
this._timeoutSettings = new TimeoutSettings(this._browserContext._timeoutSettings);
|
|
|
|
|
2020-07-01 23:55:29 +03:00
|
|
|
this.accessibility = new Accessibility(this._channel);
|
|
|
|
this.keyboard = new Keyboard(this._channel);
|
|
|
|
this.mouse = new Mouse(this._channel);
|
2020-10-19 20:07:33 +03:00
|
|
|
this.touchscreen = new Touchscreen(this._channel);
|
2020-06-26 02:05:36 +03:00
|
|
|
|
2020-06-26 22:28:27 +03:00
|
|
|
this._mainFrame = Frame.from(initializer.mainFrame);
|
|
|
|
this._mainFrame._page = this;
|
2020-06-26 02:05:36 +03:00
|
|
|
this._frames.add(this._mainFrame);
|
2020-07-21 03:38:06 +03:00
|
|
|
this._viewportSize = initializer.viewportSize || null;
|
2020-07-10 23:15:39 +03:00
|
|
|
this._closed = initializer.isClosed;
|
2021-04-02 21:15:07 +03:00
|
|
|
this._opener = Page.fromNullable(initializer.opener);
|
2020-06-26 02:05:36 +03:00
|
|
|
|
2020-07-15 04:26:50 +03:00
|
|
|
this._channel.on('bindingCall', ({ binding }) => this._onBinding(BindingCall.from(binding)));
|
2020-06-26 21:51:47 +03:00
|
|
|
this._channel.on('close', () => this._onClose());
|
2020-07-15 04:26:50 +03:00
|
|
|
this._channel.on('console', ({ message }) => this.emit(Events.Page.Console, ConsoleMessage.from(message)));
|
2020-06-27 07:22:03 +03:00
|
|
|
this._channel.on('crash', () => this._onCrash());
|
2021-02-03 21:34:45 +03:00
|
|
|
this._channel.on('dialog', ({ dialog }) => {
|
|
|
|
if (!this.emit(Events.Page.Dialog, Dialog.from(dialog)))
|
|
|
|
dialog.dismiss().catch(() => {});
|
|
|
|
});
|
2021-01-22 20:58:31 +03:00
|
|
|
this._channel.on('domcontentloaded', () => this.emit(Events.Page.DOMContentLoaded, this));
|
2021-03-31 20:38:05 +03:00
|
|
|
this._channel.on('download', ({ url, suggestedFilename, artifact }) => {
|
|
|
|
const artifactObject = Artifact.from(artifact);
|
2021-05-06 19:34:06 +03:00
|
|
|
artifactObject._isRemote = !!this._browserContext._browser && !!this._browserContext._browser._remoteType;
|
2021-05-14 00:18:21 +03:00
|
|
|
this.emit(Events.Page.Download, new Download(this, url, suggestedFilename, artifactObject));
|
2021-03-31 20:38:05 +03:00
|
|
|
});
|
2020-06-30 20:55:11 +03:00
|
|
|
this._channel.on('fileChooser', ({ element, isMultiple }) => this.emit(Events.Page.FileChooser, new FileChooser(this, ElementHandle.from(element), isMultiple)));
|
2020-07-15 04:26:50 +03:00
|
|
|
this._channel.on('frameAttached', ({ frame }) => this._onFrameAttached(Frame.from(frame)));
|
|
|
|
this._channel.on('frameDetached', ({ frame }) => this._onFrameDetached(Frame.from(frame)));
|
2021-01-22 20:58:31 +03:00
|
|
|
this._channel.on('load', () => this.emit(Events.Page.Load, this));
|
2020-06-26 21:51:47 +03:00
|
|
|
this._channel.on('pageError', ({ error }) => this.emit(Events.Page.PageError, parseError(error)));
|
|
|
|
this._channel.on('route', ({ route, request }) => this._onRoute(Route.from(route), Request.from(request)));
|
2021-03-31 20:38:05 +03:00
|
|
|
this._channel.on('video', ({ artifact }) => {
|
|
|
|
const artifactObject = Artifact.from(artifact);
|
|
|
|
this._forceVideo()._artifactReady(artifactObject);
|
|
|
|
});
|
2020-10-27 08:20:43 +03:00
|
|
|
this._channel.on('webSocket', ({ webSocket }) => this.emit(Events.Page.WebSocket, WebSocket.from(webSocket)));
|
2020-07-15 04:26:50 +03:00
|
|
|
this._channel.on('worker', ({ worker }) => this._onWorker(Worker.from(worker)));
|
2020-06-26 21:51:47 +03:00
|
|
|
|
2021-04-02 04:47:14 +03:00
|
|
|
this.coverage = new Coverage(this._channel);
|
2021-03-31 20:38:05 +03:00
|
|
|
|
|
|
|
this._closedOrCrashedPromise = Promise.race([
|
|
|
|
new Promise<void>(f => this.once(Events.Page.Close, f)),
|
|
|
|
new Promise<void>(f => this.once(Events.Page.Crash, f)),
|
|
|
|
]);
|
2020-06-27 07:22:03 +03:00
|
|
|
}
|
|
|
|
|
2020-06-26 02:05:36 +03:00
|
|
|
private _onFrameAttached(frame: Frame) {
|
2020-06-26 22:28:27 +03:00
|
|
|
frame._page = this;
|
2020-06-26 02:05:36 +03:00
|
|
|
this._frames.add(frame);
|
|
|
|
if (frame._parentFrame)
|
|
|
|
frame._parentFrame._childFrames.add(frame);
|
|
|
|
this.emit(Events.Page.FrameAttached, frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
private _onFrameDetached(frame: Frame) {
|
|
|
|
this._frames.delete(frame);
|
2020-06-27 03:24:21 +03:00
|
|
|
frame._detached = true;
|
2020-06-26 02:05:36 +03:00
|
|
|
if (frame._parentFrame)
|
|
|
|
frame._parentFrame._childFrames.delete(frame);
|
|
|
|
this.emit(Events.Page.FrameDetached, frame);
|
|
|
|
}
|
|
|
|
|
2020-06-26 21:51:47 +03:00
|
|
|
private _onRoute(route: Route, request: Request) {
|
|
|
|
for (const {url, handler} of this._routes) {
|
2020-08-19 23:27:58 +03:00
|
|
|
if (urlMatches(request.url(), url)) {
|
2020-06-26 21:51:47 +03:00
|
|
|
handler(route, request);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2020-07-14 01:26:09 +03:00
|
|
|
this._browserContext._onRoute(route, request);
|
2020-06-26 21:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async _onBinding(bindingCall: BindingCall) {
|
2020-06-26 22:28:27 +03:00
|
|
|
const func = this._bindings.get(bindingCall._initializer.name);
|
2020-07-04 04:04:08 +03:00
|
|
|
if (func) {
|
2021-03-22 19:59:39 +03:00
|
|
|
await bindingCall.call(func);
|
2020-07-04 04:04:08 +03:00
|
|
|
return;
|
|
|
|
}
|
2021-03-22 19:59:39 +03:00
|
|
|
await this._browserContext._onBinding(bindingCall);
|
2020-06-26 21:51:47 +03:00
|
|
|
}
|
|
|
|
|
2020-06-30 20:55:11 +03:00
|
|
|
_onWorker(worker: Worker): void {
|
|
|
|
this._workers.add(worker);
|
|
|
|
worker._page = this;
|
|
|
|
this.emit(Events.Page.Worker, worker);
|
|
|
|
}
|
|
|
|
|
2020-08-13 23:24:49 +03:00
|
|
|
_onClose() {
|
2020-06-27 07:22:03 +03:00
|
|
|
this._closed = true;
|
2020-07-14 01:26:09 +03:00
|
|
|
this._browserContext._pages.delete(this);
|
2021-05-12 23:15:04 +03:00
|
|
|
this._browserContext._backgroundPages.delete(this);
|
2021-01-22 20:58:31 +03:00
|
|
|
this.emit(Events.Page.Close, this);
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-06-27 07:22:03 +03:00
|
|
|
private _onCrash() {
|
2021-01-22 20:58:31 +03:00
|
|
|
this.emit(Events.Page.Crash, this);
|
2020-06-27 07:22:03 +03:00
|
|
|
}
|
|
|
|
|
2020-06-26 02:05:36 +03:00
|
|
|
context(): BrowserContext {
|
2020-07-14 01:26:09 +03:00
|
|
|
return this._browserContext;
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async opener(): Promise<Page | null> {
|
2021-04-02 21:15:07 +03:00
|
|
|
if (!this._opener || this._opener.isClosed())
|
|
|
|
return null;
|
|
|
|
return this._opener;
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mainFrame(): Frame {
|
2020-06-26 22:28:27 +03:00
|
|
|
return this._mainFrame;
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-12-04 09:28:11 +03:00
|
|
|
frame(frameSelector: string | { name?: string, url?: URLMatch }): Frame | null {
|
|
|
|
const name = isString(frameSelector) ? frameSelector : frameSelector.name;
|
|
|
|
const url = isObject(frameSelector) ? frameSelector.url : undefined;
|
2020-06-26 02:05:36 +03:00
|
|
|
assert(name || url, 'Either name or url matcher should be specified');
|
|
|
|
return this.frames().find(f => {
|
|
|
|
if (name)
|
|
|
|
return f.name() === name;
|
2020-08-19 23:27:58 +03:00
|
|
|
return urlMatches(f.url(), url);
|
2020-06-26 02:05:36 +03:00
|
|
|
}) || null;
|
|
|
|
}
|
|
|
|
|
|
|
|
frames(): Frame[] {
|
|
|
|
return [...this._frames];
|
|
|
|
}
|
|
|
|
|
|
|
|
setDefaultNavigationTimeout(timeout: number) {
|
2020-07-14 02:03:24 +03:00
|
|
|
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
|
2020-06-26 02:05:36 +03:00
|
|
|
this._channel.setDefaultNavigationTimeoutNoReply({ timeout });
|
|
|
|
}
|
|
|
|
|
|
|
|
setDefaultTimeout(timeout: number) {
|
2020-06-27 07:22:03 +03:00
|
|
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
2020-06-26 02:05:36 +03:00
|
|
|
this._channel.setDefaultTimeoutNoReply({ timeout });
|
|
|
|
}
|
|
|
|
|
2021-03-31 20:38:05 +03:00
|
|
|
private _forceVideo(): Video {
|
|
|
|
if (!this._video)
|
|
|
|
this._video = new Video(this);
|
|
|
|
return this._video;
|
|
|
|
}
|
|
|
|
|
2020-10-14 08:15:51 +03:00
|
|
|
video(): Video | null {
|
2021-03-31 20:38:05 +03:00
|
|
|
// Note: we are creating Video object lazily, because we do not know
|
|
|
|
// BrowserContextOptions when constructing the page - it is assigned
|
|
|
|
// too late during launchPersistentContext.
|
2020-11-03 06:42:05 +03:00
|
|
|
if (!this._browserContext._options.recordVideo)
|
2020-10-14 08:15:51 +03:00
|
|
|
return null;
|
2021-03-31 20:38:05 +03:00
|
|
|
return this._forceVideo();
|
2020-10-14 08:15:51 +03:00
|
|
|
}
|
|
|
|
|
2020-06-30 04:58:09 +03:00
|
|
|
private _attributeToPage<T>(func: () => T): T {
|
|
|
|
try {
|
|
|
|
this._isPageCall = true;
|
|
|
|
return func();
|
|
|
|
} finally {
|
|
|
|
this._isPageCall = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
async $(selector: string): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.$(selector));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
waitForSelector(selector: string, options: channels.FrameWaitForSelectorOptions & { state: 'attached' | 'visible' }): Promise<ElementHandle<SVGElement | HTMLElement>>;
|
|
|
|
waitForSelector(selector: string, options?: channels.FrameWaitForSelectorOptions): Promise<ElementHandle<SVGElement | HTMLElement> | null>;
|
|
|
|
async waitForSelector(selector: string, options?: channels.FrameWaitForSelectorOptions): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.waitForSelector(selector, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async dispatchEvent(selector: string, type: string, eventInit?: any, options?: channels.FrameDispatchEventOptions): Promise<void> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.dispatchEvent(selector, type, eventInit, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
async evaluateHandle<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<structs.SmartHandle<R>> {
|
2020-06-26 02:05:36 +03:00
|
|
|
assertMaxArguments(arguments.length, 2);
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.evaluateHandle(pageFunction, arg));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
async $eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element, Arg, R>, arg?: Arg): Promise<R> {
|
2020-06-26 02:05:36 +03:00
|
|
|
assertMaxArguments(arguments.length, 3);
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.$eval(selector, pageFunction, arg));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
async $$eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element[], Arg, R>, arg?: Arg): Promise<R> {
|
2020-06-26 02:05:36 +03:00
|
|
|
assertMaxArguments(arguments.length, 3);
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.$$eval(selector, pageFunction, arg));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
async $$(selector: string): Promise<ElementHandle<SVGElement | HTMLElement>[]> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.$$(selector));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2021-01-09 03:17:54 +03:00
|
|
|
async addScriptTag(options: { url?: string; path?: string; content?: string; type?: string; } = {}): Promise<ElementHandle> {
|
|
|
|
return this._attributeToPage(() => this._mainFrame.addScriptTag(options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2021-01-09 03:17:54 +03:00
|
|
|
async addStyleTag(options: { url?: string; path?: string; content?: string; } = {}): Promise<ElementHandle> {
|
|
|
|
return this._attributeToPage(() => this._mainFrame.addStyleTag(options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2021-01-05 00:50:29 +03:00
|
|
|
async exposeFunction(name: string, callback: Function) {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.exposeFunction', async (channel: channels.PageChannel) => {
|
|
|
|
await channel.exposeBinding({ name });
|
2021-01-05 00:50:29 +03:00
|
|
|
const binding = (source: structs.BindingSource, ...args: any[]) => callback(...args);
|
2020-10-02 08:47:31 +03:00
|
|
|
this._bindings.set(name, binding);
|
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2021-01-05 00:50:29 +03:00
|
|
|
async exposeBinding(name: string, callback: (source: structs.BindingSource, ...args: any[]) => any, options: { handle?: boolean } = {}) {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.exposeBinding', async (channel: channels.PageChannel) => {
|
|
|
|
await channel.exposeBinding({ name, needsHandle: options.handle });
|
2021-01-05 00:50:29 +03:00
|
|
|
this._bindings.set(name, callback);
|
2020-07-17 00:32:21 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-07-30 03:26:59 +03:00
|
|
|
async setExtraHTTPHeaders(headers: Headers) {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.setExtraHTTPHeaders', async (channel: channels.PageChannel) => {
|
2020-08-19 01:38:29 +03:00
|
|
|
validateHeaders(headers);
|
2021-02-20 03:21:39 +03:00
|
|
|
await channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) });
|
2020-07-17 00:32:21 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
url(): string {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.url());
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async content(): Promise<string> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.content());
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async setContent(html: string, options?: channels.FrameSetContentOptions): Promise<void> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.setContent(html, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async goto(url: string, options?: channels.FrameGotoOptions): Promise<Response | null> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.goto(url, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async reload(options: channels.PageReloadOptions = {}): Promise<Response | null> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.reload', async (channel: channels.PageChannel) => {
|
2020-07-23 04:05:07 +03:00
|
|
|
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
2021-02-20 03:21:39 +03:00
|
|
|
return Response.fromNullable((await channel.reload({ ...options, waitUntil })).response);
|
2020-07-17 00:32:21 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-07-30 03:26:59 +03:00
|
|
|
async waitForLoadState(state?: LifecycleEvent, options?: { timeout?: number }): Promise<void> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.waitForLoadState(state, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-07-30 03:26:59 +03:00
|
|
|
async waitForNavigation(options?: WaitForNavigationOptions): Promise<Response | null> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.waitForNavigation(options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2021-03-31 07:51:22 +03:00
|
|
|
async waitForURL(url: URLMatch, options?: { waitUntil?: LifecycleEvent, timeout?: number }): Promise<void> {
|
|
|
|
return this._attributeToPage(() => this._mainFrame.waitForURL(url, options));
|
|
|
|
}
|
|
|
|
|
2021-04-19 20:32:51 +03:00
|
|
|
async waitForRequest(urlOrPredicate: string | RegExp | ((r: Request) => boolean | Promise<boolean>), options: { timeout?: number } = {}): Promise<Request> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.waitForRequest', async (channel: channels.PageChannel) => {
|
2021-01-22 17:49:59 +03:00
|
|
|
const predicate = (request: Request) => {
|
|
|
|
if (isString(urlOrPredicate) || isRegExp(urlOrPredicate))
|
|
|
|
return urlMatches(request.url(), urlOrPredicate);
|
|
|
|
return urlOrPredicate(request);
|
|
|
|
};
|
|
|
|
const trimmedUrl = trimUrl(urlOrPredicate);
|
2021-02-18 02:11:23 +03:00
|
|
|
const logLine = trimmedUrl ? `waiting for request ${trimmedUrl}` : undefined;
|
2021-01-22 17:49:59 +03:00
|
|
|
return this._waitForEvent(Events.Page.Request, { predicate, timeout: options.timeout }, logLine);
|
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2021-04-19 20:32:51 +03:00
|
|
|
async waitForResponse(urlOrPredicate: string | RegExp | ((r: Response) => boolean | Promise<boolean>), options: { timeout?: number } = {}): Promise<Response> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.waitForResponse', async (channel: channels.PageChannel) => {
|
2021-01-22 17:49:59 +03:00
|
|
|
const predicate = (response: Response) => {
|
|
|
|
if (isString(urlOrPredicate) || isRegExp(urlOrPredicate))
|
|
|
|
return urlMatches(response.url(), urlOrPredicate);
|
|
|
|
return urlOrPredicate(response);
|
|
|
|
};
|
|
|
|
const trimmedUrl = trimUrl(urlOrPredicate);
|
2021-02-18 02:11:23 +03:00
|
|
|
const logLine = trimmedUrl ? `waiting for response ${trimmedUrl}` : undefined;
|
2021-01-22 17:49:59 +03:00
|
|
|
return this._waitForEvent(Events.Page.Response, { predicate, timeout: options.timeout }, logLine);
|
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-07-30 03:26:59 +03:00
|
|
|
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.waitForEvent', async (channel: channels.PageChannel) => {
|
2021-01-22 17:49:59 +03:00
|
|
|
return this._waitForEvent(event, optionsOrPredicate, `waiting for event "${event}"`);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private async _waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions, logLine?: string): Promise<any> {
|
2020-07-17 08:38:52 +03:00
|
|
|
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
|
|
|
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
2021-02-20 05:12:33 +03:00
|
|
|
const waiter = Waiter.createForEvent(this, 'page', event);
|
2021-01-22 17:49:59 +03:00
|
|
|
if (logLine)
|
|
|
|
waiter.log(logLine);
|
2020-07-22 09:48:21 +03:00
|
|
|
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
2020-07-14 02:03:24 +03:00
|
|
|
if (event !== Events.Page.Crash)
|
|
|
|
waiter.rejectOnEvent(this, Events.Page.Crash, new Error('Page crashed'));
|
|
|
|
if (event !== Events.Page.Close)
|
|
|
|
waiter.rejectOnEvent(this, Events.Page.Close, new Error('Page closed'));
|
|
|
|
const result = await waiter.waitForEvent(this, event, predicate as any);
|
|
|
|
waiter.dispose();
|
2020-06-27 07:22:03 +03:00
|
|
|
return result;
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async goBack(options: channels.PageGoBackOptions = {}): Promise<Response | null> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.goBack', async (channel: channels.PageChannel) => {
|
2020-07-23 04:05:07 +03:00
|
|
|
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
2021-02-20 03:21:39 +03:00
|
|
|
return Response.fromNullable((await channel.goBack({ ...options, waitUntil })).response);
|
2020-07-17 00:32:21 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async goForward(options: channels.PageGoForwardOptions = {}): Promise<Response | null> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.goForward', async (channel: channels.PageChannel) => {
|
2020-07-23 04:05:07 +03:00
|
|
|
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
2021-02-20 03:21:39 +03:00
|
|
|
return Response.fromNullable((await channel.goForward({ ...options, waitUntil })).response);
|
2020-07-17 00:32:21 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2021-05-22 02:56:09 +03:00
|
|
|
async emulateMedia(options: { media?: 'screen' | 'print' | null, colorScheme?: 'dark' | 'light' | 'no-preference' | null, reducedMotion?: 'reduce' | 'no-preference' | null } = {}) {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.emulateMedia', async (channel: channels.PageChannel) => {
|
|
|
|
await channel.emulateMedia({
|
2021-01-28 01:19:37 +03:00
|
|
|
media: options.media === null ? 'null' : options.media,
|
|
|
|
colorScheme: options.colorScheme === null ? 'null' : options.colorScheme,
|
2021-05-22 02:56:09 +03:00
|
|
|
reducedMotion: options.reducedMotion === null ? 'null' : options.reducedMotion,
|
2020-07-22 04:56:41 +03:00
|
|
|
});
|
2020-07-17 00:32:21 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-07-30 03:26:59 +03:00
|
|
|
async setViewportSize(viewportSize: Size) {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.setViewportSize', async (channel: channels.PageChannel) => {
|
2020-07-17 00:32:21 +03:00
|
|
|
this._viewportSize = viewportSize;
|
2021-02-20 03:21:39 +03:00
|
|
|
await channel.setViewportSize({ viewportSize });
|
2020-07-17 00:32:21 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-07-30 03:26:59 +03:00
|
|
|
viewportSize(): Size | null {
|
2020-06-26 02:05:36 +03:00
|
|
|
return this._viewportSize;
|
|
|
|
}
|
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
async evaluate<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<R> {
|
2020-06-26 02:05:36 +03:00
|
|
|
assertMaxArguments(arguments.length, 2);
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.evaluate(pageFunction, arg));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any) {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.addInitScript', async (channel: channels.PageChannel) => {
|
2020-08-19 23:27:58 +03:00
|
|
|
const source = await evaluationScript(script, arg);
|
2021-02-20 03:21:39 +03:00
|
|
|
await channel.addInitScript({ source });
|
2020-07-17 00:32:21 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-07-30 03:26:59 +03:00
|
|
|
async route(url: URLMatch, handler: RouteHandler): Promise<void> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.route', async (channel: channels.PageChannel) => {
|
2020-07-17 00:32:21 +03:00
|
|
|
this._routes.push({ url, handler });
|
|
|
|
if (this._routes.length === 1)
|
2021-02-20 03:21:39 +03:00
|
|
|
await channel.setNetworkInterceptionEnabled({ enabled: true });
|
2020-07-17 00:32:21 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-07-30 03:26:59 +03:00
|
|
|
async unroute(url: URLMatch, handler?: RouteHandler): Promise<void> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.unroute', async (channel: channels.PageChannel) => {
|
2020-07-17 00:32:21 +03:00
|
|
|
this._routes = this._routes.filter(route => route.url !== url || (handler && route.handler !== handler));
|
|
|
|
if (this._routes.length === 0)
|
2021-02-20 03:21:39 +03:00
|
|
|
await channel.setNetworkInterceptionEnabled({ enabled: false });
|
2020-07-17 00:32:21 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async screenshot(options: channels.PageScreenshotOptions & { path?: string } = {}): Promise<Buffer> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.screenshot', async (channel: channels.PageChannel) => {
|
2020-10-27 10:02:35 +03:00
|
|
|
const copy = { ...options };
|
|
|
|
if (!copy.type)
|
|
|
|
copy.type = determineScreenshotType(options);
|
2021-02-20 03:21:39 +03:00
|
|
|
const result = await channel.screenshot(copy);
|
2020-08-19 04:46:56 +03:00
|
|
|
const buffer = Buffer.from(result.binary, 'base64');
|
2020-08-18 02:53:19 +03:00
|
|
|
if (options.path) {
|
|
|
|
await mkdirIfNeeded(options.path);
|
2021-06-03 19:55:33 +03:00
|
|
|
await fs.promises.writeFile(options.path, buffer);
|
2020-08-18 02:53:19 +03:00
|
|
|
}
|
2020-08-08 01:41:34 +03:00
|
|
|
return buffer;
|
2020-07-16 00:04:39 +03:00
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async title(): Promise<string> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.title());
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-07-21 19:36:54 +03:00
|
|
|
async bringToFront(): Promise<void> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.bringToFront', async (channel: channels.PageChannel) => {
|
|
|
|
await channel.bringToFront();
|
2020-07-21 19:36:54 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-06-26 02:05:36 +03:00
|
|
|
async close(options: { runBeforeUnload?: boolean } = {runBeforeUnload: undefined}) {
|
2020-10-01 07:17:30 +03:00
|
|
|
try {
|
2021-02-20 03:21:39 +03:00
|
|
|
await this._wrapApiCall('page.close', async (channel: channels.PageChannel) => {
|
|
|
|
await channel.close(options);
|
2020-10-01 07:17:30 +03:00
|
|
|
if (this._ownedContext)
|
|
|
|
await this._ownedContext.close();
|
|
|
|
});
|
|
|
|
} catch (e) {
|
|
|
|
if (isSafeCloseError(e))
|
|
|
|
return;
|
|
|
|
throw e;
|
|
|
|
}
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
isClosed(): boolean {
|
|
|
|
return this._closed;
|
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async click(selector: string, options?: channels.FrameClickOptions) {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.click(selector, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async dblclick(selector: string, options?: channels.FrameDblclickOptions) {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.dblclick(selector, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-10-19 20:07:33 +03:00
|
|
|
async tap(selector: string, options?: channels.FrameTapOptions) {
|
|
|
|
return this._attributeToPage(() => this._mainFrame.tap(selector, options));
|
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async fill(selector: string, value: string, options?: channels.FrameFillOptions) {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.fill(selector, value, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async focus(selector: string, options?: channels.FrameFocusOptions) {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.focus(selector, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async textContent(selector: string, options?: channels.FrameTextContentOptions): Promise<null|string> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.textContent(selector, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async innerText(selector: string, options?: channels.FrameInnerTextOptions): Promise<string> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.innerText(selector, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async innerHTML(selector: string, options?: channels.FrameInnerHTMLOptions): Promise<string> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.innerHTML(selector, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async getAttribute(selector: string, name: string, options?: channels.FrameGetAttributeOptions): Promise<string | null> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.getAttribute(selector, name, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2021-01-09 04:36:17 +03:00
|
|
|
async isChecked(selector: string, options?: channels.FrameIsCheckedOptions): Promise<boolean> {
|
|
|
|
return this._attributeToPage(() => this._mainFrame.isChecked(selector, options));
|
|
|
|
}
|
|
|
|
|
2021-01-08 23:27:54 +03:00
|
|
|
async isDisabled(selector: string, options?: channels.FrameIsDisabledOptions): Promise<boolean> {
|
|
|
|
return this._attributeToPage(() => this._mainFrame.isDisabled(selector, options));
|
|
|
|
}
|
|
|
|
|
|
|
|
async isEditable(selector: string, options?: channels.FrameIsEditableOptions): Promise<boolean> {
|
|
|
|
return this._attributeToPage(() => this._mainFrame.isEditable(selector, options));
|
|
|
|
}
|
|
|
|
|
|
|
|
async isEnabled(selector: string, options?: channels.FrameIsEnabledOptions): Promise<boolean> {
|
|
|
|
return this._attributeToPage(() => this._mainFrame.isEnabled(selector, options));
|
|
|
|
}
|
|
|
|
|
|
|
|
async isHidden(selector: string, options?: channels.FrameIsHiddenOptions): Promise<boolean> {
|
|
|
|
return this._attributeToPage(() => this._mainFrame.isHidden(selector, options));
|
|
|
|
}
|
|
|
|
|
|
|
|
async isVisible(selector: string, options?: channels.FrameIsVisibleOptions): Promise<boolean> {
|
|
|
|
return this._attributeToPage(() => this._mainFrame.isVisible(selector, options));
|
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async hover(selector: string, options?: channels.FrameHoverOptions) {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.hover(selector, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
async selectOption(selector: string, values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null, options?: SelectOptionOptions): Promise<string[]> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.selectOption(selector, values, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async setInputFiles(selector: string, files: string | FilePayload | string[] | FilePayload[], options?: channels.FrameSetInputFilesOptions): Promise<void> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.setInputFiles(selector, files, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async type(selector: string, text: string, options?: channels.FrameTypeOptions) {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.type(selector, text, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async press(selector: string, key: string, options?: channels.FramePressOptions) {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.press(selector, key, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async check(selector: string, options?: channels.FrameCheckOptions) {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.check(selector, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
async uncheck(selector: string, options?: channels.FrameUncheckOptions) {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.uncheck(selector, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async waitForTimeout(timeout: number) {
|
2021-01-22 17:49:59 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.waitForTimeout(timeout));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
async waitForFunction<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg, options?: WaitForFunctionOptions): Promise<structs.SmartHandle<R>> {
|
2020-06-30 04:58:09 +03:00
|
|
|
return this._attributeToPage(() => this._mainFrame.waitForFunction(pageFunction, arg, options));
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
workers(): Worker[] {
|
2020-06-30 20:55:11 +03:00
|
|
|
return [...this._workers];
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
on(event: string | symbol, listener: Listener): this {
|
2020-11-06 23:30:16 +03:00
|
|
|
if (event === Events.Page.FileChooser && !this.listenerCount(event))
|
|
|
|
this._channel.setFileChooserInterceptedNoReply({ intercepted: true });
|
2020-06-26 02:05:36 +03:00
|
|
|
super.on(event, listener);
|
|
|
|
return this;
|
2020-08-15 04:24:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
addListener(event: string | symbol, listener: Listener): this {
|
2020-11-06 23:30:16 +03:00
|
|
|
if (event === Events.Page.FileChooser && !this.listenerCount(event))
|
|
|
|
this._channel.setFileChooserInterceptedNoReply({ intercepted: true });
|
2020-08-15 04:24:36 +03:00
|
|
|
super.addListener(event, listener);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
off(event: string | symbol, listener: Listener): this {
|
|
|
|
super.off(event, listener);
|
|
|
|
if (event === Events.Page.FileChooser && !this.listenerCount(event))
|
|
|
|
this._channel.setFileChooserInterceptedNoReply({ intercepted: false });
|
|
|
|
return this;
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
removeListener(event: string | symbol, listener: Listener): this {
|
|
|
|
super.removeListener(event, listener);
|
|
|
|
if (event === Events.Page.FileChooser && !this.listenerCount(event))
|
|
|
|
this._channel.setFileChooserInterceptedNoReply({ intercepted: false });
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2021-02-04 03:01:51 +03:00
|
|
|
async pause() {
|
2021-02-20 05:12:33 +03:00
|
|
|
return this.context()._wrapApiCall('page.pause', async (channel: channels.BrowserContextChannel) => {
|
|
|
|
await channel.pause();
|
|
|
|
});
|
2021-01-23 05:47:02 +03:00
|
|
|
}
|
|
|
|
|
2021-04-02 04:47:14 +03:00
|
|
|
async pdf(options: PDFOptions = {}): Promise<Buffer> {
|
2021-02-20 03:21:39 +03:00
|
|
|
return this._wrapApiCall('page.pdf', async (channel: channels.PageChannel) => {
|
2021-01-22 17:49:59 +03:00
|
|
|
const transportOptions: channels.PagePdfParams = { ...options } as channels.PagePdfParams;
|
|
|
|
if (transportOptions.margin)
|
|
|
|
transportOptions.margin = { ...transportOptions.margin };
|
|
|
|
if (typeof options.width === 'number')
|
|
|
|
transportOptions.width = options.width + 'px';
|
|
|
|
if (typeof options.height === 'number')
|
|
|
|
transportOptions.height = options.height + 'px';
|
|
|
|
for (const margin of ['top', 'right', 'bottom', 'left']) {
|
|
|
|
const index = margin as 'top' | 'right' | 'bottom' | 'left';
|
|
|
|
if (options.margin && typeof options.margin[index] === 'number')
|
|
|
|
transportOptions.margin![index] = transportOptions.margin![index] + 'px';
|
|
|
|
}
|
2021-02-20 03:21:39 +03:00
|
|
|
const result = await channel.pdf(transportOptions);
|
2021-01-22 17:49:59 +03:00
|
|
|
const buffer = Buffer.from(result.pdf, 'base64');
|
|
|
|
if (options.path) {
|
2021-06-03 19:55:33 +03:00
|
|
|
await fs.promises.mkdir(path.dirname(options.path), { recursive: true });
|
|
|
|
await fs.promises.writeFile(options.path, buffer);
|
2021-01-22 17:49:59 +03:00
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
});
|
2020-06-26 02:05:36 +03:00
|
|
|
}
|
|
|
|
}
|
2020-06-26 21:51:47 +03:00
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
export class BindingCall extends ChannelOwner<channels.BindingCallChannel, channels.BindingCallInitializer> {
|
|
|
|
static from(channel: channels.BindingCallChannel): BindingCall {
|
2020-07-02 04:36:09 +03:00
|
|
|
return (channel as any)._object;
|
2020-06-26 21:51:47 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 03:05:16 +03:00
|
|
|
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.BindingCallInitializer) {
|
2020-07-11 04:00:10 +03:00
|
|
|
super(parent, type, guid, initializer);
|
2020-06-26 21:51:47 +03:00
|
|
|
}
|
|
|
|
|
2020-12-27 04:05:57 +03:00
|
|
|
async call(func: (source: structs.BindingSource, ...args: any[]) => any) {
|
2020-06-26 21:51:47 +03:00
|
|
|
try {
|
2020-06-26 22:28:27 +03:00
|
|
|
const frame = Frame.from(this._initializer.frame);
|
|
|
|
const source = {
|
2020-06-27 07:22:03 +03:00
|
|
|
context: frame._page!.context(),
|
2020-06-26 22:28:27 +03:00
|
|
|
page: frame._page!,
|
|
|
|
frame
|
|
|
|
};
|
2020-10-02 08:47:31 +03:00
|
|
|
let result: any;
|
|
|
|
if (this._initializer.handle)
|
|
|
|
result = await func(source, JSHandle.from(this._initializer.handle));
|
|
|
|
else
|
|
|
|
result = await func(source, ...this._initializer.args!.map(parseResult));
|
2020-12-03 21:51:59 +03:00
|
|
|
this._channel.resolve({ result: serializeArgument(result) }).catch(() => {});
|
2020-06-26 21:51:47 +03:00
|
|
|
} catch (e) {
|
2020-12-03 21:51:59 +03:00
|
|
|
this._channel.reject({ error: serializeError(e) }).catch(() => {});
|
2020-06-26 21:51:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-22 17:49:59 +03:00
|
|
|
|
2021-02-18 02:11:23 +03:00
|
|
|
function trimEnd(s: string): string {
|
|
|
|
if (s.length > 50)
|
|
|
|
s = s.substring(0, 50) + '\u2026';
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2021-01-22 17:49:59 +03:00
|
|
|
function trimUrl(param: any): string | undefined {
|
2021-02-18 02:11:23 +03:00
|
|
|
if (isRegExp(param))
|
|
|
|
return `/${trimEnd(param.source)}/${param.flags}`;
|
|
|
|
if (isString(param))
|
|
|
|
return `"${trimEnd(param)}"`;
|
2021-01-22 17:49:59 +03:00
|
|
|
}
|