/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const URL = "about:blank"; async function getBrowsingContextId(browser, id) { return SpecialPowers.spawn(browser, [id], async function(id) { let contextId = content.window.docShell.browsingContext.id; let frames = [content.window]; while (frames.length) { let frame = frames.pop(); let target = frame.document.getElementById(id); if (target) { contextId = target.docShell.browsingContext.id; break; } frames = frames.concat(Array.from(frame.frames)); } return contextId; }); } async function addFrame(browser, id, parentId) { return SpecialPowers.spawn(browser, [{ parentId, id }], async function({ parentId, id, }) { let parent = null; if (parentId) { let frames = [content.window]; while (frames.length) { let frame = frames.pop(); let target = frame.document.getElementById(parentId); if (target) { parent = target.contentWindow.document.body; break; } frames = frames.concat(Array.from(frame.frames)); } } else { parent = content.document.body; } let frame = await new Promise(resolve => { let frame = content.document.createElement("iframe"); frame.id = id || ""; frame.url = "about:blank"; frame.onload = () => resolve(frame); parent.appendChild(frame); }); return frame.contentWindow.docShell.browsingContext.id; }); } async function removeFrame(browser, id) { return SpecialPowers.spawn(browser, [id], async function(id) { let frames = [content.window]; while (frames.length) { let frame = frames.pop(); let target = frame.document.getElementById(id); if (target) { target.remove(); break; } frames = frames.concat(Array.from(frame.frames)); } }); } function getBrowsingContextById(id) { return BrowsingContext.get(id); } add_task(async function() { await BrowserTestUtils.withNewTab({ gBrowser, url: URL }, async function( browser ) { let topId = await getBrowsingContextId(browser, ""); let topContext = getBrowsingContextById(topId); isnot(topContext, null); is(topContext.parent, null); is( topId, browser.browsingContext.id, " has the correct browsingContext" ); is( browser.browserId, topContext.browserId, "browsing context should have a correct id" ); let id0 = await addFrame(browser, "frame0"); let browsingContext0 = getBrowsingContextById(id0); isnot(browsingContext0, null); is(browsingContext0.parent, topContext); await removeFrame(browser, "frame0"); is(topContext.children.indexOf(browsingContext0), -1); // TODO(farre): Handle browsingContext removal [see Bug 1486719]. todo_isnot(browsingContext0.parent, topContext); }); }); add_task(async function() { await BrowserTestUtils.withNewTab( { gBrowser, url: getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.com" ) + "dummy_page.html", }, async function(browser) { let path = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.com" ); await SpecialPowers.spawn(browser, [path], async function(path) { function waitForMessage(command) { let r; let p = new Promise(resolve => { content.window.addEventListener( "message", e => resolve({ result: r, event: e }), { once: true } ); }); r = command(); return p; } // Open a new window and wait for the message. let { result: win, event: e1 } = await waitForMessage(_ => content.window.open(path + "onpageshow_message.html") ); is(e1.data, "pageshow"); { // Create, attach and load an iframe into the window's document. let frame = win.document.createElement("iframe"); win.document.body.appendChild(frame); frame.src = "dummy_page.html"; await ContentTaskUtils.waitForEvent(frame, "load"); } is(win.frames.length, 1, "Here we should have an iframe"); // The frame should have expected browsing context and docshell. let frameBC = win.frames[0].docShell.browsingContext; let winDocShell = win.frames[0].docShell; // Navigate the window and wait for the message. let { event: e2 } = await waitForMessage( _ => (win.location = path + "onload_message.html") ); is(e2.data, "load"); is(win.frames.length, 0, "Here there shouldn't be an iframe"); // Return to the previous document. N.B. we expect to trigger // BFCache here, hence we wait for pageshow. let { event: e3 } = await waitForMessage(_ => win.history.back()); is(e3.data, "pageshow"); is(win.frames.length, 1, "And again there should be an iframe"); is(winDocShell, win.frames[0].docShell, "BF cache cached docshell"); is( frameBC, win.frames[0].docShell.browsingContext, "BF cache cached BC" ); is( frameBC.id, win.frames[0].docShell.browsingContext.id, "BF cached BC's have same id" ); is( win.docShell.browsingContext.children[0], frameBC, "BF cached BC's should still be a child of its parent" ); is( win.docShell.browsingContext, frameBC.parent, "BF cached BC's should still be a connected to its parent" ); win.close(); }); } ); });