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_search_telemetry_searchbar.js | 440 +++++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 browser/components/search/test/browser/browser_search_telemetry_searchbar.js (limited to 'browser/components/search/test/browser/browser_search_telemetry_searchbar.js') diff --git a/browser/components/search/test/browser/browser_search_telemetry_searchbar.js b/browser/components/search/test/browser/browser_search_telemetry_searchbar.js new file mode 100644 index 0000000000..15f512452a --- /dev/null +++ b/browser/components/search/test/browser/browser_search_telemetry_searchbar.js @@ -0,0 +1,440 @@ +"use strict"; + +const SCALAR_SEARCHBAR = "browser.engagement.navigation.searchbar"; + +ChromeUtils.defineESModuleGetters(this, { + UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.sys.mjs", +}); + +let suggestionEngine; + +function checkHistogramResults(resultIndexes, expected, histogram) { + for (let [i, val] of Object.entries(resultIndexes.values)) { + if (i == expected) { + Assert.equal( + val, + 1, + `expected counts should match for ${histogram} index ${i}` + ); + } else { + Assert.equal( + !!val, + false, + `unexpected counts should be zero for ${histogram} index ${i}` + ); + } + } +} + +/** + * Click one of the entries in the search suggestion popup. + * + * @param {string} entryName + * The name of the elemet to click on. + * @param {object} [clickOptions] + * The options to use for the click. + */ +function clickSearchbarSuggestion(entryName, clickOptions = {}) { + let richlistbox = BrowserSearch.searchBar.textbox.popup.richlistbox; + let richlistitem = Array.prototype.find.call( + richlistbox.children, + item => item.getAttribute("ac-value") == entryName + ); + + // Make sure the suggestion is visible and simulate the click. + richlistbox.ensureElementIsVisible(richlistitem); + EventUtils.synthesizeMouseAtCenter(richlistitem, clickOptions); +} + +add_setup(async function () { + await gCUITestUtils.addSearchBar(); + const url = getRootDirectory(gTestPath) + "telemetrySearchSuggestions.xml"; + suggestionEngine = await SearchTestUtils.promiseNewSearchEngine({ url }); + + registerCleanupFunction(() => { + gCUITestUtils.removeSearchBar(); + }); + + // Create two new search engines. Mark one as the default engine, so + // the test don't crash. We need to engines for this test as the searchbar + // doesn't display the default search engine among the one-off engines. + await SearchTestUtils.installSearchExtension( + { + name: "MozSearch", + keyword: "mozalias", + }, + { setAsDefault: true } + ); + await SearchTestUtils.installSearchExtension({ + name: "MozSearch2", + keyword: "mozalias2", + }); + + // Move the second engine at the beginning of the one-off list. + let engineOneOff = Services.search.getEngineByName("MozSearch2"); + await Services.search.moveEngine(engineOneOff, 0); + + // Enable local telemetry recording for the duration of the tests. + let oldCanRecord = Services.telemetry.canRecordExtended; + Services.telemetry.canRecordExtended = true; + + // Enable event recording for the events tested here. + Services.telemetry.setEventRecordingEnabled("navigation", true); + + registerCleanupFunction(async function () { + Services.telemetry.canRecordExtended = oldCanRecord; + Services.telemetry.setEventRecordingEnabled("navigation", false); + }); +}); + +add_task(async function test_plainQuery() { + // Let's reset the counts. + Services.telemetry.clearScalars(); + Services.telemetry.clearEvents(); + let resultMethodHist = TelemetryTestUtils.getAndClearHistogram( + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + let search_hist = + TelemetryTestUtils.getAndClearKeyedHistogram("SEARCH_COUNTS"); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:blank" + ); + + info("Simulate entering a simple search."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await searchInSearchbar("simple query"); + EventUtils.synthesizeKey("KEY_Enter"); + await p; + + // Check if the scalars contain the expected values. + const scalars = TelemetryTestUtils.getProcessScalars("parent", true, false); + TelemetryTestUtils.assertKeyedScalar( + scalars, + SCALAR_SEARCHBAR, + "search_enter", + 1 + ); + Assert.equal( + Object.keys(scalars[SCALAR_SEARCHBAR]).length, + 1, + "This search must only increment one entry in the scalar." + ); + + // Make sure SEARCH_COUNTS contains identical values. + TelemetryTestUtils.assertKeyedHistogramSum( + search_hist, + "other-MozSearch.searchbar", + 1 + ); + + // Also check events. + TelemetryTestUtils.assertEvents( + [ + { + object: "searchbar", + value: "enter", + extra: { engine: "other-MozSearch" }, + }, + ], + { category: "navigation", method: "search" } + ); + + // Check the histograms as well. + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults( + resultMethods, + UrlbarTestUtils.SELECTED_RESULT_METHODS.enter, + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + + BrowserTestUtils.removeTab(tab); +}); + +// Performs a search using the first result, a one-off button, and the Return +// (Enter) key. +add_task(async function test_oneOff_enter() { + // Let's reset the counts. + Services.telemetry.clearScalars(); + Services.telemetry.clearEvents(); + let resultMethodHist = TelemetryTestUtils.getAndClearHistogram( + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + let search_hist = + TelemetryTestUtils.getAndClearKeyedHistogram("SEARCH_COUNTS"); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:blank" + ); + + info("Perform a one-off search using the first engine."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await searchInSearchbar("query"); + + info("Pressing Alt+Down to highlight the first one off engine."); + EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true }); + EventUtils.synthesizeKey("KEY_Enter"); + await p; + + // Check if the scalars contain the expected values. + const scalars = TelemetryTestUtils.getProcessScalars("parent", true, false); + TelemetryTestUtils.assertKeyedScalar( + scalars, + SCALAR_SEARCHBAR, + "search_oneoff", + 1 + ); + Assert.equal( + Object.keys(scalars[SCALAR_SEARCHBAR]).length, + 1, + "This search must only increment one entry in the scalar." + ); + + // Make sure SEARCH_COUNTS contains identical values. + TelemetryTestUtils.assertKeyedHistogramSum( + search_hist, + "other-MozSearch2.searchbar", + 1 + ); + + // Also check events. + TelemetryTestUtils.assertEvents( + [ + { + object: "searchbar", + value: "oneoff", + extra: { engine: "other-MozSearch2" }, + }, + ], + { category: "navigation", method: "search" } + ); + + // Check the histograms as well. + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults( + resultMethods, + UrlbarTestUtils.SELECTED_RESULT_METHODS.enter, + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + + BrowserTestUtils.removeTab(tab); +}); + +// Performs a search using the second result, a one-off button, and the Return +// (Enter) key. This only tests the FX_SEARCHBAR_SELECTED_RESULT_METHOD +// histogram since test_oneOff_enter covers everything else. +add_task(async function test_oneOff_enterSelection() { + // Let's reset the counts. + Services.telemetry.clearScalars(); + let resultMethodHist = TelemetryTestUtils.getAndClearHistogram( + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + + let previousEngine = await Services.search.getDefault(); + await Services.search.setDefault( + suggestionEngine, + Ci.nsISearchService.CHANGE_REASON_UNKNOWN + ); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:blank" + ); + + info("Type a query. Suggestions should be generated by the test engine."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await searchInSearchbar("query"); + + info( + "Select the second result, press Alt+Down to take us to the first one-off engine." + ); + EventUtils.synthesizeKey("KEY_ArrowDown"); + EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true }); + EventUtils.synthesizeKey("KEY_Enter"); + await p; + + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults( + resultMethods, + UrlbarTestUtils.SELECTED_RESULT_METHODS.enterSelection, + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + + await Services.search.setDefault( + previousEngine, + Ci.nsISearchService.CHANGE_REASON_UNKNOWN + ); + BrowserTestUtils.removeTab(tab); +}); + +// Performs a search using a click on a one-off button. This only tests the +// FX_SEARCHBAR_SELECTED_RESULT_METHOD histogram since test_oneOff_enter covers +// everything else. +add_task(async function test_oneOff_click() { + // Let's reset the counts. + Services.telemetry.clearScalars(); + let resultMethodHist = TelemetryTestUtils.getAndClearHistogram( + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:blank" + ); + + info("Type a query."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + let popup = await searchInSearchbar("query"); + info("Click the first one-off button."); + popup.oneOffButtons.getSelectableButtons(false)[0].click(); + await p; + + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults( + resultMethods, + UrlbarTestUtils.SELECTED_RESULT_METHODS.click, + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + + BrowserTestUtils.removeTab(tab); +}); + +async function checkSuggestionClick(clickOptions, waitForActionFn) { + // Let's reset the counts. + Services.telemetry.clearScalars(); + Services.telemetry.clearEvents(); + let resultMethodHist = TelemetryTestUtils.getAndClearHistogram( + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + let search_hist = + TelemetryTestUtils.getAndClearKeyedHistogram("SEARCH_COUNTS"); + + let previousEngine = await Services.search.getDefault(); + await Services.search.setDefault( + suggestionEngine, + Ci.nsISearchService.CHANGE_REASON_UNKNOWN + ); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:blank" + ); + + info("Perform a one-off search using the first engine."); + let p = waitForActionFn(tab); + await searchInSearchbar("query"); + info("Clicking the searchbar suggestion."); + clickSearchbarSuggestion("queryfoo", clickOptions); + await p; + + // Check if the scalars contain the expected values. + const scalars = TelemetryTestUtils.getProcessScalars("parent", true, false); + TelemetryTestUtils.assertKeyedScalar( + scalars, + SCALAR_SEARCHBAR, + "search_suggestion", + 1 + ); + Assert.equal( + Object.keys(scalars[SCALAR_SEARCHBAR]).length, + 1, + "This search must only increment one entry in the scalar." + ); + + // Make sure SEARCH_COUNTS contains identical values. + let searchEngineId = "other-" + suggestionEngine.name; + TelemetryTestUtils.assertKeyedHistogramSum( + search_hist, + searchEngineId + ".searchbar", + 1 + ); + + // Also check events. + TelemetryTestUtils.assertEvents( + [ + { + object: "searchbar", + value: "suggestion", + extra: { engine: searchEngineId }, + }, + ], + { category: "navigation", method: "search" } + ); + + // Check the histograms as well. + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults( + resultMethods, + UrlbarTestUtils.SELECTED_RESULT_METHODS.click, + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + + await Services.search.setDefault( + previousEngine, + Ci.nsISearchService.CHANGE_REASON_UNKNOWN + ); + BrowserTestUtils.removeTab(tab); +} + +// Clicks the first suggestion offered by the test search engine. +add_task(async function test_suggestion_click() { + await checkSuggestionClick({}, tab => { + return BrowserTestUtils.browserLoaded(tab.linkedBrowser); + }); +}); + +add_task(async function test_suggestion_middle_click() { + let openedTab; + await checkSuggestionClick({ button: 1 }, () => { + return BrowserTestUtils.waitForNewTab(gBrowser, "http://example.com/").then( + tab => (openedTab = tab) + ); + }); + BrowserTestUtils.removeTab(openedTab); +}); + +// Selects and presses the Return (Enter) key on the first suggestion offered by +// the test search engine. This only tests the +// FX_SEARCHBAR_SELECTED_RESULT_METHOD histogram since test_suggestion_click +// covers everything else. +add_task(async function test_suggestion_enterSelection() { + // Let's reset the counts. + Services.telemetry.clearScalars(); + let resultMethodHist = TelemetryTestUtils.getAndClearHistogram( + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + + let previousEngine = await Services.search.getDefault(); + await Services.search.setDefault( + suggestionEngine, + Ci.nsISearchService.CHANGE_REASON_UNKNOWN + ); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:blank" + ); + + info("Type a query. Suggestions should be generated by the test engine."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await searchInSearchbar("query"); + info("Select the second result and press Return."); + EventUtils.synthesizeKey("KEY_ArrowDown"); + EventUtils.synthesizeKey("KEY_Enter"); + await p; + + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults( + resultMethods, + UrlbarTestUtils.SELECTED_RESULT_METHODS.enterSelection, + "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + + await Services.search.setDefault( + previousEngine, + Ci.nsISearchService.CHANGE_REASON_UNKNOWN + ); + BrowserTestUtils.removeTab(tab); +}); -- cgit v1.2.3