408 lines
13 KiB
JavaScript
408 lines
13 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
const { NavigationManager } = ChromeUtils.importESModule(
|
|
"chrome://remote/content/shared/NavigationManager.sys.mjs"
|
|
);
|
|
const { TabManager } = ChromeUtils.importESModule(
|
|
"chrome://remote/content/shared/TabManager.sys.mjs"
|
|
);
|
|
|
|
const FIRST_URL = "https://example.com/document-builder.sjs?html=first";
|
|
const SECOND_URL = "https://example.com/document-builder.sjs?html=second";
|
|
const THIRD_URL = "https://example.com/document-builder.sjs?html=third";
|
|
|
|
const FIRST_COOP_URL =
|
|
"https://example.com/document-builder.sjs?headers=Cross-Origin-Opener-Policy:same-origin&html=first_coop";
|
|
const SECOND_COOP_URL =
|
|
"https://example.net/document-builder.sjs?headers=Cross-Origin-Opener-Policy:same-origin&html=second_coop";
|
|
|
|
add_task(async function test_simpleNavigation() {
|
|
const events = [];
|
|
const onEvent = (name, data) => events.push({ name, data });
|
|
|
|
const navigationManager = new NavigationManager();
|
|
navigationManager.on("navigation-started", onEvent);
|
|
navigationManager.on("navigation-stopped", onEvent);
|
|
|
|
const tab = addTab(gBrowser, FIRST_URL);
|
|
const browser = tab.linkedBrowser;
|
|
await BrowserTestUtils.browserLoaded(browser);
|
|
|
|
const navigableId = TabManager.getIdForBrowser(browser);
|
|
|
|
navigationManager.startMonitoring();
|
|
is(
|
|
navigationManager.getNavigationForBrowsingContext(browser.browsingContext),
|
|
null,
|
|
"No navigation recorded yet"
|
|
);
|
|
is(events.length, 0, "No event recorded");
|
|
|
|
await loadURL(browser, SECOND_URL);
|
|
await BrowserTestUtils.waitForCondition(() => events.length === 2);
|
|
|
|
const firstNavigation = navigationManager.getNavigationForBrowsingContext(
|
|
browser.browsingContext
|
|
);
|
|
assertNavigation(firstNavigation, SECOND_URL);
|
|
|
|
is(events.length, 2, "Two events recorded");
|
|
assertNavigationEvents(
|
|
events,
|
|
SECOND_URL,
|
|
firstNavigation.navigationId,
|
|
navigableId
|
|
);
|
|
|
|
await loadURL(browser, THIRD_URL);
|
|
await BrowserTestUtils.waitForCondition(() => events.length === 4);
|
|
|
|
const secondNavigation = navigationManager.getNavigationForBrowsingContext(
|
|
browser.browsingContext
|
|
);
|
|
assertNavigation(secondNavigation, THIRD_URL);
|
|
assertUniqueNavigationIds(firstNavigation, secondNavigation);
|
|
|
|
is(events.length, 4, "Two new events recorded");
|
|
assertNavigationEvents(
|
|
events,
|
|
THIRD_URL,
|
|
secondNavigation.navigationId,
|
|
navigableId
|
|
);
|
|
|
|
navigationManager.stopMonitoring();
|
|
|
|
// Navigate again to the first URL
|
|
await loadURL(browser, FIRST_URL);
|
|
is(events.length, 4, "No new event recorded");
|
|
is(
|
|
navigationManager.getNavigationForBrowsingContext(browser.browsingContext),
|
|
null,
|
|
"No navigation recorded"
|
|
);
|
|
|
|
navigationManager.off("navigation-started", onEvent);
|
|
navigationManager.off("navigation-stopped", onEvent);
|
|
});
|
|
|
|
add_task(async function test_loadTwoTabsSimultaneously() {
|
|
const events = [];
|
|
const onEvent = (name, data) => events.push({ name, data });
|
|
|
|
const navigationManager = new NavigationManager();
|
|
navigationManager.on("navigation-started", onEvent);
|
|
navigationManager.on("navigation-stopped", onEvent);
|
|
|
|
navigationManager.startMonitoring();
|
|
|
|
info("Add two tabs simultaneously");
|
|
const tab1 = addTab(gBrowser, FIRST_URL);
|
|
const browser1 = tab1.linkedBrowser;
|
|
const navigableId1 = TabManager.getIdForBrowser(browser1);
|
|
const onLoad1 = BrowserTestUtils.browserLoaded(browser1, false, FIRST_URL);
|
|
|
|
const tab2 = addTab(gBrowser, SECOND_URL);
|
|
const browser2 = tab2.linkedBrowser;
|
|
const navigableId2 = TabManager.getIdForBrowser(browser2);
|
|
const onLoad2 = BrowserTestUtils.browserLoaded(browser2, false, SECOND_URL);
|
|
|
|
info("Wait for the tabs to load");
|
|
await Promise.all([onLoad1, onLoad2]);
|
|
await BrowserTestUtils.waitForCondition(() => events.length === 4);
|
|
|
|
is(events.length, 4, "Recorded 4 navigation events");
|
|
|
|
info("Check navigation monitored for tab1");
|
|
const nav1 = navigationManager.getNavigationForBrowsingContext(
|
|
browser1.browsingContext
|
|
);
|
|
assertNavigation(nav1, FIRST_URL);
|
|
assertNavigationEvents(events, FIRST_URL, nav1.navigationId, navigableId1);
|
|
|
|
info("Check navigation monitored for tab2");
|
|
const nav2 = navigationManager.getNavigationForBrowsingContext(
|
|
browser2.browsingContext
|
|
);
|
|
assertNavigation(nav2, SECOND_URL);
|
|
assertNavigationEvents(events, SECOND_URL, nav2.navigationId, navigableId2);
|
|
assertUniqueNavigationIds(nav1, nav2);
|
|
|
|
info("Reload the two tabs simultaneously");
|
|
await Promise.all([
|
|
BrowserTestUtils.reloadTab(tab1),
|
|
BrowserTestUtils.reloadTab(tab2),
|
|
]);
|
|
await BrowserTestUtils.waitForCondition(() => events.length === 8);
|
|
|
|
is(events.length, 8, "Recorded 8 navigation events");
|
|
|
|
info("Check the second navigation for tab1");
|
|
const nav3 = navigationManager.getNavigationForBrowsingContext(
|
|
browser1.browsingContext
|
|
);
|
|
assertNavigation(nav3, FIRST_URL);
|
|
assertNavigationEvents(events, FIRST_URL, nav3.navigationId, navigableId1);
|
|
|
|
info("Check the second navigation monitored for tab2");
|
|
const nav4 = navigationManager.getNavigationForBrowsingContext(
|
|
browser2.browsingContext
|
|
);
|
|
assertNavigation(nav4, SECOND_URL);
|
|
assertNavigationEvents(events, SECOND_URL, nav4.navigationId, navigableId2);
|
|
assertUniqueNavigationIds(nav1, nav2, nav3, nav4);
|
|
|
|
navigationManager.off("navigation-started", onEvent);
|
|
navigationManager.off("navigation-stopped", onEvent);
|
|
navigationManager.stopMonitoring();
|
|
});
|
|
|
|
add_task(async function test_loadPageWithIframes() {
|
|
if (
|
|
Services.prefs.getBoolPref(
|
|
"remote.experimental-parent-navigation.enabled",
|
|
false
|
|
)
|
|
) {
|
|
todo(
|
|
false,
|
|
"The ParentWebProgressListener misses events from same process iframes"
|
|
);
|
|
return;
|
|
}
|
|
|
|
const events = [];
|
|
const onEvent = (name, data) => events.push({ name, data });
|
|
|
|
const navigationManager = new NavigationManager();
|
|
navigationManager.on("navigation-started", onEvent);
|
|
navigationManager.on("navigation-stopped", onEvent);
|
|
|
|
navigationManager.startMonitoring();
|
|
|
|
info("Add a tab with iframes");
|
|
const testUrl = createTestPageWithFrames();
|
|
const tab = addTab(gBrowser, testUrl);
|
|
const browser = tab.linkedBrowser;
|
|
await BrowserTestUtils.browserLoaded(browser, false, testUrl);
|
|
await BrowserTestUtils.waitForCondition(() => events.length === 8);
|
|
|
|
is(events.length, 8, "Recorded 8 navigation events");
|
|
const contexts = browser.browsingContext.getAllBrowsingContextsInSubtree();
|
|
|
|
const navigations = [];
|
|
for (const context of contexts) {
|
|
const navigation =
|
|
navigationManager.getNavigationForBrowsingContext(context);
|
|
const navigable = TabManager.getIdForBrowsingContext(context);
|
|
|
|
const url = context.currentWindowGlobal.documentURI.spec;
|
|
assertNavigation(navigation, url);
|
|
assertNavigationEvents(events, url, navigation.navigationId, navigable);
|
|
navigations.push(navigation);
|
|
}
|
|
assertUniqueNavigationIds(...navigations);
|
|
|
|
await BrowserTestUtils.reloadTab(tab);
|
|
await BrowserTestUtils.waitForCondition(() => events.length === 16);
|
|
|
|
is(events.length, 16, "Recorded 8 additional navigation events");
|
|
const newContexts = browser.browsingContext.getAllBrowsingContextsInSubtree();
|
|
|
|
for (const context of newContexts) {
|
|
const navigation =
|
|
navigationManager.getNavigationForBrowsingContext(context);
|
|
const navigable = TabManager.getIdForBrowsingContext(context);
|
|
|
|
const url = context.currentWindowGlobal.documentURI.spec;
|
|
assertNavigation(navigation, url);
|
|
assertNavigationEvents(events, url, navigation.navigationId, navigable);
|
|
navigations.push(navigation);
|
|
}
|
|
assertUniqueNavigationIds(...navigations);
|
|
|
|
navigationManager.off("navigation-started", onEvent);
|
|
navigationManager.off("navigation-stopped", onEvent);
|
|
navigationManager.stopMonitoring();
|
|
});
|
|
|
|
add_task(async function test_loadPageWithCoop() {
|
|
if (
|
|
Services.prefs.getBoolPref(
|
|
"remote.experimental-parent-navigation.enabled",
|
|
false
|
|
)
|
|
) {
|
|
todo(
|
|
false,
|
|
"The ParentWebProgressListener misses navigation stopped for coop navigation"
|
|
);
|
|
return;
|
|
}
|
|
|
|
const tab = addTab(gBrowser, FIRST_COOP_URL);
|
|
const browser = tab.linkedBrowser;
|
|
await BrowserTestUtils.browserLoaded(browser, false, FIRST_COOP_URL);
|
|
|
|
const events = [];
|
|
const onEvent = (name, data) => events.push({ name, data });
|
|
|
|
const navigationManager = new NavigationManager();
|
|
navigationManager.on("navigation-started", onEvent);
|
|
navigationManager.on("navigation-stopped", onEvent);
|
|
|
|
navigationManager.startMonitoring();
|
|
|
|
const navigableId = TabManager.getIdForBrowser(browser);
|
|
await loadURL(browser, SECOND_COOP_URL);
|
|
await BrowserTestUtils.waitForCondition(() => events.length === 2);
|
|
|
|
const coopNavigation = navigationManager.getNavigationForBrowsingContext(
|
|
browser.browsingContext
|
|
);
|
|
assertNavigation(coopNavigation, SECOND_COOP_URL);
|
|
|
|
is(events.length, 2, "Two events recorded");
|
|
assertNavigationEvents(
|
|
events,
|
|
SECOND_COOP_URL,
|
|
coopNavigation.navigationId,
|
|
navigableId
|
|
);
|
|
|
|
navigationManager.off("navigation-started", onEvent);
|
|
navigationManager.off("navigation-stopped", onEvent);
|
|
navigationManager.stopMonitoring();
|
|
});
|
|
|
|
add_task(async function test_sameDocumentNavigation() {
|
|
const events = [];
|
|
const onEvent = (name, data) => events.push({ name, data });
|
|
|
|
const navigationManager = new NavigationManager();
|
|
navigationManager.on("fragment-navigated", onEvent);
|
|
navigationManager.on("navigation-started", onEvent);
|
|
navigationManager.on("navigation-stopped", onEvent);
|
|
navigationManager.on("same-document-changed", onEvent);
|
|
|
|
const url = "https://example.com/document-builder.sjs?html=test";
|
|
const tab = addTab(gBrowser, url);
|
|
const browser = tab.linkedBrowser;
|
|
await BrowserTestUtils.browserLoaded(browser);
|
|
|
|
navigationManager.startMonitoring();
|
|
const navigableId = TabManager.getIdForBrowser(browser);
|
|
|
|
is(events.length, 0, "No event recorded");
|
|
|
|
info("Perform a same-document navigation");
|
|
let onFragmentNavigated = navigationManager.once("fragment-navigated");
|
|
BrowserTestUtils.startLoadingURIString(browser, url + "#hash");
|
|
await onFragmentNavigated;
|
|
|
|
const hashNavigation = navigationManager.getNavigationForBrowsingContext(
|
|
browser.browsingContext
|
|
);
|
|
is(events.length, 1, "Recorded 1 navigation event");
|
|
assertNavigationEvents(
|
|
events,
|
|
url + "#hash",
|
|
hashNavigation.navigationId,
|
|
navigableId,
|
|
true
|
|
);
|
|
|
|
// Navigate from `url + "#hash"` to `url`, this will trigger a regular
|
|
// navigation and we can use `loadURL` to properly wait for the navigation to
|
|
// complete.
|
|
info("Perform a regular navigation");
|
|
await loadURL(browser, url);
|
|
await BrowserTestUtils.waitForCondition(() => events.length === 3);
|
|
|
|
const regularNavigation = navigationManager.getNavigationForBrowsingContext(
|
|
browser.browsingContext
|
|
);
|
|
is(events.length, 3, "Recorded 2 additional navigation events");
|
|
assertNavigationEvents(
|
|
events,
|
|
url,
|
|
regularNavigation.navigationId,
|
|
navigableId
|
|
);
|
|
|
|
info("Perform another hash navigation");
|
|
onFragmentNavigated = navigationManager.once("fragment-navigated");
|
|
BrowserTestUtils.startLoadingURIString(browser, url + "#foo");
|
|
await onFragmentNavigated;
|
|
|
|
const otherHashNavigation = navigationManager.getNavigationForBrowsingContext(
|
|
browser.browsingContext
|
|
);
|
|
|
|
is(events.length, 4, "Recorded 1 additional navigation event");
|
|
|
|
info("Perform a same-hash navigation");
|
|
onFragmentNavigated = navigationManager.once("fragment-navigated");
|
|
BrowserTestUtils.startLoadingURIString(browser, url + "#foo");
|
|
await onFragmentNavigated;
|
|
|
|
const sameHashNavigation = navigationManager.getNavigationForBrowsingContext(
|
|
browser.browsingContext
|
|
);
|
|
|
|
is(events.length, 5, "Recorded 1 additional navigation event");
|
|
assertNavigationEvents(
|
|
events,
|
|
url + "#foo",
|
|
sameHashNavigation.navigationId,
|
|
navigableId,
|
|
true
|
|
);
|
|
|
|
assertUniqueNavigationIds([
|
|
hashNavigation,
|
|
regularNavigation,
|
|
otherHashNavigation,
|
|
sameHashNavigation,
|
|
]);
|
|
|
|
navigationManager.off("fragment-navigated", onEvent);
|
|
navigationManager.off("navigation-started", onEvent);
|
|
navigationManager.off("navigation-stopped", onEvent);
|
|
navigationManager.off("same-document-changed", onEvent);
|
|
|
|
navigationManager.stopMonitoring();
|
|
});
|
|
|
|
add_task(async function test_startNavigationAndCloseTab() {
|
|
const events = [];
|
|
const onEvent = (name, data) => events.push({ name, data });
|
|
|
|
const navigationManager = new NavigationManager();
|
|
navigationManager.on("navigation-started", onEvent);
|
|
navigationManager.on("navigation-stopped", onEvent);
|
|
|
|
const tab = addTab(gBrowser, FIRST_URL);
|
|
const browser = tab.linkedBrowser;
|
|
await BrowserTestUtils.browserLoaded(browser);
|
|
|
|
navigationManager.startMonitoring();
|
|
loadURL(browser, SECOND_URL);
|
|
gBrowser.removeTab(tab);
|
|
|
|
// On top of the assertions below, the test also validates that there is no
|
|
// unhandled promise rejection related to handling the navigation-started event
|
|
// for the destroyed browsing context.
|
|
is(events.length, 0, "No event was received");
|
|
is(
|
|
navigationManager.getNavigationForBrowsingContext(browser.browsingContext),
|
|
null,
|
|
"No navigation was recorded for the destroyed tab"
|
|
);
|
|
navigationManager.stopMonitoring();
|
|
|
|
navigationManager.off("navigation-started", onEvent);
|
|
navigationManager.off("navigation-stopped", onEvent);
|
|
});
|