From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../urlbar/tests/browser/browser_tabToSearch.js | 641 +++++++++++++++++++++ 1 file changed, 641 insertions(+) create mode 100644 browser/components/urlbar/tests/browser/browser_tabToSearch.js (limited to 'browser/components/urlbar/tests/browser/browser_tabToSearch.js') diff --git a/browser/components/urlbar/tests/browser/browser_tabToSearch.js b/browser/components/urlbar/tests/browser/browser_tabToSearch.js new file mode 100644 index 0000000000..b029682eda --- /dev/null +++ b/browser/components/urlbar/tests/browser/browser_tabToSearch.js @@ -0,0 +1,641 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests tab-to-search results. See also + * browser/components/urlbar/tests/unit/test_providerTabToSearch.js. + */ + +"use strict"; + +const TEST_ENGINE_NAME = "Test"; +const TEST_ENGINE_DOMAIN = "example.com"; + +const DYNAMIC_RESULT_TYPE = "onboardTabToSearch"; + +ChromeUtils.defineESModuleGetters(this, { + UrlbarProviderTabToSearch: + "resource:///modules/UrlbarProviderTabToSearch.sys.mjs", +}); + +add_setup(async function () { + await PlacesUtils.history.clear(); + await SpecialPowers.pushPrefEnv({ + set: [ + // Disable onboarding results for general tests. They are enabled in tests + // that specifically address onboarding. + ["browser.urlbar.tabToSearch.onboard.interactionsLeft", 0], + ], + }); + + await SearchTestUtils.installSearchExtension({ + name: TEST_ENGINE_NAME, + search_url: `https://${TEST_ENGINE_DOMAIN}/`, + }); + + for (let i = 0; i < 3; i++) { + await PlacesTestUtils.addVisits([`https://${TEST_ENGINE_DOMAIN}/`]); + } + + registerCleanupFunction(async () => { + await PlacesUtils.history.clear(); + }); +}); + +// Tests that tab-to-search results preview search mode when highlighted. These +// results are worth testing separately since they do not set the +// payload.keyword parameter. +add_task(async function basic() { + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + let autofillResult = await UrlbarTestUtils.getDetailsOfResultAt(window, 0); + Assert.ok(autofillResult.autofill); + Assert.equal( + autofillResult.url, + `https://${TEST_ENGINE_DOMAIN}/`, + "The autofilled URL matches the engine domain." + ); + + let tabToSearchResult = ( + await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1) + ).result; + Assert.equal( + tabToSearchResult.providerName, + "TabToSearch", + "The second result is a tab-to-search result." + ); + Assert.equal( + tabToSearchResult.payload.engine, + TEST_ENGINE_NAME, + "The tab-to-search result is for the correct engine." + ); + let tabToSearchDetails = await UrlbarTestUtils.getDetailsOfResultAt( + window, + 1 + ); + let [actionTabToSearch] = await document.l10n.formatValues([ + { + id: Services.search.getEngineByName( + tabToSearchDetails.searchParams.engine + ).isGeneralPurposeEngine + ? "urlbar-result-action-tabtosearch-web" + : "urlbar-result-action-tabtosearch-other-engine", + args: { engine: tabToSearchDetails.searchParams.engine }, + }, + ]); + Assert.equal( + tabToSearchDetails.displayed.title, + `Search with ${tabToSearchDetails.searchParams.engine}`, + "The result's title is set correctly." + ); + Assert.equal( + tabToSearchDetails.displayed.action, + actionTabToSearch, + "The correct action text is displayed in the tab-to-search result." + ); + + EventUtils.synthesizeKey("KEY_ArrowDown"); + Assert.equal( + UrlbarTestUtils.getSelectedRowIndex(window), + 1, + "Sanity check: The second result is selected." + ); + await UrlbarTestUtils.assertSearchMode(window, { + engineName: TEST_ENGINE_NAME, + entry: "tabtosearch", + isPreview: true, + }); + + await UrlbarTestUtils.exitSearchMode(window); + await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur()); +}); + +// Tests that we do not set aria-activedescendant after tabbing to a +// tab-to-search result when the pref +// browser.urlbar.accessibility.tabToSearch.announceResults is true. If that +// pref is true, the result was already announced while the user was typing. +add_task(async function activedescendant_tab() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.urlbar.accessibility.tabToSearch.announceResults", true]], + }); + + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + Assert.equal( + UrlbarTestUtils.getResultCount(window), + 2, + "There should be two results." + ); + let tabToSearchRow = await UrlbarTestUtils.waitForAutocompleteResultAt( + window, + 1 + ); + Assert.equal( + tabToSearchRow.result.providerName, + "TabToSearch", + "The second result is a tab-to-search result." + ); + + EventUtils.synthesizeKey("KEY_Tab"); + + await UrlbarTestUtils.assertSearchMode(window, { + engineName: TEST_ENGINE_NAME, + entry: "tabtosearch", + isPreview: true, + }); + let aadID = gURLBar.inputField.getAttribute("aria-activedescendant"); + Assert.equal(aadID, null, "aria-activedescendant was not set."); + + // Cycle through all the results then return to the tab-to-search result. It + // should be announced. + EventUtils.synthesizeKey("KEY_Tab"); + aadID = gURLBar.inputField.getAttribute("aria-activedescendant"); + let firstRow = await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0); + Assert.equal( + aadID, + firstRow._content.id, + "aria-activedescendant was set to the row after the tab-to-search result." + ); + EventUtils.synthesizeKey("KEY_Tab"); + aadID = gURLBar.inputField.getAttribute("aria-activedescendant"); + Assert.equal( + aadID, + tabToSearchRow._content.id, + "aria-activedescendant was set to the tab-to-search result." + ); + + // Now close and reopen the view, then do another search that yields a + // tab-to-search result. aria-activedescendant should not be set when it is + // selected. + await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur()); + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + tabToSearchRow = await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1); + Assert.equal( + tabToSearchRow.result.providerName, + "TabToSearch", + "The second result is a tab-to-search result." + ); + + EventUtils.synthesizeKey("KEY_Tab"); + + await UrlbarTestUtils.assertSearchMode(window, { + engineName: TEST_ENGINE_NAME, + entry: "tabtosearch", + isPreview: true, + }); + aadID = gURLBar.inputField.getAttribute("aria-activedescendant"); + Assert.equal(aadID, null, "aria-activedescendant was not set."); + + await UrlbarTestUtils.exitSearchMode(window); + await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur()); + await SpecialPowers.popPrefEnv(); +}); + +// Tests that we set aria-activedescendant after accessing a tab-to-search +// result with the arrow keys. +add_task(async function activedescendant_arrow() { + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + let tabToSearchRow = await UrlbarTestUtils.waitForAutocompleteResultAt( + window, + 1 + ); + Assert.equal( + tabToSearchRow.result.providerName, + "TabToSearch", + "The second result is a tab-to-search result." + ); + + EventUtils.synthesizeKey("KEY_ArrowDown"); + + await UrlbarTestUtils.assertSearchMode(window, { + engineName: TEST_ENGINE_NAME, + entry: "tabtosearch", + isPreview: true, + }); + let aadID = gURLBar.inputField.getAttribute("aria-activedescendant"); + Assert.equal( + aadID, + tabToSearchRow._content.id, + "aria-activedescendant was set to the tab-to-search result." + ); + + // Move selection away from the tab-to-search result then return. It should + // be announced. + EventUtils.synthesizeKey("KEY_ArrowDown"); + aadID = gURLBar.inputField.getAttribute("aria-activedescendant"); + Assert.equal( + aadID, + UrlbarTestUtils.getOneOffSearchButtons(window).selectedButton.id, + "aria-activedescendant was moved to the first one-off." + ); + EventUtils.synthesizeKey("KEY_ArrowUp"); + aadID = gURLBar.inputField.getAttribute("aria-activedescendant"); + Assert.equal( + aadID, + tabToSearchRow._content.id, + "aria-activedescendant was set to the tab-to-search result." + ); + + await UrlbarTestUtils.exitSearchMode(window); + await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur()); +}); + +add_task(async function tab_key_race() { + // Mac Debug tinderboxes are just too slow and fail intermittently + // even if the EventBufferer timeout is set to an high value. + if (AppConstants.platform == "macosx" && AppConstants.DEBUG) { + return; + } + info( + "Test typing a letter followed shortly by down arrow consistently selects a tab-to-search result" + ); + Assert.equal(gURLBar.value, "", "Sanity check urlbar is empty"); + let promiseQueryStarted = new Promise(resolve => { + /** + * A no-op test provider. + * We use this to wait for the query to start, because otherwise TAB will + * move to the next widget since the panel is closed and there's no running + * query. This means waiting for the UrlbarProvidersManager to at least + * evaluate the isActive status of providers. + * In the future we should try to reduce this latency, to defer user events + * even more efficiently. + */ + class ListeningTestProvider extends UrlbarProvider { + constructor() { + super(); + } + get name() { + return "ListeningTestProvider"; + } + get type() { + return UrlbarUtils.PROVIDER_TYPE.PROFILE; + } + isActive(context) { + executeSoon(resolve); + return false; + } + isRestricting(context) { + return false; + } + async startQuery(context, addCallback) { + // Nothing to do. + } + } + let provider = new ListeningTestProvider(); + UrlbarProvidersManager.registerProvider(provider); + registerCleanupFunction(async function () { + UrlbarProvidersManager.unregisterProvider(provider); + }); + }); + gURLBar.focus(); + info("Type the beginning of the search string to get tab-to-search"); + EventUtils.synthesizeKey(TEST_ENGINE_DOMAIN.slice(0, 1)); + info("Awaiting for the query to start"); + await promiseQueryStarted; + EventUtils.synthesizeKey("KEY_ArrowDown"); + await UrlbarTestUtils.promiseSearchComplete(window); + await TestUtils.waitForCondition( + () => UrlbarTestUtils.getSelectedRowIndex(window) == 1, + "Wait for down arrow key to be handled" + ); + await UrlbarTestUtils.assertSearchMode(window, { + engineName: TEST_ENGINE_NAME, + entry: "tabtosearch", + isPreview: true, + }); + + await UrlbarTestUtils.exitSearchMode(window); + await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur()); +}); + +// Test that large-style onboarding results appear and have the correct +// properties. +add_task(async function onboard() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.urlbar.tabToSearch.onboard.interactionsLeft", 3]], + }); + + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + let autofillResult = await UrlbarTestUtils.getDetailsOfResultAt(window, 0); + Assert.ok(autofillResult.autofill); + Assert.equal( + autofillResult.url, + `https://${TEST_ENGINE_DOMAIN}/`, + "The autofilled URL matches the engine domain." + ); + EventUtils.synthesizeKey("KEY_ArrowDown"); + Assert.equal( + UrlbarTestUtils.getSelectedRowIndex(window), + 1, + "Sanity check: The second result is selected." + ); + + // Now check the properties of the onboarding result. + let onboardingElement = await UrlbarTestUtils.waitForAutocompleteResultAt( + window, + 1 + ); + Assert.equal( + onboardingElement.result.payload.dynamicType, + DYNAMIC_RESULT_TYPE, + "The tab-to-search result is an onboarding result." + ); + Assert.equal( + onboardingElement.result.resultSpan, + 2, + "The correct resultSpan was set." + ); + Assert.ok( + onboardingElement + .querySelector(".urlbarView-row-inner") + .hasAttribute("selected"), + "The onboarding element set the selected attribute." + ); + + let [titleOnboarding, actionOnboarding, descriptionOnboarding] = + await document.l10n.formatValues([ + { + id: "urlbar-result-action-search-w-engine", + args: { + engine: onboardingElement.result.payload.engine, + }, + }, + { + id: Services.search.getEngineByName( + onboardingElement.result.payload.engine + ).isGeneralPurposeEngine + ? "urlbar-result-action-tabtosearch-web" + : "urlbar-result-action-tabtosearch-other-engine", + args: { engine: onboardingElement.result.payload.engine }, + }, + { + id: "urlbar-tabtosearch-onboard", + }, + ]); + let onboardingDetails = await UrlbarTestUtils.getDetailsOfResultAt(window, 1); + Assert.equal( + onboardingDetails.displayed.title, + titleOnboarding, + "The correct title was set." + ); + Assert.equal( + onboardingDetails.displayed.action, + actionOnboarding, + "The correct action text was set." + ); + Assert.equal( + onboardingDetails.element.row.querySelector( + ".urlbarView-dynamic-onboardTabToSearch-description" + ).textContent, + descriptionOnboarding, + "The correct description was set." + ); + + // Check that the onboarding result enters search mode. + await UrlbarTestUtils.assertSearchMode(window, { + engineName: TEST_ENGINE_NAME, + entry: "tabtosearch_onboard", + isPreview: true, + }); + let searchPromise = UrlbarTestUtils.promiseSearchComplete(window); + EventUtils.synthesizeKey("KEY_Enter"); + await searchPromise; + await UrlbarTestUtils.assertSearchMode(window, { + engineName: TEST_ENGINE_NAME, + entry: "tabtosearch_onboard", + }); + await UrlbarTestUtils.exitSearchMode(window); + await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur()); + UrlbarPrefs.set("tabToSearch.onboard.interactionsLeft", 3); + delete UrlbarProviderTabToSearch.onboardingInteractionAtTime; + await SpecialPowers.popPrefEnv(); +}); + +// Tests that we show the onboarding result until the user interacts with it +// `browser.urlbar.tabToSearch.onboard.interactionsLeft` times. +add_task(async function onboard_limit() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.urlbar.tabToSearch.onboard.interactionsLeft", 3]], + }); + + Assert.equal( + UrlbarPrefs.get("tabToSearch.onboard.interactionsLeft"), + 3, + "Sanity check: interactionsLeft is 3." + ); + + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + let onboardingResult = ( + await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1) + ).result; + Assert.equal( + onboardingResult.payload.dynamicType, + DYNAMIC_RESULT_TYPE, + "The second result is an onboarding result." + ); + await EventUtils.synthesizeKey("KEY_ArrowDown"); + await UrlbarTestUtils.assertSearchMode(window, { + engineName: TEST_ENGINE_NAME, + entry: "tabtosearch_onboard", + isPreview: true, + }); + Assert.equal(UrlbarPrefs.get("tabToSearch.onboard.interactionsLeft"), 2); + await UrlbarTestUtils.exitSearchMode(window); + + // We don't increment the counter if we showed the onboarding result less than + // 5 minutes ago. + for (let i = 0; i < 5; i++) { + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + onboardingResult = ( + await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1) + ).result; + Assert.equal( + onboardingResult.payload.dynamicType, + DYNAMIC_RESULT_TYPE, + "The second result is an onboarding result." + ); + await EventUtils.synthesizeKey("KEY_ArrowDown"); + await UrlbarTestUtils.assertSearchMode(window, { + engineName: TEST_ENGINE_NAME, + entry: "tabtosearch_onboard", + isPreview: true, + }); + Assert.equal( + UrlbarPrefs.get("tabToSearch.onboard.interactionsLeft"), + 2, + "We shouldn't decrement interactionsLeft if an onboarding result was just shown." + ); + await UrlbarTestUtils.exitSearchMode(window); + } + + // If the user doesn't interact with the result, we don't increment the + // counter. + for (let i = 0; i < 5; i++) { + delete UrlbarProviderTabToSearch.onboardingInteractionAtTime; + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + let tabToSearchResult = ( + await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1) + ).result; + Assert.equal( + tabToSearchResult.providerName, + "TabToSearch", + "The second result is a tab-to-search result." + ); + Assert.equal( + tabToSearchResult.type, + UrlbarUtils.RESULT_TYPE.DYNAMIC, + "The tab-to-search result is an onboarding result." + ); + Assert.equal( + UrlbarPrefs.get("tabToSearch.onboard.interactionsLeft"), + 2, + "We shouldn't decrement interactionsLeft if the user doesn't interact with onboarding." + ); + } + + // Test that we increment the counter if the user interacts with the result + // and it's been 5+ minutes since they last interacted with it. + for (let i = 1; i >= 0; i--) { + delete UrlbarProviderTabToSearch.onboardingInteractionAtTime; + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + let tabToSearchResult = ( + await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1) + ).result; + Assert.equal( + tabToSearchResult.providerName, + "TabToSearch", + "The second result is a tab-to-search result." + ); + Assert.equal( + onboardingResult.payload.dynamicType, + DYNAMIC_RESULT_TYPE, + "The second result is an onboarding result." + ); + await EventUtils.synthesizeKey("KEY_ArrowDown"); + await UrlbarTestUtils.assertSearchMode(window, { + engineName: TEST_ENGINE_NAME, + entry: "tabtosearch_onboard", + isPreview: true, + }); + Assert.equal( + UrlbarPrefs.get("tabToSearch.onboard.interactionsLeft"), + i, + "We decremented interactionsLeft." + ); + await UrlbarTestUtils.exitSearchMode(window); + } + + delete UrlbarProviderTabToSearch.onboardingInteractionAtTime; + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + let tabToSearchResult = ( + await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1) + ).result; + Assert.equal( + tabToSearchResult.providerName, + "TabToSearch", + "The second result is a tab-to-search result." + ); + Assert.notEqual( + tabToSearchResult.type, + UrlbarUtils.RESULT_TYPE.DYNAMIC, + "Now that interactionsLeft is 0, we don't show onboarding results." + ); + + await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur()); + UrlbarPrefs.set("tabToSearch.onboard.interactionsLeft", 3); + delete UrlbarProviderTabToSearch.onboardingInteractionAtTime; + await SpecialPowers.popPrefEnv(); +}); + +// Tests that we show at most one onboarding result at a time. See +// tests/unit/test_providerTabToSearch.js:multipleEnginesForHostname for a test +// that ensures only one normal tab-to-search result is shown in this scenario. +add_task(async function onboard_multipleEnginesForHostname() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.urlbar.tabToSearch.onboard.interactionsLeft", 3]], + }); + + let extension = await SearchTestUtils.installSearchExtension( + { + name: `${TEST_ENGINE_NAME}Maps`, + search_url: `https://${TEST_ENGINE_DOMAIN}/maps/`, + }, + { skipUnload: true } + ); + + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: TEST_ENGINE_DOMAIN.slice(0, 4), + fireInputEvent: true, + }); + + Assert.equal( + UrlbarTestUtils.getResultCount(window), + 2, + "Only two results are shown." + ); + let firstResult = ( + await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0) + ).result; + Assert.notEqual( + firstResult.providerName, + "TabToSearch", + "The first result is not from TabToSearch." + ); + let secondResult = ( + await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1) + ).result; + Assert.equal( + secondResult.providerName, + "TabToSearch", + "The second result is from TabToSearch." + ); + Assert.equal( + secondResult.type, + UrlbarUtils.RESULT_TYPE.DYNAMIC, + "The tab-to-search result is the only onboarding result." + ); + await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur()); + await extension.unload(); + UrlbarPrefs.set("tabToSearch.onboard.interactionsLeft", 3); + delete UrlbarProviderTabToSearch.onboardingInteractionAtTime; + await SpecialPowers.popPrefEnv(); +}); -- cgit v1.2.3