mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-25 20:01:50 +00:00
Bug 1599260 - Include loader id in Page.lifecycleEvent r=remote-protocol-reviewers,whimboo
Differential Revision: https://phabricator.services.mozilla.com/D74580
This commit is contained in:
parent
6604ce89a1
commit
f260a91bb8
@ -285,53 +285,39 @@ class Page extends ContentProcessDomain {
|
||||
}
|
||||
|
||||
handleEvent({ type, target }) {
|
||||
const isFrame = target.defaultView != this.content;
|
||||
|
||||
if (isFrame) {
|
||||
if (target.defaultView != this.content) {
|
||||
// Ignore iframes for now
|
||||
return;
|
||||
}
|
||||
|
||||
const timestamp = Date.now();
|
||||
const timestamp = Date.now() / 1000;
|
||||
const frameId = target.defaultView.docShell.browsingContext.id.toString();
|
||||
const url = target.location.href;
|
||||
const loaderId =
|
||||
this._lastRequest?.frameId == frameId
|
||||
? this._lastRequest?.loaderId
|
||||
: null;
|
||||
|
||||
switch (type) {
|
||||
case "DOMContentLoaded":
|
||||
this.emit("Page.domContentEventFired", { timestamp });
|
||||
if (!isFrame) {
|
||||
this.emitLifecycleEvent(
|
||||
frameId,
|
||||
/* loaderId */ null,
|
||||
"DOMContentLoaded",
|
||||
timestamp
|
||||
);
|
||||
}
|
||||
this.emitLifecycleEvent(
|
||||
frameId,
|
||||
loaderId,
|
||||
"DOMContentLoaded",
|
||||
timestamp
|
||||
);
|
||||
break;
|
||||
|
||||
case "pagehide":
|
||||
// Maybe better to bound to "unload" once we can register for this event
|
||||
this.emit("Page.frameStartedLoading", { frameId });
|
||||
if (!isFrame) {
|
||||
this.emitLifecycleEvent(
|
||||
frameId,
|
||||
/* loaderId */ null,
|
||||
"init",
|
||||
timestamp
|
||||
);
|
||||
}
|
||||
this.emitLifecycleEvent(frameId, loaderId, "init", timestamp);
|
||||
break;
|
||||
|
||||
case "load":
|
||||
this.emit("Page.loadEventFired", { timestamp });
|
||||
if (!isFrame) {
|
||||
this.emitLifecycleEvent(
|
||||
frameId,
|
||||
/* loaderId */ null,
|
||||
"load",
|
||||
timestamp
|
||||
);
|
||||
}
|
||||
this.emitLifecycleEvent(frameId, loaderId, "load", timestamp);
|
||||
|
||||
// XXX this should most likely be sent differently
|
||||
this.emit("Page.navigatedWithinDocument", { frameId, url });
|
||||
@ -340,16 +326,15 @@ class Page extends ContentProcessDomain {
|
||||
|
||||
case "readystatechange":
|
||||
if (this.content.document.readState === "loading") {
|
||||
this.emitLifecycleEvent(
|
||||
frameId,
|
||||
/* loaderId */ null,
|
||||
"init",
|
||||
timestamp
|
||||
);
|
||||
this.emitLifecycleEvent(frameId, loaderId, "init", timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_updateLoaderId(data) {
|
||||
this._lastRequest = data;
|
||||
}
|
||||
|
||||
_contentRect() {
|
||||
const docEl = this.content.document.documentElement;
|
||||
|
||||
|
@ -59,11 +59,13 @@ class Page extends Domain {
|
||||
super(session);
|
||||
|
||||
this._onDialogLoaded = this._onDialogLoaded.bind(this);
|
||||
this._onRequest = this._onRequest.bind(this);
|
||||
|
||||
this.enabled = false;
|
||||
this.session.networkObserver.startTrackingBrowserNetwork(
|
||||
this.session.target.browser
|
||||
);
|
||||
this.session.networkObserver.on("request", this._onRequest);
|
||||
}
|
||||
|
||||
destructor() {
|
||||
@ -71,6 +73,7 @@ class Page extends Domain {
|
||||
this._isDestroyed = false;
|
||||
this.disable();
|
||||
|
||||
this.session.networkObserver.off("request", this._onRequest);
|
||||
this.session.networkObserver.stopTrackingBrowserNetwork(
|
||||
this.session.target.browser
|
||||
);
|
||||
@ -108,7 +111,8 @@ class Page extends Domain {
|
||||
} catch (e) {
|
||||
throw new Error("Error: Cannot navigate to invalid URL");
|
||||
}
|
||||
if (frameId && frameId != this.session.browsingContext.id.toString()) {
|
||||
const topFrameId = this.session.browsingContext.id.toString();
|
||||
if (frameId && frameId != topFrameId) {
|
||||
throw new UnsupportedError("frameId not supported");
|
||||
}
|
||||
|
||||
@ -160,14 +164,10 @@ class Page extends Domain {
|
||||
};
|
||||
this.session.browsingContext.loadURI(url, opts);
|
||||
// clients expect loaderId == requestId for a document navigation request
|
||||
const {
|
||||
// TODO as part of Bug 1599260
|
||||
// navigationRequestId: loaderId,
|
||||
errorCode,
|
||||
} = await requestDone;
|
||||
const { navigationRequestId: loaderId, errorCode } = await requestDone;
|
||||
const result = {
|
||||
frameId: this.session.browsingContext.id.toString(),
|
||||
// loaderId,
|
||||
frameId: topFrameId,
|
||||
loaderId,
|
||||
};
|
||||
if (errorCode) {
|
||||
result.errorText = errorCode;
|
||||
@ -736,6 +736,20 @@ class Page extends Domain {
|
||||
// on the actual tests relying on this API.
|
||||
this.emit("Page.javascriptDialogOpening", { message, type });
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles HTTP request to propagate loaderId to events emitted from
|
||||
* content process
|
||||
*/
|
||||
_onRequest(_type, _ch, data) {
|
||||
if (!data.loaderId) {
|
||||
return;
|
||||
}
|
||||
this.executeInChild("_updateLoaderId", {
|
||||
loaderId: data.loaderId,
|
||||
frameId: this.session.browsingContext.id.toString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function transitionToLoadFlag(transitionType) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test order and consistency of Network events as a whole.
|
||||
// Test order and consistency of Network/Page events as a whole.
|
||||
// Details of specific events are checked in event-specific test files.
|
||||
|
||||
const PAGE_URL =
|
||||
@ -14,17 +14,19 @@ const JS_URL =
|
||||
add_task(async function documentNavigationWithScriptResource({ client }) {
|
||||
const { Page, Network } = client;
|
||||
await Network.enable();
|
||||
await Page.enable();
|
||||
await Page.setLifecycleEventsEnabled({ enabled: true });
|
||||
const { history, urlToEvents } = configureHistory(client);
|
||||
const navigateDone = history.addPromise("Page.navigate");
|
||||
|
||||
const { frameId } = await Page.navigate({ url: PAGE_URL }).then(navigateDone);
|
||||
ok(frameId, "Page.navigate returned a frameId");
|
||||
|
||||
info("Wait for Network events");
|
||||
info("Wait for events");
|
||||
const events = await history.record();
|
||||
is(events.length, 5, "Expected number of events");
|
||||
is(events.length, 8, "Expected number of events");
|
||||
const eventNames = events.map(
|
||||
item => `${item.eventName}(${item.payload.type || ""})`
|
||||
item => `${item.eventName}(${item.payload.type || item.payload.name})`
|
||||
);
|
||||
info(`Received events: ${eventNames}`);
|
||||
const documentEvents = urlToEvents.get(PAGE_URL);
|
||||
@ -43,6 +45,19 @@ add_task(async function documentNavigationWithScriptResource({ client }) {
|
||||
const docRequest = documentEvents[0].event;
|
||||
is(docRequest.request.url, PAGE_URL, "Got the doc request");
|
||||
is(docRequest.documentURL, PAGE_URL, "documenURL matches request url");
|
||||
const lifeCycleEvents = history.findEvents("Page.lifecycleEvent");
|
||||
const firstLifecycle = history.indexOf("Page.lifecycleEvent");
|
||||
ok(
|
||||
firstLifecycle > documentEvents[1].index,
|
||||
"First lifecycle event is after document response"
|
||||
);
|
||||
for (const e of lifeCycleEvents) {
|
||||
is(
|
||||
e.loaderId,
|
||||
docRequest.loaderId,
|
||||
`${e.name} lifecycle event has same loaderId as document request`
|
||||
);
|
||||
}
|
||||
|
||||
const resourceRequest = resourceEvents[0].event;
|
||||
is(resourceRequest.documentURL, PAGE_URL, "documentURL is trigger document");
|
||||
@ -53,13 +68,17 @@ add_task(async function documentNavigationWithScriptResource({ client }) {
|
||||
);
|
||||
const navigateStep = history.indexOf("Page.navigate");
|
||||
ok(
|
||||
documentEvents[1].index < navigateStep,
|
||||
navigateStep > documentEvents[1].index,
|
||||
"Page.navigate returns after document response"
|
||||
);
|
||||
ok(
|
||||
navigateStep < resourceEvents[0].index,
|
||||
"Page.navigate returns before resource request"
|
||||
);
|
||||
ok(
|
||||
navigateStep < firstLifecycle,
|
||||
"Page.navigate returns before first lifecycle event"
|
||||
);
|
||||
|
||||
const docResponse = documentEvents[1].event;
|
||||
is(docResponse.response.url, PAGE_URL, "Got the doc response");
|
||||
@ -106,9 +125,10 @@ add_task(async function documentNavigationWithScriptResource({ client }) {
|
||||
function configureHistory(client) {
|
||||
const REQUEST = "Network.requestWillBeSent";
|
||||
const RESPONSE = "Network.responseReceived";
|
||||
const LIFECYCLE = "Page.lifecycleEvent";
|
||||
|
||||
const { Network } = client;
|
||||
const history = new RecordEvents(4);
|
||||
const { Network, Page } = client;
|
||||
const history = new RecordEvents(8);
|
||||
const urlToEvents = new Map();
|
||||
function updateUrlToEvents(kind) {
|
||||
return ({ payload, index, eventName }) => {
|
||||
@ -141,5 +161,14 @@ function configureHistory(client) {
|
||||
},
|
||||
callback: updateUrlToEvents("response"),
|
||||
});
|
||||
|
||||
history.addRecorder({
|
||||
event: Page.lifecycleEvent,
|
||||
eventName: LIFECYCLE,
|
||||
messageFn: payload => {
|
||||
return `Received ${LIFECYCLE} ${payload.name}`;
|
||||
},
|
||||
});
|
||||
|
||||
return { history, urlToEvents };
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ add_task(async function noEventsAfterNetworkDomainDisabled({ client }) {
|
||||
add_task(async function documentNavigationWithResource({ client }) {
|
||||
const { Page, Network } = client;
|
||||
await Network.enable();
|
||||
const history = configureHistory(client);
|
||||
const history = configureHistory(client, 2);
|
||||
|
||||
const { frameId: frameIdNav } = await Page.navigate({ url: PAGE_URL });
|
||||
ok(frameIdNav, "Page.navigate returned a frameId");
|
||||
@ -82,11 +82,11 @@ add_task(async function documentNavigationWithResource({ client }) {
|
||||
);
|
||||
});
|
||||
|
||||
function configureHistory(client) {
|
||||
function configureHistory(client, total) {
|
||||
const REQUEST = "Network.requestWillBeSent";
|
||||
|
||||
const { Network } = client;
|
||||
const history = new RecordEvents(4);
|
||||
const history = new RecordEvents(total);
|
||||
|
||||
history.addRecorder({
|
||||
event: Network.requestWillBeSent,
|
||||
|
@ -6,6 +6,8 @@
|
||||
// Test the Page lifecycle events
|
||||
|
||||
const DOC = toDataURL("default-test-page");
|
||||
const PAGE_URL =
|
||||
"http://example.com/browser/remote/test/browser/page/doc_empty.html";
|
||||
|
||||
add_task(async function noInitialEvents({ client }) {
|
||||
const { Page } = client;
|
||||
@ -41,7 +43,7 @@ add_task(async function noEventsAfterDisable({ client }) {
|
||||
await assertNavigationLifecycleEvents({ promise, frameId, timeout: 1000 });
|
||||
});
|
||||
|
||||
add_task(async function navigateEvents({ client }) {
|
||||
add_task(async function navigateToDataURLEvents({ client }) {
|
||||
const { Page } = client;
|
||||
await Page.enable();
|
||||
info("Page domain has been enabled");
|
||||
@ -51,11 +53,32 @@ add_task(async function navigateEvents({ client }) {
|
||||
info("Lifecycle events have been enabled");
|
||||
|
||||
let pageLoaded = Page.loadEventFired();
|
||||
const { frameId } = await Page.navigate({ url: DOC });
|
||||
const { frameId, loaderId } = await Page.navigate({ url: DOC });
|
||||
// Bug 1632007 return a loaderId for data: url
|
||||
todo(!!loaderId, "Page.navigate returns a loaderId");
|
||||
await pageLoaded;
|
||||
info("A new page has been loaded");
|
||||
|
||||
await assertNavigationLifecycleEvents({ promise, frameId });
|
||||
await assertNavigationLifecycleEvents({ promise, frameId, loaderId });
|
||||
});
|
||||
|
||||
add_task(async function navigateToPageURLEvents({ client }) {
|
||||
const { Page } = client;
|
||||
await Page.enable();
|
||||
info("Page domain has been enabled");
|
||||
|
||||
await Page.setLifecycleEventsEnabled({ enabled: true });
|
||||
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
|
||||
info("Lifecycle events have been enabled");
|
||||
|
||||
let pageLoaded = Page.loadEventFired();
|
||||
const { frameId, loaderId } = await Page.navigate({ url: PAGE_URL });
|
||||
ok(!!loaderId, "Page.navigate returns a loaderId");
|
||||
|
||||
await pageLoaded;
|
||||
info("A new page has been loaded");
|
||||
|
||||
await assertNavigationLifecycleEvents({ promise, frameId, loaderId });
|
||||
});
|
||||
|
||||
add_task(async function navigateEventsOnReload({ client }) {
|
||||
@ -118,7 +141,8 @@ function recordPromises(Page, names) {
|
||||
});
|
||||
}
|
||||
|
||||
async function assertNavigationLifecycleEvents({ promise, frameId, timeout }) {
|
||||
async function assertNavigationLifecycleEvents(options = {}) {
|
||||
const { promise, frameId, loaderId, timeout } = options;
|
||||
// Wait for all the promises to resolve
|
||||
const promises = [promise];
|
||||
|
||||
@ -142,8 +166,8 @@ async function assertNavigationLifecycleEvents({ promise, frameId, timeout }) {
|
||||
);
|
||||
|
||||
// Now assert the data exposed by each of these events
|
||||
const frameStartedLoading = resolutions.get("init");
|
||||
is(frameStartedLoading.frameId, frameId, "init frameId is the same one");
|
||||
const init = resolutions.get("init");
|
||||
is(init.frameId, frameId, "init frameId is the same one");
|
||||
|
||||
const DOMContentLoaded = resolutions.get("DOMContentLoaded");
|
||||
is(
|
||||
@ -154,4 +178,25 @@ async function assertNavigationLifecycleEvents({ promise, frameId, timeout }) {
|
||||
|
||||
const load = resolutions.get("load");
|
||||
is(load.frameId, frameId, "load frameId is the same one");
|
||||
|
||||
ok(init.timestamp, "init has a timestamp");
|
||||
ok(
|
||||
init.timestamp <= DOMContentLoaded.timestamp,
|
||||
"init precedes DOMContentLoaded"
|
||||
);
|
||||
ok(
|
||||
DOMContentLoaded.timestamp <= load.timestamp,
|
||||
"DOMContentLoaded precedes load"
|
||||
);
|
||||
|
||||
if (!loaderId) {
|
||||
return;
|
||||
}
|
||||
is(init.loaderId, loaderId, "init has expected loaderId");
|
||||
is(load.loaderId, loaderId, "load has expected loaderId");
|
||||
is(
|
||||
DOMContentLoaded.loaderId,
|
||||
loaderId,
|
||||
"DOMContentLoaded has expected loaderId"
|
||||
);
|
||||
}
|
||||
|
@ -7,14 +7,22 @@ const pageEmptyURL =
|
||||
"http://example.com/browser/remote/test/browser/page/doc_empty.html";
|
||||
|
||||
add_task(async function testBasicNavigation({ client }) {
|
||||
const { Page } = client;
|
||||
const { Page, Network } = client;
|
||||
await Page.enable();
|
||||
await Network.enable();
|
||||
const loadEventFired = Page.loadEventFired();
|
||||
const requestEvent = Network.requestWillBeSent();
|
||||
const { frameId, loaderId, errorText } = await Page.navigate({
|
||||
url: pageEmptyURL,
|
||||
});
|
||||
const { loaderId: requestLoaderId } = await requestEvent;
|
||||
|
||||
todo(!!loaderId, "Page.navigate returns loaderId");
|
||||
ok(!!loaderId, "Page.navigate returns loaderId");
|
||||
is(
|
||||
loaderId,
|
||||
requestLoaderId,
|
||||
"Page.navigate returns same loaderId as corresponding request"
|
||||
);
|
||||
is(errorText, undefined, "No errorText on a successful navigation");
|
||||
|
||||
await loadEventFired;
|
||||
@ -29,12 +37,15 @@ add_task(async function testBasicNavigation({ client }) {
|
||||
});
|
||||
|
||||
add_task(async function testTwoNavigations({ client }) {
|
||||
const { Page } = client;
|
||||
const { Page, Network } = client;
|
||||
await Page.enable();
|
||||
await Network.enable();
|
||||
let requestEvent = Network.requestWillBeSent();
|
||||
let loadEventFired = Page.loadEventFired();
|
||||
const { frameId, loaderId, errorText } = await Page.navigate({
|
||||
url: pageEmptyURL,
|
||||
});
|
||||
const { loaderId: requestLoaderId } = await requestEvent;
|
||||
await loadEventFired;
|
||||
is(
|
||||
gBrowser.selectedBrowser.currentURI.spec,
|
||||
@ -43,6 +54,7 @@ add_task(async function testTwoNavigations({ client }) {
|
||||
);
|
||||
|
||||
loadEventFired = Page.loadEventFired();
|
||||
requestEvent = Network.requestWillBeSent();
|
||||
const {
|
||||
frameId: frameId2,
|
||||
loaderId: loaderId2,
|
||||
@ -50,7 +62,20 @@ add_task(async function testTwoNavigations({ client }) {
|
||||
} = await Page.navigate({
|
||||
url: pageEmptyURL,
|
||||
});
|
||||
todo(loaderId !== loaderId2, "Page.navigate returns different loaderIds");
|
||||
const { loaderId: requestLoaderId2 } = await requestEvent;
|
||||
ok(!!loaderId, "Page.navigate returns loaderId");
|
||||
ok(!!loaderId2, "Page.navigate returns loaderId");
|
||||
isnot(loaderId, loaderId2, "Page.navigate returns different loaderIds");
|
||||
is(
|
||||
loaderId,
|
||||
requestLoaderId,
|
||||
"Page.navigate returns same loaderId as corresponding request"
|
||||
);
|
||||
is(
|
||||
loaderId2,
|
||||
requestLoaderId2,
|
||||
"Page.navigate returns same loaderId as corresponding request"
|
||||
);
|
||||
is(errorText, undefined, "No errorText on a successful navigation");
|
||||
is(errorText2, undefined, "No errorText on a successful navigation");
|
||||
is(frameId, frameId2, "Page.navigate return same frameId");
|
||||
@ -64,16 +89,25 @@ add_task(async function testTwoNavigations({ client }) {
|
||||
});
|
||||
|
||||
add_task(async function testRedirect({ client }) {
|
||||
const { Page } = client;
|
||||
const { Page, Network } = client;
|
||||
const sjsURL =
|
||||
"http://example.com/browser/remote/test/browser/page/sjs_redirect.sjs";
|
||||
const redirectURL = `${sjsURL}?${pageEmptyURL}`;
|
||||
await Page.enable();
|
||||
await Network.enable();
|
||||
const requestEvent = Network.requestWillBeSent();
|
||||
const loadEventFired = Page.loadEventFired();
|
||||
|
||||
const { frameId, loaderId, errorText } = await Page.navigate({
|
||||
url: redirectURL,
|
||||
});
|
||||
todo(!!loaderId, "Page.navigate returns loaderId");
|
||||
const { loaderId: requestLoaderId } = await requestEvent;
|
||||
ok(!!loaderId, "Page.navigate returns loaderId");
|
||||
is(
|
||||
loaderId,
|
||||
requestLoaderId,
|
||||
"Page.navigate returns same loaderId as original request"
|
||||
);
|
||||
is(errorText, undefined, "No errorText on a successful navigation");
|
||||
ok(!!frameId, "Page.navigate returns frameId");
|
||||
|
||||
@ -91,7 +125,7 @@ add_task(async function testUnknownHost({ client }) {
|
||||
url: "http://example-does-not-exist.com",
|
||||
});
|
||||
ok(!!frameId, "Page.navigate returns frameId");
|
||||
todo(!!loaderId, "Page.navigate returns loaderId");
|
||||
ok(!!loaderId, "Page.navigate returns loaderId");
|
||||
is(errorText, "NS_ERROR_UNKNOWN_HOST", "Failed navigation returns errorText");
|
||||
});
|
||||
|
||||
@ -101,7 +135,7 @@ add_task(async function testExpiredCertificate({ client }) {
|
||||
url: "https://expired.example.com",
|
||||
});
|
||||
ok(!!frameId, "Page.navigate returns frameId");
|
||||
todo(!!loaderId, "Page.navigate returns loaderId");
|
||||
ok(!!loaderId, "Page.navigate returns loaderId");
|
||||
is(
|
||||
errorText,
|
||||
"SEC_ERROR_EXPIRED_CERTIFICATE",
|
||||
@ -110,12 +144,20 @@ add_task(async function testExpiredCertificate({ client }) {
|
||||
});
|
||||
|
||||
add_task(async function testUnknownCertificate({ client }) {
|
||||
const { Page } = client;
|
||||
const { Page, Network } = client;
|
||||
await Network.enable();
|
||||
const requestEvent = Network.requestWillBeSent();
|
||||
const { frameId, loaderId, errorText } = await Page.navigate({
|
||||
url: "https://self-signed.example.com",
|
||||
});
|
||||
const { loaderId: requestLoaderId } = await requestEvent;
|
||||
ok(!!frameId, "Page.navigate returns frameId");
|
||||
todo(!!loaderId, "Page.navigate returns loaderId");
|
||||
ok(!!loaderId, "Page.navigate returns loaderId");
|
||||
is(
|
||||
loaderId,
|
||||
requestLoaderId,
|
||||
"Page.navigate returns same loaderId as original request"
|
||||
);
|
||||
is(errorText, "SSL_ERROR_UNKNOWN", "Failed navigation returns errorText");
|
||||
});
|
||||
|
||||
@ -125,7 +167,7 @@ add_task(async function testNotFound({ client }) {
|
||||
url: "http://example.com/browser/remote/doesnotexist.html",
|
||||
});
|
||||
ok(!!frameId, "Page.navigate returns frameId");
|
||||
todo(!!loaderId, "Page.navigate returns loaderId");
|
||||
ok(!!loaderId, "Page.navigate returns loaderId");
|
||||
is(errorText, undefined, "No errorText on a 404");
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user