Skip to content

Commit 45a175d

Browse files
authored
fix(chromium): ignore lifecycle events for the initial empty page (#1486)
1 parent 1ddf051 commit 45a175d

File tree

4 files changed

+22
-34
lines changed

4 files changed

+22
-34
lines changed

src/chromium/crBrowser.ts

+1-22
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
4040
_targets = new Map<string, CRTarget>();
4141
readonly _firstPagePromise: Promise<void>;
4242
private _firstPageCallback = () => {};
43-
private _popupOpeners: string[] = [];
4443

4544
private _tracingRecording = false;
4645
private _tracingPath: string | null = '';
@@ -105,15 +104,6 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
105104
return createPageInNewContext(this, options);
106105
}
107106

108-
_onWindowOpen(openerId: string, payload: Protocol.Page.windowOpenPayload) {
109-
// window.open($url) with noopener forces a new browser-initiated window, not
110-
// a renderer-initiated one. When url is about:blank, we only get an
111-
// initial navigation, and no real navigation to $url.
112-
if (payload.windowFeatures.includes('noopener') && payload.url.startsWith('about:blank'))
113-
return;
114-
this._popupOpeners.push(openerId);
115-
}
116-
117107
_onAttachedToTarget({targetInfo, sessionId, waitingForDebugger}: Protocol.Target.attachedToTargetPayload) {
118108
const session = this._connection.session(sessionId)!;
119109
if (!CRTarget.isPageType(targetInfo.type) && targetInfo.type !== 'service_worker') {
@@ -159,18 +149,7 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
159149
private _createTarget(targetInfo: Protocol.Target.TargetInfo, session: CRSession) {
160150
const {browserContextId} = targetInfo;
161151
const context = (browserContextId && this._contexts.has(browserContextId)) ? this._contexts.get(browserContextId)! : this._defaultContext;
162-
let hasInitialAboutBlank = false;
163-
if (CRTarget.isPageType(targetInfo.type) && targetInfo.openerId) {
164-
const openerIndex = this._popupOpeners.indexOf(targetInfo.openerId);
165-
if (openerIndex !== -1) {
166-
this._popupOpeners.splice(openerIndex, 1);
167-
// When this page is a result of window.open($url) call, we should have it's opener
168-
// in the list of popup openers. In this case we know there is an initial
169-
// about:blank navigation, followed by a navigation to $url.
170-
hasInitialAboutBlank = true;
171-
}
172-
}
173-
const target = new CRTarget(this, targetInfo, context, session, hasInitialAboutBlank);
152+
const target = new CRTarget(this, targetInfo, context, session);
174153
assert(!this._targets.has(targetInfo.targetId), 'Target should not exist before targetCreated');
175154
this._targets.set(targetInfo.targetId, target);
176155
return { context, target };

src/chromium/crPage.ts

+16-5
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ export class CRPage implements PageDelegate {
6969
this._firstNonInitialNavigationCommittedPromise = new Promise(f => this._firstNonInitialNavigationCommittedCallback = f);
7070
}
7171

72-
async initialize(hasInitialAboutBlank: boolean) {
72+
async initialize() {
73+
let lifecycleEventsEnabled: Promise<any>;
7374
const promises: Promise<any>[] = [
7475
this._client.send('Page.enable'),
7576
this._client.send('Page.getFrameTree').then(({frameTree}) => {
@@ -84,7 +85,6 @@ export class CRPage implements PageDelegate {
8485
helper.addEventListener(this._client, 'Page.frameRequestedNavigation', event => this._onFrameRequestedNavigation(event)),
8586
helper.addEventListener(this._client, 'Page.frameStoppedLoading', event => this._onFrameStoppedLoading(event.frameId)),
8687
helper.addEventListener(this._client, 'Page.javascriptDialogOpening', event => this._onDialog(event)),
87-
helper.addEventListener(this._client, 'Page.lifecycleEvent', event => this._onLifecycleEvent(event)),
8888
helper.addEventListener(this._client, 'Page.navigatedWithinDocument', event => this._onFrameNavigatedWithinDocument(event.frameId, event.url)),
8989
helper.addEventListener(this._client, 'Runtime.bindingCalled', event => this._onBindingCalled(event)),
9090
helper.addEventListener(this._client, 'Runtime.consoleAPICalled', event => this._onConsoleAPI(event)),
@@ -105,9 +105,21 @@ export class CRPage implements PageDelegate {
105105
for (const binding of this._browserContext._pageBindings.values())
106106
frame.evaluate(binding.source).catch(debugError);
107107
}
108+
const isInitialEmptyPage = this._page.mainFrame().url() === ':';
109+
if (isInitialEmptyPage) {
110+
// Ignore lifecycle events for the initial empty page. It is never the final page
111+
// hence we are going to get more lifecycle updates after the actual navigation has
112+
// started (even if the target url is about:blank).
113+
lifecycleEventsEnabled.then(() => {
114+
this._eventListeners.push(helper.addEventListener(this._client, 'Page.lifecycleEvent', event => this._onLifecycleEvent(event)));
115+
});
116+
} else {
117+
this._firstNonInitialNavigationCommittedCallback();
118+
this._eventListeners.push(helper.addEventListener(this._client, 'Page.lifecycleEvent', event => this._onLifecycleEvent(event)));
119+
}
108120
}),
109121
this._client.send('Log.enable', {}),
110-
this._client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
122+
lifecycleEventsEnabled = this._client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
111123
this._client.send('Runtime.enable', {}),
112124
this._client.send('Page.addScriptToEvaluateOnNewDocument', {
113125
source: `//# sourceURL=${EVALUATION_SCRIPT_URL}`,
@@ -145,8 +157,7 @@ export class CRPage implements PageDelegate {
145157
for (const source of this._browserContext._evaluateOnNewDocumentSources)
146158
promises.push(this.evaluateOnNewDocument(source));
147159
promises.push(this._client.send('Runtime.runIfWaitingForDebugger'));
148-
if (hasInitialAboutBlank)
149-
promises.push(this._firstNonInitialNavigationCommittedPromise);
160+
promises.push(this._firstNonInitialNavigationCommittedPromise);
150161
await Promise.all(promises);
151162
}
152163

src/chromium/crTarget.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { assert, helper } from '../helper';
18+
import { assert } from '../helper';
1919
import { Page, Worker } from '../page';
2020
import { CRBrowser, CRBrowserContext } from './crBrowser';
2121
import { CRSession, CRSessionEvents } from './crConnection';
@@ -48,19 +48,17 @@ export class CRTarget {
4848
browser: CRBrowser,
4949
targetInfo: Protocol.Target.TargetInfo,
5050
browserContext: CRBrowserContext,
51-
session: CRSession,
52-
hasInitialAboutBlank: boolean) {
51+
session: CRSession) {
5352
this._targetInfo = targetInfo;
5453
this._browser = browser;
5554
this._browserContext = browserContext;
5655
this._targetId = targetInfo.targetId;
5756
if (CRTarget.isPageType(targetInfo.type)) {
5857
this._crPage = new CRPage(session, this._browser, this._browserContext);
59-
helper.addEventListener(session, 'Page.windowOpen', event => browser._onWindowOpen(targetInfo.targetId, event));
6058
const page = this._crPage.page();
6159
(page as any)[targetSymbol] = this;
6260
session.once(CRSessionEvents.Disconnected, () => page._didDisconnect());
63-
this._pagePromise = this._crPage.initialize(hasInitialAboutBlank).then(() => this._initializedPage = page).catch(e => e);
61+
this._pagePromise = this._crPage.initialize().then(() => this._initializedPage = page).catch(e => e);
6462
} else if (targetInfo.type === 'service_worker') {
6563
this._workerPromise = this._initializeServiceWorker(session);
6664
} else {

test/emulation.spec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ module.exports.describe = function({testRunner, expect, playwright, headless, FF
342342
await context.close();
343343
}
344344
});
345-
it.fail(CHROMIUM || FFOX)('should format number in popups', async({browser, server}) => {
345+
it.fail(FFOX)('should format number in popups', async({browser, server}) => {
346346
const context = await browser.newContext({ locale: 'fr-CH' });
347347
const page = await context.newPage();
348348
await page.goto(server.EMPTY_PAGE);
@@ -356,7 +356,7 @@ module.exports.describe = function({testRunner, expect, playwright, headless, FF
356356
expect(result).toBe('1 000 000,5');
357357
await context.close();
358358
});
359-
it.fail(CHROMIUM)('should affect navigator.language in popups', async({browser, server}) => {
359+
it('should affect navigator.language in popups', async({browser, server}) => {
360360
const context = await browser.newContext({ locale: 'fr-CH' });
361361
const page = await context.newPage();
362362
await page.goto(server.EMPTY_PAGE);

0 commit comments

Comments
 (0)