/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- * vim:set ts=2 sw=2 sts=2 et: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; /** * Tests for ensuring that the tab switch results correctly match what is * currently available. */ requestLongerTimeout(2); const TEST_URL_BASES = [ `${TEST_BASE_URL}dummy_page.html#tabmatch`, `${TEST_BASE_URL}moz.png#tabmatch`, ]; const RESTRICT_TOKEN_OPENPAGE = "%"; var gTabCounter = 0; add_task(async function step_1() { info("Running step 1"); let maxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults"); let promises = []; for (let i = 0; i < maxResults - 1; i++) { let tab = BrowserTestUtils.addTab(gBrowser); promises.push(loadTab(tab, TEST_URL_BASES[0] + ++gTabCounter)); } await Promise.all(promises); await ensure_opentabs_match_db(); }); add_task(async function step_2() { info("Running step 2"); gBrowser.selectTabAtIndex(1); gBrowser.removeCurrentTab(); gBrowser.selectTabAtIndex(1); gBrowser.removeCurrentTab(); gBrowser.selectTabAtIndex(0); let promises = []; for (let i = 1; i < gBrowser.tabs.length; i++) { promises.push(loadTab(gBrowser.tabs[i], TEST_URL_BASES[1] + ++gTabCounter)); } await Promise.all(promises); await ensure_opentabs_match_db(); }); add_task(async function step_3() { info("Running step 3"); let promises = []; for (let i = 1; i < gBrowser.tabs.length; i++) { promises.push(loadTab(gBrowser.tabs[i], TEST_URL_BASES[0] + gTabCounter)); } await Promise.all(promises); await ensure_opentabs_match_db(); }); add_task(async function step_4() { info("Running step 4 - ensure we don't register subframes as open pages"); let tab = BrowserTestUtils.addTab( gBrowser, 'data:text/html,' ); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { let iframe_loaded = ContentTaskUtils.waitForEvent( content.document, "load", true ); content.document.querySelector("iframe").src = "http://test2.example.org/"; await iframe_loaded; }); await ensure_opentabs_match_db(); }); add_task(async function step_5() { info("Running step 5 - remove tab immediately"); let tab = BrowserTestUtils.addTab(gBrowser, "about:logo"); BrowserTestUtils.removeTab(tab); await ensure_opentabs_match_db(); }); add_task(async function step_6() { info( "Running step 6 - check swapBrowsersAndCloseOther preserves registered switch-to-tab result" ); let tabToKeep = BrowserTestUtils.addTab(gBrowser); let tab = BrowserTestUtils.addTab(gBrowser, "about:mozilla"); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); gBrowser.updateBrowserRemoteness(tabToKeep.linkedBrowser, { remoteType: tab.linkedBrowser.isRemoteBrowser ? E10SUtils.DEFAULT_REMOTE_TYPE : E10SUtils.NOT_REMOTE, }); gBrowser.swapBrowsersAndCloseOther(tabToKeep, tab); await ensure_opentabs_match_db(); BrowserTestUtils.removeTab(tabToKeep); await ensure_opentabs_match_db(); }); add_task(async function step_7() { info("Running step 7 - close all tabs"); Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand"); BrowserTestUtils.addTab(gBrowser, "about:blank", { skipAnimation: true }); while (gBrowser.tabs.length > 1) { info("Removing tab: " + gBrowser.tabs[0].linkedBrowser.currentURI.spec); gBrowser.selectTabAtIndex(0); gBrowser.removeCurrentTab(); } await ensure_opentabs_match_db(); }); add_task(async function cleanup() { info("Cleaning up"); await PlacesUtils.history.clear(); }); function loadTab(tab, url) { // Because adding visits is async, we will not be notified immediately. let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser); let visited = new Promise(resolve => { Services.obs.addObserver(function observer(aSubject, aTopic, aData) { if (url != aSubject.QueryInterface(Ci.nsIURI).spec) { return; } Services.obs.removeObserver(observer, aTopic); resolve(); }, "uri-visit-saved"); }); info("Loading page: " + url); BrowserTestUtils.loadURIString(tab.linkedBrowser, url); return Promise.all([loaded, visited]); } function ensure_opentabs_match_db() { let tabs = {}; for (let browserWin of Services.wm.getEnumerator("navigator:browser")) { // skip closed-but-not-destroyed windows if (browserWin.closed) { continue; } for (let i = 0; i < browserWin.gBrowser.tabs.length; i++) { let browser = browserWin.gBrowser.getBrowserAtIndex(i); let url = browser.currentURI.spec; if (browserWin.isBlankPageURL(url)) { continue; } if (!(url in tabs)) { tabs[url] = 1; } else { tabs[url]++; } } } return checkAutocompleteResults(tabs); } async function checkAutocompleteResults(expected) { info("Searching open pages."); await UrlbarTestUtils.promiseAutocompleteResultPopup({ window, value: RESTRICT_TOKEN_OPENPAGE, }); let resultCount = UrlbarTestUtils.getResultCount(window); for (let i = 0; i < resultCount; i++) { let result = await UrlbarTestUtils.getDetailsOfResultAt(window, i); if (result.heuristic) { info("Skip heuristic match"); continue; } Assert.equal( result.type, UrlbarUtils.RESULT_TYPE.TAB_SWITCH, "Should have a tab switch result" ); let url = result.url; info(`Search for ${url} in open tabs.`); let inExpected = url in expected; Assert.ok( inExpected, `${url} was found in autocomplete, was ${ inExpected ? "" : "not " } expected` ); // Remove the found entry from expected results. delete expected[url]; } await UrlbarTestUtils.promisePopupClose(window, () => EventUtils.synthesizeKey("KEY_Escape") ); // Make sure there is no reported open page that is not open. for (let entry in expected) { Assert.ok(!entry, `Should have been found in autocomplete`); } }