fix(chromium): ignore lifecycle events for the initial empty page (#1486)
This commit is contained in:
parent
1ddf05113b
commit
45a175d8fe
|
|
@ -40,7 +40,6 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
|
||||||
_targets = new Map<string, CRTarget>();
|
_targets = new Map<string, CRTarget>();
|
||||||
readonly _firstPagePromise: Promise<void>;
|
readonly _firstPagePromise: Promise<void>;
|
||||||
private _firstPageCallback = () => {};
|
private _firstPageCallback = () => {};
|
||||||
private _popupOpeners: string[] = [];
|
|
||||||
|
|
||||||
private _tracingRecording = false;
|
private _tracingRecording = false;
|
||||||
private _tracingPath: string | null = '';
|
private _tracingPath: string | null = '';
|
||||||
|
|
@ -105,15 +104,6 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
|
||||||
return createPageInNewContext(this, options);
|
return createPageInNewContext(this, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onWindowOpen(openerId: string, payload: Protocol.Page.windowOpenPayload) {
|
|
||||||
// window.open($url) with noopener forces a new browser-initiated window, not
|
|
||||||
// a renderer-initiated one. When url is about:blank, we only get an
|
|
||||||
// initial navigation, and no real navigation to $url.
|
|
||||||
if (payload.windowFeatures.includes('noopener') && payload.url.startsWith('about:blank'))
|
|
||||||
return;
|
|
||||||
this._popupOpeners.push(openerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onAttachedToTarget({targetInfo, sessionId, waitingForDebugger}: Protocol.Target.attachedToTargetPayload) {
|
_onAttachedToTarget({targetInfo, sessionId, waitingForDebugger}: Protocol.Target.attachedToTargetPayload) {
|
||||||
const session = this._connection.session(sessionId)!;
|
const session = this._connection.session(sessionId)!;
|
||||||
if (!CRTarget.isPageType(targetInfo.type) && targetInfo.type !== 'service_worker') {
|
if (!CRTarget.isPageType(targetInfo.type) && targetInfo.type !== 'service_worker') {
|
||||||
|
|
@ -159,18 +149,7 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
|
||||||
private _createTarget(targetInfo: Protocol.Target.TargetInfo, session: CRSession) {
|
private _createTarget(targetInfo: Protocol.Target.TargetInfo, session: CRSession) {
|
||||||
const {browserContextId} = targetInfo;
|
const {browserContextId} = targetInfo;
|
||||||
const context = (browserContextId && this._contexts.has(browserContextId)) ? this._contexts.get(browserContextId)! : this._defaultContext;
|
const context = (browserContextId && this._contexts.has(browserContextId)) ? this._contexts.get(browserContextId)! : this._defaultContext;
|
||||||
let hasInitialAboutBlank = false;
|
const target = new CRTarget(this, targetInfo, context, session);
|
||||||
if (CRTarget.isPageType(targetInfo.type) && targetInfo.openerId) {
|
|
||||||
const openerIndex = this._popupOpeners.indexOf(targetInfo.openerId);
|
|
||||||
if (openerIndex !== -1) {
|
|
||||||
this._popupOpeners.splice(openerIndex, 1);
|
|
||||||
// When this page is a result of window.open($url) call, we should have it's opener
|
|
||||||
// in the list of popup openers. In this case we know there is an initial
|
|
||||||
// about:blank navigation, followed by a navigation to $url.
|
|
||||||
hasInitialAboutBlank = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const target = new CRTarget(this, targetInfo, context, session, hasInitialAboutBlank);
|
|
||||||
assert(!this._targets.has(targetInfo.targetId), 'Target should not exist before targetCreated');
|
assert(!this._targets.has(targetInfo.targetId), 'Target should not exist before targetCreated');
|
||||||
this._targets.set(targetInfo.targetId, target);
|
this._targets.set(targetInfo.targetId, target);
|
||||||
return { context, target };
|
return { context, target };
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,8 @@ export class CRPage implements PageDelegate {
|
||||||
this._firstNonInitialNavigationCommittedPromise = new Promise(f => this._firstNonInitialNavigationCommittedCallback = f);
|
this._firstNonInitialNavigationCommittedPromise = new Promise(f => this._firstNonInitialNavigationCommittedCallback = f);
|
||||||
}
|
}
|
||||||
|
|
||||||
async initialize(hasInitialAboutBlank: boolean) {
|
async initialize() {
|
||||||
|
let lifecycleEventsEnabled: Promise<any>;
|
||||||
const promises: Promise<any>[] = [
|
const promises: Promise<any>[] = [
|
||||||
this._client.send('Page.enable'),
|
this._client.send('Page.enable'),
|
||||||
this._client.send('Page.getFrameTree').then(({frameTree}) => {
|
this._client.send('Page.getFrameTree').then(({frameTree}) => {
|
||||||
|
|
@ -84,7 +85,6 @@ export class CRPage implements PageDelegate {
|
||||||
helper.addEventListener(this._client, 'Page.frameRequestedNavigation', event => this._onFrameRequestedNavigation(event)),
|
helper.addEventListener(this._client, 'Page.frameRequestedNavigation', event => this._onFrameRequestedNavigation(event)),
|
||||||
helper.addEventListener(this._client, 'Page.frameStoppedLoading', event => this._onFrameStoppedLoading(event.frameId)),
|
helper.addEventListener(this._client, 'Page.frameStoppedLoading', event => this._onFrameStoppedLoading(event.frameId)),
|
||||||
helper.addEventListener(this._client, 'Page.javascriptDialogOpening', event => this._onDialog(event)),
|
helper.addEventListener(this._client, 'Page.javascriptDialogOpening', event => this._onDialog(event)),
|
||||||
helper.addEventListener(this._client, 'Page.lifecycleEvent', event => this._onLifecycleEvent(event)),
|
|
||||||
helper.addEventListener(this._client, 'Page.navigatedWithinDocument', event => this._onFrameNavigatedWithinDocument(event.frameId, event.url)),
|
helper.addEventListener(this._client, 'Page.navigatedWithinDocument', event => this._onFrameNavigatedWithinDocument(event.frameId, event.url)),
|
||||||
helper.addEventListener(this._client, 'Runtime.bindingCalled', event => this._onBindingCalled(event)),
|
helper.addEventListener(this._client, 'Runtime.bindingCalled', event => this._onBindingCalled(event)),
|
||||||
helper.addEventListener(this._client, 'Runtime.consoleAPICalled', event => this._onConsoleAPI(event)),
|
helper.addEventListener(this._client, 'Runtime.consoleAPICalled', event => this._onConsoleAPI(event)),
|
||||||
|
|
@ -105,9 +105,21 @@ export class CRPage implements PageDelegate {
|
||||||
for (const binding of this._browserContext._pageBindings.values())
|
for (const binding of this._browserContext._pageBindings.values())
|
||||||
frame.evaluate(binding.source).catch(debugError);
|
frame.evaluate(binding.source).catch(debugError);
|
||||||
}
|
}
|
||||||
|
const isInitialEmptyPage = this._page.mainFrame().url() === ':';
|
||||||
|
if (isInitialEmptyPage) {
|
||||||
|
// Ignore lifecycle events for the initial empty page. It is never the final page
|
||||||
|
// hence we are going to get more lifecycle updates after the actual navigation has
|
||||||
|
// started (even if the target url is about:blank).
|
||||||
|
lifecycleEventsEnabled.then(() => {
|
||||||
|
this._eventListeners.push(helper.addEventListener(this._client, 'Page.lifecycleEvent', event => this._onLifecycleEvent(event)));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this._firstNonInitialNavigationCommittedCallback();
|
||||||
|
this._eventListeners.push(helper.addEventListener(this._client, 'Page.lifecycleEvent', event => this._onLifecycleEvent(event)));
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
this._client.send('Log.enable', {}),
|
this._client.send('Log.enable', {}),
|
||||||
this._client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
|
lifecycleEventsEnabled = this._client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
|
||||||
this._client.send('Runtime.enable', {}),
|
this._client.send('Runtime.enable', {}),
|
||||||
this._client.send('Page.addScriptToEvaluateOnNewDocument', {
|
this._client.send('Page.addScriptToEvaluateOnNewDocument', {
|
||||||
source: `//# sourceURL=${EVALUATION_SCRIPT_URL}`,
|
source: `//# sourceURL=${EVALUATION_SCRIPT_URL}`,
|
||||||
|
|
@ -145,8 +157,7 @@ export class CRPage implements PageDelegate {
|
||||||
for (const source of this._browserContext._evaluateOnNewDocumentSources)
|
for (const source of this._browserContext._evaluateOnNewDocumentSources)
|
||||||
promises.push(this.evaluateOnNewDocument(source));
|
promises.push(this.evaluateOnNewDocument(source));
|
||||||
promises.push(this._client.send('Runtime.runIfWaitingForDebugger'));
|
promises.push(this._client.send('Runtime.runIfWaitingForDebugger'));
|
||||||
if (hasInitialAboutBlank)
|
promises.push(this._firstNonInitialNavigationCommittedPromise);
|
||||||
promises.push(this._firstNonInitialNavigationCommittedPromise);
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { assert, helper } from '../helper';
|
import { assert } from '../helper';
|
||||||
import { Page, Worker } from '../page';
|
import { Page, Worker } from '../page';
|
||||||
import { CRBrowser, CRBrowserContext } from './crBrowser';
|
import { CRBrowser, CRBrowserContext } from './crBrowser';
|
||||||
import { CRSession, CRSessionEvents } from './crConnection';
|
import { CRSession, CRSessionEvents } from './crConnection';
|
||||||
|
|
@ -48,19 +48,17 @@ export class CRTarget {
|
||||||
browser: CRBrowser,
|
browser: CRBrowser,
|
||||||
targetInfo: Protocol.Target.TargetInfo,
|
targetInfo: Protocol.Target.TargetInfo,
|
||||||
browserContext: CRBrowserContext,
|
browserContext: CRBrowserContext,
|
||||||
session: CRSession,
|
session: CRSession) {
|
||||||
hasInitialAboutBlank: boolean) {
|
|
||||||
this._targetInfo = targetInfo;
|
this._targetInfo = targetInfo;
|
||||||
this._browser = browser;
|
this._browser = browser;
|
||||||
this._browserContext = browserContext;
|
this._browserContext = browserContext;
|
||||||
this._targetId = targetInfo.targetId;
|
this._targetId = targetInfo.targetId;
|
||||||
if (CRTarget.isPageType(targetInfo.type)) {
|
if (CRTarget.isPageType(targetInfo.type)) {
|
||||||
this._crPage = new CRPage(session, this._browser, this._browserContext);
|
this._crPage = new CRPage(session, this._browser, this._browserContext);
|
||||||
helper.addEventListener(session, 'Page.windowOpen', event => browser._onWindowOpen(targetInfo.targetId, event));
|
|
||||||
const page = this._crPage.page();
|
const page = this._crPage.page();
|
||||||
(page as any)[targetSymbol] = this;
|
(page as any)[targetSymbol] = this;
|
||||||
session.once(CRSessionEvents.Disconnected, () => page._didDisconnect());
|
session.once(CRSessionEvents.Disconnected, () => page._didDisconnect());
|
||||||
this._pagePromise = this._crPage.initialize(hasInitialAboutBlank).then(() => this._initializedPage = page).catch(e => e);
|
this._pagePromise = this._crPage.initialize().then(() => this._initializedPage = page).catch(e => e);
|
||||||
} else if (targetInfo.type === 'service_worker') {
|
} else if (targetInfo.type === 'service_worker') {
|
||||||
this._workerPromise = this._initializeServiceWorker(session);
|
this._workerPromise = this._initializeServiceWorker(session);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -342,7 +342,7 @@ module.exports.describe = function({testRunner, expect, playwright, headless, FF
|
||||||
await context.close();
|
await context.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
it.fail(CHROMIUM || FFOX)('should format number in popups', async({browser, server}) => {
|
it.fail(FFOX)('should format number in popups', async({browser, server}) => {
|
||||||
const context = await browser.newContext({ locale: 'fr-CH' });
|
const context = await browser.newContext({ locale: 'fr-CH' });
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
|
@ -356,7 +356,7 @@ module.exports.describe = function({testRunner, expect, playwright, headless, FF
|
||||||
expect(result).toBe('1 000 000,5');
|
expect(result).toBe('1 000 000,5');
|
||||||
await context.close();
|
await context.close();
|
||||||
});
|
});
|
||||||
it.fail(CHROMIUM)('should affect navigator.language in popups', async({browser, server}) => {
|
it('should affect navigator.language in popups', async({browser, server}) => {
|
||||||
const context = await browser.newContext({ locale: 'fr-CH' });
|
const context = await browser.newContext({ locale: 'fr-CH' });
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue