fix(chromium): do not await extra promises in initialize() to attach early enough (#1311)

This commit is contained in:
Dmitry Gozman 2020-03-10 10:06:17 -07:00 committed by GitHub
parent 008e0b2ecd
commit d5a2781e80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 19 deletions

View File

@ -46,7 +46,6 @@ export class CRPage implements PageDelegate {
private readonly _page: Page;
readonly _networkManager: CRNetworkManager;
private _contextIdToContext = new Map<number, dom.FrameExecutionContext>();
private _isolatedWorlds = new Set<string>();
private _eventListeners: RegisteredListener[] = [];
rawMouse: RawMouseImpl;
rawKeyboard: RawKeyboardImpl;
@ -93,10 +92,19 @@ export class CRPage implements PageDelegate {
helper.addEventListener(this._client, 'Target.attachedToTarget', event => this._onAttachedToTarget(event)),
helper.addEventListener(this._client, 'Target.detachedFromTarget', event => this._onDetachedFromTarget(event)),
];
this._page.frames().map(frame => this._client.send('Page.createIsolatedWorld', {
frameId: frame._id,
grantUniveralAccess: true,
worldName: UTILITY_WORLD_NAME,
}).catch(debugError)); // frames might be removed before we send this.
}),
this._client.send('Log.enable', {}),
this._client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
this._client.send('Runtime.enable', {}).then(() => this._ensureIsolatedWorld(UTILITY_WORLD_NAME)),
this._client.send('Runtime.enable', {}),
this._client.send('Page.addScriptToEvaluateOnNewDocument', {
source: `//# sourceURL=${EVALUATION_SCRIPT_URL}`,
worldName: UTILITY_WORLD_NAME,
}),
this._networkManager.initialize(),
this._client.send('Target.setAutoAttach', { autoAttach: true, waitForDebuggerOnStart: true, flatten: true }),
this._client.send('Emulation.setFocusEmulationEnabled', { enabled: true }),
@ -182,21 +190,6 @@ export class CRPage implements PageDelegate {
this._page._frameManager.frameRequestedNavigation(payload.frameId);
}
async _ensureIsolatedWorld(name: string) {
if (this._isolatedWorlds.has(name))
return;
this._isolatedWorlds.add(name);
await this._client.send('Page.addScriptToEvaluateOnNewDocument', {
source: `//# sourceURL=${EVALUATION_SCRIPT_URL}`,
worldName: name,
});
await Promise.all(this._page.frames().map(frame => this._client.send('Page.createIsolatedWorld', {
frameId: frame._id,
grantUniveralAccess: true,
worldName: name,
}).catch(debugError))); // frames might be removed before we send this
}
_onFrameNavigatedWithinDocument(frameId: string, url: string) {
this._page._frameManager.frameCommittedSameDocumentNavigation(frameId, url);
}
@ -209,8 +202,6 @@ export class CRPage implements PageDelegate {
const frame = contextPayload.auxData ? this._page._frameManager.frame(contextPayload.auxData.frameId) : null;
if (!frame)
return;
if (contextPayload.auxData && contextPayload.auxData.type === 'isolated')
this._isolatedWorlds.add(contextPayload.name);
const delegate = new CRExecutionContext(this._client, contextPayload);
const context = new dom.FrameExecutionContext(delegate, frame);
if (contextPayload.auxData && !!contextPayload.auxData.isDefault)

View File

@ -88,6 +88,7 @@ export class FFPage implements PageDelegate {
async _initialize() {
try {
await Promise.all([
// TODO: we should get rid of this call to resolve before any early events arrive, e.g. dialogs.
this._session.send('Page.addScriptToEvaluateOnNewDocument', {
script: '',
worldName: UTILITY_WORLD_NAME,

View File

@ -204,6 +204,24 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE
expect(popupEvent).toBeTruthy();
await context.close();
});
it.fail(FFOX)('should be able to capture alert', async({browser}) => {
// Firefox:
// - immediately closes dialog by itself, without protocol call;
// - waits for Page.addScriptToEvaluateOnNewDocument before resolving page(), which is too late.
const context = await browser.newContext();
const page = await context.newPage();
const evaluatePromise = page.evaluate(() => {
const win = window.open('about:blank');
win.alert('hello');
});
const popupEvent = await page.waitForEvent('popup');
const popup = await popupEvent.page();
const dialog = await popup.waitForEvent('dialog');
expect(dialog.message()).toBe('hello');
await dialog.dismiss();
await evaluatePromise;
await context.close();
});
it('should work with empty url', async({browser}) => {
const context = await browser.newContext();
const page = await context.newPage();