/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; // Tests retained results. // When there is a pending search (user typed a search string and blurred // without picking a result), on focus we should the search results again. async function checkPanelStatePersists(win, isOpen) { // Check for popup events, we should not see any of them because the urlbar // popup state should not change. This also ensures we don't cause flickering // open/close actions. function handler(event) { Assert.ok(false, `Received unexpected event ${event.type}`); } win.gURLBar.addEventListener("popupshowing", handler); win.gURLBar.addEventListener("popuphiding", handler); // Because the panel opening may not be immediate, we must wait a bit. // eslint-disable-next-line mozilla/no-arbitrary-setTimeout await new Promise(resolve => setTimeout(resolve, 300)); win.gURLBar.removeEventListener("popupshowing", handler); win.gURLBar.removeEventListener("popuphiding", handler); Assert.equal( isOpen, win.gURLBar.view.isOpen, `check urlbar remains ${isOpen ? "open" : "closed"}` ); } async function checkOpensOnFocus(win, state) { Assert.ok(!win.gURLBar.view.isOpen, "check urlbar panel is not open"); win.gURLBar.blur(); info("Check the keyboard shortcut."); await UrlbarTestUtils.promisePopupOpen(win, () => { win.document.getElementById("Browser:OpenLocation").doCommand(); }); await UrlbarTestUtils.promiseSearchComplete(win); Assert.equal(state.selectionStart, win.gURLBar.selectionStart); Assert.equal(state.selectionEnd, win.gURLBar.selectionEnd); await UrlbarTestUtils.promisePopupClose(win, () => { win.gURLBar.blur(); }); info("Focus with the mouse."); await UrlbarTestUtils.promisePopupOpen(win, () => { EventUtils.synthesizeMouseAtCenter(win.gURLBar.inputField, {}, win); }); await UrlbarTestUtils.promiseSearchComplete(win); Assert.equal(state.selectionStart, win.gURLBar.selectionStart); Assert.equal(state.selectionEnd, win.gURLBar.selectionEnd); } async function checkDoesNotOpenOnFocus(win) { Assert.ok(!win.gURLBar.view.isOpen, "check urlbar panel is not open"); win.gURLBar.blur(); info("Check the keyboard shortcut."); let promiseState = checkPanelStatePersists(win, false); win.document.getElementById("Browser:OpenLocation").doCommand(); await promiseState; win.gURLBar.blur(); info("Focus with the mouse."); promiseState = checkPanelStatePersists(win, false); EventUtils.synthesizeMouseAtCenter(win.gURLBar.inputField, {}, win); await promiseState; } add_setup(async function () { await SpecialPowers.pushPrefEnv({ set: [["browser.urlbar.autoFill", true]], }); // Add some history for the empty panel and autofill. await PlacesTestUtils.addVisits([ { uri: "https://example.com/", transition: PlacesUtils.history.TRANSITIONS.TYPED, }, { uri: "https://example.com/foo/", transition: PlacesUtils.history.TRANSITIONS.TYPED, }, ]); registerCleanupFunction(async function () { await PlacesUtils.history.clear(); }); }); async function test_window(win) { for (let url of ["about:newtab", "about:home", "https://example.com/"]) { // withNewTab may hang on preloaded pages, thus instead of waiting for load // we just wait for the expected currentURI value. await BrowserTestUtils.withNewTab( { gBrowser: win.gBrowser, url, waitForLoad: false }, async browser => { await TestUtils.waitForCondition( () => win.gBrowser.currentURI.spec == url, "Ensure we're on the expected page" ); // In one case use a value that triggers autofill. let autofill = url == "https://example.com/"; await UrlbarTestUtils.promiseAutocompleteResultPopup({ window: win, value: autofill ? "ex" : "foo", fireInputEvent: true, }); let { value, selectionStart, selectionEnd } = win.gURLBar; if (!autofill) { selectionStart = 0; } info("expected " + value + " " + selectionStart + " " + selectionEnd); await UrlbarTestUtils.promisePopupClose(win, () => { win.gURLBar.blur(); }); info("The panel should open when there's a search string"); await checkOpensOnFocus(win, { value, selectionStart, selectionEnd }); await UrlbarTestUtils.promisePopupClose(win, () => { win.gURLBar.blur(); }); } ); } } add_task(async function test_normalWindow() { let win = await BrowserTestUtils.openNewBrowserWindow(); await test_window(win); await BrowserTestUtils.closeWindow(win); }); add_task(async function test_privateWindow() { let privateWin = await BrowserTestUtils.openNewBrowserWindow({ private: true, }); await test_window(privateWin); await BrowserTestUtils.closeWindow(privateWin); }); add_task(async function test_tabSwitch() { info("Check that switching tabs reopens the view."); let win = await BrowserTestUtils.openNewBrowserWindow(); await UrlbarTestUtils.promiseAutocompleteResultPopup({ window: win, value: "ex", fireInputEvent: true, }); let { value, selectionStart, selectionEnd } = win.gURLBar; Assert.equal(value, "example.com/", "Check autofill value"); Assert.ok( selectionStart > 0 && selectionEnd > selectionStart, "Check autofill selection" ); Assert.ok(win.gURLBar.focused, "The urlbar should be focused"); let tab1 = win.gBrowser.selectedTab; async function check_autofill() { // The urlbar code waits for both TabSelect and the focus change, thus // we can't just wait for search completion here, we have to poll for a // value. await TestUtils.waitForCondition( () => win.gURLBar.value == "example.com/", "wait for autofill value" ); // Ensure stable results. await UrlbarTestUtils.promiseSearchComplete(win); Assert.equal(selectionStart, win.gURLBar.selectionStart); Assert.equal(selectionEnd, win.gURLBar.selectionEnd); } info("Open a new tab with the same search"); let tab2 = await BrowserTestUtils.openNewForegroundTab(win.gBrowser); await UrlbarTestUtils.promiseAutocompleteResultPopup({ window: win, value: "ex", fireInputEvent: true, }); info("Switch across tabs"); for (let tab of win.gBrowser.tabs) { await UrlbarTestUtils.promisePopupOpen(win, async () => { await BrowserTestUtils.switchTab(win.gBrowser, tab); }); await check_autofill(); } info("Close tab and check the view is open."); await UrlbarTestUtils.promisePopupOpen(win, () => { BrowserTestUtils.removeTab(tab2); }); await check_autofill(); info("Open a new tab with a different search"); tab2 = await BrowserTestUtils.openNewForegroundTab(win.gBrowser); await UrlbarTestUtils.promiseAutocompleteResultPopup({ window: win, value: "xam", fireInputEvent: true, }); info("Switch to the first tab and check the panel remains open"); let promiseState = checkPanelStatePersists(win, true); await BrowserTestUtils.switchTab(win.gBrowser, tab1); await promiseState; await UrlbarTestUtils.promiseSearchComplete(win); await check_autofill(); info("Switch to the second tab and check the panel remains open"); promiseState = checkPanelStatePersists(win, true); await BrowserTestUtils.switchTab(win.gBrowser, tab2); await promiseState; await UrlbarTestUtils.promiseSearchComplete(win); Assert.equal(win.gURLBar.value, "xam", "check value"); Assert.equal(win.gURLBar.selectionStart, 3); Assert.equal(win.gURLBar.selectionEnd, 3); info("autofill in tab2, switch to tab1, then back to tab2 with the mouse"); await UrlbarTestUtils.promiseAutocompleteResultPopup({ window: win, value: "e", fireInputEvent: true, }); // Adjust selection start, we are using a different search string. await BrowserTestUtils.switchTab(win.gBrowser, tab1); await UrlbarTestUtils.promiseSearchComplete(win); await check_autofill(); tab2.click(); selectionStart = 1; await check_autofill(); info("Check we don't rerun a search if the shortcut is used on an open view"); EventUtils.synthesizeKey("KEY_Backspace", {}, win); await UrlbarTestUtils.promiseSearchComplete(win); Assert.ok(win.gURLBar.view.isOpen, "The view should be open"); Assert.equal(win.gURLBar.value, "e", "The value should be the typed one"); win.document.getElementById("Browser:OpenLocation").doCommand(); // A search should not run here, so there's nothing to wait for. // eslint-disable-next-line mozilla/no-arbitrary-setTimeout await new Promise(resolve => setTimeout(resolve, 300)); Assert.ok(win.gURLBar.view.isOpen, "The view should be open"); Assert.equal(win.gURLBar.value, "e", "The value should not change"); info( "Tab switch from an empty search tab with unfocused urlbar to a tab with a search string and a focused urlbar" ); win.gURLBar.value = ""; win.gURLBar.blur(); await UrlbarTestUtils.promisePopupOpen(win, async () => { await BrowserTestUtils.switchTab(win.gBrowser, tab1); }); await BrowserTestUtils.closeWindow(win); }); add_task(async function test_tabSwitch_pageproxystate() { info("Switching tabs on valid pageproxystate doesn't reopen."); info("Adding some visits for the empty panel"); await PlacesTestUtils.addVisits([ "https://example.com/", "https://example.org/", ]); registerCleanupFunction(PlacesUtils.history.clear); let win = await BrowserTestUtils.openNewBrowserWindow(); BrowserTestUtils.loadURIString(win.gBrowser.selectedBrowser, "about:robots"); let tab1 = win.gBrowser.selectedTab; info("Open a new tab and the empty search"); let tab2 = await BrowserTestUtils.openNewForegroundTab(win.gBrowser); await UrlbarTestUtils.promisePopupOpen(win, async () => { win.gURLBar.focus(); // On Linux and Mac down moves caret to the end of the text unless it's // there already. win.gURLBar.selectionStart = win.gURLBar.selectionEnd = win.gURLBar.value.length; EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); }); await UrlbarTestUtils.promiseSearchComplete(win); let result = await UrlbarTestUtils.getDetailsOfResultAt(win, 0); Assert.notEqual(result.url, "about:robots"); info("Switch to the first tab and start searching with DOWN"); await UrlbarTestUtils.promisePopupClose(win, async () => { await BrowserTestUtils.switchTab(win.gBrowser, tab1); }); await checkPanelStatePersists(win, false); await UrlbarTestUtils.promisePopupOpen(win, async () => { win.gURLBar.focus(); // On Linux and Mac down moves caret to the end of the text unless it's // there already. win.gURLBar.selectionStart = win.gURLBar.selectionEnd = win.gURLBar.value.length; EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); }); await UrlbarTestUtils.promiseSearchComplete(win); info("Switcihng to the second tab should not reopen the search"); await UrlbarTestUtils.promisePopupClose(win, async () => { await BrowserTestUtils.switchTab(win.gBrowser, tab2); }); await checkPanelStatePersists(win, false); info("Switching to the first tab should not reopen the search"); let promiseState = await checkPanelStatePersists(win, false); await BrowserTestUtils.switchTab(win.gBrowser, tab1); await promiseState; await BrowserTestUtils.closeWindow(win); }); add_task(async function test_tabSwitch_emptySearch() { info("Switching between empty-search tabs should not reopen the view."); let win = await BrowserTestUtils.openNewBrowserWindow(); info("Open the empty search"); let tab1 = win.gBrowser.selectedTab; await UrlbarTestUtils.promisePopupOpen(win, async () => { win.gURLBar.focus(); // On Linux and Mac down moves caret to the end of the text unless it's // there already. win.gURLBar.selectionStart = win.gURLBar.selectionEnd = win.gURLBar.value.length; EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); }); await UrlbarTestUtils.promiseSearchComplete(win); info("Open a new tab and the empty search"); let tab2 = await BrowserTestUtils.openNewForegroundTab(win.gBrowser); await UrlbarTestUtils.promisePopupOpen(win, async () => { win.gURLBar.focus(); // On Linux and Mac down moves caret to the end of the text unless it's // there already. win.gURLBar.selectionStart = win.gURLBar.selectionEnd = win.gURLBar.value.length; EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); }); await UrlbarTestUtils.promiseSearchComplete(win); info("Switching to the first tab should not reopen the view"); await UrlbarTestUtils.promisePopupClose(win, async () => { await BrowserTestUtils.switchTab(win.gBrowser, tab1); }); await checkPanelStatePersists(win, false); info("Switching to the second tab should not reopen the view"); let promiseState = await checkPanelStatePersists(win, false); await BrowserTestUtils.switchTab(win.gBrowser, tab2); await promiseState; await BrowserTestUtils.closeWindow(win); }); add_task(async function test_pageproxystate_valid() { info("Focusing on valid pageproxystate should not reopen the view."); let win = await BrowserTestUtils.openNewBrowserWindow(); info("Search for a full url and confirm it with Enter"); await UrlbarTestUtils.promiseAutocompleteResultPopup({ window: win, value: "about:robots", fireInputEvent: true, }); let loadedPromise = BrowserTestUtils.browserLoaded( win.gBrowser.selectedBrowser ); EventUtils.synthesizeKey("KEY_Enter", {}, win); await loadedPromise; Assert.ok(!win.gURLBar.focused, "The urlbar should not be focused"); info("Focus the urlbar"); win.document.getElementById("Browser:OpenLocation").doCommand(); await BrowserTestUtils.closeWindow(win); }); add_task(async function test_allowAutofill() { info("Check we respect allowAutofill from the last search"); let win = await BrowserTestUtils.openNewBrowserWindow(); await UrlbarTestUtils.promisePopupOpen(win, async () => { await selectAndPaste("e", win); }); Assert.equal(win.gURLBar.value, "e", "Should not autofill"); let context = await win.gURLBar.lastQueryContextPromise; Assert.equal(context.allowAutofill, false, "Check initial allowAutofill"); await UrlbarTestUtils.promisePopupClose(win); await UrlbarTestUtils.promisePopupOpen(win, async () => { win.document.getElementById("Browser:OpenLocation").doCommand(); }); await UrlbarTestUtils.promiseSearchComplete(win); Assert.equal(win.gURLBar.value, "e", "Should not autofill"); context = await win.gURLBar.lastQueryContextPromise; Assert.equal(context.allowAutofill, false, "Check reopened allowAutofill"); await BrowserTestUtils.closeWindow(win); }); add_task(async function test_clicks_after_autofill() { info( "Check that clickin on an autofilled input field doesn't requery, causing loss of the caret position" ); let win = await BrowserTestUtils.openNewBrowserWindow(); info("autofill in tab2, switch to tab1, then back to tab2 with the mouse"); await UrlbarTestUtils.promiseAutocompleteResultPopup({ window: win, value: "e", fireInputEvent: true, }); Assert.equal(win.gURLBar.value, "example.com/", "Should have autofilled"); // Check single click. let input = win.gURLBar.inputField; EventUtils.synthesizeMouse(input, 30, 10, {}, win); // Wait a bit, in case of a mistake this would run a query, otherwise not. // eslint-disable-next-line mozilla/no-arbitrary-setTimeout await new Promise(resolve => setTimeout(resolve, 300)); Assert.ok(win.gURLBar.selectionStart < win.gURLBar.value.length); Assert.equal(win.gURLBar.selectionStart, win.gURLBar.selectionEnd); // Check double click. EventUtils.synthesizeMouse(input, 30, 10, { clickCount: 2 }, win); // Wait a bit, in case of a mistake this would run a query, otherwise not. // eslint-disable-next-line mozilla/no-arbitrary-setTimeout await new Promise(resolve => setTimeout(resolve, 300)); Assert.ok(win.gURLBar.selectionStart < win.gURLBar.value.length); Assert.ok(win.gURLBar.selectionEnd > win.gURLBar.selectionStart); await BrowserTestUtils.closeWindow(win); });