summaryrefslogtreecommitdiffstats
path: root/docshell/test/browser/browser_isInitialDocument.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--docshell/test/browser/browser_isInitialDocument.js319
1 files changed, 319 insertions, 0 deletions
diff --git a/docshell/test/browser/browser_isInitialDocument.js b/docshell/test/browser/browser_isInitialDocument.js
new file mode 100644
index 0000000000..7a047c61d0
--- /dev/null
+++ b/docshell/test/browser/browser_isInitialDocument.js
@@ -0,0 +1,319 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tag every new WindowGlobalParent with an expando indicating whether or not
+// they were an initial document when they were created for the duration of this
+// test.
+function wasInitialDocumentObserver(subject) {
+ subject._test_wasInitialDocument = subject.isInitialDocument;
+}
+Services.obs.addObserver(wasInitialDocumentObserver, "window-global-created");
+SimpleTest.registerCleanupFunction(function () {
+ Services.obs.removeObserver(
+ wasInitialDocumentObserver,
+ "window-global-created"
+ );
+});
+
+add_task(async function new_about_blank_tab() {
+ await BrowserTestUtils.withNewTab("about:blank", async browser => {
+ is(
+ browser.browsingContext.currentWindowGlobal.isInitialDocument,
+ false,
+ "After loading an actual, final about:blank in the tab, the field is false"
+ );
+ });
+});
+
+add_task(async function iframe_initial_about_blank() {
+ await BrowserTestUtils.withNewTab(
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.com/document-builder.sjs?html=com",
+ async browser => {
+ info("Create an iframe without any explicit location");
+ await SpecialPowers.spawn(browser, [], async () => {
+ const iframe = content.document.createElement("iframe");
+ // Add the iframe to the DOM tree in order to be able to have its browsingContext
+ content.document.body.appendChild(iframe);
+ const { browsingContext } = iframe;
+
+ is(
+ iframe.contentDocument.isInitialDocument,
+ true,
+ "The field is true on just-created iframes"
+ );
+ let beforeLoadPromise = SpecialPowers.spawnChrome(
+ [browsingContext],
+ bc => [
+ bc.currentWindowGlobal.isInitialDocument,
+ bc.currentWindowGlobal._test_wasInitialDocument,
+ ]
+ );
+
+ await new Promise(resolve => {
+ iframe.addEventListener("load", resolve, { once: true });
+ });
+ is(
+ iframe.contentDocument.isInitialDocument,
+ false,
+ "The field is false after having loaded the final about:blank document"
+ );
+ let afterLoadPromise = SpecialPowers.spawnChrome(
+ [browsingContext],
+ bc => [
+ bc.currentWindowGlobal.isInitialDocument,
+ bc.currentWindowGlobal._test_wasInitialDocument,
+ ]
+ );
+
+ // Wait to await the parent process promises, so we can't miss the "load" event.
+ let [beforeIsInitial, beforeWasInitial] = await beforeLoadPromise;
+ is(beforeIsInitial, true, "before load is initial in parent");
+ is(beforeWasInitial, true, "before load was initial in parent");
+ let [afterIsInitial, afterWasInitial] = await afterLoadPromise;
+ is(afterIsInitial, false, "after load is not initial in parent");
+ is(afterWasInitial, true, "after load was initial in parent");
+ iframe.remove();
+ });
+
+ info("Create an iframe with a cross origin location");
+ const iframeBC = await SpecialPowers.spawn(browser, [], async () => {
+ const iframe = content.document.createElement("iframe");
+ await new Promise(resolve => {
+ iframe.addEventListener("load", resolve, { once: true });
+ iframe.src =
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.org/document-builder.sjs?html=org-iframe";
+ content.document.body.appendChild(iframe);
+ });
+
+ return iframe.browsingContext;
+ });
+
+ is(
+ iframeBC.currentWindowGlobal.isInitialDocument,
+ false,
+ "The field is true after having loaded the final document"
+ );
+ }
+ );
+});
+
+add_task(async function window_open() {
+ async function testWindowOpen({ browser, args, isCrossOrigin, willLoad }) {
+ info(`Open popup with ${JSON.stringify(args)}`);
+ const onNewTab = BrowserTestUtils.waitForNewTab(
+ gBrowser,
+ args[0] || "about:blank"
+ );
+ await SpecialPowers.spawn(
+ browser,
+ [args, isCrossOrigin, willLoad],
+ async (args, crossOrigin, willLoad) => {
+ const win = content.window.open(...args);
+ is(
+ win.document.isInitialDocument,
+ true,
+ "The field is true right after calling window.open()"
+ );
+ let beforeLoadPromise = SpecialPowers.spawnChrome(
+ [win.browsingContext],
+ bc => [
+ bc.currentWindowGlobal.isInitialDocument,
+ bc.currentWindowGlobal._test_wasInitialDocument,
+ ]
+ );
+
+ // In cross origin, it is harder to watch for new document load, and if
+ // no argument is passed no load will happen.
+ if (!crossOrigin && willLoad) {
+ await new Promise(r =>
+ win.addEventListener("load", r, { once: true })
+ );
+ is(
+ win.document.isInitialDocument,
+ false,
+ "The field becomes false right after the popup document is loaded"
+ );
+ }
+
+ // Perform the await after the load to avoid missing it.
+ let [beforeIsInitial, beforeWasInitial] = await beforeLoadPromise;
+ is(beforeIsInitial, true, "before load is initial in parent");
+ is(beforeWasInitial, true, "before load was initial in parent");
+ }
+ );
+ const newTab = await onNewTab;
+ const windowGlobal =
+ newTab.linkedBrowser.browsingContext.currentWindowGlobal;
+ if (willLoad) {
+ is(
+ windowGlobal.isInitialDocument,
+ false,
+ "The field is false in the parent process after having loaded the final document"
+ );
+ } else {
+ is(
+ windowGlobal.isInitialDocument,
+ true,
+ "The field remains true in the parent process as nothing will be loaded"
+ );
+ }
+ BrowserTestUtils.removeTab(newTab);
+ }
+
+ await BrowserTestUtils.withNewTab(
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.com/document-builder.sjs?html=com",
+ async browser => {
+ info("Use window.open() with cross-origin document");
+ await testWindowOpen({
+ browser,
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ args: ["http://example.org/document-builder.sjs?html=org-popup"],
+ isCrossOrigin: true,
+ willLoad: true,
+ });
+
+ info("Use window.open() with same-origin document");
+ await testWindowOpen({
+ browser,
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ args: ["http://example.com/document-builder.sjs?html=com-popup"],
+ isCrossOrigin: false,
+ willLoad: true,
+ });
+
+ info("Use window.open() with final about:blank document");
+ await testWindowOpen({
+ browser,
+ args: ["about:blank"],
+ isCrossOrigin: false,
+ willLoad: true,
+ });
+
+ info("Use window.open() with no argument");
+ await testWindowOpen({
+ browser,
+ args: [],
+ isCrossOrigin: false,
+ willLoad: false,
+ });
+ }
+ );
+});
+
+add_task(async function document_open() {
+ await BrowserTestUtils.withNewTab(
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.com/document-builder.sjs?html=com",
+ async browser => {
+ is(browser.browsingContext.currentWindowGlobal.isInitialDocument, false);
+ await SpecialPowers.spawn(browser, [], async () => {
+ const iframe = content.document.createElement("iframe");
+ // Add the iframe to the DOM tree in order to be able to have its browsingContext
+ content.document.body.appendChild(iframe);
+ const { browsingContext } = iframe;
+
+ // Check the state before the call in both parent and content.
+ is(
+ iframe.contentDocument.isInitialDocument,
+ true,
+ "Is an initial document before calling document.open"
+ );
+ let beforeOpenParentPromise = SpecialPowers.spawnChrome(
+ [browsingContext],
+ bc => [
+ bc.currentWindowGlobal.isInitialDocument,
+ bc.currentWindowGlobal._test_wasInitialDocument,
+ bc.currentWindowGlobal.innerWindowId,
+ ]
+ );
+
+ // Run the `document.open` call with reduced permissions.
+ iframe.contentWindow.eval(`
+ document.open();
+ document.write("new document");
+ document.close();
+ `);
+
+ is(
+ iframe.contentDocument.isInitialDocument,
+ false,
+ "Is no longer an initial document after calling document.open"
+ );
+ let [afterIsInitial, afterWasInitial, afterID] =
+ await SpecialPowers.spawnChrome([browsingContext], bc => [
+ bc.currentWindowGlobal.isInitialDocument,
+ bc.currentWindowGlobal._test_wasInitialDocument,
+ bc.currentWindowGlobal.innerWindowId,
+ ]);
+ let [beforeIsInitial, beforeWasInitial, beforeID] =
+ await beforeOpenParentPromise;
+ is(beforeIsInitial, true, "Should be initial before in the parent");
+ is(beforeWasInitial, true, "Was initial before in the parent");
+ is(afterIsInitial, false, "Should not be initial after in the parent");
+ is(afterWasInitial, true, "Was initial after in the parent");
+ is(beforeID, afterID, "Should be the same WindowGlobalParent");
+ });
+ }
+ );
+});
+
+add_task(async function windowless_browser() {
+ info("Create a Windowless browser");
+ const browser = Services.appShell.createWindowlessBrowser(false);
+ const { browsingContext } = browser;
+ is(
+ browsingContext.currentWindowGlobal.isInitialDocument,
+ true,
+ "The field is true for a freshly created WindowlessBrowser"
+ );
+ is(
+ browser.currentURI.spec,
+ "about:blank",
+ "The location is immediately set to about:blank"
+ );
+
+ const principal = Services.scriptSecurityManager.getSystemPrincipal();
+ browser.docShell.createAboutBlankContentViewer(principal, principal);
+ is(
+ browsingContext.currentWindowGlobal.isInitialDocument,
+ false,
+ "The field becomes false when creating an artificial blank document"
+ );
+
+ info("Load a final about:blank document in it");
+ const onLocationChange = new Promise(resolve => {
+ let wpl = {
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIWebProgressListener",
+ "nsISupportsWeakReference",
+ ]),
+ onLocationChange() {
+ browsingContext.webProgress.removeProgressListener(
+ wpl,
+ Ci.nsIWebProgress.NOTIFY_ALL
+ );
+ resolve();
+ },
+ };
+ browsingContext.webProgress.addProgressListener(
+ wpl,
+ Ci.nsIWebProgress.NOTIFY_ALL
+ );
+ });
+ browser.loadURI(Services.io.newURI("about:blank"), {
+ triggeringPrincipal: principal,
+ });
+ info("Wait for the location change");
+ await onLocationChange;
+ is(
+ browsingContext.currentWindowGlobal.isInitialDocument,
+ false,
+ "The field is false after the location change event"
+ );
+ browser.close();
+});