/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; requestLongerTimeout(2); /** * Ensure that starting a load invalidates shistory. */ add_task(async function test_load_start() { // Create a new tab. let tab = BrowserTestUtils.addTab(gBrowser, "about:blank"); let browser = tab.linkedBrowser; await promiseBrowserLoaded(browser); const PAGE = "http://example.com/"; // Load a new URI. let historyReplacePromise = promiseOnHistoryReplaceEntry(browser); BrowserTestUtils.loadURIString(browser, PAGE); // Remove the tab before it has finished loading. await historyReplacePromise; await promiseRemoveTabAndSessionState(tab); // Undo close the tab. tab = ss.undoCloseTab(window, 0); browser = tab.linkedBrowser; await promiseTabRestored(tab); // Check that the correct URL was restored. is(browser.currentURI.spec, PAGE, "url is correct"); // Cleanup. gBrowser.removeTab(tab); }); /** * Ensure that anchor navigation invalidates shistory. */ add_task(async function test_hashchange() { const PATH = getRootDirectory(gTestPath).replace( "chrome://mochitests/content/", "http://example.com/" ); const URL = PATH + "file_sessionHistory_hashchange.html"; // Create a new tab. let tab = BrowserTestUtils.addTab(gBrowser, URL); let browser = tab.linkedBrowser; await promiseBrowserLoaded(browser); // Check that we start with a single shistory entry. await TabStateFlusher.flush(browser); let { entries } = JSON.parse(ss.getTabState(tab)); is(entries.length, 1, "there is one shistory entry"); // Click the link and wait for a hashchange event. let eventPromise = BrowserTestUtils.waitForContentEvent( browser, "hashchange", true ); await SpecialPowers.spawn(browser, [], async function () { content.document.querySelector("#a").click(); }); info("About to watch for a hash change event"); await eventPromise; info("Got a hash change event"); // Check that we now have two shistory entries. await TabStateFlusher.flush(browser); ({ entries } = JSON.parse(ss.getTabState(tab))); is(entries.length, 2, "there are two shistory entries"); // Cleanup. gBrowser.removeTab(tab); }); /** * Ensure that loading pages from the bfcache invalidates shistory. */ add_task(async function test_pageshow() { const URL = "data:text/html;charset=utf-8,

first

"; const URL2 = "data:text/html;charset=utf-8,

second

"; // Create a new tab. let tab = BrowserTestUtils.addTab(gBrowser, URL); let browser = tab.linkedBrowser; await promiseBrowserLoaded(browser); // Create a second shistory entry. BrowserTestUtils.loadURIString(browser, URL2); await promiseBrowserLoaded(browser); // Wait until shistory changes. let pageShowPromise = BrowserTestUtils.waitForContentEvent( browser, "pageshow", true ); // Go back to the previous url which is loaded from the bfcache. browser.goBack(); await pageShowPromise; is(browser.currentURI.spec, URL, "correct url after going back"); // Check that loading from bfcache did invalidate shistory. await TabStateFlusher.flush(browser); let { index } = JSON.parse(ss.getTabState(tab)); is(index, 1, "first history entry is selected"); // Cleanup. gBrowser.removeTab(tab); }); /** * Ensure that subframe navigation invalidates shistory. */ add_task(async function test_subframes() { const URL = "data:text/html;charset=utf-8," + "" + "clickme" + "clickme"; // Create a new tab. let tab = BrowserTestUtils.addTab(gBrowser, URL); let browser = tab.linkedBrowser; await promiseBrowserLoaded(browser); // Check that we have a single shistory entry. await TabStateFlusher.flush(browser); let { entries } = JSON.parse(ss.getTabState(tab)); is(entries.length, 1, "there is one shistory entry"); is(entries[0].children.length, 1, "the entry has one child"); // Navigate the subframe. await SpecialPowers.spawn(browser, [], async function () { content.document.querySelector("#a1").click(); }); await promiseBrowserLoaded( browser, false /* wait for subframe load only */, "http://example.com/1" ); // Check shistory. await TabStateFlusher.flush(browser); ({ entries } = JSON.parse(ss.getTabState(tab))); is(entries.length, 2, "there now are two shistory entries"); is(entries[1].children.length, 1, "the second entry has one child"); // Go back in history. let goneBack = promiseBrowserLoaded( browser, false /* wait for subframe load only */, "http://example.com/" ); info("About to go back in history"); browser.goBack(); await goneBack; // Navigate the subframe again. let eventPromise = BrowserTestUtils.waitForContentEvent( browser, "hashchange", true ); await SpecialPowers.spawn(browser, [], async function () { content.document.querySelector("#a2").click(); }); await eventPromise; // Check shistory. await TabStateFlusher.flush(browser); ({ entries } = JSON.parse(ss.getTabState(tab))); is(entries.length, 2, "there now are two shistory entries"); is(entries[1].children.length, 1, "the second entry has one child"); // Cleanup. gBrowser.removeTab(tab); }); /** * Ensure that navigating from an about page invalidates shistory. */ add_task(async function test_about_page_navigate() { // Create a new tab. let tab = BrowserTestUtils.addTab(gBrowser, "about:blank"); let browser = tab.linkedBrowser; await promiseBrowserLoaded(browser); // Check that we have a single shistory entry. await TabStateFlusher.flush(browser); let { entries } = JSON.parse(ss.getTabState(tab)); is(entries.length, 1, "there is one shistory entry"); is(entries[0].url, "about:blank", "url is correct"); // Verify that the title is also recorded. is(entries[0].title, "about:blank", "title is correct"); BrowserTestUtils.loadURIString(browser, "about:robots"); await promiseBrowserLoaded(browser); // Check that we have changed the history entry. await TabStateFlusher.flush(browser); ({ entries } = JSON.parse(ss.getTabState(tab))); is(entries.length, 1, "there is one shistory entry"); is(entries[0].url, "about:robots", "url is correct"); // Cleanup. gBrowser.removeTab(tab); }); /** * Ensure that history.pushState and history.replaceState invalidate shistory. */ add_task(async function test_pushstate_replacestate() { // Create a new tab. let tab = BrowserTestUtils.addTab(gBrowser, "http://example.com/1"); let browser = tab.linkedBrowser; await promiseBrowserLoaded(browser); // Check that we have a single shistory entry. await TabStateFlusher.flush(browser); let { entries } = JSON.parse(ss.getTabState(tab)); is(entries.length, 1, "there is one shistory entry"); is(entries[0].url, "http://example.com/1", "url is correct"); await SpecialPowers.spawn(browser, [], async function () { content.window.history.pushState({}, "", "test-entry/"); }); // Check that we have added the history entry. await TabStateFlusher.flush(browser); ({ entries } = JSON.parse(ss.getTabState(tab))); is(entries.length, 2, "there is another shistory entry"); is(entries[1].url, "http://example.com/test-entry/", "url is correct"); await SpecialPowers.spawn(browser, [], async function () { content.window.history.replaceState({}, "", "test-entry2/"); }); // Check that we have modified the history entry. await TabStateFlusher.flush(browser); ({ entries } = JSON.parse(ss.getTabState(tab))); is(entries.length, 2, "there is still two shistory entries"); is( entries[1].url, "http://example.com/test-entry/test-entry2/", "url is correct" ); // Cleanup. gBrowser.removeTab(tab); }); /** * Ensure that slow loading subframes will invalidate shistory. */ add_task(async function test_slow_subframe_load() { const SLOW_URL = "http://mochi.test:8888/browser/browser/components/" + "sessionstore/test/browser_sessionHistory_slow.sjs"; const URL = "data:text/html;charset=utf-8," + "" + "" + ""; // Add a new tab with a slow loading subframe let tab = BrowserTestUtils.addTab(gBrowser, URL); let browser = tab.linkedBrowser; await promiseBrowserLoaded(browser); await TabStateFlusher.flush(browser); let { entries } = JSON.parse(ss.getTabState(tab)); // Check the number of children. is(entries.length, 1, "there is one root entry ..."); is(entries[0].children.length, 1, "... with one child entries"); // Check URLs. ok(entries[0].url.startsWith("data:text/html"), "correct root url"); is(entries[0].children[0].url, SLOW_URL, "correct url for subframe"); // Cleanup. gBrowser.removeTab(tab); }); /** * Ensure that document wireframes can be persisted when they're enabled. */ add_task(async function test_wireframes() { // Wireframes only works when Fission and SHIP are enabled. if ( !Services.appinfo.fissionAutostart || !Services.appinfo.sessionHistoryInParent ) { ok(true, "Skipping test_wireframes when Fission or SHIP is not enabled."); return; } await SpecialPowers.pushPrefEnv({ set: [["browser.history.collectWireframes", true]], }); let tab = BrowserTestUtils.addTab(gBrowser, "http://example.com"); let browser = tab.linkedBrowser; await promiseBrowserLoaded(browser); await TabStateFlusher.flush(browser); let { entries } = JSON.parse(ss.getTabState(tab)); // Check the number of children. is(entries.length, 1, "there is one shistory entry"); // Check for the wireframe ok(entries[0].wireframe, "A wireframe was captured and serialized."); ok( entries[0].wireframe.rects.length, "Several wireframe rects were captured." ); // Cleanup. gBrowser.removeTab(tab); });