chore: simplify logging a bit (#2512)
This merges a few classes and stops inheriting from InnerLogger.
This commit is contained in:
parent
492a65f9d3
commit
80705ff5e9
|
|
@ -20,7 +20,7 @@ import { EventEmitter } from 'events';
|
||||||
import { Download } from './download';
|
import { Download } from './download';
|
||||||
import type { BrowserServer } from './server/browserServer';
|
import type { BrowserServer } from './server/browserServer';
|
||||||
import { Events } from './events';
|
import { Events } from './events';
|
||||||
import { InnerLogger, Log } from './logger';
|
import { InnerLogger } from './logger';
|
||||||
import { ProxySettings } from './types';
|
import { ProxySettings } from './types';
|
||||||
|
|
||||||
export type BrowserOptions = {
|
export type BrowserOptions = {
|
||||||
|
|
@ -41,7 +41,7 @@ export interface Browser extends EventEmitter {
|
||||||
close(): Promise<void>;
|
close(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class BrowserBase extends EventEmitter implements Browser, InnerLogger {
|
export abstract class BrowserBase extends EventEmitter implements Browser {
|
||||||
readonly _options: BrowserOptions;
|
readonly _options: BrowserOptions;
|
||||||
private _downloads = new Map<string, Download>();
|
private _downloads = new Map<string, Download>();
|
||||||
_defaultContext: BrowserContextBase | null = null;
|
_defaultContext: BrowserContextBase | null = null;
|
||||||
|
|
@ -93,13 +93,5 @@ export abstract class BrowserBase extends EventEmitter implements Browser, Inner
|
||||||
if (this.isConnected())
|
if (this.isConnected())
|
||||||
await new Promise(x => this.once(Events.Browser.Disconnected, x));
|
await new Promise(x => this.once(Events.Browser.Disconnected, x));
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLogEnabled(log: Log): boolean {
|
|
||||||
return this._options.logger._isLogEnabled(log);
|
|
||||||
}
|
|
||||||
|
|
||||||
_log(log: Log, message: string | Error, ...args: any[]) {
|
|
||||||
return this._options.logger._log(log, message, ...args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import { Events } from './events';
|
||||||
import { ExtendedEventEmitter } from './extendedEventEmitter';
|
import { ExtendedEventEmitter } from './extendedEventEmitter';
|
||||||
import { Download } from './download';
|
import { Download } from './download';
|
||||||
import { BrowserBase } from './browser';
|
import { BrowserBase } from './browser';
|
||||||
import { Log, InnerLogger, Logger, RootLogger } from './logger';
|
import { InnerLogger, Logger } from './logger';
|
||||||
import { FunctionWithSource } from './frames';
|
import { FunctionWithSource } from './frames';
|
||||||
import * as debugSupport from './debug/debugSupport';
|
import * as debugSupport from './debug/debugSupport';
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ export type BrowserContextOptions = CommonContextOptions & {
|
||||||
logger?: Logger,
|
logger?: Logger,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface BrowserContext extends InnerLogger {
|
export interface BrowserContext {
|
||||||
setDefaultNavigationTimeout(timeout: number): void;
|
setDefaultNavigationTimeout(timeout: number): void;
|
||||||
setDefaultTimeout(timeout: number): void;
|
setDefaultTimeout(timeout: number): void;
|
||||||
pages(): Page[];
|
pages(): Page[];
|
||||||
|
|
@ -87,13 +87,13 @@ export abstract class BrowserContextBase extends ExtendedEventEmitter implements
|
||||||
readonly _permissions = new Map<string, string[]>();
|
readonly _permissions = new Map<string, string[]>();
|
||||||
readonly _downloads = new Set<Download>();
|
readonly _downloads = new Set<Download>();
|
||||||
readonly _browserBase: BrowserBase;
|
readonly _browserBase: BrowserBase;
|
||||||
private _logger: InnerLogger;
|
readonly _logger: InnerLogger;
|
||||||
|
|
||||||
constructor(browserBase: BrowserBase, options: BrowserContextOptions) {
|
constructor(browserBase: BrowserBase, options: BrowserContextOptions) {
|
||||||
super();
|
super();
|
||||||
this._browserBase = browserBase;
|
this._browserBase = browserBase;
|
||||||
this._options = options;
|
this._options = options;
|
||||||
this._logger = options.logger ? new RootLogger(options.logger) : browserBase;
|
this._logger = options.logger ? new InnerLogger(options.logger) : browserBase._options.logger;
|
||||||
this._closePromise = new Promise(fulfill => this._closePromiseFulfill = fulfill);
|
this._closePromise = new Promise(fulfill => this._closePromiseFulfill = fulfill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,14 +188,6 @@ export abstract class BrowserContextBase extends ExtendedEventEmitter implements
|
||||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLogEnabled(log: Log): boolean {
|
|
||||||
return this._logger._isLogEnabled(log);
|
|
||||||
}
|
|
||||||
|
|
||||||
_log(log: Log, message: string | Error, ...args: any[]) {
|
|
||||||
return this._logger._log(log, message, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
async _loadDefaultContext() {
|
async _loadDefaultContext() {
|
||||||
if (!this.pages().length)
|
if (!this.pages().length)
|
||||||
await this.waitForEvent('page');
|
await this.waitForEvent('page');
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ class CRServiceWorker extends Worker {
|
||||||
readonly _browserContext: CRBrowserContext;
|
readonly _browserContext: CRBrowserContext;
|
||||||
|
|
||||||
constructor(browserContext: CRBrowserContext, session: CRSession, url: string) {
|
constructor(browserContext: CRBrowserContext, session: CRSession, url: string) {
|
||||||
super(browserContext, url);
|
super(url);
|
||||||
this._browserContext = browserContext;
|
this._browserContext = browserContext;
|
||||||
session.once('Runtime.executionContextCreated', event => {
|
session.once('Runtime.executionContextCreated', event => {
|
||||||
this._createExecutionContext(new CRExecutionContext(session, event.context));
|
this._createExecutionContext(new CRExecutionContext(session, event.context));
|
||||||
|
|
|
||||||
|
|
@ -62,15 +62,15 @@ export class CRConnection extends EventEmitter {
|
||||||
const message: ProtocolRequest = { id, method, params };
|
const message: ProtocolRequest = { id, method, params };
|
||||||
if (sessionId)
|
if (sessionId)
|
||||||
message.sessionId = sessionId;
|
message.sessionId = sessionId;
|
||||||
if (this._logger._isLogEnabled(protocolLog))
|
if (this._logger.isLogEnabled(protocolLog))
|
||||||
this._logger._log(protocolLog, 'SEND ► ' + rewriteInjectedScriptEvaluationLog(message));
|
this._logger.log(protocolLog, 'SEND ► ' + rewriteInjectedScriptEvaluationLog(message));
|
||||||
this._transport.send(message);
|
this._transport.send(message);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onMessage(message: ProtocolResponse) {
|
async _onMessage(message: ProtocolResponse) {
|
||||||
if (this._logger._isLogEnabled(protocolLog))
|
if (this._logger.isLogEnabled(protocolLog))
|
||||||
this._logger._log(protocolLog, '◀ RECV ' + JSON.stringify(message));
|
this._logger.log(protocolLog, '◀ RECV ' + JSON.stringify(message));
|
||||||
if (message.id === kBrowserCloseMessageId)
|
if (message.id === kBrowserCloseMessageId)
|
||||||
return;
|
return;
|
||||||
if (message.method === 'Target.attachedToTarget') {
|
if (message.method === 'Target.attachedToTarget') {
|
||||||
|
|
@ -168,7 +168,7 @@ export class CRSession extends EventEmitter {
|
||||||
_sendMayFail<T extends keyof Protocol.CommandParameters>(method: T, params?: Protocol.CommandParameters[T]): Promise<Protocol.CommandReturnValues[T] | void> {
|
_sendMayFail<T extends keyof Protocol.CommandParameters>(method: T, params?: Protocol.CommandParameters[T]): Promise<Protocol.CommandReturnValues[T] | void> {
|
||||||
return this.send(method, params).catch(error => {
|
return this.send(method, params).catch(error => {
|
||||||
if (this._connection)
|
if (this._connection)
|
||||||
this._connection._logger._log(errorLog, error, []);
|
this._connection._logger.log(errorLog, error, []);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -566,7 +566,7 @@ class FrameSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = event.targetInfo.url;
|
const url = event.targetInfo.url;
|
||||||
const worker = new Worker(this._page, url);
|
const worker = new Worker(url);
|
||||||
this._page._addWorker(event.sessionId, worker);
|
this._page._addWorker(event.sessionId, worker);
|
||||||
session.once('Runtime.executionContextCreated', async event => {
|
session.once('Runtime.executionContextCreated', async event => {
|
||||||
worker._createExecutionContext(new CRExecutionContext(session, event.context));
|
worker._createExecutionContext(new CRExecutionContext(session, event.context));
|
||||||
|
|
|
||||||
42
src/dom.ts
42
src/dom.ts
|
|
@ -28,7 +28,7 @@ import { Page } from './page';
|
||||||
import { selectors } from './selectors';
|
import { selectors } from './selectors';
|
||||||
import * as types from './types';
|
import * as types from './types';
|
||||||
import { NotConnectedError } from './errors';
|
import { NotConnectedError } from './errors';
|
||||||
import { logError, apiLog } from './logger';
|
import { apiLog } from './logger';
|
||||||
import { Progress, runAbortableTask } from './progress';
|
import { Progress, runAbortableTask } from './progress';
|
||||||
|
|
||||||
export type PointerActionOptions = {
|
export type PointerActionOptions = {
|
||||||
|
|
@ -45,7 +45,7 @@ export class FrameExecutionContext extends js.ExecutionContext {
|
||||||
private _injectedPromise?: Promise<js.JSHandle>;
|
private _injectedPromise?: Promise<js.JSHandle>;
|
||||||
|
|
||||||
constructor(delegate: js.ExecutionContextDelegate, frame: frames.Frame) {
|
constructor(delegate: js.ExecutionContextDelegate, frame: frames.Frame) {
|
||||||
super(delegate, frame._page);
|
super(delegate);
|
||||||
this.frame = frame;
|
this.frame = frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,7 +234,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
private async _offsetPoint(offset: types.Point): Promise<types.Point | 'invisible'> {
|
private async _offsetPoint(offset: types.Point): Promise<types.Point | 'invisible'> {
|
||||||
const [box, border] = await Promise.all([
|
const [box, border] = await Promise.all([
|
||||||
this.boundingBox(),
|
this.boundingBox(),
|
||||||
this._evaluateInUtility(([injected, node]) => injected.getElementBorderWidth(node), {}).catch(logError(this._context._logger)),
|
this._evaluateInUtility(([injected, node]) => injected.getElementBorderWidth(node), {}).catch(e => {}),
|
||||||
]);
|
]);
|
||||||
if (!box || !border)
|
if (!box || !border)
|
||||||
return 'invisible';
|
return 'invisible';
|
||||||
|
|
@ -317,7 +317,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
hover(options: PointerActionOptions & types.PointerActionWaitOptions = {}): Promise<void> {
|
hover(options: PointerActionOptions & types.PointerActionWaitOptions = {}): Promise<void> {
|
||||||
return runAbortableTask(progress => this._hover(progress, options), this._page, this._page._timeoutSettings.timeout(options));
|
return runAbortableTask(progress => this._hover(progress, options), this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
_hover(progress: Progress, options: PointerActionOptions & types.PointerActionWaitOptions): Promise<void> {
|
_hover(progress: Progress, options: PointerActionOptions & types.PointerActionWaitOptions): Promise<void> {
|
||||||
|
|
@ -325,7 +325,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
click(options: ClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}): Promise<void> {
|
click(options: ClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||||
return runAbortableTask(progress => this._click(progress, options), this._page, this._page._timeoutSettings.timeout(options));
|
return runAbortableTask(progress => this._click(progress, options), this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
_click(progress: Progress, options: ClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<void> {
|
_click(progress: Progress, options: ClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<void> {
|
||||||
|
|
@ -333,7 +333,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
dblclick(options: MultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}): Promise<void> {
|
dblclick(options: MultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||||
return runAbortableTask(progress => this._dblclick(progress, options), this._page, this._page._timeoutSettings.timeout(options));
|
return runAbortableTask(progress => this._dblclick(progress, options), this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
_dblclick(progress: Progress, options: MultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<void> {
|
_dblclick(progress: Progress, options: MultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<void> {
|
||||||
|
|
@ -341,7 +341,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectOption(values: string | ElementHandle | types.SelectOption | string[] | ElementHandle[] | types.SelectOption[], options: types.NavigatingActionWaitOptions = {}): Promise<string[]> {
|
async selectOption(values: string | ElementHandle | types.SelectOption | string[] | ElementHandle[] | types.SelectOption[], options: types.NavigatingActionWaitOptions = {}): Promise<string[]> {
|
||||||
return runAbortableTask(progress => this._selectOption(progress, values, options), this._page, this._page._timeoutSettings.timeout(options));
|
return runAbortableTask(progress => this._selectOption(progress, values, options), this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _selectOption(progress: Progress, values: string | ElementHandle | types.SelectOption | string[] | ElementHandle[] | types.SelectOption[], options: types.NavigatingActionWaitOptions): Promise<string[]> {
|
async _selectOption(progress: Progress, values: string | ElementHandle | types.SelectOption | string[] | ElementHandle[] | types.SelectOption[], options: types.NavigatingActionWaitOptions): Promise<string[]> {
|
||||||
|
|
@ -368,7 +368,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fill(value: string, options: types.NavigatingActionWaitOptions = {}): Promise<void> {
|
async fill(value: string, options: types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||||
return runAbortableTask(progress => this._fill(progress, value, options), this._page, this._page._timeoutSettings.timeout(options));
|
return runAbortableTask(progress => this._fill(progress, value, options), this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _fill(progress: Progress, value: string, options: types.NavigatingActionWaitOptions): Promise<void> {
|
async _fill(progress: Progress, value: string, options: types.NavigatingActionWaitOptions): Promise<void> {
|
||||||
|
|
@ -391,13 +391,14 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectText(): Promise<void> {
|
async selectText(): Promise<void> {
|
||||||
this._page._log(apiLog, `elementHandle.selectText()`);
|
return runAbortableTask(async progress => {
|
||||||
const injectedResult = await this._evaluateInUtility(([injected, node]) => injected.selectText(node), {});
|
const injectedResult = await this._evaluateInUtility(([injected, node]) => injected.selectText(node), {});
|
||||||
handleInjectedResult(injectedResult);
|
handleInjectedResult(injectedResult);
|
||||||
|
}, this._page._logger, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setInputFiles(files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions = {}) {
|
async setInputFiles(files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions = {}) {
|
||||||
return runAbortableTask(async progress => this._setInputFiles(progress, files, options), this._page, this._page._timeoutSettings.timeout(options));
|
return runAbortableTask(async progress => this._setInputFiles(progress, files, options), this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _setInputFiles(progress: Progress, files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions) {
|
async _setInputFiles(progress: Progress, files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions) {
|
||||||
|
|
@ -435,31 +436,34 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async focus() {
|
async focus() {
|
||||||
this._page._log(apiLog, `elementHandle.focus()`);
|
return runAbortableTask(progress => this._focus(progress), this._page._logger, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _focus(progress: Progress) {
|
||||||
const injectedResult = await this._evaluateInUtility(([injected, node]) => injected.focusNode(node), {});
|
const injectedResult = await this._evaluateInUtility(([injected, node]) => injected.focusNode(node), {});
|
||||||
handleInjectedResult(injectedResult);
|
handleInjectedResult(injectedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
async type(text: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
async type(text: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
||||||
return runAbortableTask(progress => this._type(progress, text, options), this._page, this._page._timeoutSettings.timeout(options));
|
return runAbortableTask(progress => this._type(progress, text, options), this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _type(progress: Progress, text: string, options: { delay?: number } & types.NavigatingActionWaitOptions) {
|
async _type(progress: Progress, text: string, options: { delay?: number } & types.NavigatingActionWaitOptions) {
|
||||||
progress.log(apiLog, `elementHandle.type("${text}")`);
|
progress.log(apiLog, `elementHandle.type("${text}")`);
|
||||||
return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
||||||
await this.focus();
|
await this._focus(progress);
|
||||||
await this._page.keyboard.type(text, options);
|
await this._page.keyboard.type(text, options);
|
||||||
}, 'input');
|
}, 'input');
|
||||||
}
|
}
|
||||||
|
|
||||||
async press(key: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
async press(key: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
||||||
return runAbortableTask(progress => this._press(progress, key, options), this._page, this._page._timeoutSettings.timeout(options));
|
return runAbortableTask(progress => this._press(progress, key, options), this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _press(progress: Progress, key: string, options: { delay?: number } & types.NavigatingActionWaitOptions) {
|
async _press(progress: Progress, key: string, options: { delay?: number } & types.NavigatingActionWaitOptions) {
|
||||||
progress.log(apiLog, `elementHandle.press("${key}")`);
|
progress.log(apiLog, `elementHandle.press("${key}")`);
|
||||||
return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
||||||
await this.focus();
|
await this._focus(progress);
|
||||||
await this._page.keyboard.press(key, options);
|
await this._page.keyboard.press(key, options);
|
||||||
}, 'input');
|
}, 'input');
|
||||||
}
|
}
|
||||||
|
|
@ -468,14 +472,14 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return runAbortableTask(async progress => {
|
return runAbortableTask(async progress => {
|
||||||
progress.log(apiLog, `elementHandle.check()`);
|
progress.log(apiLog, `elementHandle.check()`);
|
||||||
await this._setChecked(progress, true, options);
|
await this._setChecked(progress, true, options);
|
||||||
}, this._page, this._page._timeoutSettings.timeout(options));
|
}, this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async uncheck(options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
async uncheck(options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||||
return runAbortableTask(async progress => {
|
return runAbortableTask(async progress => {
|
||||||
progress.log(apiLog, `elementHandle.uncheck()`);
|
progress.log(apiLog, `elementHandle.uncheck()`);
|
||||||
await this._setChecked(progress, false, options);
|
await this._setChecked(progress, false, options);
|
||||||
}, this._page, this._page._timeoutSettings.timeout(options));
|
}, this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _setChecked(progress: Progress, state: boolean, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions) {
|
async _setChecked(progress: Progress, state: boolean, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions) {
|
||||||
|
|
|
||||||
|
|
@ -79,14 +79,14 @@ export class FFConnection extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
_rawSend(message: ProtocolRequest) {
|
_rawSend(message: ProtocolRequest) {
|
||||||
if (this._logger._isLogEnabled(protocolLog))
|
if (this._logger.isLogEnabled(protocolLog))
|
||||||
this._logger._log(protocolLog, 'SEND ► ' + rewriteInjectedScriptEvaluationLog(message));
|
this._logger.log(protocolLog, 'SEND ► ' + rewriteInjectedScriptEvaluationLog(message));
|
||||||
this._transport.send(message);
|
this._transport.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onMessage(message: ProtocolResponse) {
|
async _onMessage(message: ProtocolResponse) {
|
||||||
if (this._logger._isLogEnabled(protocolLog))
|
if (this._logger.isLogEnabled(protocolLog))
|
||||||
this._logger._log(protocolLog, '◀ RECV ' + JSON.stringify(message));
|
this._logger.log(protocolLog, '◀ RECV ' + JSON.stringify(message));
|
||||||
if (message.id === kBrowserCloseMessageId)
|
if (message.id === kBrowserCloseMessageId)
|
||||||
return;
|
return;
|
||||||
if (message.sessionId) {
|
if (message.sessionId) {
|
||||||
|
|
@ -187,7 +187,7 @@ export class FFSession extends EventEmitter {
|
||||||
|
|
||||||
sendMayFail<T extends keyof Protocol.CommandParameters>(method: T, params?: Protocol.CommandParameters[T]): Promise<Protocol.CommandReturnValues[T] | void> {
|
sendMayFail<T extends keyof Protocol.CommandParameters>(method: T, params?: Protocol.CommandParameters[T]): Promise<Protocol.CommandReturnValues[T] | void> {
|
||||||
return this.send(method, params).catch(error => {
|
return this.send(method, params).catch(error => {
|
||||||
this._connection._logger._log(errorLog, error, []);
|
this._connection._logger.log(errorLog, error, []);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ export class FFPage implements PageDelegate {
|
||||||
|
|
||||||
async _onWorkerCreated(event: Protocol.Page.workerCreatedPayload) {
|
async _onWorkerCreated(event: Protocol.Page.workerCreatedPayload) {
|
||||||
const workerId = event.workerId;
|
const workerId = event.workerId;
|
||||||
const worker = new Worker(this._page, event.url);
|
const worker = new Worker(event.url);
|
||||||
const workerSession = new FFSession(this._session._connection, 'worker', workerId, (message: any) => {
|
const workerSession = new FFSession(this._session._connection, 'worker', workerId, (message: any) => {
|
||||||
this._session.send('Page.sendMessageToWorker', {
|
this._session.send('Page.sendMessageToWorker', {
|
||||||
frameId: event.frameId,
|
frameId: event.frameId,
|
||||||
|
|
|
||||||
|
|
@ -342,7 +342,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
async goto(url: string, options: GotoOptions = {}): Promise<network.Response | null> {
|
async goto(url: string, options: GotoOptions = {}): Promise<network.Response | null> {
|
||||||
const progressController = new ProgressController(this._page, this._page._timeoutSettings.navigationTimeout(options));
|
const progressController = new ProgressController(this._page._logger, this._page._timeoutSettings.navigationTimeout(options));
|
||||||
abortProgressOnFrameDetach(progressController, this);
|
abortProgressOnFrameDetach(progressController, this);
|
||||||
return progressController.run(async progress => {
|
return progressController.run(async progress => {
|
||||||
progress.log(apiLog, `navigating to "${url}", waiting until "${options.waitUntil || 'load'}"`);
|
progress.log(apiLog, `navigating to "${url}", waiting until "${options.waitUntil || 'load'}"`);
|
||||||
|
|
@ -377,7 +377,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForNavigation(options: types.WaitForNavigationOptions = {}): Promise<network.Response | null> {
|
async waitForNavigation(options: types.WaitForNavigationOptions = {}): Promise<network.Response | null> {
|
||||||
const progressController = new ProgressController(this._page, this._page._timeoutSettings.navigationTimeout(options));
|
const progressController = new ProgressController(this._page._logger, this._page._timeoutSettings.navigationTimeout(options));
|
||||||
abortProgressOnFrameDetach(progressController, this);
|
abortProgressOnFrameDetach(progressController, this);
|
||||||
return progressController.run(async progress => {
|
return progressController.run(async progress => {
|
||||||
const toUrl = typeof options.url === 'string' ? ` to "${options.url}"` : '';
|
const toUrl = typeof options.url === 'string' ? ` to "${options.url}"` : '';
|
||||||
|
|
@ -396,7 +396,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForLoadState(state: types.LifecycleEvent = 'load', options: types.TimeoutOptions = {}): Promise<void> {
|
async waitForLoadState(state: types.LifecycleEvent = 'load', options: types.TimeoutOptions = {}): Promise<void> {
|
||||||
const progressController = new ProgressController(this._page, this._page._timeoutSettings.navigationTimeout(options));
|
const progressController = new ProgressController(this._page._logger, this._page._timeoutSettings.navigationTimeout(options));
|
||||||
abortProgressOnFrameDetach(progressController, this);
|
abortProgressOnFrameDetach(progressController, this);
|
||||||
return progressController.run(progress => this._waitForLoadState(progress, state));
|
return progressController.run(progress => this._waitForLoadState(progress, state));
|
||||||
}
|
}
|
||||||
|
|
@ -469,7 +469,7 @@ export class Frame {
|
||||||
return adopted;
|
return adopted;
|
||||||
}
|
}
|
||||||
return handle;
|
return handle;
|
||||||
}, this._page, this._page._timeoutSettings.timeout(options));
|
}, this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async dispatchEvent(selector: string, type: string, eventInit?: Object, options: types.TimeoutOptions = {}): Promise<void> {
|
async dispatchEvent(selector: string, type: string, eventInit?: Object, options: types.TimeoutOptions = {}): Promise<void> {
|
||||||
|
|
@ -478,7 +478,7 @@ export class Frame {
|
||||||
progress.log(apiLog, `Dispatching "${type}" event on selector "${selector}"...`);
|
progress.log(apiLog, `Dispatching "${type}" event on selector "${selector}"...`);
|
||||||
const result = await this._scheduleRerunnableTask(progress, 'main', task);
|
const result = await this._scheduleRerunnableTask(progress, 'main', task);
|
||||||
result.dispose();
|
result.dispose();
|
||||||
}, this._page, this._page._timeoutSettings.timeout(options));
|
}, this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async $eval<R, Arg>(selector: string, pageFunction: types.FuncOn<Element, Arg, R>, arg: Arg): Promise<R>;
|
async $eval<R, Arg>(selector: string, pageFunction: types.FuncOn<Element, Arg, R>, arg: Arg): Promise<R>;
|
||||||
|
|
@ -520,7 +520,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
async setContent(html: string, options: types.NavigateOptions = {}): Promise<void> {
|
async setContent(html: string, options: types.NavigateOptions = {}): Promise<void> {
|
||||||
const progressController = new ProgressController(this._page, this._page._timeoutSettings.navigationTimeout(options));
|
const progressController = new ProgressController(this._page._logger, this._page._timeoutSettings.navigationTimeout(options));
|
||||||
abortProgressOnFrameDetach(progressController, this);
|
abortProgressOnFrameDetach(progressController, this);
|
||||||
return progressController.run(async progress => {
|
return progressController.run(async progress => {
|
||||||
const waitUntil = options.waitUntil === undefined ? 'load' : options.waitUntil;
|
const waitUntil = options.waitUntil === undefined ? 'load' : options.waitUntil;
|
||||||
|
|
@ -726,7 +726,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined as any;
|
return undefined as any;
|
||||||
}, this._page, this._page._timeoutSettings.timeout(options));
|
}, this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async click(selector: string, options: dom.ClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
async click(selector: string, options: dom.ClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||||
|
|
@ -742,7 +742,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
async focus(selector: string, options: types.TimeoutOptions = {}) {
|
async focus(selector: string, options: types.TimeoutOptions = {}) {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle.focus());
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._focus(progress));
|
||||||
}
|
}
|
||||||
|
|
||||||
async textContent(selector: string, options: types.TimeoutOptions = {}): Promise<null|string> {
|
async textContent(selector: string, options: types.TimeoutOptions = {}): Promise<null|string> {
|
||||||
|
|
@ -814,7 +814,7 @@ export class Frame {
|
||||||
};
|
};
|
||||||
return runAbortableTask(
|
return runAbortableTask(
|
||||||
progress => this._scheduleRerunnableTask(progress, 'main', task),
|
progress => this._scheduleRerunnableTask(progress, 'main', task),
|
||||||
this._page, this._page._timeoutSettings.timeout(options));
|
this._page._logger, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async title(): Promise<string> {
|
async title(): Promise<string> {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export function waitForTimeoutWasUsed(page: Page) {
|
||||||
if (waitForTimeoutWasUsedReported)
|
if (waitForTimeoutWasUsedReported)
|
||||||
return;
|
return;
|
||||||
waitForTimeoutWasUsedReported = true;
|
waitForTimeoutWasUsedReported = true;
|
||||||
page._log(hintsLog, `WARNING: page.waitForTimeout(timeout) should only be used for debugging.
|
page._logger.log(hintsLog, `WARNING: page.waitForTimeout(timeout) should only be used for debugging.
|
||||||
Tests using the timer in production are going to be flaky.
|
Tests using the timer in production are going to be flaky.
|
||||||
Use signals such as network events, selectors becoming visible, etc. instead.`);
|
Use signals such as network events, selectors becoming visible, etc. instead.`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
import * as types from './types';
|
import * as types from './types';
|
||||||
import * as dom from './dom';
|
import * as dom from './dom';
|
||||||
import * as utilityScriptSource from './generated/utilityScriptSource';
|
import * as utilityScriptSource from './generated/utilityScriptSource';
|
||||||
import { InnerLogger } from './logger';
|
|
||||||
import * as debugSupport from './debug/debugSupport';
|
import * as debugSupport from './debug/debugSupport';
|
||||||
import { serializeAsCallArgument } from './utilityScriptSerializers';
|
import { serializeAsCallArgument } from './utilityScriptSerializers';
|
||||||
import { helper } from './helper';
|
import { helper } from './helper';
|
||||||
|
|
@ -38,12 +37,10 @@ export interface ExecutionContextDelegate {
|
||||||
|
|
||||||
export class ExecutionContext {
|
export class ExecutionContext {
|
||||||
readonly _delegate: ExecutionContextDelegate;
|
readonly _delegate: ExecutionContextDelegate;
|
||||||
readonly _logger: InnerLogger;
|
|
||||||
private _utilityScriptPromise: Promise<JSHandle> | undefined;
|
private _utilityScriptPromise: Promise<JSHandle> | undefined;
|
||||||
|
|
||||||
constructor(delegate: ExecutionContextDelegate, logger: InnerLogger) {
|
constructor(delegate: ExecutionContextDelegate) {
|
||||||
this._delegate = delegate;
|
this._delegate = delegate;
|
||||||
this._logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
adoptIfNeeded(handle: JSHandle): Promise<JSHandle> | null {
|
adoptIfNeeded(handle: JSHandle): Promise<JSHandle> | null {
|
||||||
|
|
|
||||||
|
|
@ -29,34 +29,35 @@ export interface Logger {
|
||||||
log(name: string, severity: LoggerSeverity, message: string | Error, args: any[], hints: { color?: string }): void;
|
log(name: string, severity: LoggerSeverity, message: string | Error, args: any[], hints: { color?: string }): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InnerLogger {
|
|
||||||
_isLogEnabled(log: Log): boolean;
|
|
||||||
_log(log: Log, message: string | Error, ...args: any[]): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const errorLog: Log = { name: 'generic', severity: 'error' };
|
export const errorLog: Log = { name: 'generic', severity: 'error' };
|
||||||
export const apiLog: Log = { name: 'api', color: 'cyan' };
|
export const apiLog: Log = { name: 'api', color: 'cyan' };
|
||||||
|
|
||||||
export function logError(logger: InnerLogger): (error: Error) => void {
|
export function logError(logger: InnerLogger): (error: Error) => void {
|
||||||
return error => logger._log(errorLog, error, []);
|
return error => logger.log(errorLog, error, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RootLogger implements InnerLogger {
|
export class InnerLogger {
|
||||||
private _logger = new MultiplexingLogger();
|
private _userSink: Logger | undefined;
|
||||||
|
private _debugSink: DebugLogger;
|
||||||
|
|
||||||
constructor(userSink: Logger | undefined) {
|
constructor(userSink: Logger | undefined) {
|
||||||
if (userSink)
|
this._userSink = userSink;
|
||||||
this._logger.add('user', userSink);
|
this._debugSink = new DebugLogger();
|
||||||
this._logger.add('debug', new DebugLogger());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLogEnabled(log: Log): boolean {
|
isLogEnabled(log: Log): boolean {
|
||||||
return this._logger.isEnabled(log.name, log.severity || 'info');
|
const severity = log.severity || 'info';
|
||||||
|
if (this._userSink && this._userSink.isEnabled(log.name, severity))
|
||||||
|
return true;
|
||||||
|
return this._debugSink.isEnabled(log.name, severity);
|
||||||
}
|
}
|
||||||
|
|
||||||
_log(log: Log, message: string | Error, ...args: any[]) {
|
log(log: Log, message: string | Error, ...args: any[]) {
|
||||||
if (this._logger.isEnabled(log.name, log.severity || 'info'))
|
const severity = log.severity || 'info';
|
||||||
this._logger.log(log.name, log.severity || 'info', message, args, log.color ? { color: log.color } : {});
|
const hints = log.color ? { color: log.color } : {};
|
||||||
|
if (this._userSink && this._userSink.isEnabled(log.name, severity))
|
||||||
|
this._userSink.log(log.name, severity, message, args, hints);
|
||||||
|
this._debugSink.log(log.name, severity, message, args, hints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,36 +71,7 @@ const colorMap = new Map<string, number>([
|
||||||
['reset', 0],
|
['reset', 0],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
class MultiplexingLogger implements Logger {
|
class DebugLogger {
|
||||||
private _loggers = new Map<string, Logger>();
|
|
||||||
|
|
||||||
add(id: string, logger: Logger) {
|
|
||||||
this._loggers.set(id, logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
get(id: string): Logger | undefined {
|
|
||||||
return this._loggers.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(id: string) {
|
|
||||||
this._loggers.delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
isEnabled(name: string, severity: LoggerSeverity): boolean {
|
|
||||||
for (const logger of this._loggers.values()) {
|
|
||||||
if (logger.isEnabled(name, severity))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
log(name: string, severity: LoggerSeverity, message: string | Error, args: any[], hints: { color?: string }) {
|
|
||||||
for (const logger of this._loggers.values())
|
|
||||||
logger.log(name, severity, message, args, hints);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DebugLogger implements Logger {
|
|
||||||
private _debuggers = new Map<string, debug.IDebugger>();
|
private _debuggers = new Map<string, debug.IDebugger>();
|
||||||
|
|
||||||
isEnabled(name: string, severity: LoggerSeverity): boolean {
|
isEnabled(name: string, severity: LoggerSeverity): boolean {
|
||||||
|
|
|
||||||
24
src/page.ts
24
src/page.ts
|
|
@ -31,7 +31,7 @@ import * as accessibility from './accessibility';
|
||||||
import { ExtendedEventEmitter } from './extendedEventEmitter';
|
import { ExtendedEventEmitter } from './extendedEventEmitter';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { FileChooser } from './fileChooser';
|
import { FileChooser } from './fileChooser';
|
||||||
import { logError, InnerLogger, Log } from './logger';
|
import { logError, InnerLogger } from './logger';
|
||||||
|
|
||||||
export interface PageDelegate {
|
export interface PageDelegate {
|
||||||
readonly rawMouse: input.RawMouse;
|
readonly rawMouse: input.RawMouse;
|
||||||
|
|
@ -88,7 +88,7 @@ type PageState = {
|
||||||
extraHTTPHeaders: network.Headers | null;
|
extraHTTPHeaders: network.Headers | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Page extends ExtendedEventEmitter implements InnerLogger {
|
export class Page extends ExtendedEventEmitter {
|
||||||
private _closed = false;
|
private _closed = false;
|
||||||
private _closedCallback: () => void;
|
private _closedCallback: () => void;
|
||||||
private _closedPromise: Promise<void>;
|
private _closedPromise: Promise<void>;
|
||||||
|
|
@ -100,6 +100,7 @@ export class Page extends ExtendedEventEmitter implements InnerLogger {
|
||||||
readonly mouse: input.Mouse;
|
readonly mouse: input.Mouse;
|
||||||
readonly _timeoutSettings: TimeoutSettings;
|
readonly _timeoutSettings: TimeoutSettings;
|
||||||
readonly _delegate: PageDelegate;
|
readonly _delegate: PageDelegate;
|
||||||
|
readonly _logger: InnerLogger;
|
||||||
readonly _state: PageState;
|
readonly _state: PageState;
|
||||||
readonly _pageBindings = new Map<string, PageBinding>();
|
readonly _pageBindings = new Map<string, PageBinding>();
|
||||||
readonly _screenshotter: Screenshotter;
|
readonly _screenshotter: Screenshotter;
|
||||||
|
|
@ -114,6 +115,7 @@ export class Page extends ExtendedEventEmitter implements InnerLogger {
|
||||||
constructor(delegate: PageDelegate, browserContext: BrowserContextBase) {
|
constructor(delegate: PageDelegate, browserContext: BrowserContextBase) {
|
||||||
super();
|
super();
|
||||||
this._delegate = delegate;
|
this._delegate = delegate;
|
||||||
|
this._logger = browserContext._logger;
|
||||||
this._closedCallback = () => {};
|
this._closedCallback = () => {};
|
||||||
this._closedPromise = new Promise(f => this._closedCallback = f);
|
this._closedPromise = new Promise(f => this._closedCallback = f);
|
||||||
this._disconnectedCallback = () => {};
|
this._disconnectedCallback = () => {};
|
||||||
|
|
@ -141,7 +143,7 @@ export class Page extends ExtendedEventEmitter implements InnerLogger {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _getLogger(): InnerLogger {
|
protected _getLogger(): InnerLogger {
|
||||||
return this;
|
return this._logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _getTimeoutSettings(): TimeoutSettings {
|
protected _getTimeoutSettings(): TimeoutSettings {
|
||||||
|
|
@ -552,33 +554,23 @@ export class Page extends ExtendedEventEmitter implements InnerLogger {
|
||||||
this._delegate.setFileChooserIntercepted(false);
|
this._delegate.setFileChooserIntercepted(false);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLogEnabled(log: Log): boolean {
|
|
||||||
return this._browserContext._isLogEnabled(log);
|
|
||||||
}
|
|
||||||
|
|
||||||
_log(log: Log, message: string | Error, ...args: any[]) {
|
|
||||||
return this._browserContext._log(log, message, ...args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Worker extends EventEmitter {
|
export class Worker extends EventEmitter {
|
||||||
private _logger: InnerLogger;
|
|
||||||
private _url: string;
|
private _url: string;
|
||||||
private _executionContextPromise: Promise<js.ExecutionContext>;
|
private _executionContextPromise: Promise<js.ExecutionContext>;
|
||||||
private _executionContextCallback: (value?: js.ExecutionContext) => void;
|
private _executionContextCallback: (value?: js.ExecutionContext) => void;
|
||||||
_existingExecutionContext: js.ExecutionContext | null = null;
|
_existingExecutionContext: js.ExecutionContext | null = null;
|
||||||
|
|
||||||
constructor(logger: InnerLogger, url: string) {
|
constructor(url: string) {
|
||||||
super();
|
super();
|
||||||
this._logger = logger;
|
|
||||||
this._url = url;
|
this._url = url;
|
||||||
this._executionContextCallback = () => {};
|
this._executionContextCallback = () => {};
|
||||||
this._executionContextPromise = new Promise(x => this._executionContextCallback = x);
|
this._executionContextPromise = new Promise(x => this._executionContextCallback = x);
|
||||||
}
|
}
|
||||||
|
|
||||||
_createExecutionContext(delegate: js.ExecutionContextDelegate) {
|
_createExecutionContext(delegate: js.ExecutionContextDelegate) {
|
||||||
this._existingExecutionContext = new js.ExecutionContext(delegate, this._logger);
|
this._existingExecutionContext = new js.ExecutionContext(delegate);
|
||||||
this._executionContextCallback(this._existingExecutionContext);
|
this._executionContextCallback(this._existingExecutionContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -627,7 +619,7 @@ export class PageBinding {
|
||||||
else
|
else
|
||||||
expression = helper.evaluationString(deliverErrorValue, name, seq, error);
|
expression = helper.evaluationString(deliverErrorValue, name, seq, error);
|
||||||
}
|
}
|
||||||
context.evaluateInternal(expression).catch(logError(page));
|
context.evaluateInternal(expression).catch(logError(page._logger));
|
||||||
|
|
||||||
function deliverResult(name: string, seq: number, result: any) {
|
function deliverResult(name: string, seq: number, result: any) {
|
||||||
(window as any)[name]['callbacks'].get(seq).resolve(result);
|
(window as any)[name]['callbacks'].get(seq).resolve(result);
|
||||||
|
|
|
||||||
|
|
@ -84,13 +84,13 @@ export class ProgressController {
|
||||||
log: (log: Log, message: string | Error) => {
|
log: (log: Log, message: string | Error) => {
|
||||||
if (this._state === 'running') {
|
if (this._state === 'running') {
|
||||||
this._logRecording.push(message.toString());
|
this._logRecording.push(message.toString());
|
||||||
this._logger._log(log, ' ' + message);
|
this._logger.log(log, ' ' + message);
|
||||||
} else {
|
} else {
|
||||||
this._logger._log(log, message);
|
this._logger.log(log, message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this._logger._log(apiLog, `=> ${this._apiName} started`);
|
this._logger.log(apiLog, `=> ${this._apiName} started`);
|
||||||
|
|
||||||
const timeoutError = new TimeoutError(`Timeout ${this._timeout}ms exceeded during ${this._apiName}.`);
|
const timeoutError = new TimeoutError(`Timeout ${this._timeout}ms exceeded during ${this._apiName}.`);
|
||||||
const timer = setTimeout(() => this._forceAbort(timeoutError), progress.timeUntilDeadline());
|
const timer = setTimeout(() => this._forceAbort(timeoutError), progress.timeUntilDeadline());
|
||||||
|
|
@ -100,7 +100,7 @@ export class ProgressController {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
this._state = 'finished';
|
this._state = 'finished';
|
||||||
this._logRecording = [];
|
this._logRecording = [];
|
||||||
this._logger._log(apiLog, `<= ${this._apiName} succeeded`);
|
this._logger.log(apiLog, `<= ${this._apiName} succeeded`);
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._aborted();
|
this._aborted();
|
||||||
|
|
@ -108,7 +108,7 @@ export class ProgressController {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
this._state = 'aborted';
|
this._state = 'aborted';
|
||||||
this._logRecording = [];
|
this._logRecording = [];
|
||||||
this._logger._log(apiLog, `<= ${this._apiName} failed`);
|
this._logger.log(apiLog, `<= ${this._apiName} failed`);
|
||||||
await Promise.all(this._cleanups.splice(0).map(cleanup => runCleanup(cleanup)));
|
await Promise.all(this._cleanups.splice(0).map(cleanup => runCleanup(cleanup)));
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import * as util from 'util';
|
||||||
import { BrowserContext, PersistentContextOptions, verifyProxySettings, validateBrowserContextOptions } from '../browserContext';
|
import { BrowserContext, PersistentContextOptions, verifyProxySettings, validateBrowserContextOptions } from '../browserContext';
|
||||||
import { BrowserServer, WebSocketWrapper } from './browserServer';
|
import { BrowserServer, WebSocketWrapper } from './browserServer';
|
||||||
import * as browserPaths from '../install/browserPaths';
|
import * as browserPaths from '../install/browserPaths';
|
||||||
import { Logger, RootLogger, InnerLogger } from '../logger';
|
import { Logger, InnerLogger } from '../logger';
|
||||||
import { ConnectionTransport, WebSocketTransport } from '../transport';
|
import { ConnectionTransport, WebSocketTransport } from '../transport';
|
||||||
import { BrowserBase, BrowserOptions, Browser } from '../browser';
|
import { BrowserBase, BrowserOptions, Browser } from '../browser';
|
||||||
import { assert } from '../helper';
|
import { assert } from '../helper';
|
||||||
|
|
@ -108,7 +108,7 @@ export abstract class BrowserTypeBase implements BrowserType {
|
||||||
async launch(options: LaunchOptions = {}): Promise<Browser> {
|
async launch(options: LaunchOptions = {}): Promise<Browser> {
|
||||||
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
|
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
|
||||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||||
const logger = new RootLogger(options.logger);
|
const logger = new InnerLogger(options.logger);
|
||||||
const browser = await runAbortableTask(progress => this._innerLaunch(progress, options, logger, undefined), logger, TimeoutSettings.timeout(options));
|
const browser = await runAbortableTask(progress => this._innerLaunch(progress, options, logger, undefined), logger, TimeoutSettings.timeout(options));
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
@ -116,12 +116,12 @@ export abstract class BrowserTypeBase implements BrowserType {
|
||||||
async launchPersistentContext(userDataDir: string, options: LaunchOptions & PersistentContextOptions = {}): Promise<BrowserContext> {
|
async launchPersistentContext(userDataDir: string, options: LaunchOptions & PersistentContextOptions = {}): Promise<BrowserContext> {
|
||||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||||
const persistent = validateBrowserContextOptions(options);
|
const persistent = validateBrowserContextOptions(options);
|
||||||
const logger = new RootLogger(options.logger);
|
const logger = new InnerLogger(options.logger);
|
||||||
const browser = await runAbortableTask(progress => this._innerLaunch(progress, options, logger, persistent, userDataDir), logger, TimeoutSettings.timeout(options));
|
const browser = await runAbortableTask(progress => this._innerLaunch(progress, options, logger, persistent, userDataDir), logger, TimeoutSettings.timeout(options));
|
||||||
return browser._defaultContext!;
|
return browser._defaultContext!;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _innerLaunch(progress: Progress, options: LaunchOptions, logger: RootLogger, persistent: PersistentContextOptions | undefined, userDataDir?: string): Promise<BrowserBase> {
|
async _innerLaunch(progress: Progress, options: LaunchOptions, logger: InnerLogger, persistent: PersistentContextOptions | undefined, userDataDir?: string): Promise<BrowserBase> {
|
||||||
options.proxy = options.proxy ? verifyProxySettings(options.proxy) : undefined;
|
options.proxy = options.proxy ? verifyProxySettings(options.proxy) : undefined;
|
||||||
const { browserServer, downloadsPath, transport } = await this._launchServer(progress, options, !!persistent, logger, userDataDir);
|
const { browserServer, downloadsPath, transport } = await this._launchServer(progress, options, !!persistent, logger, userDataDir);
|
||||||
if ((options as any).__testHookBeforeCreateBrowser)
|
if ((options as any).__testHookBeforeCreateBrowser)
|
||||||
|
|
@ -147,7 +147,7 @@ export abstract class BrowserTypeBase implements BrowserType {
|
||||||
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> {
|
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> {
|
||||||
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launchServer`. Use `browserType.launchPersistentContext` instead');
|
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launchServer`. Use `browserType.launchPersistentContext` instead');
|
||||||
const { port = 0 } = options;
|
const { port = 0 } = options;
|
||||||
const logger = new RootLogger(options.logger);
|
const logger = new InnerLogger(options.logger);
|
||||||
return runAbortableTask(async progress => {
|
return runAbortableTask(async progress => {
|
||||||
const { browserServer, transport } = await this._launchServer(progress, options, false, logger);
|
const { browserServer, transport } = await this._launchServer(progress, options, false, logger);
|
||||||
browserServer._webSocketWrapper = this._wrapTransportWithWebSocket(transport, logger, port);
|
browserServer._webSocketWrapper = this._wrapTransportWithWebSocket(transport, logger, port);
|
||||||
|
|
@ -156,7 +156,7 @@ export abstract class BrowserTypeBase implements BrowserType {
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(options: ConnectOptions): Promise<Browser> {
|
async connect(options: ConnectOptions): Promise<Browser> {
|
||||||
const logger = new RootLogger(options.logger);
|
const logger = new InnerLogger(options.logger);
|
||||||
return runAbortableTask(async progress => {
|
return runAbortableTask(async progress => {
|
||||||
const transport = await WebSocketTransport.connect(progress, options.wsEndpoint);
|
const transport = await WebSocketTransport.connect(progress, options.wsEndpoint);
|
||||||
progress.cleanupWhenAborted(() => transport.closeAndWait());
|
progress.cleanupWhenAborted(() => transport.closeAndWait());
|
||||||
|
|
@ -167,7 +167,7 @@ export abstract class BrowserTypeBase implements BrowserType {
|
||||||
}, logger, TimeoutSettings.timeout(options));
|
}, logger, TimeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _launchServer(progress: Progress, options: LaunchServerOptions, isPersistent: boolean, logger: RootLogger, userDataDir?: string): Promise<{ browserServer: BrowserServer, downloadsPath: string, transport: ConnectionTransport }> {
|
private async _launchServer(progress: Progress, options: LaunchServerOptions, isPersistent: boolean, logger: InnerLogger, userDataDir?: string): Promise<{ browserServer: BrowserServer, downloadsPath: string, transport: ConnectionTransport }> {
|
||||||
const {
|
const {
|
||||||
ignoreDefaultArgs = false,
|
ignoreDefaultArgs = false,
|
||||||
args = [],
|
args = [],
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import { CRExecutionContext } from '../chromium/crExecutionContext';
|
||||||
import { Events } from '../events';
|
import { Events } from '../events';
|
||||||
import { ExtendedEventEmitter } from '../extendedEventEmitter';
|
import { ExtendedEventEmitter } from '../extendedEventEmitter';
|
||||||
import * as js from '../javascript';
|
import * as js from '../javascript';
|
||||||
import { InnerLogger, Logger, RootLogger } from '../logger';
|
import { InnerLogger, Logger } from '../logger';
|
||||||
import { Page } from '../page';
|
import { Page } from '../page';
|
||||||
import { TimeoutSettings } from '../timeoutSettings';
|
import { TimeoutSettings } from '../timeoutSettings';
|
||||||
import { WebSocketTransport } from '../transport';
|
import { WebSocketTransport } from '../transport';
|
||||||
|
|
@ -130,7 +130,7 @@ export class ElectronApplication extends ExtendedEventEmitter {
|
||||||
|
|
||||||
async _init() {
|
async _init() {
|
||||||
this._nodeSession.once('Runtime.executionContextCreated', event => {
|
this._nodeSession.once('Runtime.executionContextCreated', event => {
|
||||||
this._nodeExecutionContext = new js.ExecutionContext(new CRExecutionContext(this._nodeSession, event.context), this._logger);
|
this._nodeExecutionContext = new js.ExecutionContext(new CRExecutionContext(this._nodeSession, event.context));
|
||||||
});
|
});
|
||||||
await this._nodeSession.send('Runtime.enable', {}).catch(e => {});
|
await this._nodeSession.send('Runtime.enable', {}).catch(e => {});
|
||||||
this._nodeElectronHandle = await js.evaluate(this._nodeExecutionContext!, false /* returnByValue */, () => {
|
this._nodeElectronHandle = await js.evaluate(this._nodeExecutionContext!, false /* returnByValue */, () => {
|
||||||
|
|
@ -171,7 +171,7 @@ export class Electron {
|
||||||
handleSIGTERM = true,
|
handleSIGTERM = true,
|
||||||
handleSIGHUP = true,
|
handleSIGHUP = true,
|
||||||
} = options;
|
} = options;
|
||||||
const logger = new RootLogger(options.logger);
|
const logger = new InnerLogger(options.logger);
|
||||||
return runAbortableTask(async progress => {
|
return runAbortableTask(async progress => {
|
||||||
let app: ElectronApplication | undefined = undefined;
|
let app: ElectronApplication | undefined = undefined;
|
||||||
const electronArguments = ['--inspect=0', '--remote-debugging-port=0', '--require', path.join(__dirname, 'electronLoader.js'), ...args];
|
const electronArguments = ['--inspect=0', '--remote-debugging-port=0', '--require', path.join(__dirname, 'electronLoader.js'), ...args];
|
||||||
|
|
|
||||||
|
|
@ -55,14 +55,14 @@ export class WKConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
rawSend(message: ProtocolRequest) {
|
rawSend(message: ProtocolRequest) {
|
||||||
if (this._logger._isLogEnabled(protocolLog))
|
if (this._logger.isLogEnabled(protocolLog))
|
||||||
this._logger._log(protocolLog, 'SEND ► ' + rewriteInjectedScriptEvaluationLog(message));
|
this._logger.log(protocolLog, 'SEND ► ' + rewriteInjectedScriptEvaluationLog(message));
|
||||||
this._transport.send(message);
|
this._transport.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _dispatchMessage(message: ProtocolResponse) {
|
private _dispatchMessage(message: ProtocolResponse) {
|
||||||
if (this._logger._isLogEnabled(protocolLog))
|
if (this._logger.isLogEnabled(protocolLog))
|
||||||
this._logger._log(protocolLog, '◀ RECV ' + JSON.stringify(message));
|
this._logger.log(protocolLog, '◀ RECV ' + JSON.stringify(message));
|
||||||
if (message.id === kBrowserCloseMessageId)
|
if (message.id === kBrowserCloseMessageId)
|
||||||
return;
|
return;
|
||||||
if (message.pageProxyId) {
|
if (message.pageProxyId) {
|
||||||
|
|
@ -139,7 +139,7 @@ export class WKSession extends EventEmitter {
|
||||||
|
|
||||||
sendMayFail<T extends keyof Protocol.CommandParameters>(method: T, params?: Protocol.CommandParameters[T]): Promise<Protocol.CommandReturnValues[T] | void> {
|
sendMayFail<T extends keyof Protocol.CommandParameters>(method: T, params?: Protocol.CommandParameters[T]): Promise<Protocol.CommandReturnValues[T] | void> {
|
||||||
return this.send(method, params).catch(error => {
|
return this.send(method, params).catch(error => {
|
||||||
this.connection._logger._log(errorLog, error, []);
|
this.connection._logger.log(errorLog, error, []);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ import { selectors } from '../selectors';
|
||||||
import * as jpeg from 'jpeg-js';
|
import * as jpeg from 'jpeg-js';
|
||||||
import * as png from 'pngjs';
|
import * as png from 'pngjs';
|
||||||
import { NotConnectedError } from '../errors';
|
import { NotConnectedError } from '../errors';
|
||||||
import { logError } from '../logger';
|
|
||||||
import { ConsoleMessageLocation } from '../console';
|
import { ConsoleMessageLocation } from '../console';
|
||||||
import { JSHandle } from '../javascript';
|
import { JSHandle } from '../javascript';
|
||||||
|
|
||||||
|
|
@ -364,7 +363,7 @@ export class WKPage implements PageDelegate {
|
||||||
// as well to always be in sync with the backend.
|
// as well to always be in sync with the backend.
|
||||||
if (this._provisionalPage)
|
if (this._provisionalPage)
|
||||||
sessions.push(this._provisionalPage._session);
|
sessions.push(this._provisionalPage._session);
|
||||||
await Promise.all(sessions.map(session => callback(session).catch(logError(this._page))));
|
await Promise.all(sessions.map(session => callback(session).catch(e => {})));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onFrameScheduledNavigation(frameId: string) {
|
private _onFrameScheduledNavigation(frameId: string) {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export class WKWorkers {
|
||||||
this.clear();
|
this.clear();
|
||||||
this._sessionListeners = [
|
this._sessionListeners = [
|
||||||
helper.addEventListener(session, 'Worker.workerCreated', (event: Protocol.Worker.workerCreatedPayload) => {
|
helper.addEventListener(session, 'Worker.workerCreated', (event: Protocol.Worker.workerCreatedPayload) => {
|
||||||
const worker = new Worker(this._page, event.url);
|
const worker = new Worker(event.url);
|
||||||
const workerSession = new WKSession(session.connection, event.workerId, 'Most likely the worker has been closed.', (message: any) => {
|
const workerSession = new WKSession(session.connection, event.workerId, 'Most likely the worker has been closed.', (message: any) => {
|
||||||
session.send('Worker.sendMessageToWorker', {
|
session.send('Worker.sendMessageToWorker', {
|
||||||
workerId: event.workerId,
|
workerId: event.workerId,
|
||||||
|
|
|
||||||
|
|
@ -426,3 +426,13 @@ describe('ElementHandle.selectOption', function() {
|
||||||
expect(await page.evaluate(() => result.onChange)).toEqual(['blue']);
|
expect(await page.evaluate(() => result.onChange)).toEqual(['blue']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('ElementHandle.focus', function() {
|
||||||
|
it('should focus a button', async({page, server}) => {
|
||||||
|
await page.goto(server.PREFIX + '/input/button.html');
|
||||||
|
const button = await page.$('button');
|
||||||
|
expect(await button.evaluate(button => document.activeElement === button)).toBe(false);
|
||||||
|
await button.focus();
|
||||||
|
expect(await button.evaluate(button => document.activeElement === button)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue