diff options
Diffstat (limited to '')
-rw-r--r-- | docshell/test/browser/browser_isInitialDocument.js | 319 |
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(); +}); |