/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ /** * Tests search mode and session store. Also tests that search mode is * duplicated when duplicating tabs, since tab duplication is handled by session * store. */ "use strict"; ChromeUtils.defineESModuleGetters(this, { SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs", }); // This test takes a long time on the OS X 10.14 machines, so request a longer // timeout. See bug 1671045. This may also fix a different failure on Linux in // bug 1671087, but it's not clear. Regardless, a longer timeout won't hurt. requestLongerTimeout(5); const SEARCH_STRING = "test browser_sessionStore.js"; const URL = "http://example.com/"; // A URL in gInitialPages. We test this separately since SessionStore sometimes // takes different paths for these URLs. const INITIAL_URL = "about:newtab"; // The following tasks make sure non-null search mode is restored. add_task(async function initialPageOnRestore() { await doTest({ urls: [INITIAL_URL], searchModeTabIndex: 0, exitSearchMode: false, switchTabsAfterEnteringSearchMode: false, }); }); add_task(async function switchToInitialPage() { await doTest({ urls: [URL, INITIAL_URL], searchModeTabIndex: 1, exitSearchMode: false, switchTabsAfterEnteringSearchMode: true, }); }); add_task(async function nonInitialPageOnRestore() { await doTest({ urls: [URL], searchModeTabIndex: 0, exitSearchMode: false, switchTabsAfterEnteringSearchMode: false, }); }); add_task(async function switchToNonInitialPage() { await doTest({ urls: [INITIAL_URL, URL], searchModeTabIndex: 1, exitSearchMode: false, switchTabsAfterEnteringSearchMode: true, }); }); // The following tasks enter and then exit search mode to make sure that no // search mode is restored. add_task(async function initialPageOnRestore_exit() { await doTest({ urls: [INITIAL_URL], searchModeTabIndex: 0, exitSearchMode: true, switchTabsAfterEnteringSearchMode: false, }); }); add_task(async function switchToInitialPage_exit() { await doTest({ urls: [URL, INITIAL_URL], searchModeTabIndex: 1, exitSearchMode: true, switchTabsAfterEnteringSearchMode: true, }); }); add_task(async function nonInitialPageOnRestore_exit() { await doTest({ urls: [URL], searchModeTabIndex: 0, exitSearchMode: true, switchTabsAfterEnteringSearchMode: false, }); }); add_task(async function switchToNonInitialPage_exit() { await doTest({ urls: [INITIAL_URL, URL], searchModeTabIndex: 1, exitSearchMode: true, switchTabsAfterEnteringSearchMode: true, }); }); /** * The main test function. Opens some URLs in a new window, enters search mode * in one of the tabs, closes the window, restores it, and makes sure that * search mode is restored properly. * * @param {object} options * Options object * @param {Array} options.urls * Array of string URLs to open. * @param {number} options.searchModeTabIndex * The index of the tab in which to enter search mode. * @param {boolean} options.exitSearchMode * If true, search mode will be immediately exited after entering it. Use * this to make sure search mode is *not* restored after it's exited. * @param {boolean} options.switchTabsAfterEnteringSearchMode * If true, we'll switch to a tab other than the one that search mode was * entered in before closing the window. `urls` should contain more than one * URL in this case. */ async function doTest({ urls, searchModeTabIndex, exitSearchMode, switchTabsAfterEnteringSearchMode, }) { let searchModeURL = urls[searchModeTabIndex]; let otherTabIndex = (searchModeTabIndex + 1) % urls.length; let otherURL = urls[otherTabIndex]; await withNewWindow(urls, async win => { if (win.gBrowser.selectedTab != win.gBrowser.tabs[searchModeTabIndex]) { await BrowserTestUtils.switchTab( win.gBrowser, win.gBrowser.tabs[searchModeTabIndex] ); } Assert.equal( win.gBrowser.currentURI.spec, searchModeURL, `Sanity check: Tab at index ${searchModeTabIndex} is correct` ); Assert.equal( searchModeURL == INITIAL_URL, win.gInitialPages.includes(win.gBrowser.currentURI.spec), `Sanity check: ${searchModeURL} is or is not in gInitialPages as expected` ); await UrlbarTestUtils.promiseAutocompleteResultPopup({ window: win, value: SEARCH_STRING, fireInputEvent: true, }); await UrlbarTestUtils.enterSearchMode(win, { source: UrlbarUtils.RESULT_SOURCE.BOOKMARKS, }); if (exitSearchMode) { await UrlbarTestUtils.exitSearchMode(win); } // Make sure session store is updated. await TabStateFlusher.flush(win.gBrowser.selectedBrowser); if (switchTabsAfterEnteringSearchMode) { await BrowserTestUtils.switchTab( win.gBrowser, win.gBrowser.tabs[otherTabIndex] ); } }); let restoredURL = switchTabsAfterEnteringSearchMode ? otherURL : searchModeURL; let win = await restoreWindow(restoredURL); Assert.equal( win.gBrowser.currentURI.spec, restoredURL, "Sanity check: Initially selected tab in restored window is correct" ); if (switchTabsAfterEnteringSearchMode) { // Switch back to the tab with search mode. await BrowserTestUtils.switchTab( win.gBrowser, win.gBrowser.tabs[searchModeTabIndex] ); } if (exitSearchMode) { // If we exited search mode, it should be null. await new Promise(r => win.setTimeout(r, 500)); await UrlbarTestUtils.assertSearchMode(win, null); } else { // If we didn't exit search mode, it should be restored. await TestUtils.waitForCondition( () => win.gURLBar.searchMode, "Waiting for search mode to be restored" ); await UrlbarTestUtils.assertSearchMode(win, { source: UrlbarUtils.RESULT_SOURCE.BOOKMARKS, entry: "oneoff", }); Assert.equal( win.gURLBar.value, SEARCH_STRING, "Search string should be restored" ); } await BrowserTestUtils.closeWindow(win); } async function openTabMenuFor(tab) { let tabMenu = tab.ownerDocument.getElementById("tabContextMenu"); let tabMenuShown = BrowserTestUtils.waitForEvent(tabMenu, "popupshown"); EventUtils.synthesizeMouseAtCenter( tab, { type: "contextmenu" }, tab.ownerGlobal ); await tabMenuShown; return tabMenu; } // Tests that search mode is duplicated when duplicating tabs. Note that tab // duplication is handled by session store. add_task(async function duplicateTabs() { let tab = await BrowserTestUtils.openNewForegroundTab( gBrowser, "http://example.net/" ); gBrowser.selectedTab = tab; // Enter search mode with a search string in the current tab. await UrlbarTestUtils.promiseAutocompleteResultPopup({ window, value: SEARCH_STRING, fireInputEvent: true, }); await UrlbarTestUtils.enterSearchMode(window, { source: UrlbarUtils.RESULT_SOURCE.BOOKMARKS, }); // Now duplicate the current tab using the context menu item. const menu = await openTabMenuFor(gBrowser.selectedTab); let tabPromise = BrowserTestUtils.waitForNewTab( gBrowser, gBrowser.currentURI.spec ); menu.activateItem(document.getElementById("context_duplicateTab")); let newTab = await tabPromise; Assert.equal( gBrowser.selectedTab, newTab, "Sanity check: The duplicated tab is now the selected tab" ); // Wait for search mode, then check it and the input value. await TestUtils.waitForCondition( () => gURLBar.searchMode, "Waiting for search mode to be duplicated/restored" ); await UrlbarTestUtils.assertSearchMode(window, { source: UrlbarUtils.RESULT_SOURCE.BOOKMARKS, entry: "oneoff", }); Assert.equal( gURLBar.value, SEARCH_STRING, "Search string should be duplicated/restored" ); BrowserTestUtils.removeTab(tab); BrowserTestUtils.removeTab(newTab); gURLBar.handleRevert(); }); /** * Opens a new browser window with the given URLs, calls a callback, and then * closes the window. * * @param {Array} urls * Array of string URLs to open. * @param {Function} callback * The callback. */ async function withNewWindow(urls, callback) { let win = await BrowserTestUtils.openNewBrowserWindow(); for (let url of urls) { await BrowserTestUtils.openNewForegroundTab({ url, gBrowser: win.gBrowser, waitForLoad: url != "about:newtab", }); if (url == "about:newtab") { await TestUtils.waitForCondition( () => win.gBrowser.currentURI.spec == "about:newtab", "Waiting for about:newtab" ); } } BrowserTestUtils.removeTab(win.gBrowser.tabs[0]); await callback(win); await BrowserTestUtils.closeWindow(win); } /** * Uses SessionStore to reopen the last closed window. * * @param {string} expectedRestoredURL * The URL you expect will be restored in the selected browser. */ async function restoreWindow(expectedRestoredURL) { let winPromise = BrowserTestUtils.waitForNewWindow(); let win = SessionStore.undoCloseWindow(0); await winPromise; await TestUtils.waitForCondition( () => win.gBrowser.currentURI.spec == expectedRestoredURL, "Waiting for restored selected browser to have expected URI" ); return win; }