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 --- .../browser/browser_quicksuggest_indexes.js | 425 +++++++++++++++++++++ 1 file changed, 425 insertions(+) create mode 100644 browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_indexes.js (limited to 'browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_indexes.js') diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_indexes.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_indexes.js new file mode 100644 index 0000000000..282e1a2ba0 --- /dev/null +++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_indexes.js @@ -0,0 +1,425 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests the configurable indexes of sponsored and non-sponsored ("Firefox +// Suggest") quick suggest results. + +"use strict"; + +const SUGGESTIONS_FIRST_PREF = "browser.urlbar.showSearchSuggestionsFirst"; +const SUGGESTIONS_PREF = "browser.urlbar.suggest.searches"; + +const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml"; +const MAX_RESULTS = UrlbarPrefs.get("maxRichResults"); + +const SPONSORED_INDEX_PREF = "browser.urlbar.quicksuggest.sponsoredIndex"; +const NON_SPONSORED_INDEX_PREF = + "browser.urlbar.quicksuggest.nonSponsoredIndex"; + +const SPONSORED_SEARCH_STRING = "frabbits"; +const NON_SPONSORED_SEARCH_STRING = "nonspon"; + +const TEST_URL = "http://example.com/quicksuggest"; + +const REMOTE_SETTINGS_RESULTS = [ + { + id: 1, + url: `${TEST_URL}?q=${SPONSORED_SEARCH_STRING}`, + title: "frabbits", + keywords: [SPONSORED_SEARCH_STRING], + click_url: "http://click.reporting.test.com/", + impression_url: "http://impression.reporting.test.com/", + advertiser: "TestAdvertiser", + }, + { + id: 2, + url: `${TEST_URL}?q=${NON_SPONSORED_SEARCH_STRING}`, + title: "Non-Sponsored", + keywords: [NON_SPONSORED_SEARCH_STRING], + click_url: "http://click.reporting.test.com/nonsponsored", + impression_url: "http://impression.reporting.test.com/nonsponsored", + advertiser: "TestAdvertiserNonSponsored", + iab_category: "5 - Education", + }, +]; + +add_setup(async function () { + // This test intermittently times out on Mac TV WebRender. + if (AppConstants.platform == "macosx") { + requestLongerTimeout(3); + } + + await PlacesUtils.history.clear(); + await PlacesUtils.bookmarks.eraseEverything(); + await UrlbarTestUtils.formHistory.clear(); + + // Add a mock engine so we don't hit the network. + await SearchTestUtils.installSearchExtension({}, { setAsDefault: true }); + + await QuickSuggestTestUtils.ensureQuickSuggestInit({ + remoteSettingsResults: [ + { + type: "data", + attachment: REMOTE_SETTINGS_RESULTS, + }, + ], + }); + + registerCleanupFunction(async () => { + await PlacesUtils.history.clear(); + }); +}); + +// Tests with history only +add_task(async function noSuggestions() { + await doTestPermutations(({ withHistory, generalIndex }) => ({ + expectedResultCount: withHistory ? MAX_RESULTS : 2, + expectedIndex: generalIndex == 0 || !withHistory ? 1 : MAX_RESULTS - 1, + })); +}); + +// Tests with suggestions followed by history +add_task(async function suggestionsFirst() { + await SpecialPowers.pushPrefEnv({ + set: [[SUGGESTIONS_FIRST_PREF, true]], + }); + await withSuggestions(async () => { + await doTestPermutations(({ withHistory, generalIndex }) => ({ + expectedResultCount: withHistory ? MAX_RESULTS : 4, + expectedIndex: generalIndex == 0 || !withHistory ? 3 : MAX_RESULTS - 1, + })); + }); + await SpecialPowers.popPrefEnv(); +}); + +// Tests with history followed by suggestions +add_task(async function suggestionsLast() { + await SpecialPowers.pushPrefEnv({ + set: [[SUGGESTIONS_FIRST_PREF, false]], + }); + await withSuggestions(async () => { + await doTestPermutations(({ withHistory, generalIndex }) => ({ + expectedResultCount: withHistory ? MAX_RESULTS : 4, + expectedIndex: generalIndex == 0 || !withHistory ? 1 : MAX_RESULTS - 3, + })); + }); + await SpecialPowers.popPrefEnv(); +}); + +// Tests with history only plus a suggestedIndex result with a resultSpan +add_task(async function otherSuggestedIndex_noSuggestions() { + await doSuggestedIndexTest([ + // heuristic + { heuristic: true }, + // TestProvider result + { suggestedIndex: 1, resultSpan: 2 }, + // history + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + // quick suggest + { + type: UrlbarUtils.RESULT_TYPE.URL, + providerName: UrlbarProviderQuickSuggest.name, + }, + ]); +}); + +// Tests with suggestions followed by history plus a suggestedIndex result with +// a resultSpan +add_task(async function otherSuggestedIndex_suggestionsFirst() { + await SpecialPowers.pushPrefEnv({ + set: [[SUGGESTIONS_FIRST_PREF, true]], + }); + await withSuggestions(async () => { + await doSuggestedIndexTest([ + // heuristic + { heuristic: true }, + // TestProvider result + { suggestedIndex: 1, resultSpan: 2 }, + // search suggestions + { + type: UrlbarUtils.RESULT_TYPE.SEARCH, + payload: { suggestion: SPONSORED_SEARCH_STRING + "foo" }, + }, + { + type: UrlbarUtils.RESULT_TYPE.SEARCH, + payload: { suggestion: SPONSORED_SEARCH_STRING + "bar" }, + }, + // history + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + // quick suggest + { + type: UrlbarUtils.RESULT_TYPE.URL, + providerName: UrlbarProviderQuickSuggest.name, + }, + ]); + }); + await SpecialPowers.popPrefEnv(); +}); + +// Tests with history followed by suggestions plus a suggestedIndex result with +// a resultSpan +add_task(async function otherSuggestedIndex_suggestionsLast() { + await SpecialPowers.pushPrefEnv({ + set: [[SUGGESTIONS_FIRST_PREF, false]], + }); + await withSuggestions(async () => { + await doSuggestedIndexTest([ + // heuristic + { heuristic: true }, + // TestProvider result + { suggestedIndex: 1, resultSpan: 2 }, + // history + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + { type: UrlbarUtils.RESULT_TYPE.URL }, + // quick suggest + { + type: UrlbarUtils.RESULT_TYPE.URL, + providerName: UrlbarProviderQuickSuggest.name, + }, + // search suggestions + { + type: UrlbarUtils.RESULT_TYPE.SEARCH, + payload: { suggestion: SPONSORED_SEARCH_STRING + "foo" }, + }, + { + type: UrlbarUtils.RESULT_TYPE.SEARCH, + payload: { suggestion: SPONSORED_SEARCH_STRING + "bar" }, + }, + ]); + }); + await SpecialPowers.popPrefEnv(); +}); + +/** + * A test provider that returns one result with a suggestedIndex and resultSpan. + */ +class TestProvider extends UrlbarTestUtils.TestProvider { + constructor() { + super({ + results: [ + Object.assign( + new UrlbarResult( + UrlbarUtils.RESULT_TYPE.URL, + UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + { url: "http://example.com/test" } + ), + { + suggestedIndex: 1, + resultSpan: 2, + } + ), + ], + }); + } +} + +/** + * Does a round of test permutations. + * + * @param {Function} callback + * For each permutation, this will be called with the arguments of `doTest()`, + * and it should return an object with the appropriate values of + * `expectedResultCount` and `expectedIndex`. + */ +async function doTestPermutations(callback) { + for (let isSponsored of [true, false]) { + for (let withHistory of [true, false]) { + for (let generalIndex of [0, -1]) { + let opts = { + isSponsored, + withHistory, + generalIndex, + }; + await doTest(Object.assign(opts, callback(opts))); + } + } + } +} + +/** + * Does one test run. + * + * @param {object} options + * Options for the test. + * @param {boolean} options.isSponsored + * True to use a sponsored result, false to use a non-sponsored result. + * @param {boolean} options.withHistory + * True to run with a bunch of history, false to run with no history. + * @param {number} options.generalIndex + * The value to set as the relevant index pref, i.e., the index within the + * general group of the quick suggest result. + * @param {number} options.expectedResultCount + * The expected total result count for sanity checking. + * @param {number} options.expectedIndex + * The expected index of the quick suggest result in the whole results list. + */ +async function doTest({ + isSponsored, + withHistory, + generalIndex, + expectedResultCount, + expectedIndex, +}) { + info( + "Running test with options: " + + JSON.stringify({ + isSponsored, + withHistory, + generalIndex, + expectedResultCount, + expectedIndex, + }) + ); + + // Set the index pref. + let indexPref = isSponsored ? SPONSORED_INDEX_PREF : NON_SPONSORED_INDEX_PREF; + await SpecialPowers.pushPrefEnv({ + set: [[indexPref, generalIndex]], + }); + + // Add history. + if (withHistory) { + await addHistory(); + } + + // Do a search. + let value = isSponsored + ? SPONSORED_SEARCH_STRING + : NON_SPONSORED_SEARCH_STRING; + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value, + }); + + // Check the result count and quick suggest result. + Assert.equal( + UrlbarTestUtils.getResultCount(window), + expectedResultCount, + "Expected result count" + ); + await QuickSuggestTestUtils.assertIsQuickSuggest({ + window, + isSponsored, + index: expectedIndex, + url: isSponsored + ? `${TEST_URL}?q=${SPONSORED_SEARCH_STRING}` + : `${TEST_URL}?q=${NON_SPONSORED_SEARCH_STRING}`, + }); + + await UrlbarTestUtils.promisePopupClose(window); + await PlacesUtils.history.clear(); + await SpecialPowers.popPrefEnv(); +} + +/** + * Adds history that matches the sponsored and non-sponsored search strings. + */ +async function addHistory() { + for (let i = 0; i < MAX_RESULTS; i++) { + await PlacesTestUtils.addVisits([ + "http://example.com/" + SPONSORED_SEARCH_STRING + i, + "http://example.com/" + NON_SPONSORED_SEARCH_STRING + i, + ]); + } +} + +/** + * Adds a search engine that provides suggestions, calls your callback, and then + * removes the engine. + * + * @param {Function} callback + * Your callback function. + */ +async function withSuggestions(callback) { + await SpecialPowers.pushPrefEnv({ + set: [[SUGGESTIONS_PREF, true]], + }); + let engine = await SearchTestUtils.promiseNewSearchEngine({ + url: getRootDirectory(gTestPath) + TEST_ENGINE_BASENAME, + }); + let oldDefaultEngine = await Services.search.getDefault(); + await Services.search.setDefault( + engine, + Ci.nsISearchService.CHANGE_REASON_UNKNOWN + ); + try { + await callback(engine); + } finally { + await Services.search.setDefault( + oldDefaultEngine, + Ci.nsISearchService.CHANGE_REASON_UNKNOWN + ); + await Services.search.removeEngine(engine); + await SpecialPowers.popPrefEnv(); + } +} + +/** + * Registers a test provider that returns a result with a suggestedIndex and + * resultSpan and asserts the given expected results match the actual results. + * + * @param {Array} expectedProps + * See `checkResults()`. + */ +async function doSuggestedIndexTest(expectedProps) { + await addHistory(); + let provider = new TestProvider(); + UrlbarProvidersManager.registerProvider(provider); + + let context = await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: SPONSORED_SEARCH_STRING, + }); + checkResults(context.results, expectedProps); + await UrlbarTestUtils.promisePopupClose(window); + + UrlbarProvidersManager.unregisterProvider(provider); + await PlacesUtils.history.clear(); +} + +/** + * Asserts the given actual and expected results match. + * + * @param {Array} actualResults + * Array of actual results. + * @param {Array} expectedProps + * Array of expected result-like objects. Only the properties defined in each + * of these objects are compared against the corresponding actual result. + */ +function checkResults(actualResults, expectedProps) { + Assert.equal( + actualResults.length, + expectedProps.length, + "Expected result count" + ); + + let actualProps = actualResults.map((actual, i) => { + if (expectedProps.length <= i) { + return actual; + } + let props = {}; + let expected = expectedProps[i]; + for (let [key, expectedValue] of Object.entries(expected)) { + if (key != "payload") { + props[key] = actual[key]; + } else { + props.payload = {}; + for (let pkey of Object.keys(expectedValue)) { + props.payload[pkey] = actual.payload[pkey]; + } + } + } + return props; + }); + Assert.deepEqual(actualProps, expectedProps); +} -- cgit v1.2.3