/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; ChromeUtils.defineESModuleGetters(this, { UrlbarUtils: "resource:///modules/UrlbarUtils.sys.mjs", }); const TEST_ENGINE_NAME = "Test"; const TEST_ENGINE_ALIAS = "@test"; const TEST_ENGINE_DOMAIN = "example.com"; // Each test is a function that executes an urlbar action and returns the // expected event object. const tests = [ async function (win) { info("Type something, blur."); win.gURLBar.select(); EventUtils.synthesizeKey("x", {}, win); win.gURLBar.blur(); return { category: "urlbar", method: "abandonment", object: "blur", value: "typed", extra: { elapsed: val => parseInt(val) > 0, numChars: "1", numWords: "1", }, }; }, async function (win) { info("Open the panel with DOWN, don't type, blur it."); await addTopSite("http://example.org/"); win.gURLBar.value = ""; win.gURLBar.select(); await UrlbarTestUtils.promisePopupOpen(win, () => { EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); }); win.gURLBar.blur(); return { category: "urlbar", method: "abandonment", object: "blur", value: "topsites", extra: { elapsed: val => parseInt(val) > 0, numChars: "0", numWords: "0", }, }; }, async function (win) { info("With pageproxystate=valid, autoopen the panel, don't type, blur it."); win.gURLBar.value = ""; await UrlbarTestUtils.promisePopupOpen(win, () => { win.document.getElementById("Browser:OpenLocation").doCommand(); }); win.gURLBar.blur(); return { category: "urlbar", method: "abandonment", object: "blur", value: "topsites", extra: { elapsed: val => parseInt(val) > 0, numChars: "0", numWords: "0", }, }; }, async function (win) { info("Enter search mode from Top Sites."); await updateTopSites(sites => true, /* enableSearchShorcuts */ true); win.gURLBar.value = ""; win.gURLBar.select(); await BrowserTestUtils.waitForCondition(async () => { await UrlbarTestUtils.promisePopupOpen(win, () => { EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); }); if (UrlbarTestUtils.getResultCount(win) > 1) { return true; } win.gURLBar.view.close(); return false; }); while (win.gURLBar.searchMode?.engineName != "Google") { EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); } let element = UrlbarTestUtils.getSelectedRow(win); Assert.ok( element.result.source == UrlbarUtils.RESULT_SOURCE.SEARCH, "The selected result is a search Top Site." ); let engine = element.result.payload.engine; let searchPromise = UrlbarTestUtils.promiseSearchComplete(win); EventUtils.synthesizeMouseAtCenter(element, {}, win); await searchPromise; await UrlbarTestUtils.assertSearchMode(win, { engineName: engine, source: UrlbarUtils.RESULT_SOURCE.SEARCH, entry: "topsites_urlbar", }); await UrlbarTestUtils.exitSearchMode(win); // To avoid needing to add a custom search shortcut Top Site, we just // abandon this interaction. await UrlbarTestUtils.promisePopupClose(win, () => { win.gURLBar.blur(); }); return [ // engagement on the top sites search engine to enter search mode { category: "urlbar", method: "engagement", object: "click", value: "topsites", extra: { elapsed: val => parseInt(val) > 0, numChars: "0", numWords: "0", selIndex: "0", selType: "searchengine", provider: "UrlbarProviderTopSites", }, }, // abandonment { category: "urlbar", method: "abandonment", object: "blur", value: "topsites", extra: { elapsed: val => parseInt(val) > 0, numChars: "0", numWords: "0", }, }, ]; }, async function (win) { info("Open search mode from a tab-to-search result."); await SpecialPowers.pushPrefEnv({ set: [["browser.urlbar.tabToSearch.onboard.interactionsLeft", 0]], }); await PlacesUtils.history.clear(); for (let i = 0; i < 3; i++) { await PlacesTestUtils.addVisits([`https://${TEST_ENGINE_DOMAIN}/`]); } await UrlbarTestUtils.promiseAutocompleteResultPopup({ window: win, value: TEST_ENGINE_DOMAIN.slice(0, 4), }); let tabToSearchResult = ( await UrlbarTestUtils.waitForAutocompleteResultAt(win, 1) ).result; Assert.equal( tabToSearchResult.providerName, "TabToSearch", "The second result is a tab-to-search result." ); // Select the tab-to-search result. EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); let searchPromise = UrlbarTestUtils.promiseSearchComplete(win); EventUtils.synthesizeKey("KEY_Enter", {}, win); await searchPromise; await UrlbarTestUtils.assertSearchMode(win, { engineName: TEST_ENGINE_NAME, entry: "tabtosearch", }); // Abandon the interaction since simply entering search mode is not // considered the end of an engagement. await UrlbarTestUtils.promisePopupClose(win, () => { win.gURLBar.blur(); }); await PlacesUtils.history.clear(); await SpecialPowers.popPrefEnv(); return [ // engagement on the tab-to-search to enter search mode { category: "urlbar", method: "engagement", object: "enter", value: "typed", extra: { elapsed: val => parseInt(val) > 0, numChars: "4", numWords: "1", selIndex: "1", selType: "tabtosearch", provider: "TabToSearch", }, }, // abandonment { category: "urlbar", method: "abandonment", object: "blur", value: "typed", extra: { elapsed: val => parseInt(val) > 0, numChars: "0", numWords: "0", }, }, ]; }, async function (win) { info( "With pageproxystate=invalid, open retained results, don't type, blur it." ); win.gURLBar.value = "mochi.test"; win.gURLBar.setPageProxyState("invalid"); await UrlbarTestUtils.promisePopupOpen(win, () => { win.document.getElementById("Browser:OpenLocation").doCommand(); }); win.gURLBar.blur(); return { category: "urlbar", method: "abandonment", object: "blur", value: "returned", extra: { elapsed: val => parseInt(val) > 0, numChars: "10", numWords: "1", }, }; }, ]; add_setup(async function () { await PlacesUtils.history.clear(); // Create a new search engine and mark it as default let engine = await SearchTestUtils.promiseNewSearchEngine({ url: getRootDirectory(gTestPath) + "searchSuggestionEngine.xml", setAsDefault: true, }); await Services.search.moveEngine(engine, 0); await SearchTestUtils.installSearchExtension({ name: TEST_ENGINE_NAME, keyword: TEST_ENGINE_ALIAS, search_url: `https://${TEST_ENGINE_DOMAIN}/`, }); // This test used to rely on the initial timer of // TestUtils.waitForCondition. See bug 1667216. let originalWaitForCondition = TestUtils.waitForCondition; TestUtils.waitForCondition = async function ( condition, msg, interval = 100, maxTries = 50 ) { // eslint-disable-next-line mozilla/no-arbitrary-setTimeout await new Promise(resolve => setTimeout(resolve, 100)); return originalWaitForCondition(condition, msg, interval, maxTries); }; registerCleanupFunction(async function () { await PlacesUtils.history.clear(); TestUtils.waitForCondition = originalWaitForCondition; }); }); async function doTest(eventTelemetryEnabled) { await SpecialPowers.pushPrefEnv({ set: [["browser.urlbar.eventTelemetry.enabled", eventTelemetryEnabled]], }); const win = await BrowserTestUtils.openNewBrowserWindow(); // This is not necessary after each loop, because assertEvents does it. Services.telemetry.clearEvents(); Services.telemetry.clearScalars(); for (let i = 0; i < tests.length; i++) { info(`Running test at index ${i}`); let events = await tests[i](win); if (!Array.isArray(events)) { events = [events]; } // Always blur to ensure it's not accounted as an additional abandonment. win.gURLBar.setSearchMode({}); win.gURLBar.blur(); TelemetryTestUtils.assertEvents(eventTelemetryEnabled ? events : [], { category: "urlbar", }); // Scalars should be recorded regardless of `eventTelemetry.enabled`. let scalars = TelemetryTestUtils.getProcessScalars("parent", false, true); TelemetryTestUtils.assertScalar( scalars, "urlbar.engagement", events.filter(e => e.method == "engagement").length || undefined ); TelemetryTestUtils.assertScalar( scalars, "urlbar.abandonment", events.filter(e => e.method == "abandonment").length || undefined ); await UrlbarTestUtils.formHistory.clear(win); } await BrowserTestUtils.closeWindow(win); await SpecialPowers.popPrefEnv(); } add_task(async function enabled() { await doTest(true); }); add_task(async function disabled() { await doTest(false); }); /** * Replaces the contents of Top Sites with the specified site. * * @param {string} site * A site to add to Top Sites. */ async function addTopSite(site) { await PlacesUtils.history.clear(); for (let i = 0; i < 5; i++) { await PlacesTestUtils.addVisits(site); } await updateTopSites(sites => sites && sites[0] && sites[0].url == site); }