mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-15 14:11:50 +03:00
chore: introduce session.sendMayFail to ease error logging (#2480)
This commit is contained in:
parent
fc2432a23a
commit
c08da50bb3
@ -29,7 +29,6 @@ import { readProtocolStream } from './crProtocolHelper';
|
||||
import { Events } from './events';
|
||||
import { Protocol } from './protocol';
|
||||
import { CRExecutionContext } from './crExecutionContext';
|
||||
import { logError } from '../logger';
|
||||
import { CRDevTools } from '../debug/crDevTools';
|
||||
|
||||
export class CRBrowser extends BrowserBase {
|
||||
@ -133,8 +132,8 @@ export class CRBrowser extends BrowserBase {
|
||||
if (targetInfo.type === 'other' || !context) {
|
||||
if (waitingForDebugger) {
|
||||
// Ideally, detaching should resume any target, but there is a bug in the backend.
|
||||
session.send('Runtime.runIfWaitingForDebugger').catch(logError(this)).then(() => {
|
||||
this._session.send('Target.detachFromTarget', { sessionId }).catch(logError(this));
|
||||
session._sendMayFail('Runtime.runIfWaitingForDebugger').then(() => {
|
||||
this._session._sendMayFail('Target.detachFromTarget', { sessionId });
|
||||
});
|
||||
}
|
||||
return;
|
||||
|
@ -19,7 +19,7 @@ import { assert } from '../helper';
|
||||
import { ConnectionTransport, ProtocolRequest, ProtocolResponse, protocolLog } from '../transport';
|
||||
import { Protocol } from './protocol';
|
||||
import { EventEmitter } from 'events';
|
||||
import { InnerLogger } from '../logger';
|
||||
import { InnerLogger, errorLog } from '../logger';
|
||||
import { rewriteErrorMessage } from '../debug/stackTrace';
|
||||
|
||||
export const ConnectionEvents = {
|
||||
@ -36,7 +36,7 @@ export class CRConnection extends EventEmitter {
|
||||
private readonly _sessions = new Map<string, CRSession>();
|
||||
readonly rootSession: CRSession;
|
||||
_closed = false;
|
||||
private _logger: InnerLogger;
|
||||
readonly _logger: InnerLogger;
|
||||
|
||||
constructor(transport: ConnectionTransport, logger: InnerLogger) {
|
||||
super();
|
||||
@ -165,6 +165,13 @@ export class CRSession extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
_sendMayFail<T extends keyof Protocol.CommandParameters>(method: T, params?: Protocol.CommandParameters[T]): Promise<Protocol.CommandReturnValues[T] | void> {
|
||||
return this.send(method, params).catch(error => {
|
||||
if (this._connection)
|
||||
this._connection._logger._log(errorLog, error, []);
|
||||
});
|
||||
}
|
||||
|
||||
_onMessage(object: ProtocolResponse) {
|
||||
if (object.id && this._callbacks.has(object.id)) {
|
||||
const callback = this._callbacks.get(object.id)!;
|
||||
|
@ -20,7 +20,6 @@ import { assert, helper, RegisteredListener } from '../helper';
|
||||
import { Protocol } from './protocol';
|
||||
import * as types from '../types';
|
||||
import * as debugSupport from '../debug/debugSupport';
|
||||
import { logError, InnerLogger } from '../logger';
|
||||
|
||||
type JSRange = {
|
||||
startOffset: number,
|
||||
@ -50,9 +49,9 @@ export class CRCoverage {
|
||||
private _jsCoverage: JSCoverage;
|
||||
private _cssCoverage: CSSCoverage;
|
||||
|
||||
constructor(client: CRSession, logger: InnerLogger) {
|
||||
this._jsCoverage = new JSCoverage(client, logger);
|
||||
this._cssCoverage = new CSSCoverage(client, logger);
|
||||
constructor(client: CRSession) {
|
||||
this._jsCoverage = new JSCoverage(client);
|
||||
this._cssCoverage = new CSSCoverage(client);
|
||||
}
|
||||
|
||||
async startJSCoverage(options?: types.JSCoverageOptions) {
|
||||
@ -80,11 +79,9 @@ class JSCoverage {
|
||||
_eventListeners: RegisteredListener[];
|
||||
_resetOnNavigation: boolean;
|
||||
_reportAnonymousScripts = false;
|
||||
private _logger: InnerLogger;
|
||||
|
||||
constructor(client: CRSession, logger: InnerLogger) {
|
||||
constructor(client: CRSession) {
|
||||
this._client = client;
|
||||
this._logger = logger;
|
||||
this._enabled = false;
|
||||
this._scriptIds = new Set();
|
||||
this._scriptSources = new Map();
|
||||
@ -131,13 +128,10 @@ class JSCoverage {
|
||||
// Ignore other anonymous scripts unless the reportAnonymousScripts option is true.
|
||||
if (!event.url && !this._reportAnonymousScripts)
|
||||
return;
|
||||
try {
|
||||
const response = await this._client.send('Debugger.getScriptSource', {scriptId: event.scriptId});
|
||||
// This might fail if the page has already navigated away.
|
||||
const response = await this._client._sendMayFail('Debugger.getScriptSource', {scriptId: event.scriptId});
|
||||
if (response)
|
||||
this._scriptSources.set(event.scriptId, response.scriptSource);
|
||||
} catch (e) {
|
||||
// This might happen if the page has already navigated away.
|
||||
logError(this._logger)(e);
|
||||
}
|
||||
}
|
||||
|
||||
async stop(): Promise<JSCoverageEntry[]> {
|
||||
@ -174,11 +168,9 @@ class CSSCoverage {
|
||||
_stylesheetSources: Map<string, string>;
|
||||
_eventListeners: RegisteredListener[];
|
||||
_resetOnNavigation: boolean;
|
||||
private _logger: InnerLogger;
|
||||
|
||||
constructor(client: CRSession, logger: InnerLogger) {
|
||||
constructor(client: CRSession) {
|
||||
this._client = client;
|
||||
this._logger = logger;
|
||||
this._enabled = false;
|
||||
this._stylesheetURLs = new Map();
|
||||
this._stylesheetSources = new Map();
|
||||
@ -216,13 +208,11 @@ class CSSCoverage {
|
||||
// Ignore anonymous scripts
|
||||
if (!header.sourceURL)
|
||||
return;
|
||||
try {
|
||||
const response = await this._client.send('CSS.getStyleSheetText', {styleSheetId: header.styleSheetId});
|
||||
// This might fail if the page has already navigated away.
|
||||
const response = await this._client._sendMayFail('CSS.getStyleSheetText', {styleSheetId: header.styleSheetId});
|
||||
if (response) {
|
||||
this._stylesheetURLs.set(header.styleSheetId, header.sourceURL);
|
||||
this._stylesheetSources.set(header.styleSheetId, response.text);
|
||||
} catch (e) {
|
||||
// This might happen if the page has already navigated away.
|
||||
logError(this._logger)(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@ import * as network from '../network';
|
||||
import * as frames from '../frames';
|
||||
import { Credentials } from '../types';
|
||||
import { CRPage } from './crPage';
|
||||
import { logError } from '../logger';
|
||||
|
||||
export class CRNetworkManager {
|
||||
private _client: CRSession;
|
||||
@ -130,26 +129,26 @@ export class CRNetworkManager {
|
||||
this._attemptedAuthentications.add(event.requestId);
|
||||
}
|
||||
const {username, password} = this._credentials || {username: undefined, password: undefined};
|
||||
this._client.send('Fetch.continueWithAuth', {
|
||||
this._client._sendMayFail('Fetch.continueWithAuth', {
|
||||
requestId: event.requestId,
|
||||
authChallengeResponse: { response, username, password },
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
}
|
||||
|
||||
_onRequestPaused(workerFrame: frames.Frame | undefined, event: Protocol.Fetch.requestPausedPayload) {
|
||||
if (!this._userRequestInterceptionEnabled && this._protocolRequestInterceptionEnabled) {
|
||||
this._client.send('Fetch.continueRequest', {
|
||||
this._client._sendMayFail('Fetch.continueRequest', {
|
||||
requestId: event.requestId
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
}
|
||||
if (!event.networkId) {
|
||||
// Fetch without networkId means that request was not recongnized by inspector, and
|
||||
// it will never receive Network.requestWillBeSent. Most likely, this is an internal request
|
||||
// that we can safely fail.
|
||||
this._client.send('Fetch.failRequest', {
|
||||
this._client._sendMayFail('Fetch.failRequest', {
|
||||
requestId: event.requestId,
|
||||
errorReason: 'Aborted',
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (event.request.url.startsWith('data:'))
|
||||
@ -189,7 +188,7 @@ export class CRNetworkManager {
|
||||
|
||||
if (!frame) {
|
||||
if (requestPausedEvent)
|
||||
this._client.send('Fetch.continueRequest', { requestId: requestPausedEvent.requestId }).catch(logError(this._page));
|
||||
this._client._sendMayFail('Fetch.continueRequest', { requestId: requestPausedEvent.requestId });
|
||||
return;
|
||||
}
|
||||
const isNavigationRequest = requestWillBeSentEvent.requestId === requestWillBeSentEvent.loaderId && requestWillBeSentEvent.type === 'Document';
|
||||
@ -325,15 +324,13 @@ class InterceptableRequest implements network.RouteDelegate {
|
||||
}
|
||||
|
||||
async continue(overrides: { method?: string; headers?: network.Headers; postData?: string } = {}) {
|
||||
await this._client.send('Fetch.continueRequest', {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
await this._client._sendMayFail('Fetch.continueRequest', {
|
||||
requestId: this._interceptionId!,
|
||||
headers: overrides.headers ? headersArray(overrides.headers) : undefined,
|
||||
method: overrides.method,
|
||||
postData: overrides.postData
|
||||
}).catch(error => {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
logError(this.request._page)(error);
|
||||
});
|
||||
}
|
||||
|
||||
@ -350,29 +347,25 @@ class InterceptableRequest implements network.RouteDelegate {
|
||||
if (responseBody && !('content-length' in responseHeaders))
|
||||
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
|
||||
|
||||
await this._client.send('Fetch.fulfillRequest', {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
await this._client._sendMayFail('Fetch.fulfillRequest', {
|
||||
requestId: this._interceptionId!,
|
||||
responseCode: response.status || 200,
|
||||
responsePhrase: network.STATUS_TEXTS[String(response.status || 200)],
|
||||
responseHeaders: headersArray(responseHeaders),
|
||||
body: responseBody ? responseBody.toString('base64') : undefined,
|
||||
}).catch(error => {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
logError(this.request._page)(error);
|
||||
});
|
||||
}
|
||||
|
||||
async abort(errorCode: string = 'failed') {
|
||||
const errorReason = errorReasons[errorCode];
|
||||
assert(errorReason, 'Unknown error code: ' + errorCode);
|
||||
await this._client.send('Fetch.failRequest', {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
await this._client._sendMayFail('Fetch.failRequest', {
|
||||
requestId: this._interceptionId!,
|
||||
errorReason
|
||||
}).catch(error => {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
logError(this.request._page)(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ import { CRBrowserContext } from './crBrowser';
|
||||
import * as types from '../types';
|
||||
import { ConsoleMessage } from '../console';
|
||||
import { NotConnectedError } from '../errors';
|
||||
import { logError } from '../logger';
|
||||
import * as debugSupport from '../debug/debugSupport';
|
||||
import { rewriteErrorMessage } from '../debug/stackTrace';
|
||||
|
||||
@ -70,7 +69,7 @@ export class CRPage implements PageDelegate {
|
||||
this.rawKeyboard = new RawKeyboardImpl(client);
|
||||
this.rawMouse = new RawMouseImpl(client);
|
||||
this._pdf = new CRPDF(client);
|
||||
this._coverage = new CRCoverage(client, browserContext);
|
||||
this._coverage = new CRCoverage(client);
|
||||
this._browserContext = browserContext;
|
||||
this._page = new Page(this, browserContext);
|
||||
this._mainFrameSession = new FrameSession(this, client, targetId, null);
|
||||
@ -121,7 +120,7 @@ export class CRPage implements PageDelegate {
|
||||
|
||||
async exposeBinding(binding: PageBinding) {
|
||||
await this._forAllFrameSessions(frame => frame._initBinding(binding));
|
||||
await Promise.all(this._page.frames().map(frame => frame.evaluate(binding.source).catch(logError(this._page))));
|
||||
await Promise.all(this._page.frames().map(frame => frame.evaluate(binding.source).catch(e => {})));
|
||||
}
|
||||
|
||||
async updateExtraHTTPHeaders(): Promise<void> {
|
||||
@ -384,13 +383,13 @@ class FrameSession {
|
||||
const localFrames = this._isMainFrame() ? this._page.frames() : [ this._page._frameManager.frame(this._targetId)! ];
|
||||
for (const frame of localFrames) {
|
||||
// Note: frames might be removed before we send these.
|
||||
this._client.send('Page.createIsolatedWorld', {
|
||||
this._client._sendMayFail('Page.createIsolatedWorld', {
|
||||
frameId: frame._id,
|
||||
grantUniveralAccess: true,
|
||||
worldName: UTILITY_WORLD_NAME,
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
for (const binding of this._crPage._browserContext._pageBindings.values())
|
||||
frame.evaluate(binding.source).catch(logError(this._page));
|
||||
frame.evaluate(binding.source).catch(e => {});
|
||||
}
|
||||
const isInitialEmptyPage = this._isMainFrame() && this._page.mainFrame().url() === ':';
|
||||
if (isInitialEmptyPage) {
|
||||
@ -560,8 +559,8 @@ class FrameSession {
|
||||
|
||||
if (event.targetInfo.type !== 'worker') {
|
||||
// Ideally, detaching should resume any target, but there is a bug in the backend.
|
||||
session.send('Runtime.runIfWaitingForDebugger').catch(logError(this._page)).then(() => {
|
||||
this._client.send('Target.detachFromTarget', { sessionId: event.sessionId }).catch(logError(this._page));
|
||||
session._sendMayFail('Runtime.runIfWaitingForDebugger').then(() => {
|
||||
this._client._sendMayFail('Target.detachFromTarget', { sessionId: event.sessionId });
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -573,10 +572,10 @@ class FrameSession {
|
||||
worker._createExecutionContext(new CRExecutionContext(session, event.context));
|
||||
});
|
||||
Promise.all([
|
||||
session.send('Runtime.enable'),
|
||||
session.send('Network.enable'),
|
||||
session.send('Runtime.runIfWaitingForDebugger'),
|
||||
]).catch(logError(this._page)); // This might fail if the target is closed before we initialize.
|
||||
session._sendMayFail('Runtime.enable'),
|
||||
session._sendMayFail('Network.enable'),
|
||||
session._sendMayFail('Runtime.runIfWaitingForDebugger'),
|
||||
]); // This might fail if the target is closed before we initialize.
|
||||
session.on('Runtime.consoleAPICalled', event => {
|
||||
const args = event.args.map(o => worker._existingExecutionContext!.createHandle(o));
|
||||
this._page._addConsoleMessage(event.type, args, toConsoleMessageLocation(event.stackTrace));
|
||||
@ -816,9 +815,9 @@ class FrameSession {
|
||||
}
|
||||
|
||||
async _getBoundingBox(handle: dom.ElementHandle): Promise<types.Rect | null> {
|
||||
const result = await this._client.send('DOM.getBoxModel', {
|
||||
const result = await this._client._sendMayFail('DOM.getBoxModel', {
|
||||
objectId: handle._objectId
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
if (!result)
|
||||
return null;
|
||||
const quad = result.model.border;
|
||||
@ -843,9 +842,9 @@ class FrameSession {
|
||||
}
|
||||
|
||||
async _getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null> {
|
||||
const result = await this._client.send('DOM.getContentQuads', {
|
||||
const result = await this._client._sendMayFail('DOM.getContentQuads', {
|
||||
objectId: handle._objectId
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
if (!result)
|
||||
return null;
|
||||
return result.quads.map(quad => [
|
||||
@ -864,10 +863,10 @@ class FrameSession {
|
||||
}
|
||||
|
||||
async _adoptBackendNodeId(backendNodeId: Protocol.DOM.BackendNodeId, to: dom.FrameExecutionContext): Promise<dom.ElementHandle> {
|
||||
const result = await this._client.send('DOM.resolveNode', {
|
||||
const result = await this._client._sendMayFail('DOM.resolveNode', {
|
||||
backendNodeId,
|
||||
executionContextId: (to._delegate as CRExecutionContext)._contextId,
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
if (!result || result.object.subtype === 'null')
|
||||
throw new Error('Unable to adopt element handle from a different document');
|
||||
return to.createHandle(result.object).asElement()!;
|
||||
|
@ -19,7 +19,7 @@ import { EventEmitter } from 'events';
|
||||
import { assert } from '../helper';
|
||||
import { ConnectionTransport, ProtocolRequest, ProtocolResponse, protocolLog } from '../transport';
|
||||
import { Protocol } from './protocol';
|
||||
import { InnerLogger } from '../logger';
|
||||
import { InnerLogger, errorLog } from '../logger';
|
||||
import { rewriteErrorMessage } from '../debug/stackTrace';
|
||||
|
||||
export const ConnectionEvents = {
|
||||
@ -34,7 +34,7 @@ export class FFConnection extends EventEmitter {
|
||||
private _lastId: number;
|
||||
private _callbacks: Map<number, {resolve: Function, reject: Function, error: Error, method: string}>;
|
||||
private _transport: ConnectionTransport;
|
||||
private _logger: InnerLogger;
|
||||
readonly _logger: InnerLogger;
|
||||
readonly _sessions: Map<string, FFSession>;
|
||||
_closed: boolean;
|
||||
|
||||
@ -185,6 +185,12 @@ export class FFSession extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
sendMayFail<T extends keyof Protocol.CommandParameters>(method: T, params?: Protocol.CommandParameters[T]): Promise<Protocol.CommandReturnValues[T] | void> {
|
||||
return this.send(method, params).catch(error => {
|
||||
this._connection._logger._log(errorLog, error, []);
|
||||
});
|
||||
}
|
||||
|
||||
dispatchMessage(object: ProtocolResponse) {
|
||||
if (object.id && this._callbacks.has(object.id)) {
|
||||
const callback = this._callbacks.get(object.id)!;
|
||||
|
@ -21,7 +21,6 @@ import { Page } from '../page';
|
||||
import * as network from '../network';
|
||||
import * as frames from '../frames';
|
||||
import { Protocol } from './protocol';
|
||||
import { logError } from '../logger';
|
||||
|
||||
export class FFNetworkManager {
|
||||
private _session: FFSession;
|
||||
@ -164,12 +163,12 @@ class InterceptableRequest implements network.RouteDelegate {
|
||||
headers,
|
||||
postData
|
||||
} = overrides;
|
||||
await this._session.send('Network.resumeInterceptedRequest', {
|
||||
await this._session.sendMayFail('Network.resumeInterceptedRequest', {
|
||||
requestId: this._id,
|
||||
method,
|
||||
headers: headers ? headersArray(headers) : undefined,
|
||||
postData: postData ? Buffer.from(postData).toString('base64') : undefined
|
||||
}).catch(logError(this.request._page));
|
||||
});
|
||||
}
|
||||
|
||||
async fulfill(response: network.FulfillResponse) {
|
||||
@ -185,20 +184,20 @@ class InterceptableRequest implements network.RouteDelegate {
|
||||
if (responseBody && !('content-length' in responseHeaders))
|
||||
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
|
||||
|
||||
await this._session.send('Network.fulfillInterceptedRequest', {
|
||||
await this._session.sendMayFail('Network.fulfillInterceptedRequest', {
|
||||
requestId: this._id,
|
||||
status: response.status || 200,
|
||||
statusText: network.STATUS_TEXTS[String(response.status || 200)] || '',
|
||||
headers: headersArray(responseHeaders),
|
||||
base64body: responseBody ? responseBody.toString('base64') : undefined,
|
||||
}).catch(logError(this.request._page));
|
||||
});
|
||||
}
|
||||
|
||||
async abort(errorCode: string) {
|
||||
await this._session.send('Network.abortInterceptedRequest', {
|
||||
await this._session.sendMayFail('Network.abortInterceptedRequest', {
|
||||
requestId: this._id,
|
||||
errorCode,
|
||||
}).catch(logError(this.request._page));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,6 @@ import { FFNetworkManager, headersArray } from './ffNetworkManager';
|
||||
import { Protocol } from './protocol';
|
||||
import { selectors } from '../selectors';
|
||||
import { NotConnectedError } from '../errors';
|
||||
import { logError } from '../logger';
|
||||
import { rewriteErrorMessage } from '../debug/stackTrace';
|
||||
|
||||
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
|
||||
@ -193,7 +192,7 @@ export class FFPage implements PageDelegate {
|
||||
params.type,
|
||||
params.message,
|
||||
async (accept: boolean, promptText?: string) => {
|
||||
await this._session.send('Page.handleDialog', { dialogId: params.dialogId, accept, promptText }).catch(logError(this._page));
|
||||
await this._session.sendMayFail('Page.handleDialog', { dialogId: params.dialogId, accept, promptText });
|
||||
},
|
||||
params.defaultValue));
|
||||
}
|
||||
@ -429,10 +428,10 @@ export class FFPage implements PageDelegate {
|
||||
}
|
||||
|
||||
async getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null> {
|
||||
const result = await this._session.send('Page.getContentQuads', {
|
||||
const result = await this._session.sendMayFail('Page.getContentQuads', {
|
||||
frameId: handle._context.frame._id,
|
||||
objectId: handle._objectId,
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
if (!result)
|
||||
return null;
|
||||
return result.quads.map(quad => [ quad.p1, quad.p2, quad.p3, quad.p4 ]);
|
||||
|
@ -19,7 +19,6 @@ import * as mime from 'mime';
|
||||
import * as util from 'util';
|
||||
import * as frames from './frames';
|
||||
import { assert, helper } from './helper';
|
||||
import { Page } from './page';
|
||||
import { URLSearchParams } from 'url';
|
||||
|
||||
export type NetworkCookie = {
|
||||
@ -112,14 +111,12 @@ export class Request {
|
||||
private _frame: frames.Frame;
|
||||
private _waitForResponsePromise: Promise<Response | null>;
|
||||
private _waitForResponsePromiseCallback: (value: Response | null) => void = () => {};
|
||||
readonly _page: Page;
|
||||
|
||||
constructor(routeDelegate: RouteDelegate | null, frame: frames.Frame, redirectedFrom: Request | null, documentId: string | undefined,
|
||||
url: string, resourceType: string, method: string, postData: string | null, headers: Headers) {
|
||||
assert(!url.startsWith('data:'), 'Data urls should not fire requests');
|
||||
this._routeDelegate = routeDelegate;
|
||||
this._frame = frame;
|
||||
this._page = frame._page;
|
||||
this._redirectedFrom = redirectedFrom;
|
||||
if (redirectedFrom)
|
||||
redirectedFrom._redirectedTo = this;
|
||||
|
@ -19,7 +19,7 @@ import { EventEmitter } from 'events';
|
||||
import { assert } from '../helper';
|
||||
import { ConnectionTransport, ProtocolRequest, ProtocolResponse, protocolLog } from '../transport';
|
||||
import { Protocol } from './protocol';
|
||||
import { InnerLogger } from '../logger';
|
||||
import { InnerLogger, errorLog } from '../logger';
|
||||
import { rewriteErrorMessage } from '../debug/stackTrace';
|
||||
|
||||
// WKPlaywright uses this special id to issue Browser.close command which we
|
||||
@ -36,9 +36,8 @@ export class WKConnection {
|
||||
private readonly _onDisconnect: () => void;
|
||||
private _lastId = 0;
|
||||
private _closed = false;
|
||||
|
||||
readonly browserSession: WKSession;
|
||||
private _logger: InnerLogger;
|
||||
readonly _logger: InnerLogger;
|
||||
|
||||
constructor(transport: ConnectionTransport, logger: InnerLogger, onDisconnect: () => void) {
|
||||
this._transport = transport;
|
||||
@ -138,6 +137,12 @@ export class WKSession extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
sendMayFail<T extends keyof Protocol.CommandParameters>(method: T, params?: Protocol.CommandParameters[T]): Promise<Protocol.CommandReturnValues[T] | void> {
|
||||
return this.send(method, params).catch(error => {
|
||||
this.connection._logger._log(errorLog, error, []);
|
||||
});
|
||||
}
|
||||
|
||||
markAsCrashed() {
|
||||
this._crashed = true;
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import { assert, helper } from '../helper';
|
||||
import * as network from '../network';
|
||||
import { Protocol } from './protocol';
|
||||
import { WKSession } from './wkConnection';
|
||||
import { logError } from '../logger';
|
||||
|
||||
const errorReasons: { [reason: string]: string } = {
|
||||
'aborted': 'Cancellation',
|
||||
@ -59,11 +58,9 @@ export class WKInterceptableRequest implements network.RouteDelegate {
|
||||
const reason = errorReasons[errorCode];
|
||||
assert(reason, 'Unknown error code: ' + errorCode);
|
||||
await this._interceptedPromise;
|
||||
await this._session.send('Network.interceptAsError', { requestId: this._requestId, reason }).catch(error => {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
logError(this.request._page);
|
||||
});
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
await this._session.sendMayFail('Network.interceptAsError', { requestId: this._requestId, reason });
|
||||
}
|
||||
|
||||
async fulfill(response: network.FulfillResponse) {
|
||||
@ -89,7 +86,9 @@ export class WKInterceptableRequest implements network.RouteDelegate {
|
||||
if (responseBody && !('content-length' in responseHeaders))
|
||||
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
|
||||
|
||||
await this._session.send('Network.interceptWithResponse', {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
await this._session.sendMayFail('Network.interceptWithResponse', {
|
||||
requestId: this._requestId,
|
||||
status: response.status || 200,
|
||||
statusText: network.STATUS_TEXTS[String(response.status || 200)],
|
||||
@ -97,24 +96,18 @@ export class WKInterceptableRequest implements network.RouteDelegate {
|
||||
headers: responseHeaders,
|
||||
base64Encoded,
|
||||
content: responseBody
|
||||
}).catch(error => {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
logError(this.request._page);
|
||||
});
|
||||
}
|
||||
|
||||
async continue(overrides: { method?: string; headers?: network.Headers; postData?: string }) {
|
||||
await this._interceptedPromise;
|
||||
await this._session.send('Network.interceptContinue', {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
await this._session.sendMayFail('Network.interceptContinue', {
|
||||
requestId: this._requestId,
|
||||
method: overrides.method,
|
||||
headers: overrides.headers,
|
||||
postData: overrides.postData ? Buffer.from(overrides.postData).toString('base64') : undefined
|
||||
}).catch((error: Error) => {
|
||||
// In certain cases, protocol will return error if the request was already canceled
|
||||
// or the page was closed. We should tolerate these errors.
|
||||
logError(this.request._page);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -287,7 +287,7 @@ export class WKPage implements PageDelegate {
|
||||
pageOrError = e;
|
||||
}
|
||||
if (targetInfo.isPaused)
|
||||
this._pageProxySession.send('Target.resume', { targetId: targetInfo.targetId }).catch(logError(this._page));
|
||||
this._pageProxySession.sendMayFail('Target.resume', { targetId: targetInfo.targetId });
|
||||
if ((pageOrError instanceof Page) && this._page.mainFrame().url() === '') {
|
||||
try {
|
||||
// Initial empty page has an empty url. We should wait until the first real url has been loaded,
|
||||
@ -309,7 +309,7 @@ export class WKPage implements PageDelegate {
|
||||
this._provisionalPage = new WKProvisionalPage(session, this);
|
||||
if (targetInfo.isPaused) {
|
||||
this._provisionalPage.initializationPromise.then(() => {
|
||||
this._pageProxySession.send('Target.resume', { targetId: targetInfo.targetId }).catch(logError(this._page));
|
||||
this._pageProxySession.sendMayFail('Target.resume', { targetId: targetInfo.targetId });
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -652,7 +652,7 @@ export class WKPage implements PageDelegate {
|
||||
|
||||
private async _evaluateBindingScript(binding: PageBinding): Promise<void> {
|
||||
const script = this._bindingToScript(binding);
|
||||
await Promise.all(this._page.frames().map(frame => frame.evaluate(script).catch(logError(this._page))));
|
||||
await Promise.all(this._page.frames().map(frame => frame.evaluate(script).catch(e => {})));
|
||||
}
|
||||
|
||||
async evaluateOnNewDocument(script: string): Promise<void> {
|
||||
@ -680,10 +680,10 @@ export class WKPage implements PageDelegate {
|
||||
}
|
||||
|
||||
async closePage(runBeforeUnload: boolean): Promise<void> {
|
||||
this._pageProxySession.send('Target.close', {
|
||||
this._pageProxySession.sendMayFail('Target.close', {
|
||||
targetId: this._session.sessionId,
|
||||
runBeforeUnload
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
}
|
||||
|
||||
canScreenshotOutsideViewport(): boolean {
|
||||
@ -767,9 +767,9 @@ export class WKPage implements PageDelegate {
|
||||
}
|
||||
|
||||
async getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null> {
|
||||
const result = await this._session.send('DOM.getContentQuads', {
|
||||
const result = await this._session.sendMayFail('DOM.getContentQuads', {
|
||||
objectId: handle._objectId
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
if (!result)
|
||||
return null;
|
||||
return result.quads.map(quad => [
|
||||
@ -790,10 +790,10 @@ export class WKPage implements PageDelegate {
|
||||
}
|
||||
|
||||
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> {
|
||||
const result = await this._session.send('DOM.resolveNode', {
|
||||
const result = await this._session.sendMayFail('DOM.resolveNode', {
|
||||
objectId: handle._objectId,
|
||||
executionContextId: (to._delegate as WKExecutionContext)._contextId
|
||||
}).catch(logError(this._page));
|
||||
});
|
||||
if (!result || result.object.subtype === 'null')
|
||||
throw new Error('Unable to adopt element handle from a different document');
|
||||
return to.createHandle(result.object) as dom.ElementHandle<T>;
|
||||
|
Loading…
Reference in New Issue
Block a user