mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-14 21:53:35 +03:00
fix: avoid unhandled promise rejection in WKSession.send (#770)
This commit is contained in:
parent
fd3a93084c
commit
985faebd12
@ -119,20 +119,19 @@ export class WKSession extends platform.EventEmitter {
|
||||
this.once = super.once;
|
||||
}
|
||||
|
||||
send<T extends keyof Protocol.CommandParameters>(
|
||||
async send<T extends keyof Protocol.CommandParameters>(
|
||||
method: T,
|
||||
params?: Protocol.CommandParameters[T]
|
||||
): Promise<Protocol.CommandReturnValues[T]> {
|
||||
if (this._disposed)
|
||||
return Promise.reject(new Error(`Protocol error (${method}): ${this.errorText}`));
|
||||
throw new Error(`Protocol error (${method}): ${this.errorText}`);
|
||||
const id = this.connection.nextMessageId();
|
||||
const messageObj = { id, method, params };
|
||||
platform.debug('pw:wrapped:' + this.sessionId)('SEND ► ' + JSON.stringify(messageObj, null, 2));
|
||||
const result = new Promise<Protocol.CommandReturnValues[T]>((resolve, reject) => {
|
||||
this._rawSend(messageObj);
|
||||
return new Promise<Protocol.CommandReturnValues[T]>((resolve, reject) => {
|
||||
this._callbacks.set(id, {resolve, reject, error: new Error(), method});
|
||||
});
|
||||
this._rawSend(messageObj);
|
||||
return result;
|
||||
}
|
||||
|
||||
isDisposed(): boolean {
|
||||
|
@ -120,21 +120,17 @@ export class WKExecutionContext implements js.ExecutionContextDelegate {
|
||||
throw error;
|
||||
}
|
||||
|
||||
let callFunctionOnPromise;
|
||||
try {
|
||||
callFunctionOnPromise = this._session.send('Runtime.callFunctionOn', {
|
||||
functionDeclaration: functionText + '\n' + suffix + '\n',
|
||||
objectId: thisObjectId,
|
||||
arguments: serializableArgs.map((arg: any) => this._convertArgument(arg)),
|
||||
returnByValue: false,
|
||||
emulateUserGesture: true
|
||||
});
|
||||
} catch (err) {
|
||||
return this._session.send('Runtime.callFunctionOn', {
|
||||
functionDeclaration: functionText + '\n' + suffix + '\n',
|
||||
objectId: thisObjectId,
|
||||
arguments: serializableArgs.map((arg: any) => this._convertArgument(arg)),
|
||||
returnByValue: false,
|
||||
emulateUserGesture: true
|
||||
}).catch(err => {
|
||||
if (err instanceof TypeError && err.message.startsWith('Converting circular structure to JSON'))
|
||||
err.message += ' Are you passing a nested JSHandle?';
|
||||
throw err;
|
||||
}
|
||||
return callFunctionOnPromise.then(response => {
|
||||
}).then(response => {
|
||||
if (response.result.type === 'object' && response.result.className === 'Promise') {
|
||||
return Promise.race([
|
||||
this._executionContextDestroyedPromise.then(() => contextDestroyedResult),
|
||||
|
@ -95,10 +95,24 @@ export class WKPage implements PageDelegate {
|
||||
// This method is called for provisional targets as well. The session passed as the parameter
|
||||
// may be different from the current session and may be destroyed without becoming current.
|
||||
async _initializeSession(session: WKSession, resourceTreeHandler: (r: Protocol.Page.getResourceTreeReturnValue) => void) {
|
||||
const promises : Promise<any>[] = [
|
||||
await this._initializeSessionMayThrow(session, resourceTreeHandler).catch(e => {
|
||||
if (session.isDisposed())
|
||||
return;
|
||||
// Swallow initialization errors due to newer target swap in,
|
||||
// since we will reinitialize again.
|
||||
if (this._session === session)
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
private async _initializeSessionMayThrow(session: WKSession, resourceTreeHandler: (r: Protocol.Page.getResourceTreeReturnValue) => void) {
|
||||
const [, frameTree] = await Promise.all([
|
||||
// Page agent must be enabled before Runtime.
|
||||
session.send('Page.enable'),
|
||||
session.send('Page.getResourceTree').then(resourceTreeHandler),
|
||||
session.send('Page.getResourceTree'),
|
||||
]);
|
||||
resourceTreeHandler(frameTree);
|
||||
const promises : Promise<any>[] = [
|
||||
// Resource tree should be received before first execution context.
|
||||
session.send('Runtime.enable'),
|
||||
session.send('Page.createUserWorld', { name: UTILITY_WORLD_NAME }).catch(_ => {}), // Worlds are per-process
|
||||
@ -129,19 +143,13 @@ export class WKPage implements PageDelegate {
|
||||
promises.push(session.send('Network.setExtraHTTPHeaders', { headers: this._page._state.extraHTTPHeaders }));
|
||||
if (this._page._state.hasTouch)
|
||||
promises.push(session.send('Page.setTouchEmulationEnabled', { enabled: true }));
|
||||
await Promise.all(promises).catch(e => {
|
||||
if (session.isDisposed())
|
||||
return;
|
||||
// Swallow initialization errors due to newer target swap in,
|
||||
// since we will reinitialize again.
|
||||
if (this._session === session)
|
||||
throw e;
|
||||
});
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
onProvisionalLoadStarted(provisionalSession: WKSession) {
|
||||
initializeProvisionalPage(provisionalSession: WKSession) : Promise<void> {
|
||||
assert(!this._provisionalPage);
|
||||
this._provisionalPage = new WKProvisionalPage(provisionalSession, this);
|
||||
return this._provisionalPage.initializationPromise;
|
||||
}
|
||||
|
||||
onProvisionalLoadCommitted(session: WKSession) {
|
||||
|
@ -139,10 +139,13 @@ export class WKPageProxy {
|
||||
}
|
||||
if (targetInfo.isProvisional) {
|
||||
(session as any)[isPovisionalSymbol] = true;
|
||||
if (this._wkPage)
|
||||
this._wkPage.onProvisionalLoadStarted(session);
|
||||
if (targetInfo.isPaused)
|
||||
if (this._wkPage) {
|
||||
const provisionalPageInitialized = this._wkPage.initializeProvisionalPage(session);
|
||||
if (targetInfo.isPaused)
|
||||
provisionalPageInitialized.then(() => this._resumeTarget(targetInfo.targetId));
|
||||
} else if (targetInfo.isPaused) {
|
||||
this._resumeTarget(targetInfo.targetId);
|
||||
}
|
||||
} else if (this._pagePromise) {
|
||||
assert(!this._pagePausedOnStart);
|
||||
// This is the first time page target is created, will resume
|
||||
|
@ -24,6 +24,7 @@ export class WKProvisionalPage {
|
||||
private readonly _wkPage: WKPage;
|
||||
private _sessionListeners: RegisteredListener[] = [];
|
||||
private _mainFrameId: string | null = null;
|
||||
readonly initializationPromise: Promise<void>;
|
||||
|
||||
constructor(session: WKSession, page: WKPage) {
|
||||
this._session = session;
|
||||
@ -47,7 +48,7 @@ export class WKProvisionalPage {
|
||||
helper.addEventListener(session, 'Network.loadingFailed', overrideFrameId(e => wkPage._onLoadingFailed(e))),
|
||||
];
|
||||
|
||||
this._wkPage._initializeSession(session, ({frameTree}) => this._handleFrameTree(frameTree));
|
||||
this.initializationPromise = this._wkPage._initializeSession(session, ({frameTree}) => this._handleFrameTree(frameTree));
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
Loading…
Reference in New Issue
Block a user