/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const { SearchSERPTelemetry } = ChromeUtils.importESModule( "resource:///modules/SearchSERPTelemetry.sys.mjs" ); const TEST_PROVIDER_INFO = [ { telemetryId: "example", searchPageRegexp: /^https:\/\/example.com\/browser\/browser\/components\/search\/test\/browser\/searchTelemetry(?:Ad)?.html/, queryParamName: "s", codeParamName: "abc", taggedCodes: ["ff"], followOnParamNames: ["a"], extraAdServersRegexps: [/^https:\/\/example\.com\/ad2?/], }, ]; function getPageUrl(useAdPage = false) { let page = useAdPage ? "searchTelemetryAd.html" : "searchTelemetry.html"; return `https://example.com/browser/browser/components/search/test/browser/${page}`; } // sharedData messages are only passed to the child on idle. Therefore // we wait for a few idles to try and ensure the messages have been able // to be passed across and handled. async function waitForIdle() { for (let i = 0; i < 10; i++) { await new Promise(resolve => Services.tm.idleDispatchToMainThread(resolve)); } } add_setup(async function () { SearchSERPTelemetry.overrideSearchTelemetryForTests(TEST_PROVIDER_INFO); await waitForIdle(); await SpecialPowers.pushPrefEnv({ set: [ [ "browser.newtabpage.activity-stream.improvesearch.handoffToAwesomebar", true, ], ], }); await SearchTestUtils.installSearchExtension( { search_url: getPageUrl(true), search_url_get_params: "s={searchTerms}&abc=ff", suggest_url: "https://example.com/browser/browser/components/search/test/browser/searchSuggestionEngine.sjs", suggest_url_get_params: "query={searchTerms}", }, { setAsDefault: true } ); const oldCanRecord = Services.telemetry.canRecordExtended; Services.telemetry.canRecordExtended = true; Services.telemetry.setEventRecordingEnabled("navigation", true); registerCleanupFunction(async function () { await PlacesUtils.history.clear(); Services.telemetry.canRecordExtended = oldCanRecord; Services.telemetry.setEventRecordingEnabled("navigation", false); SearchSERPTelemetry.overrideSearchTelemetryForTests(); Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); }); }); add_task(async function test_search() { Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); const histogram = TelemetryTestUtils.getAndClearKeyedHistogram("SEARCH_COUNTS"); info("Load about:newtab in new window"); const newtab = "about:newtab"; const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser); BrowserTestUtils.loadURIString(tab.linkedBrowser, newtab); await BrowserTestUtils.browserStopped(tab.linkedBrowser, newtab); info("Focus on search input in newtab content"); await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { const searchInput = content.document.querySelector(".fake-editable"); searchInput.click(); }); info("Search and wait the result"); const onLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser); EventUtils.synthesizeKey("q"); EventUtils.synthesizeKey("VK_RETURN"); await onLoaded; info("Check the telemetries"); await assertHandoffResult(histogram); BrowserTestUtils.removeTab(tab); }); add_task(async function test_search_private_mode() { Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); const histogram = TelemetryTestUtils.getAndClearKeyedHistogram("SEARCH_COUNTS"); info("Open private window"); let privateWindow = await BrowserTestUtils.openNewBrowserWindow({ private: true, }); let tab = privateWindow.gBrowser.selectedTab; info("Focus on search input in newtab content"); await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { const searchInput = content.document.querySelector(".fake-editable"); searchInput.click(); }); info("Search and wait the result"); const onLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser); EventUtils.synthesizeKey("q", {}, privateWindow); EventUtils.synthesizeKey("VK_RETURN", {}, privateWindow); await onLoaded; info("Check the telemetries"); await assertHandoffResult(histogram); await BrowserTestUtils.closeWindow(privateWindow); }); async function assertHandoffResult(histogram) { await assertScalars([ ["browser.engagement.navigation.urlbar_handoff", "search_enter", 1], ["browser.search.content.urlbar_handoff", "example:tagged:ff", 1], ]); await assertHistogram(histogram, [["other-Example.urlbar-handoff", 1]]); TelemetryTestUtils.assertEvents( [ [ "navigation", "search", "urlbar_handoff", "enter", { engine: "other-Example" }, ], ], { category: "navigation", method: "search" } ); } async function assertHistogram(histogram, expectedResults) { await TestUtils.waitForCondition(() => { const snapshot = histogram.snapshot(); return expectedResults.every(([key]) => key in snapshot); }, "Wait until the histogram has expected keys"); for (const [key, value] of expectedResults) { TelemetryTestUtils.assertKeyedHistogramSum(histogram, key, value); } } async function assertScalars(expectedResults) { await TestUtils.waitForCondition(() => { const scalars = TelemetryTestUtils.getProcessScalars("parent", true); return expectedResults.every(([scalarName]) => scalarName in scalars); }, "Wait until the scalars have expected keyed scalars"); const scalars = TelemetryTestUtils.getProcessScalars("parent", true); for (const [scalarName, key, value] of expectedResults) { TelemetryTestUtils.assertKeyedScalar(scalars, scalarName, key, value); } }