"use strict"; const SCALAR_SEARCHBAR = "browser.engagement.navigation.searchbar"; let searchInSearchbar = Task.async(function* (inputText) { let win = window; yield new Promise(r => waitForFocus(r, win)); let sb = BrowserSearch.searchBar; // Write the search query in the searchbar. sb.focus(); sb.value = inputText; sb.textbox.controller.startSearch(inputText); // Wait for the popup to show. yield BrowserTestUtils.waitForEvent(sb.textbox.popup, "popupshown"); // And then for the search to complete. yield BrowserTestUtils.waitForCondition(() => sb.textbox.controller.searchStatus >= Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH, "The search in the searchbar must complete."); }); /** * Click one of the entries in the search suggestion popup. * * @param {String} entryName * The name of the elemet to click on. */ function clickSearchbarSuggestion(entryName) { let popup = BrowserSearch.searchBar.textbox.popup; let column = popup.tree.columns[0]; for (let rowID = 0; rowID < popup.tree.view.rowCount; rowID++) { const suggestion = popup.tree.view.getValueAt(rowID, column); if (suggestion !== entryName) { continue; } // Make sure the suggestion is visible, just in case. let tbo = popup.tree.treeBoxObject; tbo.ensureRowIsVisible(rowID); // Calculate the click coordinates. let rect = tbo.getCoordsForCellItem(rowID, column, "text"); let x = rect.x + rect.width / 2; let y = rect.y + rect.height / 2; // Simulate the click. EventUtils.synthesizeMouse(popup.tree.body, x, y, {}, popup.tree.ownerGlobal); break; } } add_task(function* setup() { // 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. Services.search.addEngineWithDetails("MozSearch", "", "mozalias", "", "GET", "http://example.com/?q={searchTerms}"); Services.search.addEngineWithDetails("MozSearch2", "", "mozalias2", "", "GET", "http://example.com/?q={searchTerms}"); // Make the first engine the default search engine. let engineDefault = Services.search.getEngineByName("MozSearch"); let originalEngine = Services.search.currentEngine; Services.search.currentEngine = engineDefault; // Move the second engine at the beginning of the one-off list. let engineOneOff = Services.search.getEngineByName("MozSearch2"); Services.search.moveEngine(engineOneOff, 0); // Enable Extended Telemetry. yield SpecialPowers.pushPrefEnv({"set": [["toolkit.telemetry.enabled", true]]}); // Make sure to restore the engine once we're done. registerCleanupFunction(function* () { Services.search.currentEngine = originalEngine; Services.search.removeEngine(engineDefault); Services.search.removeEngine(engineOneOff); }); }); add_task(function* test_plainQuery() { // Let's reset the counts. Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); let search_hist = getSearchCountsHistogram(); let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); info("Simulate entering a simple search."); let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); yield searchInSearchbar("simple query"); EventUtils.sendKey("return"); yield p; // Check if the scalars contain the expected values. const scalars = Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false); checkKeyedScalar(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. checkKeyedHistogram(search_hist, 'other-MozSearch.searchbar', 1); // Also check events. let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false); events = events.filter(e => e[1] == "navigation" && e[2] == "search"); checkEvents(events, [["navigation", "search", "searchbar", "enter", {engine: "other-MozSearch"}]]); yield BrowserTestUtils.removeTab(tab); }); add_task(function* test_oneOff() { // Let's reset the counts. Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); let search_hist = getSearchCountsHistogram(); let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); info("Perform a one-off search using the first engine."); let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); yield searchInSearchbar("query"); info("Pressing Alt+Down to highlight the first one off engine."); EventUtils.synthesizeKey("VK_DOWN", { altKey: true }); EventUtils.sendKey("return"); yield p; // Check if the scalars contain the expected values. const scalars = Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false); checkKeyedScalar(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. checkKeyedHistogram(search_hist, 'other-MozSearch2.searchbar', 1); // Also check events. let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false); events = events.filter(e => e[1] == "navigation" && e[2] == "search"); checkEvents(events, [["navigation", "search", "searchbar", "oneoff", {engine: "other-MozSearch2"}]]); yield BrowserTestUtils.removeTab(tab); }); add_task(function* test_suggestion() { // Let's reset the counts. Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); let search_hist = getSearchCountsHistogram(); // Create an engine to generate search suggestions and add it as default // for this test. const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml"; let suggestionEngine = yield new Promise((resolve, reject) => { Services.search.addEngine(url, null, "", false, { onSuccess(engine) { resolve(engine) }, onError() { reject() } }); }); let previousEngine = Services.search.currentEngine; Services.search.currentEngine = suggestionEngine; let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); info("Perform a one-off search using the first engine."); let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); yield searchInSearchbar("query"); info("Clicking the searchbar suggestion."); clickSearchbarSuggestion("queryfoo"); yield p; // Check if the scalars contain the expected values. const scalars = Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false); checkKeyedScalar(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; checkKeyedHistogram(search_hist, searchEngineId + '.searchbar', 1); // Also check events. let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false); events = events.filter(e => e[1] == "navigation" && e[2] == "search"); checkEvents(events, [["navigation", "search", "searchbar", "suggestion", {engine: searchEngineId}]]); Services.search.currentEngine = previousEngine; Services.search.removeEngine(suggestionEngine); yield BrowserTestUtils.removeTab(tab); });