/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/browser/components/urlbar/tests/browser/head-common.js", this ); ChromeUtils.defineESModuleGetters(this, { QuickSuggest: "resource:///modules/QuickSuggest.sys.mjs", }); const lazy = {}; XPCOMUtils.defineLazyGetter(lazy, "QuickSuggestTestUtils", () => { const { QuickSuggestTestUtils: module } = ChromeUtils.importESModule( "resource://testing-common/QuickSuggestTestUtils.sys.mjs" ); module.init(this); return module; }); XPCOMUtils.defineLazyGetter(this, "MerinoTestUtils", () => { const { MerinoTestUtils: module } = ChromeUtils.importESModule( "resource://testing-common/MerinoTestUtils.sys.mjs" ); module.init(this); return module; }); ChromeUtils.defineESModuleGetters(lazy, { UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.sys.mjs", sinon: "resource://testing-common/Sinon.sys.mjs", }); async function addTopSites(url) { for (let i = 0; i < 5; i++) { await PlacesTestUtils.addVisits(url); } await updateTopSites(sites => { return sites && sites[0] && sites[0].url == url; }); } function assertAbandonmentTelemetry(expectedExtraList) { _assertGleanTelemetry("abandonment", expectedExtraList); } function assertEngagementTelemetry(expectedExtraList) { _assertGleanTelemetry("engagement", expectedExtraList); } function assertImpressionTelemetry(expectedExtraList) { _assertGleanTelemetry("impression", expectedExtraList); } function assertExposureTelemetry(expectedExtraList) { _assertGleanTelemetry("exposure", expectedExtraList); } function _assertGleanTelemetry(telemetryName, expectedExtraList) { const telemetries = Glean.urlbar[telemetryName].testGetValue() ?? []; Assert.equal( telemetries.length, expectedExtraList.length, "Telemetry event length matches expected event length." ); for (let i = 0; i < telemetries.length; i++) { const telemetry = telemetries[i]; Assert.equal(telemetry.category, "urlbar"); Assert.equal(telemetry.name, telemetryName); const expectedExtra = expectedExtraList[i]; for (const key of Object.keys(expectedExtra)) { Assert.equal( telemetry.extra[key], expectedExtra[key], `${key} is correct` ); } } } async function ensureQuickSuggestInit({ merinoSuggestions = undefined, config = undefined, } = {}) { return lazy.QuickSuggestTestUtils.ensureQuickSuggestInit({ config, merinoSuggestions, remoteSettingsResults: [ { type: "data", attachment: [ { id: 1, url: "https://example.com/sponsored", title: "Sponsored suggestion", keywords: ["sponsored"], click_url: "https://example.com/click", impression_url: "https://example.com/impression", advertiser: "TestAdvertiser", iab_category: "22 - Shopping", }, { id: 2, url: `https://example.com/nonsponsored`, title: "Non-sponsored suggestion", keywords: ["nonsponsored"], click_url: "https://example.com/click", impression_url: "https://example.com/impression", advertiser: "TestAdvertiser", iab_category: "5 - Education", }, ], }, { type: "weather", weather: MerinoTestUtils.WEATHER_RS_DATA, }, ], }); } async function doBlur() { await UrlbarTestUtils.promisePopupClose(window, () => { gURLBar.blur(); }); } async function doClick() { const selected = UrlbarTestUtils.getSelectedRow(window); const onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); EventUtils.synthesizeMouseAtCenter(selected, {}); await onLoad; } async function doClickSubButton(selector) { const selected = UrlbarTestUtils.getSelectedElement(window); const button = selected.closest(".urlbarView-row").querySelector(selector); EventUtils.synthesizeMouseAtCenter(button, {}); } async function doDropAndGo(data) { const onLoad = BrowserTestUtils.browserLoaded(browser); EventUtils.synthesizeDrop( document.getElementById("back-button"), gURLBar.inputField, [[{ type: "text/plain", data }]], "copy", window ); await onLoad; } async function doEnter(modifier = {}) { const onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); EventUtils.synthesizeKey("KEY_Enter", modifier); await onLoad; } async function doPaste(data) { await SimpleTest.promiseClipboardChange(data, () => { clipboardHelper.copyString(data); }); gURLBar.focus(); gURLBar.select(); document.commandDispatcher .getControllerForCommand("cmd_paste") .doCommand("cmd_paste"); await UrlbarTestUtils.promiseSearchComplete(window); } async function doPasteAndGo(data) { await SimpleTest.promiseClipboardChange(data, () => { clipboardHelper.copyString(data); }); const inputBox = gURLBar.querySelector("moz-input-box"); const contextMenu = inputBox.menupopup; const onPopup = BrowserTestUtils.waitForEvent(contextMenu, "popupshown"); EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { type: "contextmenu", button: 2, }); await onPopup; const onLoad = BrowserTestUtils.browserLoaded(browser); const menuitem = inputBox.getMenuItem("paste-and-go"); contextMenu.activateItem(menuitem); await onLoad; } async function doTest(testFn) { await Services.fog.testFlushAllChildren(); Services.fog.testResetFOG(); // Enable recording telemetry for abandonment, engagement and impression. Services.fog.setMetricsFeatureConfig( JSON.stringify({ "urlbar.abandonment": true, "urlbar.engagement": true, "urlbar.impression": true, }) ); gURLBar.controller.engagementEvent.reset(); await PlacesUtils.history.clear(); await PlacesUtils.bookmarks.eraseEverything(); await PlacesTestUtils.clearHistoryVisits(); await PlacesTestUtils.clearInputHistory(); await UrlbarTestUtils.formHistory.clear(window); await QuickSuggest.blockedSuggestions.clear(); await QuickSuggest.blockedSuggestions._test_readyPromise; await updateTopSites(() => true); try { await BrowserTestUtils.withNewTab(gBrowser, testFn); } finally { Services.fog.setMetricsFeatureConfig("{}"); } } async function initGroupTest() { /* import-globals-from head-groups.js */ Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-groups.js", this ); await setup(); } async function initInteractionTest() { /* import-globals-from head-interaction.js */ Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-interaction.js", this ); await setup(); } async function initNCharsAndNWordsTest() { /* import-globals-from head-n_chars_n_words.js */ Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-n_chars_n_words.js", this ); await setup(); } async function initSapTest() { /* import-globals-from head-sap.js */ Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-sap.js", this ); await setup(); } async function initSearchModeTest() { /* import-globals-from head-search_mode.js */ Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-search_mode.js", this ); await setup(); } async function initExposureTest() { /* import-globals-from head-exposure.js */ Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-exposure.js", this ); await setup(); } function loadOmniboxAddon({ keyword }) { return ExtensionTestUtils.loadExtension({ manifest: { permissions: ["tabs"], omnibox: { keyword, }, }, background() { /* global browser */ browser.omnibox.setDefaultSuggestion({ description: "doit", }); browser.omnibox.onInputEntered.addListener(() => { browser.tabs.update({ url: "https://example.com/" }); }); browser.omnibox.onInputChanged.addListener((text, suggest) => { suggest([]); }); }, }); } async function loadRemoteTab(url) { await SpecialPowers.pushPrefEnv({ set: [ ["browser.urlbar.suggest.searches", false], ["browser.urlbar.maxHistoricalSearchSuggestions", 0], ["browser.urlbar.autoFill", false], ["services.sync.username", "fake"], ["services.sync.syncedTabs.showRemoteTabs", true], ], }); const REMOTE_TAB = { id: "test", type: "client", lastModified: 1492201200, name: "test", clientType: "desktop", tabs: [ { type: "tab", title: "tesrt", url, icon: UrlbarUtils.ICON.DEFAULT, client: "test", lastUsed: Math.floor(Date.now() / 1000), }, ], }; const sandbox = lazy.sinon.createSandbox(); // eslint-disable-next-line no-undef const syncedTabs = SyncedTabs; const originalSyncedTabsInternal = syncedTabs._internal; syncedTabs._internal = { isConfiguredToSyncTabs: true, hasSyncedThisSession: true, getTabClients() { return Promise.resolve([]); }, syncTabs() { return Promise.resolve(); }, }; const weaveXPCService = Cc["@mozilla.org/weave/service;1"].getService( Ci.nsISupports ).wrappedJSObject; const oldWeaveServiceReady = weaveXPCService.ready; weaveXPCService.ready = true; sandbox .stub(syncedTabs._internal, "getTabClients") .callsFake(() => Promise.resolve(Cu.cloneInto([REMOTE_TAB], {}))); return { async unload() { sandbox.restore(); weaveXPCService.ready = oldWeaveServiceReady; syncedTabs._internal = originalSyncedTabsInternal; // Reset internal cache in UrlbarProviderRemoteTabs. Services.obs.notifyObservers(null, "weave:engine:sync:finish", "tabs"); await SpecialPowers.popPrefEnv(); }, }; } async function openPopup(input) { await UrlbarTestUtils.promisePopupOpen(window, async () => { await UrlbarTestUtils.inputIntoURLBar(window, input); }); await UrlbarTestUtils.promiseSearchComplete(window); } async function selectRowByURL(url) { for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) { const detail = await UrlbarTestUtils.getDetailsOfResultAt(window, i); if (detail.url === url) { UrlbarTestUtils.setSelectedRowIndex(window, i); return; } } } async function selectRowByProvider(provider) { for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) { const detail = await UrlbarTestUtils.getDetailsOfResultAt(window, i); if (detail.result.providerName === provider) { UrlbarTestUtils.setSelectedRowIndex(window, i); break; } } } async function selectRowByType(type) { for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) { const detail = await UrlbarTestUtils.getDetailsOfResultAt(window, i); if (detail.result.payload.type === type) { UrlbarTestUtils.setSelectedRowIndex(window, i); return; } } } async function setup() { await SpecialPowers.pushPrefEnv({ set: [ ["browser.urlbar.searchEngagementTelemetry.enabled", true], ["browser.urlbar.quickactions.enabled", true], ["browser.urlbar.quickactions.minimumSearchString", 0], ["browser.urlbar.suggest.quickactions", true], ["browser.urlbar.shortcuts.quickactions", true], [ "browser.urlbar.searchEngagementTelemetry.pauseImpressionIntervalMs", 100, ], ], }); const engine = await SearchTestUtils.promiseNewSearchEngine({ url: "chrome://mochitests/content/browser/browser/components/urlbar/tests/browser/searchSuggestionEngine.xml", }); const originalDefaultEngine = await Services.search.getDefault(); await Services.search.setDefault( engine, Ci.nsISearchService.CHANGE_REASON_UNKNOWN ); await Services.search.moveEngine(engine, 0); registerCleanupFunction(async function () { await SpecialPowers.popPrefEnv(); await Services.search.setDefault( originalDefaultEngine, Ci.nsISearchService.CHANGE_REASON_UNKNOWN ); }); } async function setupNimbus(variables) { return lazy.UrlbarTestUtils.initNimbusFeature(variables); } async function showResultByArrowDown() { gURLBar.value = ""; gURLBar.select(); await UrlbarTestUtils.promisePopupOpen(window, () => { EventUtils.synthesizeKey("KEY_ArrowDown"); }); await UrlbarTestUtils.promiseSearchComplete(window); } async function waitForPauseImpression() { await new Promise(r => setTimeout( r, UrlbarPrefs.get("searchEngagementTelemetry.pauseImpressionIntervalMs") ) ); await Services.fog.testFlushAllChildren(); }