michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: "use strict"; michael@0: michael@0: const URL = ROOT + "browser_frametree_sample.html"; michael@0: const URL_FRAMESET = ROOT + "browser_frametree_sample_frameset.html"; michael@0: michael@0: /** michael@0: * This ensures that loading a page normally, aborting a page load, reloading michael@0: * a page, navigating using the bfcache, and ignoring frames that were michael@0: * created dynamically work as expect. We expect the frame tree to be reset michael@0: * when a page starts loading and we also expect a valid frame tree to exist michael@0: * when it has stopped loading. michael@0: */ michael@0: add_task(function test_frametree() { michael@0: const FRAME_TREE_SINGLE = { href: URL }; michael@0: const FRAME_TREE_FRAMESET = { michael@0: href: URL_FRAMESET, michael@0: children: [{href: URL}, {href: URL}, {href: URL}] michael@0: }; michael@0: michael@0: // Create a tab with a single frame. michael@0: let tab = gBrowser.addTab(URL); michael@0: let browser = tab.linkedBrowser; michael@0: yield promiseNewFrameTree(browser); michael@0: yield checkFrameTree(browser, FRAME_TREE_SINGLE, michael@0: "loading a page resets and creates the frame tree correctly"); michael@0: michael@0: // Load the frameset and create two frames dynamically, the first on michael@0: // DOMContentLoaded and the second on load. michael@0: yield sendMessage(browser, "ss-test:createDynamicFrames", {id: "frames", url: URL}); michael@0: browser.loadURI(URL_FRAMESET); michael@0: yield promiseNewFrameTree(browser); michael@0: yield checkFrameTree(browser, FRAME_TREE_FRAMESET, michael@0: "dynamic frames created on or after the load event are ignored"); michael@0: michael@0: // Go back to the previous single-frame page. There will be no load event as michael@0: // the page is still in the bfcache. We thus make sure this type of navigation michael@0: // resets the frame tree. michael@0: browser.goBack(); michael@0: yield promiseNewFrameTree(browser); michael@0: yield checkFrameTree(browser, FRAME_TREE_SINGLE, michael@0: "loading from bfache resets and creates the frame tree correctly"); michael@0: michael@0: // Load the frameset again but abort the load early. michael@0: // The frame tree should still be reset and created. michael@0: browser.loadURI(URL_FRAMESET); michael@0: executeSoon(() => browser.stop()); michael@0: yield promiseNewFrameTree(browser); michael@0: michael@0: // Load the frameset and check the tree again. michael@0: yield sendMessage(browser, "ss-test:createDynamicFrames", {id: "frames", url: URL}); michael@0: browser.loadURI(URL_FRAMESET); michael@0: yield promiseNewFrameTree(browser); michael@0: yield checkFrameTree(browser, FRAME_TREE_FRAMESET, michael@0: "reloading a page resets and creates the frame tree correctly"); michael@0: michael@0: // Cleanup. michael@0: gBrowser.removeTab(tab); michael@0: }); michael@0: michael@0: /** michael@0: * This test ensures that we ignore frames that were created dynamically at or michael@0: * after the load event. SessionStore can't handle these and will not restore michael@0: * or collect any data for them. michael@0: */ michael@0: add_task(function test_frametree_dynamic() { michael@0: // The frame tree as expected. The first two frames are static michael@0: // and the third one was created on DOMContentLoaded. michael@0: const FRAME_TREE = { michael@0: href: URL_FRAMESET, michael@0: children: [{href: URL}, {href: URL}, {href: URL}] michael@0: }; michael@0: const FRAME_TREE_REMOVED = { michael@0: href: URL_FRAMESET, michael@0: children: [{href: URL}, {href: URL}] michael@0: }; michael@0: michael@0: // Add an empty tab for a start. michael@0: let tab = gBrowser.addTab("about:blank"); michael@0: let browser = tab.linkedBrowser; michael@0: yield promiseBrowserLoaded(browser); michael@0: michael@0: // Create dynamic frames on "DOMContentLoaded" and on "load". michael@0: yield sendMessage(browser, "ss-test:createDynamicFrames", {id: "frames", url: URL}); michael@0: browser.loadURI(URL_FRAMESET); michael@0: yield promiseNewFrameTree(browser); michael@0: michael@0: // Check that the frame tree does not contain the frame created on "load". michael@0: // The two static frames and the one created on DOMContentLoaded must be in michael@0: // the tree. michael@0: yield checkFrameTree(browser, FRAME_TREE, michael@0: "frame tree contains first four frames"); michael@0: michael@0: // Remove the last frame in the frameset. michael@0: yield sendMessage(browser, "ss-test:removeLastFrame", {id: "frames"}); michael@0: // Check that the frame tree didn't change. michael@0: yield checkFrameTree(browser, FRAME_TREE, michael@0: "frame tree contains first four frames"); michael@0: michael@0: // Remove the last frame in the frameset. michael@0: yield sendMessage(browser, "ss-test:removeLastFrame", {id: "frames"}); michael@0: // Check that the frame tree excludes the removed frame. michael@0: yield checkFrameTree(browser, FRAME_TREE_REMOVED, michael@0: "frame tree contains first three frames"); michael@0: michael@0: // Cleanup. michael@0: gBrowser.removeTab(tab); michael@0: }); michael@0: michael@0: /** michael@0: * Checks whether the current frame hierarchy of a given |browser| matches the michael@0: * |expected| frame hierarchy. michael@0: */ michael@0: function checkFrameTree(browser, expected, msg) { michael@0: return sendMessage(browser, "ss-test:mapFrameTree").then(tree => { michael@0: is(JSON.stringify(tree), JSON.stringify(expected), msg); michael@0: }); michael@0: } michael@0: michael@0: /** michael@0: * Returns a promise that will be resolved when the given |browser| has loaded michael@0: * and we received messages saying that its frame tree has been reset and michael@0: * recollected. michael@0: */ michael@0: function promiseNewFrameTree(browser) { michael@0: let reset = promiseContentMessage(browser, "ss-test:onFrameTreeCollected"); michael@0: let collect = promiseContentMessage(browser, "ss-test:onFrameTreeCollected"); michael@0: return Promise.all([reset, collect]); michael@0: }