1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
6 // Tag every new WindowGlobalParent with an expando indicating whether or not
7 // they were an initial document when they were created for the duration of this
9 function wasInitialDocumentObserver(subject) {
10 subject._test_wasInitialDocument = subject.isInitialDocument;
12 Services.obs.addObserver(wasInitialDocumentObserver, "window-global-created");
13 SimpleTest.registerCleanupFunction(function () {
14 Services.obs.removeObserver(
15 wasInitialDocumentObserver,
16 "window-global-created"
20 add_task(async function new_about_blank_tab() {
21 await BrowserTestUtils.withNewTab("about:blank", async browser => {
23 browser.browsingContext.currentWindowGlobal.isInitialDocument,
25 "After loading an actual, final about:blank in the tab, the field is false"
30 add_task(async function iframe_initial_about_blank() {
31 await BrowserTestUtils.withNewTab(
32 // eslint-disable-next-line @microsoft/sdl/no-insecure-url
33 "http://example.com/document-builder.sjs?html=com",
35 info("Create an iframe without any explicit location");
36 await SpecialPowers.spawn(browser, [], async () => {
37 const iframe = content.document.createElement("iframe");
38 // Add the iframe to the DOM tree in order to be able to have its browsingContext
39 content.document.body.appendChild(iframe);
40 const { browsingContext } = iframe;
43 iframe.contentDocument.isInitialDocument,
45 "The field is true on just-created iframes"
47 let beforeLoadPromise = SpecialPowers.spawnChrome(
50 bc.currentWindowGlobal.isInitialDocument,
51 bc.currentWindowGlobal._test_wasInitialDocument,
55 await new Promise(resolve => {
56 iframe.addEventListener("load", resolve, { once: true });
59 iframe.contentDocument.isInitialDocument,
61 "The field is false after having loaded the final about:blank document"
63 let afterLoadPromise = SpecialPowers.spawnChrome(
66 bc.currentWindowGlobal.isInitialDocument,
67 bc.currentWindowGlobal._test_wasInitialDocument,
71 // Wait to await the parent process promises, so we can't miss the "load" event.
72 let [beforeIsInitial, beforeWasInitial] = await beforeLoadPromise;
73 is(beforeIsInitial, true, "before load is initial in parent");
74 is(beforeWasInitial, true, "before load was initial in parent");
75 let [afterIsInitial, afterWasInitial] = await afterLoadPromise;
76 is(afterIsInitial, false, "after load is not initial in parent");
77 is(afterWasInitial, true, "after load was initial in parent");
81 info("Create an iframe with a cross origin location");
82 const iframeBC = await SpecialPowers.spawn(browser, [], async () => {
83 const iframe = content.document.createElement("iframe");
84 await new Promise(resolve => {
85 iframe.addEventListener("load", resolve, { once: true });
87 // eslint-disable-next-line @microsoft/sdl/no-insecure-url
88 "http://example.org/document-builder.sjs?html=org-iframe";
89 content.document.body.appendChild(iframe);
92 return iframe.browsingContext;
96 iframeBC.currentWindowGlobal.isInitialDocument,
98 "The field is true after having loaded the final document"
104 add_task(async function window_open() {
105 async function testWindowOpen({ browser, args, isCrossOrigin, willLoad }) {
106 info(`Open popup with ${JSON.stringify(args)}`);
107 const onNewTab = BrowserTestUtils.waitForNewTab(
109 args[0] || "about:blank"
111 await SpecialPowers.spawn(
113 [args, isCrossOrigin, willLoad],
114 async (args, crossOrigin, willLoad) => {
115 const win = content.window.open(...args);
117 win.document.isInitialDocument,
119 "The field is true right after calling window.open()"
121 let beforeLoadPromise = SpecialPowers.spawnChrome(
122 [win.browsingContext],
124 bc.currentWindowGlobal.isInitialDocument,
125 bc.currentWindowGlobal._test_wasInitialDocument,
129 // In cross origin, it is harder to watch for new document load, and if
130 // no argument is passed no load will happen.
131 if (!crossOrigin && willLoad) {
132 await new Promise(r =>
133 win.addEventListener("load", r, { once: true })
136 win.document.isInitialDocument,
138 "The field becomes false right after the popup document is loaded"
142 // Perform the await after the load to avoid missing it.
143 let [beforeIsInitial, beforeWasInitial] = await beforeLoadPromise;
144 is(beforeIsInitial, true, "before load is initial in parent");
145 is(beforeWasInitial, true, "before load was initial in parent");
148 const newTab = await onNewTab;
150 newTab.linkedBrowser.browsingContext.currentWindowGlobal;
153 windowGlobal.isInitialDocument,
155 "The field is false in the parent process after having loaded the final document"
159 windowGlobal.isInitialDocument,
161 "The field remains true in the parent process as nothing will be loaded"
164 BrowserTestUtils.removeTab(newTab);
167 await BrowserTestUtils.withNewTab(
168 // eslint-disable-next-line @microsoft/sdl/no-insecure-url
169 "http://example.com/document-builder.sjs?html=com",
171 info("Use window.open() with cross-origin document");
172 await testWindowOpen({
174 // eslint-disable-next-line @microsoft/sdl/no-insecure-url
175 args: ["http://example.org/document-builder.sjs?html=org-popup"],
180 info("Use window.open() with same-origin document");
181 await testWindowOpen({
183 // eslint-disable-next-line @microsoft/sdl/no-insecure-url
184 args: ["http://example.com/document-builder.sjs?html=com-popup"],
185 isCrossOrigin: false,
189 info("Use window.open() with final about:blank document");
190 await testWindowOpen({
192 args: ["about:blank"],
193 isCrossOrigin: false,
197 info("Use window.open() with no argument");
198 await testWindowOpen({
201 isCrossOrigin: false,
208 add_task(async function document_open() {
209 await BrowserTestUtils.withNewTab(
210 // eslint-disable-next-line @microsoft/sdl/no-insecure-url
211 "http://example.com/document-builder.sjs?html=com",
213 is(browser.browsingContext.currentWindowGlobal.isInitialDocument, false);
214 await SpecialPowers.spawn(browser, [], async () => {
215 const iframe = content.document.createElement("iframe");
216 // Add the iframe to the DOM tree in order to be able to have its browsingContext
217 content.document.body.appendChild(iframe);
218 const { browsingContext } = iframe;
220 // Check the state before the call in both parent and content.
222 iframe.contentDocument.isInitialDocument,
224 "Is an initial document before calling document.open"
226 let beforeOpenParentPromise = SpecialPowers.spawnChrome(
229 bc.currentWindowGlobal.isInitialDocument,
230 bc.currentWindowGlobal._test_wasInitialDocument,
231 bc.currentWindowGlobal.innerWindowId,
235 // Run the `document.open` call with reduced permissions.
236 iframe.contentWindow.eval(`
238 document.write("new document");
243 iframe.contentDocument.isInitialDocument,
245 "Is no longer an initial document after calling document.open"
247 let [afterIsInitial, afterWasInitial, afterID] =
248 await SpecialPowers.spawnChrome([browsingContext], bc => [
249 bc.currentWindowGlobal.isInitialDocument,
250 bc.currentWindowGlobal._test_wasInitialDocument,
251 bc.currentWindowGlobal.innerWindowId,
253 let [beforeIsInitial, beforeWasInitial, beforeID] =
254 await beforeOpenParentPromise;
255 is(beforeIsInitial, true, "Should be initial before in the parent");
256 is(beforeWasInitial, true, "Was initial before in the parent");
257 is(afterIsInitial, false, "Should not be initial after in the parent");
258 is(afterWasInitial, true, "Was initial after in the parent");
259 is(beforeID, afterID, "Should be the same WindowGlobalParent");
265 add_task(async function windowless_browser() {
266 info("Create a Windowless browser");
267 const browser = Services.appShell.createWindowlessBrowser(false);
268 const { browsingContext } = browser;
270 browsingContext.currentWindowGlobal.isInitialDocument,
272 "The field is true for a freshly created WindowlessBrowser"
275 browser.currentURI.spec,
277 "The location is immediately set to about:blank"
280 const principal = Services.scriptSecurityManager.getSystemPrincipal();
281 browser.docShell.createAboutBlankDocumentViewer(principal, principal);
283 browsingContext.currentWindowGlobal.isInitialDocument,
285 "The field becomes false when creating an artificial blank document"
288 info("Load a final about:blank document in it");
289 const onLocationChange = new Promise(resolve => {
291 QueryInterface: ChromeUtils.generateQI([
292 "nsIWebProgressListener",
293 "nsISupportsWeakReference",
296 browsingContext.webProgress.removeProgressListener(
298 Ci.nsIWebProgress.NOTIFY_ALL
303 browsingContext.webProgress.addProgressListener(
305 Ci.nsIWebProgress.NOTIFY_ALL
308 browser.loadURI(Services.io.newURI("about:blank"), {
309 triggeringPrincipal: principal,
311 info("Wait for the location change");
312 await onLocationChange;
314 browsingContext.currentWindowGlobal.isInitialDocument,
316 "The field is false after the location change event"