summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/tests/engagementTelemetry
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/urlbar/tests/engagementTelemetry')
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser.toml87
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_groups.js235
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction.js61
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction_persisted_search_terms_disabled.js48
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction_persisted_search_terms_enabled.js53
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_n_chars_n_words.js36
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_sap.js39
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_search_engine_default_id.js19
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_search_mode.js54
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_tips.js99
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_edge_cases.js221
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_groups.js292
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction.js90
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction_persisted_search_terms_disabled.js61
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction_persisted_search_terms_enabled.js60
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_n_chars_n_words.js36
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_sap.js33
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_search_engine_default_id.js19
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_search_mode.js63
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_selected_result.js974
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_tips.js173
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_type.js118
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_exposure.js136
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_exposure_edge_cases.js539
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_groups.js258
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction.js68
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction_persisted_search_terms_disabled.js57
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction_persisted_search_terms_enabled.js61
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_n_chars_n_words.js40
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_preferences.js41
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_sap.js38
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_search_engine_default_id.js28
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_search_mode.js72
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_timing.js91
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_record_preferences.js74
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head-exposure.js47
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head-groups.js339
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head-interaction.js340
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head-n_chars_n_words.js56
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head-sap.js66
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head-search_engine_default_id.js43
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head-search_mode.js93
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head.js473
43 files changed, 5831 insertions, 0 deletions
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser.toml b/browser/components/urlbar/tests/engagementTelemetry/browser/browser.toml
new file mode 100644
index 0000000000..68a7881399
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser.toml
@@ -0,0 +1,87 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+[DEFAULT]
+support-files = [
+ "head.js",
+ "head-search_engine_default_id.js",
+ "head-exposure.js",
+ "head-groups.js",
+ "head-interaction.js",
+ "head-n_chars_n_words.js",
+ "head-sap.js",
+ "head-search_mode.js",
+ "../../browser-tips/head.js",
+]
+prefs = ["browser.bookmarks.testing.skipDefaultBookmarksImport=true"]
+
+["browser_glean_telemetry_abandonment_groups.js"]
+
+["browser_glean_telemetry_abandonment_interaction.js"]
+
+["browser_glean_telemetry_abandonment_interaction_persisted_search_terms_disabled.js"]
+
+["browser_glean_telemetry_abandonment_interaction_persisted_search_terms_enabled.js"]
+
+["browser_glean_telemetry_abandonment_n_chars_n_words.js"]
+
+["browser_glean_telemetry_abandonment_sap.js"]
+
+["browser_glean_telemetry_abandonment_search_engine_default_id.js"]
+
+["browser_glean_telemetry_abandonment_search_mode.js"]
+
+["browser_glean_telemetry_abandonment_tips.js"]
+
+["browser_glean_telemetry_engagement_edge_cases.js"]
+
+["browser_glean_telemetry_engagement_groups.js"]
+
+["browser_glean_telemetry_engagement_interaction.js"]
+
+["browser_glean_telemetry_engagement_interaction_persisted_search_terms_disabled.js"]
+
+["browser_glean_telemetry_engagement_interaction_persisted_search_terms_enabled.js"]
+
+["browser_glean_telemetry_engagement_n_chars_n_words.js"]
+
+["browser_glean_telemetry_engagement_sap.js"]
+
+["browser_glean_telemetry_engagement_search_engine_default_id.js"]
+
+["browser_glean_telemetry_engagement_search_mode.js"]
+
+["browser_glean_telemetry_engagement_selected_result.js"]
+support-files = ["../../../../search/test/browser/trendingSuggestionEngine.sjs"]
+skip-if = ["verify"] # Bug 1852375 - MerinoTestUtils.initWeather() doesn't play well with pushPrefEnv()
+
+["browser_glean_telemetry_engagement_tips.js"]
+
+["browser_glean_telemetry_engagement_type.js"]
+
+["browser_glean_telemetry_exposure.js"]
+
+["browser_glean_telemetry_exposure_edge_cases.js"]
+
+["browser_glean_telemetry_impression_groups.js"]
+
+["browser_glean_telemetry_impression_interaction.js"]
+
+["browser_glean_telemetry_impression_interaction_persisted_search_terms_disabled.js"]
+
+["browser_glean_telemetry_impression_interaction_persisted_search_terms_enabled.js"]
+
+["browser_glean_telemetry_impression_n_chars_n_words.js"]
+
+["browser_glean_telemetry_impression_preferences.js"]
+
+["browser_glean_telemetry_impression_sap.js"]
+
+["browser_glean_telemetry_impression_search_engine_default_id.js"]
+
+["browser_glean_telemetry_impression_search_mode.js"]
+
+["browser_glean_telemetry_impression_timing.js"]
+
+["browser_glean_telemetry_record_preferences.js"]
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_groups.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_groups.js
new file mode 100644
index 0000000000..ce69d30517
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_groups.js
@@ -0,0 +1,235 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of abandonment telemetry.
+// - groups
+// - results
+// - n_results
+
+// This test has many subtests and can time out in verify mode.
+requestLongerTimeout(5);
+
+add_setup(async function () {
+ await initGroupTest();
+});
+
+add_task(async function heuristics() {
+ await doHeuristicsTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ { groups: "heuristic", results: "search_engine" },
+ ]),
+ });
+});
+
+add_task(async function adaptive_history() {
+ await doAdaptiveHistoryTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,adaptive_history",
+ results: "search_engine,history",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function search_history() {
+ await doSearchHistoryTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,search_history,search_history",
+ results: "search_engine,search_history,search_history",
+ n_results: 3,
+ },
+ ]),
+ });
+});
+
+add_task(async function recent_search() {
+ await doRecentSearchTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "recent_search,suggested_index",
+ results: "recent_search,action",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function search_suggest() {
+ await doSearchSuggestTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,search_suggest,search_suggest",
+ results: "search_engine,search_suggest,search_suggest",
+ n_results: 3,
+ },
+ ]),
+ });
+
+ await doTailSearchSuggestTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,search_suggest",
+ results: "search_engine,search_suggest",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function top_pick() {
+ await doTopPickTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,top_pick,search_suggest,search_suggest",
+ results:
+ "search_engine,merino_top_picks,search_suggest,search_suggest",
+ n_results: 4,
+ },
+ ]),
+ });
+});
+
+add_task(async function top_site() {
+ await doTopSiteTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "top_site,suggested_index",
+ results: "top_site,action",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function clipboard() {
+ await doClipboardTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "general,suggested_index",
+ results: "clipboard,action",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function remote_tab() {
+ await doRemoteTabTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,remote_tab",
+ results: "search_engine,remote_tab",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function addon() {
+ await doAddonTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "addon",
+ results: "addon",
+ n_results: 1,
+ },
+ ]),
+ });
+});
+
+add_task(async function general() {
+ await doGeneralBookmarkTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,suggested_index,general",
+ results: "search_engine,action,bookmark",
+ n_results: 3,
+ },
+ ]),
+ });
+
+ await doGeneralHistoryTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,general",
+ results: "search_engine,history",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function suggest() {
+ await doSuggestTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,suggest",
+ results: UrlbarPrefs.get("quickSuggestRustEnabled")
+ ? "search_engine,rust_adm_nonsponsored"
+ : "search_engine,rs_adm_nonsponsored",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function about_page() {
+ await doAboutPageTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,about_page,about_page",
+ results: "search_engine,history,history",
+ n_results: 3,
+ },
+ ]),
+ });
+});
+
+add_task(async function suggested_index() {
+ await doSuggestedIndexTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([
+ {
+ groups: "heuristic,suggested_index",
+ results: "search_engine,unit",
+ n_results: 2,
+ },
+ ]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction.js
new file mode 100644
index 0000000000..73820be059
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of abandonment telemetry.
+// - interaction
+
+add_setup(async function () {
+ await initInteractionTest();
+});
+
+add_task(async function topsites() {
+ await doTopsitesTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ interaction: "topsites" }]),
+ });
+});
+
+add_task(async function typed() {
+ await doTypedTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ interaction: "typed" }]),
+ });
+
+ await doTypedWithResultsPopupTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ interaction: "typed" }]),
+ });
+});
+
+add_task(async function pasted() {
+ await doPastedTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ interaction: "pasted" }]),
+ });
+
+ await doPastedWithResultsPopupTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ interaction: "pasted" }]),
+ });
+});
+
+add_task(async function topsite_search() {
+ await doTopsitesSearchTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([{ interaction: "topsite_search" }]),
+ });
+});
+
+add_task(async function returned_restarted_refined() {
+ await doReturnedRestartedRefinedTest({
+ trigger: () => doBlur(),
+ assert: expected =>
+ assertAbandonmentTelemetry([
+ { interaction: "typed" },
+ { interaction: expected },
+ ]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction_persisted_search_terms_disabled.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction_persisted_search_terms_disabled.js
new file mode 100644
index 0000000000..68799544b0
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction_persisted_search_terms_disabled.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test abandonment telemetry with persisted search terms disabled.
+
+// Allow more time for Mac machines so they don't time out in verify mode.
+if (AppConstants.platform == "macosx") {
+ requestLongerTimeout(3);
+}
+
+add_setup(async function () {
+ await initInteractionTest();
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", false]],
+ });
+});
+
+add_task(async function persisted_search_terms() {
+ await doPersistedSearchTermsTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ interaction: "typed" }]),
+ });
+});
+
+add_task(async function persisted_search_terms_restarted_refined() {
+ await doPersistedSearchTermsRestartedRefinedTest({
+ enabled: false,
+ trigger: () => doBlur(),
+ assert: expected => assertAbandonmentTelemetry([{ interaction: expected }]),
+ });
+});
+
+add_task(
+ async function persisted_search_terms_restarted_refined_via_abandonment() {
+ await doPersistedSearchTermsRestartedRefinedViaAbandonmentTest({
+ enabled: false,
+ trigger: () => doBlur(),
+ assert: expected =>
+ assertAbandonmentTelemetry([
+ { interaction: "typed" },
+ { interaction: expected },
+ ]),
+ });
+ }
+);
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction_persisted_search_terms_enabled.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction_persisted_search_terms_enabled.js
new file mode 100644
index 0000000000..f0a217805f
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction_persisted_search_terms_enabled.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test abandonment telemetry with persisted search terms enabled.
+
+// Allow more time for Mac machines so they don't time out in verify mode.
+if (AppConstants.platform == "macosx") {
+ requestLongerTimeout(3);
+}
+
+add_setup(async function () {
+ await initInteractionTest();
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.showSearchTerms.featureGate", true],
+ ["browser.urlbar.showSearchTerms.enabled", true],
+ ["browser.search.widget.inNavBar", false],
+ ],
+ });
+});
+
+add_task(async function persisted_search_terms() {
+ await doPersistedSearchTermsTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([{ interaction: "persisted_search_terms" }]),
+ });
+});
+
+add_task(async function persisted_search_terms_restarted_refined() {
+ await doPersistedSearchTermsRestartedRefinedTest({
+ enabled: true,
+ trigger: () => doBlur(),
+ assert: expected => assertAbandonmentTelemetry([{ interaction: expected }]),
+ });
+});
+
+add_task(
+ async function persisted_search_terms_restarted_refined_via_abandonment() {
+ await doPersistedSearchTermsRestartedRefinedViaAbandonmentTest({
+ enabled: true,
+ trigger: () => doBlur(),
+ assert: expected =>
+ assertAbandonmentTelemetry([
+ { interaction: "persisted_search_terms_restarted" },
+ { interaction: expected },
+ ]),
+ });
+ }
+);
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_n_chars_n_words.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_n_chars_n_words.js
new file mode 100644
index 0000000000..7427db8cbf
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_n_chars_n_words.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of abandonment telemetry.
+// - n_chars
+// - n_words
+
+add_setup(async function () {
+ await initNCharsAndNWordsTest();
+});
+
+add_task(async function n_chars() {
+ await doNCharsTest({
+ trigger: () => doBlur(),
+ assert: nChars => assertAbandonmentTelemetry([{ n_chars: nChars }]),
+ });
+
+ await doNCharsWithOverMaxTextLengthCharsTest({
+ trigger: () => doBlur(),
+ assert: nChars => assertAbandonmentTelemetry([{ n_chars: nChars }]),
+ });
+});
+
+add_task(async function n_words() {
+ await doNWordsTest({
+ trigger: () => doBlur(),
+ assert: nWords => assertAbandonmentTelemetry([{ n_words: nWords }]),
+ });
+
+ await doNWordsWithOverMaxTextLengthCharsTest({
+ trigger: () => doBlur(),
+ assert: nWords => assertAbandonmentTelemetry([{ n_words: nWords }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_sap.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_sap.js
new file mode 100644
index 0000000000..3d0af65379
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_sap.js
@@ -0,0 +1,39 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of abandonment telemetry.
+// - sap
+
+add_setup(async function () {
+ await initSapTest();
+});
+
+add_task(async function urlbar_newtab() {
+ await doUrlbarNewTabTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ sap: "urlbar_newtab" }]),
+ });
+});
+
+add_task(async function urlbar() {
+ await doUrlbarTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ sap: "urlbar" }]),
+ });
+});
+
+add_task(async function handoff() {
+ await doHandoffTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ sap: "handoff" }]),
+ });
+});
+
+add_task(async function urlbar_addonpage() {
+ await doUrlbarAddonpageTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ sap: "urlbar_addonpage" }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_search_engine_default_id.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_search_engine_default_id.js
new file mode 100644
index 0000000000..d64b540d25
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_search_engine_default_id.js
@@ -0,0 +1,19 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of abandonment telemetry.
+// - search_engine_default_id
+
+add_setup(async function () {
+ await initSearchEngineDefaultIdTest();
+});
+
+add_task(async function basic() {
+ await doSearchEngineDefaultIdTest({
+ trigger: () => doBlur(),
+ assert: engineId =>
+ assertAbandonmentTelemetry([{ search_engine_default_id: engineId }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_search_mode.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_search_mode.js
new file mode 100644
index 0000000000..7edcc47a30
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_search_mode.js
@@ -0,0 +1,54 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of abandonment telemetry.
+// - search_mode
+
+add_setup(async function () {
+ await initSearchModeTest();
+});
+
+add_task(async function not_search_mode() {
+ await doNotSearchModeTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ search_mode: "" }]),
+ });
+});
+
+add_task(async function search_engine() {
+ await doSearchEngineTest({
+ trigger: () => doBlur(),
+ assert: () =>
+ assertAbandonmentTelemetry([{ search_mode: "search_engine" }]),
+ });
+});
+
+add_task(async function bookmarks() {
+ await doBookmarksTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ search_mode: "bookmarks" }]),
+ });
+});
+
+add_task(async function history() {
+ await doHistoryTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ search_mode: "history" }]),
+ });
+});
+
+add_task(async function tabs() {
+ await doTabTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ search_mode: "tabs" }]),
+ });
+});
+
+add_task(async function actions() {
+ await doActionsTest({
+ trigger: () => doBlur(),
+ assert: () => assertAbandonmentTelemetry([{ search_mode: "actions" }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_tips.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_tips.js
new file mode 100644
index 0000000000..71087d03d0
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_tips.js
@@ -0,0 +1,99 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for abandonment telemetry for tips using Glean.
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/browser-tips/head.js",
+ this
+);
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.searchTips.test.ignoreShowLimits", true],
+ ["browser.urlbar.showSearchTerms.featureGate", true],
+ ],
+ });
+ 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
+ );
+ resetSearchTipsProvider();
+ });
+});
+
+add_task(async function tip_persist() {
+ await doTest(async browser => {
+ await showPersistSearchTip("test");
+ gURLBar.focus();
+ await UrlbarTestUtils.promisePopupClose(window, () => {
+ gURLBar.blur();
+ });
+
+ assertAbandonmentTelemetry([{ results: "tip_persist" }]);
+ });
+});
+
+add_task(async function mouse_down_with_tip() {
+ await doTest(async browser => {
+ await showPersistSearchTip("test");
+ await UrlbarTestUtils.promisePopupClose(window, () => {
+ // We intentionally turn off this a11y check, because the following click
+ // is sent to test the telemetry behavior using an alternative way of the
+ // urlbar dismissal, where other ways are accessible, therefore this test
+ // can be ignored.
+ AccessibilityUtils.setEnv({
+ mustHaveAccessibleRule: false,
+ });
+ EventUtils.synthesizeMouseAtCenter(browser, {});
+ AccessibilityUtils.resetEnv();
+ });
+
+ assertAbandonmentTelemetry([{ results: "tip_persist" }]);
+ });
+});
+
+add_task(async function mouse_down_without_tip() {
+ await doTest(async browser => {
+ // We intentionally turn off this a11y check, because the following click
+ // is sent to test the telemetry behavior using an alternative way of the
+ // urlbar dismissal, where other ways are accessible, therefore this test
+ // can be ignored.
+ AccessibilityUtils.setEnv({
+ mustHaveAccessibleRule: false,
+ });
+ EventUtils.synthesizeMouseAtCenter(browser, {});
+ AccessibilityUtils.resetEnv();
+
+ assertAbandonmentTelemetry([]);
+ });
+});
+
+async function showPersistSearchTip(word) {
+ await openPopup(word);
+ await doEnter();
+ await BrowserTestUtils.waitForCondition(async () => {
+ for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
+ const detail = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
+ if (detail.result.payload?.type === "searchTip_persist") {
+ return true;
+ }
+ }
+ return false;
+ });
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_edge_cases.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_edge_cases.js
new file mode 100644
index 0000000000..fcac924879
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_edge_cases.js
@@ -0,0 +1,221 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test edge cases for engagement.
+
+add_setup(async function () {
+ await setup();
+});
+
+/**
+ * UrlbarProvider that does not add any result.
+ */
+class NoResponseTestProvider extends UrlbarTestUtils.TestProvider {
+ constructor() {
+ super({ name: "TestProviderNoResponse ", results: [] });
+ this.#deferred = Promise.withResolvers();
+ }
+
+ get type() {
+ return UrlbarUtils.PROVIDER_TYPE.HEURISTIC;
+ }
+
+ async startQuery(context, addCallback) {
+ await this.#deferred.promise;
+ }
+
+ done() {
+ this.#deferred.resolve();
+ }
+
+ #deferred = null;
+}
+const noResponseProvider = new NoResponseTestProvider();
+
+/**
+ * UrlbarProvider that adds a heuristic result immediately as usual.
+ */
+class AnotherHeuristicProvider extends UrlbarTestUtils.TestProvider {
+ constructor({ results }) {
+ super({ name: "TestProviderAnotherHeuristic ", results });
+ this.#deferred = Promise.withResolvers();
+ }
+
+ get type() {
+ return UrlbarUtils.PROVIDER_TYPE.HEURISTIC;
+ }
+
+ async startQuery(context, addCallback) {
+ for (const result of this.results) {
+ addCallback(this, result);
+ }
+
+ this.#deferred.resolve(context);
+ }
+
+ onQueryStarted() {
+ return this.#deferred.promise;
+ }
+
+ #deferred = null;
+}
+const anotherHeuristicProvider = new AnotherHeuristicProvider({
+ results: [
+ Object.assign(
+ new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.URL,
+ UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
+ { url: "https://example.com/immediate" }
+ ),
+ { heuristic: true }
+ ),
+ ],
+});
+
+add_task(async function engagement_before_showing_results() {
+ await SpecialPowers.pushPrefEnv({
+ // Avoid showing search tip.
+ set: [["browser.urlbar.tipShownCount.searchTip_onboard", 999]],
+ });
+
+ // Increase chunk delays to delay the call to notifyResults.
+ let originalChunkTimeout = UrlbarProvidersManager.CHUNK_RESULTS_DELAY_MS;
+ UrlbarProvidersManager.CHUNK_RESULTS_DELAY_MS = 1000000;
+
+ // Add a provider that waits forever in startQuery() to avoid fireing
+ // heuristicProviderTimer.
+ UrlbarProvidersManager.registerProvider(noResponseProvider);
+
+ // Add a provider that add a result immediately as usual.
+ UrlbarProvidersManager.registerProvider(anotherHeuristicProvider);
+
+ const cleanup = () => {
+ UrlbarProvidersManager.unregisterProvider(noResponseProvider);
+ UrlbarProvidersManager.unregisterProvider(anotherHeuristicProvider);
+ UrlbarProvidersManager.CHUNK_RESULTS_DELAY_MS = originalChunkTimeout;
+ };
+ registerCleanupFunction(cleanup);
+
+ await doTest(async browser => {
+ // Try to show the results.
+ await UrlbarTestUtils.inputIntoURLBar(window, "exam");
+
+ // Wait until starting the query and filling expected results.
+ const context = await anotherHeuristicProvider.onQueryStarted();
+ const query = UrlbarProvidersManager.queries.get(context);
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ query.unsortedResults.some(
+ r => r.providerName === "HeuristicFallback"
+ ) &&
+ query.unsortedResults.some(
+ r => r.providerName === anotherHeuristicProvider.name
+ )
+ );
+
+ // Type Enter key before showing any results.
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "input_field",
+ selected_result_subtype: "",
+ provider: undefined,
+ results: "",
+ groups: "",
+ },
+ ]);
+
+ // Clear the pending query.
+ noResponseProvider.done();
+ });
+
+ cleanup();
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function engagement_after_closing_results() {
+ const TRIGGERS = [
+ () => EventUtils.synthesizeKey("KEY_Escape"),
+ () => {
+ // We intentionally turn off this a11y check, because the following click
+ // is sent to test the telemetry behavior using an alternative way of the
+ // urlbar dismissal, where other ways are accessible (and tested above),
+ // therefore this test can be ignored.
+ AccessibilityUtils.setEnv({
+ mustHaveAccessibleRule: false,
+ });
+ EventUtils.synthesizeMouseAtCenter(
+ document.getElementById("customizableui-special-spring2"),
+ {}
+ );
+ AccessibilityUtils.resetEnv();
+ },
+ ];
+
+ for (const trigger of TRIGGERS) {
+ await doTest(async browser => {
+ await openPopup("test");
+ await UrlbarTestUtils.promisePopupClose(window, () => {
+ trigger();
+ });
+ Assert.equal(
+ gURLBar.value,
+ "test",
+ "The inputted text remains even if closing the results"
+ );
+ // The tested trigger should not record abandonment event.
+ assertAbandonmentTelemetry([]);
+
+ // Endgagement.
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "input_field",
+ selected_result_subtype: "",
+ provider: undefined,
+ results: "",
+ groups: "",
+ },
+ ]);
+ });
+ }
+});
+
+add_task(async function enter_to_reload_current_url() {
+ await doTest(async browser => {
+ // Open a URL once.
+ await openPopup("https://example.com");
+ await doEnter();
+
+ // Focus the urlbar.
+ EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {});
+ await BrowserTestUtils.waitForCondition(
+ () => window.document.activeElement === gURLBar.inputField
+ );
+ await UrlbarTestUtils.promiseSearchComplete(window);
+
+ // Press Enter key to reload the page without selecting any suggestions.
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "url",
+ selected_result_subtype: "",
+ provider: "HeuristicFallback",
+ results: "url",
+ groups: "heuristic",
+ },
+ {
+ selected_result: "input_field",
+ selected_result_subtype: "",
+ provider: undefined,
+ results: "action",
+ groups: "suggested_index",
+ },
+ ]);
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_groups.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_groups.js
new file mode 100644
index 0000000000..8779487960
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_groups.js
@@ -0,0 +1,292 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of engagement telemetry.
+// - groups
+// - results
+// - n_results
+
+// This test has many subtests and can time out in verify mode.
+requestLongerTimeout(5);
+
+add_setup(async function () {
+ await initGroupTest();
+});
+
+add_task(async function heuristics() {
+ await doHeuristicsTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ { groups: "heuristic", results: "search_engine" },
+ ]),
+ });
+});
+
+add_task(async function adaptive_history() {
+ await doAdaptiveHistoryTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,adaptive_history",
+ results: "search_engine,history",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function search_history() {
+ await doSearchHistoryTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,search_history,search_history",
+ results: "search_engine,search_history,search_history",
+ n_results: 3,
+ },
+ ]),
+ });
+});
+
+add_task(async function recent_search() {
+ await doRecentSearchTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "recent_search,suggested_index",
+ results: "recent_search,action",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function search_suggest() {
+ await doSearchSuggestTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,search_suggest,search_suggest",
+ results: "search_engine,search_suggest,search_suggest",
+ n_results: 3,
+ },
+ ]),
+ });
+
+ await doTailSearchSuggestTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,search_suggest",
+ results: "search_engine,search_suggest",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function top_pick() {
+ await doTopPickTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,top_pick,search_suggest,search_suggest",
+ results:
+ "search_engine,merino_top_picks,search_suggest,search_suggest",
+ n_results: 4,
+ },
+ ]),
+ });
+});
+
+add_task(async function top_site() {
+ await doTopSiteTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "top_site,suggested_index",
+ results: "top_site,action",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function clipboard() {
+ await doClipboardTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "general,suggested_index",
+ results: "clipboard,action",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function remote_tab() {
+ await doRemoteTabTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,remote_tab",
+ results: "search_engine,remote_tab",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function addon() {
+ await doAddonTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "addon",
+ results: "addon",
+ n_results: 1,
+ },
+ ]),
+ });
+});
+
+add_task(async function general() {
+ await doGeneralBookmarkTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,suggested_index,general",
+ results: "search_engine,action,bookmark",
+ n_results: 3,
+ },
+ ]),
+ });
+
+ await doGeneralHistoryTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,general",
+ results: "search_engine,history",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function suggest() {
+ await doSuggestTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,suggest",
+ results: UrlbarPrefs.get("quickSuggestRustEnabled")
+ ? "search_engine,rust_adm_nonsponsored"
+ : "search_engine,rs_adm_nonsponsored",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function about_page() {
+ await doAboutPageTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,about_page,about_page",
+ results: "search_engine,history,history",
+ n_results: 3,
+ },
+ ]),
+ });
+});
+
+add_task(async function suggested_index() {
+ await doSuggestedIndexTest({
+ trigger: () =>
+ SimpleTest.promiseClipboardChange("100 cm", () => {
+ EventUtils.synthesizeKey("KEY_Enter");
+ }),
+ assert: () =>
+ assertEngagementTelemetry([
+ {
+ groups: "heuristic,suggested_index",
+ results: "search_engine,unit",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function always_empty_if_drop_go() {
+ const expected = [
+ {
+ engagement_type: "drop_go",
+ groups: "",
+ results: "",
+ n_results: 0,
+ },
+ ];
+
+ await doTest(async browser => {
+ await doDropAndGo("example.com");
+
+ assertEngagementTelemetry(expected);
+ });
+
+ await doTest(async browser => {
+ // Open the results view once.
+ await showResultByArrowDown();
+ await UrlbarTestUtils.promisePopupClose(window);
+
+ await doDropAndGo("example.com");
+
+ assertEngagementTelemetry(expected);
+ });
+});
+
+add_task(async function always_empty_if_paste_go() {
+ const expected = [
+ {
+ engagement_type: "paste_go",
+ groups: "",
+ results: "",
+ n_results: 0,
+ },
+ ];
+
+ await doTest(async browser => {
+ await doPasteAndGo("example.com");
+
+ assertEngagementTelemetry(expected);
+ });
+
+ await doTest(async browser => {
+ // Open the results view once.
+ await showResultByArrowDown();
+ await UrlbarTestUtils.promisePopupClose(window);
+
+ await doPasteAndGo("example.com");
+
+ assertEngagementTelemetry(expected);
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction.js
new file mode 100644
index 0000000000..f4880d2205
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction.js
@@ -0,0 +1,90 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of engagement telemetry.
+// - interaction
+
+// Allow more time for Mac machines so they don't time out in verify mode.
+if (AppConstants.platform == "macosx") {
+ requestLongerTimeout(3);
+}
+
+add_setup(async function () {
+ await initInteractionTest();
+});
+
+add_task(async function topsites() {
+ await doTopsitesTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ interaction: "topsites" }]),
+ });
+});
+
+add_task(async function typed() {
+ await doTypedTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ interaction: "typed" }]),
+ });
+
+ await doTypedWithResultsPopupTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ interaction: "typed" }]),
+ });
+});
+
+add_task(async function dropped() {
+ await doTest(async browser => {
+ await doDropAndGo("example.com");
+
+ assertEngagementTelemetry([{ interaction: "dropped" }]);
+ });
+
+ await doTest(async browser => {
+ await showResultByArrowDown();
+ await doDropAndGo("example.com");
+
+ assertEngagementTelemetry([{ interaction: "dropped" }]);
+ });
+});
+
+add_task(async function pasted() {
+ await doPastedTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ interaction: "pasted" }]),
+ });
+
+ await doPastedWithResultsPopupTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ interaction: "pasted" }]),
+ });
+
+ await doTest(async browser => {
+ await doPasteAndGo("www.example.com");
+
+ assertEngagementTelemetry([{ interaction: "pasted" }]);
+ });
+
+ await doTest(async browser => {
+ await showResultByArrowDown();
+ await doPasteAndGo("www.example.com");
+
+ assertEngagementTelemetry([{ interaction: "pasted" }]);
+ });
+});
+
+add_task(async function topsite_search() {
+ await doTopsitesSearchTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([{ interaction: "topsite_search" }]),
+ });
+});
+
+add_task(async function returned_restarted_refined() {
+ await doReturnedRestartedRefinedTest({
+ trigger: () => doEnter(),
+ assert: expected => assertEngagementTelemetry([{ interaction: expected }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction_persisted_search_terms_disabled.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction_persisted_search_terms_disabled.js
new file mode 100644
index 0000000000..1bdb4f0b61
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction_persisted_search_terms_disabled.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test engagement telemetry with persisted search terms disabled.
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-interaction.js",
+ this
+);
+
+// Allow more time for Mac machines so they don't time out in verify mode.
+if (AppConstants.platform == "macosx") {
+ requestLongerTimeout(3);
+}
+
+add_setup(async function () {
+ await initInteractionTest();
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", false]],
+ });
+});
+
+add_task(async function persisted_search_terms() {
+ await doPersistedSearchTermsTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ { interaction: "typed" },
+ { interaction: "typed" },
+ ]),
+ });
+});
+
+add_task(async function persisted_search_terms_restarted_refined() {
+ await doPersistedSearchTermsRestartedRefinedTest({
+ enabled: false,
+ trigger: () => doEnter(),
+ assert: expected =>
+ assertEngagementTelemetry([
+ { interaction: "typed" },
+ { interaction: expected },
+ ]),
+ });
+});
+
+add_task(
+ async function persisted_search_terms_restarted_refined_via_abandonment() {
+ await doPersistedSearchTermsRestartedRefinedViaAbandonmentTest({
+ enabled: false,
+ trigger: () => doEnter(),
+ assert: expected =>
+ assertEngagementTelemetry([
+ { interaction: "typed" },
+ { interaction: expected },
+ ]),
+ });
+ }
+);
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction_persisted_search_terms_enabled.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction_persisted_search_terms_enabled.js
new file mode 100644
index 0000000000..33a01fdd22
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction_persisted_search_terms_enabled.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test engagement telemetry with persisted search terms enabled.
+
+// Allow more time for Mac machines so they don't time out in verify mode.
+if (AppConstants.platform == "macosx") {
+ requestLongerTimeout(3);
+}
+
+add_setup(async function () {
+ await initInteractionTest();
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.showSearchTerms.featureGate", true],
+ ["browser.urlbar.showSearchTerms.enabled", true],
+ ["browser.search.widget.inNavBar", false],
+ ],
+ });
+});
+
+add_task(async function persisted_search_terms() {
+ await doPersistedSearchTermsTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([
+ { interaction: "typed" },
+ { interaction: "persisted_search_terms" },
+ ]),
+ });
+});
+
+add_task(async function persisted_search_terms_restarted_refined() {
+ await doPersistedSearchTermsRestartedRefinedTest({
+ enabled: true,
+ trigger: () => doEnter(),
+ assert: expected =>
+ assertEngagementTelemetry([
+ { interaction: "typed" },
+ { interaction: expected },
+ ]),
+ });
+});
+
+add_task(
+ async function persisted_search_terms_restarted_refined_via_abandonment() {
+ await doPersistedSearchTermsRestartedRefinedViaAbandonmentTest({
+ enabled: true,
+ trigger: () => doEnter(),
+ assert: expected =>
+ assertEngagementTelemetry([
+ { interaction: "typed" },
+ { interaction: expected },
+ ]),
+ });
+ }
+);
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_n_chars_n_words.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_n_chars_n_words.js
new file mode 100644
index 0000000000..498ffd9532
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_n_chars_n_words.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of engagement telemetry.
+// - n_chars
+// - n_words
+
+add_setup(async function () {
+ await initNCharsAndNWordsTest();
+});
+
+add_task(async function n_chars() {
+ await doNCharsTest({
+ trigger: () => doEnter(),
+ assert: nChars => assertEngagementTelemetry([{ n_chars: nChars }]),
+ });
+
+ await doNCharsWithOverMaxTextLengthCharsTest({
+ trigger: () => doEnter(),
+ assert: nChars => assertEngagementTelemetry([{ n_chars: nChars }]),
+ });
+});
+
+add_task(async function n_words() {
+ await doNWordsTest({
+ trigger: () => doEnter(),
+ assert: nWords => assertEngagementTelemetry([{ n_words: nWords }]),
+ });
+
+ await doNWordsWithOverMaxTextLengthCharsTest({
+ trigger: () => doEnter(),
+ assert: nWords => assertEngagementTelemetry([{ n_words: nWords }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_sap.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_sap.js
new file mode 100644
index 0000000000..d361d70229
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_sap.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of engagement telemetry.
+// - sap
+
+add_setup(async function () {
+ await initSapTest();
+});
+
+add_task(async function urlbar() {
+ await doUrlbarTest({
+ trigger: () => doEnter(),
+ assert: () =>
+ assertEngagementTelemetry([{ sap: "urlbar_newtab" }, { sap: "urlbar" }]),
+ });
+});
+
+add_task(async function handoff() {
+ await doHandoffTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ sap: "handoff" }]),
+ });
+});
+
+add_task(async function urlbar_addonpage() {
+ await doUrlbarAddonpageTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ sap: "urlbar_addonpage" }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_search_engine_default_id.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_search_engine_default_id.js
new file mode 100644
index 0000000000..60331ff53b
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_search_engine_default_id.js
@@ -0,0 +1,19 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of engagement telemetry.
+// - search_engine_default_id
+
+add_setup(async function () {
+ await initSearchEngineDefaultIdTest();
+});
+
+add_task(async function basic() {
+ await doSearchEngineDefaultIdTest({
+ trigger: () => doEnter(),
+ assert: engineId =>
+ assertEngagementTelemetry([{ search_engine_default_id: engineId }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_search_mode.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_search_mode.js
new file mode 100644
index 0000000000..013bef1904
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_search_mode.js
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of engagement telemetry.
+// - search_mode
+
+add_setup(async function () {
+ await initSearchModeTest();
+});
+
+add_task(async function not_search_mode() {
+ await doNotSearchModeTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ search_mode: "" }]),
+ });
+});
+
+add_task(async function search_engine() {
+ await doSearchEngineTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ search_mode: "search_engine" }]),
+ });
+});
+
+add_task(async function bookmarks() {
+ await doBookmarksTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ search_mode: "bookmarks" }]),
+ });
+});
+
+add_task(async function history() {
+ await doHistoryTest({
+ trigger: () => doEnter(),
+ assert: () => assertEngagementTelemetry([{ search_mode: "history" }]),
+ });
+});
+
+add_task(async function tabs() {
+ await doTabTest({
+ trigger: async () => {
+ const currentTab = gBrowser.selectedTab;
+ EventUtils.synthesizeKey("KEY_Enter");
+ await BrowserTestUtils.waitForCondition(
+ () => gBrowser.selectedTab !== currentTab
+ );
+ },
+ assert: () => assertEngagementTelemetry([{ search_mode: "tabs" }]),
+ });
+});
+
+add_task(async function actions() {
+ await doActionsTest({
+ trigger: async () => {
+ const onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ doClickSubButton(".urlbarView-quickaction-button[data-key=addons]");
+ await onLoad;
+ },
+ assert: () => assertEngagementTelemetry([{ search_mode: "actions" }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_selected_result.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_selected_result.js
new file mode 100644
index 0000000000..6a3422d939
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_selected_result.js
@@ -0,0 +1,974 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of engagement telemetry.
+// - selected_result
+// - selected_result_subtype
+// - selected_position
+// - provider
+// - results
+
+ChromeUtils.defineESModuleGetters(this, {
+ UrlbarProviderClipboard:
+ "resource:///modules/UrlbarProviderClipboard.sys.mjs",
+});
+
+// This test has many subtests and can time out in verify mode.
+requestLongerTimeout(5);
+
+add_setup(async function () {
+ await setup();
+});
+
+add_task(async function selected_result_autofill_about() {
+ await doTest(async browser => {
+ await openPopup("about:about");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "autofill_about",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "Autofill",
+ results: "autofill_about",
+ },
+ ]);
+ });
+});
+
+add_task(async function selected_result_autofill_adaptive() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.autoFill.adaptiveHistory.enabled", true]],
+ });
+
+ await doTest(async browser => {
+ await PlacesTestUtils.addVisits("https://example.com/test");
+ await UrlbarUtils.addToInputHistory("https://example.com/test", "exa");
+ await openPopup("exa");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "autofill_adaptive",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "Autofill",
+ results: "autofill_adaptive",
+ },
+ ]);
+ });
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_autofill_origin() {
+ await doTest(async browser => {
+ await PlacesTestUtils.addVisits("https://example.com/test");
+ await PlacesFrecencyRecalculator.recalculateAnyOutdatedFrecencies();
+ await openPopup("exa");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "autofill_origin",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "Autofill",
+ results: "autofill_origin,history",
+ },
+ ]);
+ });
+});
+
+add_task(async function selected_result_autofill_url() {
+ await doTest(async browser => {
+ await PlacesTestUtils.addVisits("https://example.com/test");
+ await PlacesFrecencyRecalculator.recalculateAnyOutdatedFrecencies();
+ await openPopup("https://example.com/test");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "autofill_url",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "Autofill",
+ results: "autofill_url",
+ },
+ ]);
+ });
+});
+
+add_task(async function selected_result_bookmark() {
+ await doTest(async browser => {
+ await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: "https://example.com/bookmark",
+ title: "bookmark",
+ });
+
+ await openPopup("bookmark");
+ await selectRowByURL("https://example.com/bookmark");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "bookmark",
+ selected_result_subtype: "",
+ selected_position: 3,
+ provider: "Places",
+ results: "search_engine,action,bookmark",
+ },
+ ]);
+ });
+});
+
+add_task(async function selected_result_history() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.autoFill", false]],
+ });
+
+ await doTest(async browser => {
+ await PlacesTestUtils.addVisits("https://example.com/test");
+
+ await openPopup("example");
+ await selectRowByURL("https://example.com/test");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "history",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "Places",
+ results: "search_engine,history",
+ },
+ ]);
+ });
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_keyword() {
+ await doTest(async browser => {
+ await PlacesUtils.keywords.insert({
+ keyword: "keyword",
+ url: "https://example.com/?q=%s",
+ });
+
+ await openPopup("keyword test");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "keyword",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "BookmarkKeywords",
+ results: "keyword",
+ },
+ ]);
+
+ await PlacesUtils.keywords.remove("keyword");
+ });
+});
+
+add_task(async function selected_result_search_engine() {
+ await doTest(async browser => {
+ await openPopup("x");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "search_engine",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "HeuristicFallback",
+ results: "search_engine",
+ },
+ ]);
+ });
+});
+
+add_task(async function selected_result_search_suggest() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.suggest.searches", true],
+ ["browser.urlbar.maxHistoricalSearchSuggestions", 2],
+ ],
+ });
+
+ await doTest(async browser => {
+ await openPopup("foo");
+ await selectRowByURL("http://mochi.test:8888/?terms=foofoo");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "search_suggest",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "SearchSuggestions",
+ results: "search_engine,search_suggest,search_suggest",
+ },
+ ]);
+ });
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_search_history() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.suggest.searches", true],
+ ["browser.urlbar.maxHistoricalSearchSuggestions", 2],
+ ],
+ });
+
+ await doTest(async browser => {
+ await UrlbarTestUtils.formHistory.add(["foofoo", "foobar"]);
+
+ await openPopup("foo");
+ await selectRowByURL("http://mochi.test:8888/?terms=foofoo");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "search_history",
+ selected_result_subtype: "",
+ selected_position: 3,
+ provider: "SearchSuggestions",
+ results: "search_engine,search_history,search_history",
+ },
+ ]);
+ });
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_url() {
+ await doTest(async browser => {
+ await openPopup("https://example.com/");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "url",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "HeuristicFallback",
+ results: "url",
+ },
+ ]);
+ });
+});
+
+add_task(async function selected_result_action() {
+ await doTest(async browser => {
+ await showResultByArrowDown();
+ await selectRowByProvider("quickactions");
+ const onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ doClickSubButton(".urlbarView-quickaction-button[data-key=addons]");
+ await onLoad;
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "action",
+ selected_result_subtype: "addons",
+ selected_position: 1,
+ provider: "quickactions",
+ results: "action",
+ },
+ ]);
+ });
+});
+
+add_task(async function selected_result_tab() {
+ const tab = BrowserTestUtils.addTab(gBrowser, "https://example.com/");
+
+ await doTest(async browser => {
+ await openPopup("example");
+ await selectRowByProvider("Places");
+ EventUtils.synthesizeKey("KEY_Enter");
+ await BrowserTestUtils.waitForCondition(() => gBrowser.selectedTab === tab);
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "tab",
+ selected_result_subtype: "",
+ selected_position: 4,
+ provider: "Places",
+ results: "search_engine,search_suggest,search_suggest,tab",
+ },
+ ]);
+ });
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function selected_result_remote_tab() {
+ const remoteTab = await loadRemoteTab("https://example.com");
+
+ await doTest(async browser => {
+ await openPopup("example");
+ await selectRowByProvider("RemoteTabs");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "remote_tab",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "RemoteTabs",
+ results: "search_engine,remote_tab",
+ },
+ ]);
+ });
+
+ await remoteTab.unload();
+});
+
+add_task(async function selected_result_addon() {
+ const addon = loadOmniboxAddon({ keyword: "omni" });
+ await addon.startup();
+
+ await doTest(async browser => {
+ await openPopup("omni test");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "addon",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "Omnibox",
+ results: "addon",
+ },
+ ]);
+ });
+
+ await addon.unload();
+});
+
+add_task(async function selected_result_tab_to_search() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.tabToSearch.onboard.interactionsLeft", 0]],
+ });
+
+ await SearchTestUtils.installSearchExtension({
+ name: "mozengine",
+ search_url: "https://mozengine/",
+ });
+
+ await doTest(async browser => {
+ for (let i = 0; i < 3; i++) {
+ await PlacesTestUtils.addVisits(["https://mozengine/"]);
+ }
+
+ await openPopup("moze");
+ await selectRowByProvider("TabToSearch");
+ const onComplete = UrlbarTestUtils.promiseSearchComplete(window);
+ EventUtils.synthesizeKey("KEY_Enter");
+ await onComplete;
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "tab_to_search",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "TabToSearch",
+ results: "search_engine,tab_to_search,history",
+ },
+ ]);
+ });
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_top_site() {
+ await doTest(async browser => {
+ await addTopSites("https://example.com/");
+ await showResultByArrowDown();
+ await selectRowByURL("https://example.com/");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "top_site",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "UrlbarProviderTopSites",
+ results: "top_site,action",
+ },
+ ]);
+ });
+});
+
+add_task(async function selected_result_calc() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.suggest.calculator", true]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("8*8");
+ await selectRowByProvider("calculator");
+ await SimpleTest.promiseClipboardChange("64", () => {
+ EventUtils.synthesizeKey("KEY_Enter");
+ });
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "calc",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "calculator",
+ results: "search_engine,calc",
+ },
+ ]);
+ });
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_clipboard() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.clipboard.featureGate", true],
+ ["browser.urlbar.suggest.clipboard", true],
+ ],
+ });
+ SpecialPowers.clipboardCopyString(
+ "https://example.com/selected_result_clipboard"
+ );
+
+ await doTest(async browser => {
+ await openPopup("");
+ await selectRowByProvider("UrlbarProviderClipboard");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "clipboard",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "UrlbarProviderClipboard",
+ results: "clipboard,action",
+ },
+ ]);
+ });
+
+ SpecialPowers.clipboardCopyString("");
+ UrlbarProviderClipboard.setPreviousClipboardValue("");
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_unit() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.unitConversion.enabled", true]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("1m to cm");
+ await selectRowByProvider("UnitConversion");
+ await SimpleTest.promiseClipboardChange("100 cm", () => {
+ EventUtils.synthesizeKey("KEY_Enter");
+ });
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "unit",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "UnitConversion",
+ results: "search_engine,unit",
+ },
+ ]);
+ });
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_site_specific_contextual_search() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.contextualSearch.enabled", true]],
+ });
+
+ await doTest(async browser => {
+ const extension = await SearchTestUtils.installSearchExtension(
+ {
+ name: "Contextual",
+ search_url: "https://example.com/browser",
+ },
+ { skipUnload: true }
+ );
+ const onLoaded = BrowserTestUtils.browserLoaded(
+ gBrowser.selectedBrowser,
+ false,
+ "https://example.com/"
+ );
+ BrowserTestUtils.startLoadingURIString(
+ gBrowser.selectedBrowser,
+ "https://example.com/"
+ );
+ await onLoaded;
+
+ await openPopup("search");
+ await selectRowByProvider("UrlbarProviderContextualSearch");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "site_specific_contextual_search",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "UrlbarProviderContextualSearch",
+ results: "search_engine,site_specific_contextual_search",
+ },
+ ]);
+
+ await extension.unload();
+ });
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_rs_adm_sponsored() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit({
+ prefs: [["quicksuggest.rustEnabled", false]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("sponsored");
+ await selectRowByURL("https://example.com/sponsored");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "rs_adm_sponsored",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,rs_adm_sponsored",
+ },
+ ]);
+ });
+
+ await cleanupQuickSuggest();
+});
+
+add_task(async function selected_result_rs_adm_nonsponsored() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit({
+ prefs: [["quicksuggest.rustEnabled", false]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("nonsponsored");
+ await selectRowByURL("https://example.com/nonsponsored");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "rs_adm_nonsponsored",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,rs_adm_nonsponsored",
+ },
+ ]);
+ });
+
+ await cleanupQuickSuggest();
+});
+
+add_task(async function selected_result_input_field() {
+ const expected = [
+ {
+ selected_result: "input_field",
+ selected_result_subtype: "",
+ selected_position: 0,
+ provider: null,
+ results: "",
+ },
+ ];
+
+ await doTest(async browser => {
+ await doDropAndGo("example.com");
+
+ assertEngagementTelemetry(expected);
+ });
+
+ await doTest(async browser => {
+ await doPasteAndGo("example.com");
+
+ assertEngagementTelemetry(expected);
+ });
+});
+
+add_task(async function selected_result_weather() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.quickactions.enabled", false]],
+ });
+
+ const cleanupQuickSuggest = await ensureQuickSuggestInit();
+ await MerinoTestUtils.initWeather();
+
+ let provider = UrlbarPrefs.get("quickSuggestRustEnabled")
+ ? "UrlbarProviderQuickSuggest"
+ : "Weather";
+ await doTest(async browser => {
+ await openPopup(MerinoTestUtils.WEATHER_KEYWORD);
+ await selectRowByProvider(provider);
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "weather",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider,
+ results: "search_engine,weather",
+ },
+ ]);
+ });
+
+ await cleanupQuickSuggest();
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_navigational() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit({
+ merinoSuggestions: [
+ {
+ title: "Navigational suggestion",
+ url: "https://example.com/navigational-suggestion",
+ provider: "top_picks",
+ is_sponsored: false,
+ score: 0.25,
+ block_id: 0,
+ is_top_pick: true,
+ },
+ ],
+ });
+
+ await doTest(async browser => {
+ await openPopup("only match the Merino suggestion");
+ await selectRowByProvider("UrlbarProviderQuickSuggest");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "merino_top_picks",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,merino_top_picks",
+ },
+ ]);
+ });
+
+ await cleanupQuickSuggest();
+});
+
+add_task(async function selected_result_dynamic_wikipedia() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit({
+ merinoSuggestions: [
+ {
+ block_id: 1,
+ url: "https://example.com/dynamic-wikipedia",
+ title: "Dynamic Wikipedia suggestion",
+ click_url: "https://example.com/click",
+ impression_url: "https://example.com/impression",
+ advertiser: "dynamic-wikipedia",
+ provider: "wikipedia",
+ iab_category: "5 - Education",
+ },
+ ],
+ });
+
+ await doTest(async browser => {
+ await openPopup("only match the Merino suggestion");
+ await selectRowByProvider("UrlbarProviderQuickSuggest");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "merino_wikipedia",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,merino_wikipedia",
+ },
+ ]);
+ });
+
+ await cleanupQuickSuggest();
+});
+
+add_task(async function selected_result_search_shortcut_button() {
+ await doTest(async browser => {
+ const oneOffSearchButtons = UrlbarTestUtils.getOneOffSearchButtons(window);
+ await openPopup("x");
+ Assert.ok(!oneOffSearchButtons.selectedButton);
+
+ // Select oneoff button added for test in setup().
+ for (;;) {
+ EventUtils.synthesizeKey("KEY_ArrowDown");
+ if (!oneOffSearchButtons.selectedButton) {
+ continue;
+ }
+
+ if (
+ oneOffSearchButtons.selectedButton.engine.name.includes(
+ "searchSuggestionEngine.xml"
+ )
+ ) {
+ break;
+ }
+ }
+
+ // Search immediately.
+ await doEnter({ shiftKey: true });
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "search_shortcut_button",
+ selected_result_subtype: "",
+ selected_position: 0,
+ provider: null,
+ results: "search_engine",
+ },
+ ]);
+ });
+});
+
+add_task(async function selected_result_trending() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.suggest.searches", true],
+ ["browser.urlbar.trending.featureGate", true],
+ ["browser.urlbar.trending.requireSearchMode", false],
+ ["browser.urlbar.trending.maxResultsNoSearchMode", 1],
+ ["browser.urlbar.weather.featureGate", false],
+ ],
+ });
+
+ let defaultEngine = await Services.search.getDefault();
+ let extension = await SearchTestUtils.installSearchExtension(
+ {
+ name: "mozengine",
+ search_url: "https://example.org/",
+ },
+ { setAsDefault: true, skipUnload: true }
+ );
+
+ SearchTestUtils.useMockIdleService();
+ await SearchTestUtils.updateRemoteSettingsConfig([
+ {
+ webExtension: { id: "mozengine@tests.mozilla.org" },
+ urls: {
+ trending: {
+ fullPath:
+ "https://example.com/browser/browser/components/search/test/browser/trendingSuggestionEngine.sjs",
+ query: "",
+ },
+ },
+ appliesTo: [{ included: { everywhere: true } }],
+ default: "yes",
+ },
+ ]);
+
+ await doTest(async browser => {
+ await openPopup("");
+ await selectRowByProvider("SearchSuggestions");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "trending_search",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "SearchSuggestions",
+ results: "trending_search",
+ },
+ ]);
+ });
+
+ await extension.unload();
+ await Services.search.setDefault(
+ defaultEngine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ let settingsWritten = SearchTestUtils.promiseSearchNotification(
+ "write-settings-to-disk-complete"
+ );
+ await SearchTestUtils.updateRemoteSettingsConfig();
+ await settingsWritten;
+ await PlacesUtils.history.clear();
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_trending_rich() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.richSuggestions.featureGate", true],
+ ["browser.urlbar.suggest.searches", true],
+ ["browser.urlbar.trending.featureGate", true],
+ ["browser.urlbar.trending.requireSearchMode", false],
+ ["browser.urlbar.trending.maxResultsNoSearchMode", 1],
+ ["browser.urlbar.weather.featureGate", false],
+ ],
+ });
+
+ let defaultEngine = await Services.search.getDefault();
+ let extension = await SearchTestUtils.installSearchExtension(
+ {
+ name: "mozengine",
+ search_url: "https://example.org/",
+ },
+ { setAsDefault: true, skipUnload: true }
+ );
+
+ SearchTestUtils.useMockIdleService();
+ await SearchTestUtils.updateRemoteSettingsConfig([
+ {
+ webExtension: { id: "mozengine@tests.mozilla.org" },
+ urls: {
+ trending: {
+ fullPath:
+ "https://example.com/browser/browser/components/search/test/browser/trendingSuggestionEngine.sjs?richsuggestions=true",
+ query: "",
+ },
+ },
+ appliesTo: [{ included: { everywhere: true } }],
+ default: "yes",
+ },
+ ]);
+
+ await doTest(async browser => {
+ await openPopup("");
+ await selectRowByProvider("SearchSuggestions");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "trending_search_rich",
+ selected_result_subtype: "",
+ selected_position: 1,
+ provider: "SearchSuggestions",
+ results: "trending_search_rich",
+ },
+ ]);
+ });
+
+ await extension.unload();
+ await Services.search.setDefault(
+ defaultEngine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ let settingsWritten = SearchTestUtils.promiseSearchNotification(
+ "write-settings-to-disk-complete"
+ );
+ await SearchTestUtils.updateRemoteSettingsConfig();
+ await settingsWritten;
+ await PlacesUtils.history.clear();
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_addons() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.addons.featureGate", true],
+ ["browser.urlbar.suggest.searches", false],
+ ],
+ });
+
+ const cleanupQuickSuggest = await ensureQuickSuggestInit({
+ merinoSuggestions: [
+ {
+ provider: "amo",
+ icon: "https://example.com/good-addon.svg",
+ url: "https://example.com/good-addon",
+ title: "Good Addon",
+ description: "This is a good addon",
+ custom_details: {
+ amo: {
+ rating: "4.8",
+ number_of_ratings: "1234567",
+ guid: "good@addon",
+ },
+ },
+ is_top_pick: true,
+ },
+ ],
+ });
+
+ await doTest(async browser => {
+ await openPopup("only match the Merino suggestion");
+ await selectRowByProvider("UrlbarProviderQuickSuggest");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "merino_amo",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,merino_amo",
+ },
+ ]);
+ });
+
+ await cleanupQuickSuggest();
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_rust_adm_sponsored() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit({
+ prefs: [["quicksuggest.rustEnabled", true]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("sponsored");
+ await selectRowByURL("https://example.com/sponsored");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "rust_adm_sponsored",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,rust_adm_sponsored",
+ },
+ ]);
+ });
+
+ await cleanupQuickSuggest();
+});
+
+add_task(async function selected_result_rust_adm_nonsponsored() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit({
+ prefs: [["quicksuggest.rustEnabled", true]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("nonsponsored");
+ await selectRowByURL("https://example.com/nonsponsored");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "rust_adm_nonsponsored",
+ selected_result_subtype: "",
+ selected_position: 2,
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,rust_adm_nonsponsored",
+ },
+ ]);
+ });
+
+ await cleanupQuickSuggest();
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_tips.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_tips.js
new file mode 100644
index 0000000000..2b38631747
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_tips.js
@@ -0,0 +1,173 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for engagement telemetry for tips using Glean.
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/browser-tips/head.js",
+ this
+);
+
+add_setup(async function () {
+ makeProfileResettable();
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.quickactions.enabled", false]],
+ });
+
+ registerCleanupFunction(async function () {
+ await SpecialPowers.popPrefEnv();
+ });
+});
+
+add_task(async function selected_result_tip() {
+ const testData = [
+ {
+ type: "searchTip_onboard",
+ expected: "tip_onboard",
+ },
+ {
+ type: "searchTip_persist",
+ expected: "tip_persist",
+ },
+ {
+ type: "searchTip_redirect",
+ expected: "tip_redirect",
+ },
+ {
+ type: "test",
+ expected: "tip_unknown",
+ },
+ ];
+
+ for (const { type, expected } of testData) {
+ const deferred = Promise.withResolvers();
+ const provider = new UrlbarTestUtils.TestProvider({
+ results: [
+ new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.TIP,
+ UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
+ {
+ type,
+ helpUrl: "https://example.com/",
+ titleL10n: { id: "urlbar-search-tips-confirm" },
+ buttons: [
+ {
+ url: "https://example.com/",
+ l10n: { id: "urlbar-search-tips-confirm" },
+ },
+ ],
+ }
+ ),
+ ],
+ priority: 1,
+ onEngagement: () => {
+ deferred.resolve();
+ },
+ });
+ UrlbarProvidersManager.registerProvider(provider);
+
+ await doTest(async browser => {
+ await openPopup("example");
+ await selectRowByType(type);
+ EventUtils.synthesizeKey("VK_RETURN");
+ await deferred.promise;
+
+ assertEngagementTelemetry([
+ {
+ selected_result: expected,
+ results: expected,
+ },
+ ]);
+ });
+
+ UrlbarProvidersManager.unregisterProvider(provider);
+ }
+});
+
+add_task(async function selected_result_intervention_clear() {
+ let useOldClearHistoryDialog = Services.prefs.getBoolPref(
+ "privacy.sanitize.useOldClearHistoryDialog"
+ );
+ let dialogURL = useOldClearHistoryDialog
+ ? "chrome://browser/content/sanitize.xhtml"
+ : "chrome://browser/content/sanitize_v2.xhtml";
+ await doInterventionTest(
+ SEARCH_STRINGS.CLEAR,
+ "intervention_clear",
+ dialogURL,
+ [
+ {
+ selected_result: "intervention_clear",
+ results: "search_engine,intervention_clear",
+ },
+ ]
+ );
+});
+
+add_task(async function selected_result_intervention_refresh() {
+ await doInterventionTest(
+ SEARCH_STRINGS.REFRESH,
+ "intervention_refresh",
+ "chrome://global/content/resetProfile.xhtml",
+ [
+ {
+ selected_result: "intervention_refresh",
+ results: "search_engine,intervention_refresh",
+ },
+ ]
+ );
+});
+
+add_task(async function selected_result_intervention_update() {
+ // Updates are disabled for MSIX packages, this test is irrelevant for them.
+ if (
+ AppConstants.platform === "win" &&
+ Services.sysinfo.getProperty("hasWinPackageId")
+ ) {
+ return;
+ }
+ await UpdateUtils.setAppUpdateAutoEnabled(false);
+ await initUpdate({ queryString: "&noUpdates=1" });
+ UrlbarProviderInterventions.checkForBrowserUpdate(true);
+ await processUpdateSteps([
+ {
+ panelId: "checkingForUpdates",
+ checkActiveUpdate: null,
+ continueFile: CONTINUE_CHECK,
+ },
+ {
+ panelId: "noUpdatesFound",
+ checkActiveUpdate: null,
+ continueFile: null,
+ },
+ ]);
+
+ await doInterventionTest(
+ SEARCH_STRINGS.UPDATE,
+ "intervention_update_refresh",
+ "chrome://global/content/resetProfile.xhtml",
+ [
+ {
+ selected_result: "intervention_update",
+ results: "search_engine,intervention_update",
+ },
+ ]
+ );
+});
+
+async function doInterventionTest(keyword, type, dialog, expectedTelemetry) {
+ await doTest(async browser => {
+ await openPopup(keyword);
+ await selectRowByType(type);
+ const onDialog = BrowserTestUtils.promiseAlertDialog("cancel", dialog, {
+ isSubDialog: true,
+ });
+ EventUtils.synthesizeKey("VK_RETURN");
+ await onDialog;
+
+ assertEngagementTelemetry(expectedTelemetry);
+ });
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_type.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_type.js
new file mode 100644
index 0000000000..5972dd331d
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_type.js
@@ -0,0 +1,118 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of engagement telemetry.
+// - engagement_type
+
+// This test has many subtests and can time out in verify mode.
+requestLongerTimeout(5);
+
+add_setup(async function () {
+ await setup();
+});
+
+add_task(async function engagement_type_click() {
+ await doTest(async browser => {
+ await openPopup("x");
+ await doClick();
+
+ assertEngagementTelemetry([{ engagement_type: "click" }]);
+ });
+});
+
+add_task(async function engagement_type_enter() {
+ await doTest(async browser => {
+ await openPopup("x");
+ await doEnter();
+
+ assertEngagementTelemetry([{ engagement_type: "enter" }]);
+ });
+});
+
+add_task(async function engagement_type_go_button() {
+ await doTest(async browser => {
+ await openPopup("x");
+ EventUtils.synthesizeMouseAtCenter(gURLBar.goButton, {});
+
+ assertEngagementTelemetry([{ engagement_type: "go_button" }]);
+ });
+});
+
+add_task(async function engagement_type_drop_go() {
+ await doTest(async browser => {
+ await doDropAndGo("example.com");
+
+ assertEngagementTelemetry([{ engagement_type: "drop_go" }]);
+ });
+});
+
+add_task(async function engagement_type_paste_go() {
+ await doTest(async browser => {
+ await doPasteAndGo("www.example.com");
+
+ assertEngagementTelemetry([{ engagement_type: "paste_go" }]);
+ });
+});
+
+add_task(async function engagement_type_dismiss() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit();
+
+ await doTest(async browser => {
+ await openPopup("sponsored");
+
+ const originalResultCount = UrlbarTestUtils.getResultCount(window);
+ await selectRowByURL("https://example.com/sponsored");
+ UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "D");
+ await BrowserTestUtils.waitForCondition(
+ () => originalResultCount != UrlbarTestUtils.getResultCount(window)
+ );
+
+ assertEngagementTelemetry([{ engagement_type: "dismiss" }]);
+
+ // The view should stay open after dismissing the result. Now pick the
+ // heuristic result. Another "click" engagement event should be recorded.
+ Assert.ok(
+ gURLBar.view.isOpen,
+ "View should remain open after dismissing result"
+ );
+ await doClick();
+ assertEngagementTelemetry([
+ { engagement_type: "dismiss" },
+ { engagement_type: "click", interaction: "typed" },
+ ]);
+ });
+
+ await doTest(async browser => {
+ await openPopup("sponsored");
+
+ const originalResultCount = UrlbarTestUtils.getResultCount(window);
+ await selectRowByURL("https://example.com/sponsored");
+ EventUtils.synthesizeKey("KEY_Delete", { shiftKey: true });
+ await BrowserTestUtils.waitForCondition(
+ () => originalResultCount != UrlbarTestUtils.getResultCount(window)
+ );
+
+ assertEngagementTelemetry([{ engagement_type: "dismiss" }]);
+ });
+
+ await cleanupQuickSuggest();
+});
+
+add_task(async function engagement_type_help() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit();
+
+ await doTest(async browser => {
+ await openPopup("sponsored");
+ await selectRowByURL("https://example.com/sponsored");
+ const onTabOpened = BrowserTestUtils.waitForNewTab(gBrowser);
+ UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "L");
+ const tab = await onTabOpened;
+ BrowserTestUtils.removeTab(tab);
+
+ assertEngagementTelemetry([{ engagement_type: "help" }]);
+ });
+
+ await cleanupQuickSuggest();
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_exposure.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_exposure.js
new file mode 100644
index 0000000000..07e8b9b360
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_exposure.js
@@ -0,0 +1,136 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const SPONSORED_QUERY = "sponsored";
+const NONSPONSORED_QUERY = "nonsponsored";
+
+// test for exposure events
+add_setup(async function () {
+ await initExposureTest();
+});
+
+add_task(async function exposureSponsoredOnEngagement() {
+ await doExposureTest({
+ prefs: [
+ ["browser.urlbar.exposureResults", suggestResultType("adm_sponsored")],
+ ["browser.urlbar.showExposureResults", true],
+ ],
+ query: SPONSORED_QUERY,
+ trigger: () => doClick(),
+ assert: () =>
+ assertExposureTelemetry([
+ { results: suggestResultType("adm_sponsored") },
+ ]),
+ });
+});
+
+add_task(async function exposureSponsoredOnAbandonment() {
+ await doExposureTest({
+ prefs: [
+ ["browser.urlbar.exposureResults", suggestResultType("adm_sponsored")],
+ ["browser.urlbar.showExposureResults", true],
+ ],
+ query: SPONSORED_QUERY,
+ trigger: () => doBlur(),
+ assert: () =>
+ assertExposureTelemetry([
+ { results: suggestResultType("adm_sponsored") },
+ ]),
+ });
+});
+
+add_task(async function exposureFilter() {
+ await doExposureTest({
+ prefs: [
+ ["browser.urlbar.exposureResults", suggestResultType("adm_sponsored")],
+ ["browser.urlbar.showExposureResults", false],
+ ],
+ query: SPONSORED_QUERY,
+ select: async () => {
+ // assert that the urlbar has no results
+ Assert.equal(
+ await getResultByType(suggestResultType("adm_sponsored")),
+ null
+ );
+ },
+ trigger: () => doBlur(),
+ assert: () =>
+ assertExposureTelemetry([
+ { results: suggestResultType("adm_sponsored") },
+ ]),
+ });
+});
+
+add_task(async function innerQueryExposure() {
+ await doExposureTest({
+ prefs: [
+ ["browser.urlbar.exposureResults", suggestResultType("adm_sponsored")],
+ ["browser.urlbar.showExposureResults", true],
+ ],
+ query: NONSPONSORED_QUERY,
+ select: () => {},
+ trigger: async () => {
+ // delete the old query
+ gURLBar.select();
+ EventUtils.synthesizeKey("KEY_Backspace");
+ await openPopup(SPONSORED_QUERY);
+ await defaultSelect(SPONSORED_QUERY);
+ await doClick();
+ },
+ assert: () =>
+ assertExposureTelemetry([
+ { results: suggestResultType("adm_sponsored") },
+ ]),
+ });
+});
+
+add_task(async function innerQueryInvertedExposure() {
+ await doExposureTest({
+ prefs: [
+ ["browser.urlbar.exposureResults", suggestResultType("adm_sponsored")],
+ ["browser.urlbar.showExposureResults", true],
+ ],
+ query: SPONSORED_QUERY,
+ select: () => {},
+ trigger: async () => {
+ // delete the old query
+ gURLBar.select();
+ EventUtils.synthesizeKey("KEY_Backspace");
+ await openPopup(NONSPONSORED_QUERY);
+ await defaultSelect(SPONSORED_QUERY);
+ await doClick();
+ },
+ assert: () =>
+ assertExposureTelemetry([
+ { results: suggestResultType("adm_sponsored") },
+ ]),
+ });
+});
+
+add_task(async function multipleProviders() {
+ await doExposureTest({
+ prefs: [
+ [
+ "browser.urlbar.exposureResults",
+ [
+ suggestResultType("adm_sponsored"),
+ suggestResultType("adm_nonsponsored"),
+ ].join(","),
+ ],
+ ["browser.urlbar.showExposureResults", true],
+ ],
+ query: NONSPONSORED_QUERY,
+ trigger: () => doClick(),
+ assert: () =>
+ assertExposureTelemetry([
+ { results: suggestResultType("adm_nonsponsored") },
+ ]),
+ });
+});
+
+function suggestResultType(typeWithoutSource) {
+ let source = UrlbarPrefs.get("quickSuggestRustEnabled") ? "rust" : "rs";
+ return `${source}_${typeWithoutSource}`;
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_exposure_edge_cases.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_exposure_edge_cases.js
new file mode 100644
index 0000000000..d28352b417
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_exposure_edge_cases.js
@@ -0,0 +1,539 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests edge cases related to the exposure event and view updates.
+
+"use strict";
+
+ChromeUtils.defineESModuleGetters(this, {
+ UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.sys.mjs",
+ UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs",
+ UrlbarUtils: "resource:///modules/UrlbarUtils.sys.mjs",
+ UrlbarView: "resource:///modules/UrlbarView.sys.mjs",
+});
+
+const MAX_RESULT_COUNT = 10;
+
+let gProvider;
+
+add_setup(async function () {
+ await initExposureTest();
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ // Make absolutely sure the panel stays open during the test. There are
+ // spurious blurs on WebRender TV tests as the test starts that cause the
+ // panel to close and the query to be canceled, resulting in intermittent
+ // failures without this.
+ ["ui.popup.disable_autohide", true],
+
+ // Set maxRichResults for sanity.
+ ["browser.urlbar.maxRichResults", MAX_RESULT_COUNT],
+ ],
+ });
+
+ await Services.fog.testFlushAllChildren();
+ Services.fog.testResetFOG();
+
+ gProvider = new TestProvider();
+ UrlbarProvidersManager.registerProvider(gProvider);
+
+ // Increase the timeout of the stale-rows timer so it doesn't interfere with
+ // this test, which specifically tests what happens before the timer fires.
+ let originalRemoveStaleRowsTimeout = UrlbarView.removeStaleRowsTimeout;
+ UrlbarView.removeStaleRowsTimeout = 30000;
+
+ registerCleanupFunction(() => {
+ UrlbarView.removeStaleRowsTimeout = originalRemoveStaleRowsTimeout;
+ UrlbarProvidersManager.unregisterProvider(gProvider);
+ });
+});
+
+// Does one query that fills up the view with search suggestions, starts a
+// second query that returns a history result, and cancels it before it can
+// finish but after the view is updated. Regardless of `showExposureResults`,
+// the history result should not trigger an exposure since it never had a chance
+// to be visible in the view.
+add_task(async function noExposure() {
+ for (let showExposureResults of [true, false]) {
+ await do_noExposure(showExposureResults);
+ }
+});
+
+async function do_noExposure(showExposureResults) {
+ info("Starting do_noExposure: " + JSON.stringify({ showExposureResults }));
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.exposureResults", "history"],
+ ["browser.urlbar.showExposureResults", showExposureResults],
+ ],
+ });
+
+ // Make the provider return enough search suggestions to fill the view.
+ gProvider.results = [];
+ for (let i = 0; i < MAX_RESULT_COUNT; i++) {
+ gProvider.results.push(
+ new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.SEARCH,
+ UrlbarUtils.RESULT_SOURCE.SEARCH,
+ {
+ suggestion: "suggestion " + i,
+ engine: Services.search.defaultEngine.name,
+ }
+ )
+ );
+ }
+
+ // Do the first query to fill the view with search suggestions.
+ info("Doing first query");
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "test 1",
+ });
+
+ // Now make the provider return a history result and bookmark. If
+ // `showExposureResults` is true, the history result will be added to the view
+ // but it should be hidden since the view is already full. If it's false, it
+ // shouldn't be added at all. The bookmark will always be added, which will
+ // tell us when the view has been updated either way. (It also will be hidden
+ // since the view is already full.)
+ let historyUrl = "https://example.com/history";
+ let bookmarkUrl = "https://example.com/bookmark";
+ gProvider.results = [
+ new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.URL,
+ UrlbarUtils.RESULT_SOURCE.HISTORY,
+ { url: historyUrl }
+ ),
+ new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.URL,
+ UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
+ { url: bookmarkUrl }
+ ),
+ ];
+
+ // When the provider's `startQuery()` is called, let it add its results but
+ // don't let it return. That will cause the view to be updated with the new
+ // results but prevent it from showing hidden rows since the query won't
+ // finish.
+ let queryResolver = Promise.withResolvers();
+ gProvider.finishQueryPromise = queryResolver.promise;
+
+ // Observe when the view appends the bookmark row. This will tell us when the
+ // view has been updated with the provider's new results. The bookmark row
+ // will be hidden since the view is already full with search suggestions.
+ let lastRowPromise = promiseLastRowAppended(
+ row => row.result.payload.url == bookmarkUrl
+ );
+
+ // Now start the second query but don't await it.
+ info("Starting second query");
+ let queryPromise = UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "test 2",
+ reopenOnBlur: false,
+ });
+
+ // Wait for the view to be updated.
+ info("Waiting for last row");
+ let lastRow = await lastRowPromise;
+ info("Done waiting for last row");
+
+ Assert.ok(
+ BrowserTestUtils.isHidden(lastRow),
+ "The new bookmark row should be hidden since the view is full"
+ );
+
+ // Make sure the view is full of visible rows as expected, plus the one or two
+ // hidden rows for the history and/or bookmark results.
+ let rows = UrlbarTestUtils.getResultsContainer(window);
+ let expectedCount = MAX_RESULT_COUNT + 1;
+ if (showExposureResults) {
+ expectedCount++;
+ }
+ Assert.equal(
+ rows.children.length,
+ expectedCount,
+ "The view has the expected number of rows"
+ );
+
+ // Check the visible rows.
+ for (let i = 0; i < MAX_RESULT_COUNT; i++) {
+ let row = rows.children[i];
+ Assert.ok(BrowserTestUtils.isVisible(row), `rows[${i}] should be visible`);
+ Assert.ok(
+ row.result.type == UrlbarUtils.RESULT_TYPE.SEARCH,
+ `rows[${i}].result.type should be SEARCH`
+ );
+ // The heuristic won't have a suggestion so skip it.
+ if (i > 0) {
+ Assert.ok(
+ row.result.payload.suggestion,
+ `rows[${i}] should have a suggestion`
+ );
+ }
+ }
+
+ // Check the hidden history and/or bookmark rows.
+ let expected = [
+ { source: UrlbarUtils.RESULT_SOURCE.BOOKMARKS, url: bookmarkUrl },
+ ];
+ if (showExposureResults) {
+ expected.unshift({
+ source: UrlbarUtils.RESULT_SOURCE.HISTORY,
+ url: historyUrl,
+ });
+ }
+ for (let i = 0; i < expected.length; i++) {
+ let { source, url } = expected[i];
+ let row = rows.children[MAX_RESULT_COUNT + i];
+ Assert.ok(row, `rows[${i}] should exist`);
+ Assert.ok(BrowserTestUtils.isHidden(row), `rows[${i}] should be hidden`);
+ Assert.equal(
+ row.result.type,
+ UrlbarUtils.RESULT_TYPE.URL,
+ `rows[${i}].result.type should be URL`
+ );
+ Assert.equal(
+ row.result.source,
+ source,
+ `rows[${i}].result.source should be as expected`
+ );
+ Assert.equal(
+ row.result.payload.url,
+ url,
+ `rows[${i}] URL should be as expected`
+ );
+ }
+
+ // Close the view. Blur the urlbar to end the session.
+ info("Closing view and blurring");
+ await UrlbarTestUtils.promisePopupClose(window);
+ gURLBar.blur();
+
+ // No exposure should have been recorded since the history result was never
+ // visible.
+ assertExposureTelemetry([]);
+
+ // Clean up.
+ queryResolver.resolve();
+ await queryPromise;
+ await SpecialPowers.popPrefEnv();
+ Services.fog.testResetFOG();
+}
+
+// Does one query that underfills the view and then a second query that returns
+// a search suggestion. The search suggestion should be appended and trigger an
+// exposure. When `showExposureResults` is true, it should also be shown. After
+// the view is updated, it shouldn't matter whether or not the second query is
+// canceled.
+add_task(async function exposure_append() {
+ for (let showExposureResults of [true, false]) {
+ for (let cancelSecondQuery of [true, false]) {
+ await do_exposure_append({
+ showExposureResults,
+ cancelSecondQuery,
+ });
+ }
+ }
+});
+
+async function do_exposure_append({ showExposureResults, cancelSecondQuery }) {
+ info(
+ "Starting do_exposure_append: " +
+ JSON.stringify({ showExposureResults, cancelSecondQuery })
+ );
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.exposureResults", "search_suggest"],
+ ["browser.urlbar.showExposureResults", showExposureResults],
+ ],
+ });
+
+ // Make the provider return no results at first.
+ gProvider.results = [];
+
+ // Do the first query to open the view.
+ info("Doing first query");
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "test 1",
+ });
+
+ // Now make the provider return a search suggestion and a bookmark. If
+ // `showExposureResults` is true, the suggestion should be added to the view
+ // and be visible immediately. If it's false, it shouldn't be added at
+ // all. The bookmark will always be added, which will tell us when the view
+ // has been updated either way.
+ let newSuggestion = "new suggestion";
+ let bookmarkUrl = "https://example.com/bookmark";
+ gProvider.results = [
+ new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.SEARCH,
+ UrlbarUtils.RESULT_SOURCE.SEARCH,
+ {
+ suggestion: newSuggestion,
+ engine: Services.search.defaultEngine.name,
+ }
+ ),
+ new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.URL,
+ UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
+ { url: bookmarkUrl }
+ ),
+ ];
+
+ // When the provider's `startQuery()` is called, let it add its results but
+ // don't let it return. That will cause the view to be updated with the new
+ // results but let us test the specific case where the query doesn't finish.
+ let queryResolver = Promise.withResolvers();
+ gProvider.finishQueryPromise = queryResolver.promise;
+
+ // Observe when the view appends the bookmark row. This will tell us when the
+ // view has been updated with the provider's new results.
+ let lastRowPromise = promiseLastRowAppended(
+ row => row.result.payload.url == bookmarkUrl
+ );
+
+ // Now start the second query but don't await it.
+ info("Starting second query");
+ let queryPromise = UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "test 2",
+ reopenOnBlur: false,
+ });
+
+ // Wait for the view to be updated.
+ info("Waiting for last row");
+ let lastRow = await lastRowPromise;
+ info("Done waiting for last row");
+
+ Assert.ok(
+ BrowserTestUtils.isVisible(lastRow),
+ "The new bookmark row should be visible since the view is not full"
+ );
+
+ // Check the new suggestion row.
+ let rows = UrlbarTestUtils.getResultsContainer(window);
+ let newSuggestionRow = [...rows.children].find(
+ r => r.result.payload.suggestion == newSuggestion
+ );
+ if (showExposureResults) {
+ Assert.ok(
+ newSuggestionRow,
+ "The new suggestion row should have been added"
+ );
+ Assert.ok(
+ BrowserTestUtils.isVisible(newSuggestionRow),
+ "The new suggestion row should be visible"
+ );
+ } else {
+ Assert.ok(
+ !newSuggestionRow,
+ "The new suggestion row should not have been added"
+ );
+ }
+
+ if (!cancelSecondQuery) {
+ // Finish the query.
+ queryResolver.resolve();
+ await queryPromise;
+ }
+
+ // Close the view. Blur the urlbar to end the session.
+ info("Closing view and blurring");
+ await UrlbarTestUtils.promisePopupClose(window);
+ gURLBar.blur();
+
+ // If `showExposureResults` is true, the new search suggestion should have
+ // been shown; if it's false, it would have been shown. Either way, it should
+ // have triggered an exposure.
+ assertExposureTelemetry([{ results: "search_suggest" }]);
+
+ // Clean up.
+ queryResolver.resolve();
+ await queryPromise;
+ await SpecialPowers.popPrefEnv();
+ Services.fog.testResetFOG();
+}
+
+// Does one query that returns a search suggestion and then a second query that
+// returns a new search suggestion. The new search suggestion can replace the
+// old one, so it should trigger an exposure. When `showExposureResults` is
+// true, it should actually replace it. After the view is updated, it shouldn't
+// matter whether or not the second query is canceled.
+add_task(async function exposure_replace() {
+ for (let showExposureResults of [true, false]) {
+ for (let cancelSecondQuery of [true, false]) {
+ await do_exposure_replace({ showExposureResults, cancelSecondQuery });
+ }
+ }
+});
+
+async function do_exposure_replace({ showExposureResults, cancelSecondQuery }) {
+ info(
+ "Starting do_exposure_replace: " +
+ JSON.stringify({ showExposureResults, cancelSecondQuery })
+ );
+
+ // Make the provider return a search suggestion.
+ gProvider.results = [
+ new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.SEARCH,
+ UrlbarUtils.RESULT_SOURCE.SEARCH,
+ {
+ suggestion: "suggestion",
+ engine: Services.search.defaultEngine.name,
+ }
+ ),
+ ];
+
+ // Do the first query to show the suggestion.
+ info("Doing first query");
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "test 1",
+ });
+
+ // Set exposure results to search suggestions and hide them. We can't do this
+ // before now because that would hide the search suggestions in the first
+ // query, and here we're specifically testing the case where a new row
+ // replaces an old row, which is only allowed for rows of the same type.
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.exposureResults", "search_suggest"],
+ ["browser.urlbar.showExposureResults", showExposureResults],
+ ],
+ });
+
+ // Now make the provider return another search suggestion and a bookmark. If
+ // `showExposureResults` is true, the new suggestion should replace the old
+ // one in the view and be visible immediately. If it's false, it shouldn't be
+ // added at all. The bookmark will always be added, which will tell us when
+ // the view has been updated either way.
+ let newSuggestion = "new suggestion";
+ let bookmarkUrl = "https://example.com/bookmark";
+ gProvider.results = [
+ new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.SEARCH,
+ UrlbarUtils.RESULT_SOURCE.SEARCH,
+ {
+ suggestion: newSuggestion,
+ engine: Services.search.defaultEngine.name,
+ }
+ ),
+ new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.URL,
+ UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
+ { url: bookmarkUrl }
+ ),
+ ];
+
+ // When the provider's `startQuery()` is called, let it add its results but
+ // don't let it return. That will cause the view to be updated with the new
+ // results but let us test the specific case where the query doesn't finish.
+ let queryResolver = Promise.withResolvers();
+ gProvider.finishQueryPromise = queryResolver.promise;
+
+ // Observe when the view appends the bookmark row. This will tell us when the
+ // view has been updated with the provider's new results.
+ let lastRowPromise = promiseLastRowAppended(
+ row => row.result.payload.url == bookmarkUrl
+ );
+
+ // Now start the second query but don't await it.
+ info("Starting second query");
+ let queryPromise = UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "test 2",
+ reopenOnBlur: false,
+ });
+
+ // Wait for the view to be updated.
+ info("Waiting for last row");
+ let lastRow = await lastRowPromise;
+ info("Done waiting for last row");
+
+ Assert.ok(
+ BrowserTestUtils.isVisible(lastRow),
+ "The new bookmark row should be visible since the view is not full"
+ );
+
+ // Check the new suggestion row.
+ let rows = UrlbarTestUtils.getResultsContainer(window);
+ let newSuggestionRow = [...rows.children].find(
+ r => r.result.payload.suggestion == newSuggestion
+ );
+ if (showExposureResults) {
+ Assert.ok(
+ newSuggestionRow,
+ "The new suggestion row should have replaced the old one"
+ );
+ Assert.ok(
+ BrowserTestUtils.isVisible(newSuggestionRow),
+ "The new suggestion row should be visible"
+ );
+ } else {
+ Assert.ok(
+ !newSuggestionRow,
+ "The new suggestion row should not have been added"
+ );
+ }
+
+ if (!cancelSecondQuery) {
+ // Finish the query.
+ queryResolver.resolve();
+ await queryPromise;
+ }
+
+ // Close the view. Blur the urlbar to end the session.
+ info("Closing view and blurring");
+ await UrlbarTestUtils.promisePopupClose(window);
+ gURLBar.blur();
+
+ // If `showExposureResults` is true, the new search suggestion should have
+ // been shown; if it's false, it would have been shown. Either way, it should
+ // have triggered an exposure.
+ assertExposureTelemetry([{ results: "search_suggest" }]);
+
+ // Clean up.
+ queryResolver.resolve();
+ await queryPromise;
+ await SpecialPowers.popPrefEnv();
+ Services.fog.testResetFOG();
+}
+
+/**
+ * A test provider that doesn't finish startQuery() until `finishQueryPromise`
+ * is resolved.
+ */
+class TestProvider extends UrlbarTestUtils.TestProvider {
+ finishQueryPromise = null;
+
+ async startQuery(context, addCallback) {
+ for (let result of this.results) {
+ addCallback(this, result);
+ }
+ await this.finishQueryPromise;
+ }
+}
+
+function promiseLastRowAppended(predicate) {
+ return new Promise(resolve => {
+ let rows = UrlbarTestUtils.getResultsContainer(window);
+ let observer = new MutationObserver(mutations => {
+ let lastRow = rows.children[rows.children.length - 1];
+ info(
+ "Observed mutation, lastRow.result is: " +
+ JSON.stringify(lastRow.result)
+ );
+ if (predicate(lastRow)) {
+ observer.disconnect();
+ resolve(lastRow);
+ }
+ });
+ observer.observe(rows, { childList: true });
+ });
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_groups.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_groups.js
new file mode 100644
index 0000000000..354876e512
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_groups.js
@@ -0,0 +1,258 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of impression telemetry.
+// - groups
+// - results
+// - n_results
+
+// This test has many subtests and can time out in verify mode.
+requestLongerTimeout(5);
+
+add_setup(async function () {
+ await initGroupTest();
+ // Increase the pausing time to ensure to ready for all suggestions.
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [
+ "browser.urlbar.searchEngagementTelemetry.pauseImpressionIntervalMs",
+ 500,
+ ],
+ ],
+ });
+});
+
+add_task(async function heuristics() {
+ await doHeuristicsTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ { reason: "pause", groups: "heuristic", results: "search_engine" },
+ ]),
+ });
+});
+
+add_task(async function adaptive_history() {
+ await doAdaptiveHistoryTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "heuristic,adaptive_history",
+ results: "search_engine,history",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function search_history() {
+ await doSearchHistoryTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "heuristic,search_history,search_history",
+ results: "search_engine,search_history,search_history",
+ n_results: 3,
+ },
+ ]),
+ });
+});
+
+add_task(async function recent_search() {
+ await doRecentSearchTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "recent_search,suggested_index",
+ results: "recent_search,action",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function search_suggest() {
+ await doSearchSuggestTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "heuristic,search_suggest,search_suggest",
+ results: "search_engine,search_suggest,search_suggest",
+ n_results: 3,
+ },
+ ]),
+ });
+
+ await doTailSearchSuggestTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "heuristic,search_suggest",
+ results: "search_engine,search_suggest",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function top_pick() {
+ await doTopPickTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "heuristic,top_pick,search_suggest,search_suggest",
+ results:
+ "search_engine,merino_top_picks,search_suggest,search_suggest",
+ n_results: 4,
+ },
+ ]),
+ });
+});
+
+add_task(async function top_site() {
+ await doTopSiteTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "top_site,suggested_index",
+ results: "top_site,action",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function clipboard() {
+ await doClipboardTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "general,suggested_index",
+ results: "clipboard,action",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function remote_tab() {
+ await doRemoteTabTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "heuristic,remote_tab",
+ results: "search_engine,remote_tab",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function addon() {
+ await doAddonTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "addon",
+ results: "addon",
+ n_results: 1,
+ },
+ ]),
+ });
+});
+
+add_task(async function general() {
+ await doGeneralBookmarkTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "heuristic,suggested_index,general",
+ results: "search_engine,action,bookmark",
+ n_results: 3,
+ },
+ ]),
+ });
+
+ await doGeneralHistoryTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "heuristic,general",
+ results: "search_engine,history",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function suggest() {
+ await doSuggestTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ groups: "heuristic,suggest",
+ results: UrlbarPrefs.get("quickSuggestRustEnabled")
+ ? "search_engine,rust_adm_nonsponsored"
+ : "search_engine,rs_adm_nonsponsored",
+ n_results: 2,
+ },
+ ]),
+ });
+});
+
+add_task(async function about_page() {
+ await doAboutPageTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "heuristic,about_page,about_page",
+ results: "search_engine,history,history",
+ n_results: 3,
+ },
+ ]),
+ });
+});
+
+add_task(async function suggested_index() {
+ await doSuggestedIndexTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ {
+ reason: "pause",
+ groups: "heuristic,suggested_index",
+ results: "search_engine,unit",
+ n_results: 2,
+ },
+ ]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction.js
new file mode 100644
index 0000000000..a16b55cac6
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of impression telemetry.
+// - interaction
+
+add_setup(async function () {
+ await initInteractionTest();
+});
+
+add_task(async function topsites() {
+ await doTopsitesTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", interaction: "topsites" }]),
+ });
+});
+
+add_task(async function typed() {
+ await doTypedTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", interaction: "typed" }]),
+ });
+
+ await doTypedWithResultsPopupTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", interaction: "typed" }]),
+ });
+});
+
+add_task(async function pasted() {
+ await doPastedTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", interaction: "pasted" }]),
+ });
+
+ await doPastedWithResultsPopupTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", interaction: "pasted" }]),
+ });
+});
+
+add_task(async function topsite_search() {
+ await doTopsitesSearchTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ { reason: "pause", interaction: "topsite_search" },
+ ]),
+ });
+});
+
+add_task(async function returned_restarted_refined() {
+ await doReturnedRestartedRefinedTest({
+ trigger: () => waitForPauseImpression(),
+ assert: expected =>
+ assertImpressionTelemetry([
+ { reason: "pause" },
+ { reason: "pause", interaction: expected },
+ ]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction_persisted_search_terms_disabled.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction_persisted_search_terms_disabled.js
new file mode 100644
index 0000000000..af7134b3a0
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction_persisted_search_terms_disabled.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test impression telemetry with persisted search terms disabled.
+
+// Allow more time for Mac machines so they don't time out in verify mode.
+if (AppConstants.platform == "macosx") {
+ requestLongerTimeout(3);
+}
+
+add_setup(async function () {
+ await initInteractionTest();
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", false]],
+ });
+});
+
+add_task(async function persisted_search_terms() {
+ await doPersistedSearchTermsTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ { reason: "pause" },
+ { reason: "pause", interaction: "typed" },
+ ]),
+ });
+});
+
+add_task(async function persisted_search_terms_restarted_refined() {
+ await doPersistedSearchTermsRestartedRefinedTest({
+ enabled: false,
+ trigger: () => waitForPauseImpression(),
+ assert: expected =>
+ assertImpressionTelemetry([
+ { reason: "pause" },
+ { reason: "pause", interaction: expected },
+ ]),
+ });
+});
+
+add_task(
+ async function persisted_search_terms_restarted_refined_via_abandonment() {
+ await doPersistedSearchTermsRestartedRefinedViaAbandonmentTest({
+ enabled: false,
+ trigger: () => waitForPauseImpression(),
+ assert: expected =>
+ assertImpressionTelemetry([
+ { reason: "pause" },
+ { reason: "pause" },
+ { reason: "pause", interaction: expected },
+ ]),
+ });
+ }
+);
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction_persisted_search_terms_enabled.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction_persisted_search_terms_enabled.js
new file mode 100644
index 0000000000..a29ff98b78
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction_persisted_search_terms_enabled.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test impression telemetry with persisted search terms enabled.
+
+// Allow more time for Mac machines so they don't time out in verify mode.
+if (AppConstants.platform == "macosx") {
+ requestLongerTimeout(3);
+}
+
+add_setup(async function () {
+ await initInteractionTest();
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.showSearchTerms.featureGate", true],
+ ["browser.urlbar.showSearchTerms.enabled", true],
+ ["browser.search.widget.inNavBar", false],
+ ],
+ });
+});
+
+add_task(async function interaction_persisted_search_terms() {
+ await doPersistedSearchTermsTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ { reason: "pause" },
+ { reason: "pause", interaction: "persisted_search_terms" },
+ ]),
+ });
+});
+
+add_task(async function interaction_persisted_search_terms_restarted_refined() {
+ await doPersistedSearchTermsRestartedRefinedTest({
+ enabled: true,
+ trigger: () => waitForPauseImpression(),
+ assert: expected =>
+ assertImpressionTelemetry([
+ { reason: "pause" },
+ { reason: "pause", interaction: expected },
+ ]),
+ });
+});
+
+add_task(
+ async function interaction_persisted_search_terms_restarted_refined_via_abandonment() {
+ await doPersistedSearchTermsRestartedRefinedViaAbandonmentTest({
+ enabled: true,
+ trigger: () => waitForPauseImpression(),
+ assert: expected =>
+ assertImpressionTelemetry([
+ { reason: "pause" },
+ { reason: "pause" },
+ { reason: "pause", interaction: expected },
+ ]),
+ });
+ }
+);
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_n_chars_n_words.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_n_chars_n_words.js
new file mode 100644
index 0000000000..528cc318e0
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_n_chars_n_words.js
@@ -0,0 +1,40 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of impression telemetry.
+// - n_chars
+// - n_words
+
+add_setup(async function () {
+ await initNCharsAndNWordsTest();
+});
+
+add_task(async function n_chars() {
+ await doNCharsTest({
+ trigger: () => waitForPauseImpression(),
+ assert: nChars =>
+ assertImpressionTelemetry([{ reason: "pause", n_chars: nChars }]),
+ });
+
+ await doNCharsWithOverMaxTextLengthCharsTest({
+ trigger: () => waitForPauseImpression(),
+ assert: nChars =>
+ assertImpressionTelemetry([{ reason: "pause", n_chars: nChars }]),
+ });
+});
+
+add_task(async function n_words() {
+ await doNWordsTest({
+ trigger: () => waitForPauseImpression(),
+ assert: nWords =>
+ assertImpressionTelemetry([{ reason: "pause", n_words: nWords }]),
+ });
+
+ await doNWordsWithOverMaxTextLengthCharsTest({
+ trigger: () => waitForPauseImpression(),
+ assert: nWords =>
+ assertImpressionTelemetry([{ reason: "pause", n_words: nWords }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_preferences.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_preferences.js
new file mode 100644
index 0000000000..344e238e24
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_preferences.js
@@ -0,0 +1,41 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the impression telemetry behavior with its preferences.
+
+add_setup(async function () {
+ await setup();
+});
+
+add_task(async function pauseImpressionIntervalMs() {
+ const additionalInterval = 1000;
+ const originalInterval = UrlbarPrefs.get(
+ "searchEngagementTelemetry.pauseImpressionIntervalMs"
+ );
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [
+ "browser.urlbar.searchEngagementTelemetry.pauseImpressionIntervalMs",
+ originalInterval + additionalInterval,
+ ],
+ ],
+ });
+
+ await doTest(async browser => {
+ await openPopup("https://example.com");
+
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, originalInterval));
+ await Services.fog.testFlushAllChildren();
+ assertImpressionTelemetry([]);
+
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, additionalInterval));
+ await Services.fog.testFlushAllChildren();
+ assertImpressionTelemetry([{ sap: "urlbar_newtab" }]);
+ });
+
+ await SpecialPowers.popPrefEnv();
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_sap.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_sap.js
new file mode 100644
index 0000000000..482b906024
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_sap.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of impression telemetry.
+// - sap
+
+add_setup(async function () {
+ await initSapTest();
+});
+
+add_task(async function urlbar() {
+ await doUrlbarTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ { reason: "pause", sap: "urlbar_newtab" },
+ { reason: "pause", sap: "urlbar" },
+ ]),
+ });
+});
+
+add_task(async function handoff() {
+ await doHandoffTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", sap: "handoff" }]),
+ });
+});
+
+add_task(async function urlbar_addonpage() {
+ await doUrlbarAddonpageTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", sap: "urlbar_addonpage" }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_search_engine_default_id.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_search_engine_default_id.js
new file mode 100644
index 0000000000..c5bd983d7f
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_search_engine_default_id.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of impression telemetry.
+// - search_engine_default_id
+
+add_setup(async function () {
+ await initSearchEngineDefaultIdTest();
+ // Increase the pausing time to ensure to ready for all suggestions.
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [
+ "browser.urlbar.searchEngagementTelemetry.pauseImpressionIntervalMs",
+ 500,
+ ],
+ ],
+ });
+});
+
+add_task(async function basic() {
+ await doSearchEngineDefaultIdTest({
+ trigger: () => waitForPauseImpression(),
+ assert: engineId =>
+ assertImpressionTelemetry([{ search_engine_default_id: engineId }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_search_mode.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_search_mode.js
new file mode 100644
index 0000000000..727afa3cef
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_search_mode.js
@@ -0,0 +1,72 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the following data of impression telemetry.
+// - search_mode
+
+add_setup(async function () {
+ await initSearchModeTest();
+ // Increase the pausing time to ensure entering search mode.
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [
+ "browser.urlbar.searchEngagementTelemetry.pauseImpressionIntervalMs",
+ 1000,
+ ],
+ ],
+ });
+});
+
+add_task(async function not_search_mode() {
+ await doNotSearchModeTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", search_mode: "" }]),
+ });
+});
+
+add_task(async function search_engine() {
+ await doSearchEngineTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ { reason: "pause", search_mode: "search_engine" },
+ ]),
+ });
+});
+
+add_task(async function bookmarks() {
+ await doBookmarksTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([
+ { reason: "pause", search_mode: "bookmarks" },
+ ]),
+ });
+});
+
+add_task(async function history() {
+ await doHistoryTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", search_mode: "history" }]),
+ });
+});
+
+add_task(async function tabs() {
+ await doTabTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", search_mode: "tabs" }]),
+ });
+});
+
+add_task(async function actions() {
+ await doActionsTest({
+ trigger: () => waitForPauseImpression(),
+ assert: () =>
+ assertImpressionTelemetry([{ reason: "pause", search_mode: "actions" }]),
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_timing.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_timing.js
new file mode 100644
index 0000000000..31f64996f3
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_timing.js
@@ -0,0 +1,91 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the taking timing for the impression telemetry.
+
+add_setup(async function () {
+ await setup();
+});
+
+add_task(async function cancelImpressionTimerByEngagementEvent() {
+ const additionalInterval = 1000;
+ const originalInterval = UrlbarPrefs.get(
+ "searchEngagementTelemetry.pauseImpressionIntervalMs"
+ );
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [
+ "browser.urlbar.searchEngagementTelemetry.pauseImpressionIntervalMs",
+ originalInterval + additionalInterval,
+ ],
+ ],
+ });
+
+ for (const trigger of [doEnter, doBlur]) {
+ await doTest(async browser => {
+ await openPopup("https://example.com");
+ await trigger();
+
+ // Check whether the impression timer was canceled.
+ await new Promise(r =>
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(r, originalInterval + additionalInterval)
+ );
+ assertImpressionTelemetry([]);
+ });
+ }
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function cancelInpressionTimerByType() {
+ const originalInterval = UrlbarPrefs.get(
+ "searchEngagementTelemetry.pauseImpressionIntervalMs"
+ );
+
+ await doTest(async browser => {
+ await openPopup("x");
+ await new Promise(r =>
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(r, originalInterval / 10)
+ );
+ assertImpressionTelemetry([]);
+
+ EventUtils.synthesizeKey(" ");
+ EventUtils.synthesizeKey("z");
+ await UrlbarTestUtils.promiseSearchComplete(window);
+ assertImpressionTelemetry([]);
+ await waitForPauseImpression();
+
+ assertImpressionTelemetry([{ n_chars: 3 }]);
+ });
+});
+
+add_task(async function oneImpressionInOneSession() {
+ await doTest(async browser => {
+ await openPopup("x");
+ await waitForPauseImpression();
+
+ // Sanity check.
+ assertImpressionTelemetry([{ n_chars: 1 }]);
+
+ // Add a keyword to start new query.
+ EventUtils.synthesizeKey(" ");
+ EventUtils.synthesizeKey("z");
+ await UrlbarTestUtils.promiseSearchComplete(window);
+ await waitForPauseImpression();
+
+ // No more taking impression telemetry.
+ assertImpressionTelemetry([{ n_chars: 1 }]);
+
+ // Finish the current session.
+ await doEnter();
+
+ // Should take pause impression since new session started.
+ await openPopup("x z y");
+ await waitForPauseImpression();
+ assertImpressionTelemetry([{ n_chars: 1 }, { n_chars: 5 }]);
+ });
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_record_preferences.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_record_preferences.js
new file mode 100644
index 0000000000..88adc2fc11
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_record_preferences.js
@@ -0,0 +1,74 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for preference telemetry.
+
+add_setup(async function () {
+ await Services.fog.testFlushAllChildren();
+ Services.fog.testResetFOG();
+
+ // Create a new window in order to initialize TelemetryEvent of
+ // UrlbarController.
+ const win = await BrowserTestUtils.openNewBrowserWindow();
+ registerCleanupFunction(async function () {
+ await BrowserTestUtils.closeWindow(win);
+ });
+});
+
+add_task(async function prefMaxRichResults() {
+ Assert.equal(
+ Glean.urlbar.prefMaxResults.testGetValue(),
+ UrlbarPrefs.get("maxRichResults"),
+ "Record prefMaxResults when UrlbarController is initialized"
+ );
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.maxRichResults", 0]],
+ });
+ Assert.equal(
+ Glean.urlbar.prefMaxResults.testGetValue(),
+ UrlbarPrefs.get("maxRichResults"),
+ "Record prefMaxResults when the maxRichResults pref is updated"
+ );
+});
+
+add_task(async function boolPref() {
+ const testData = [
+ {
+ green: "prefSuggestDataCollection",
+ pref: "quicksuggest.dataCollection.enabled",
+ },
+ {
+ green: "prefSuggestNonsponsored",
+ pref: "suggest.quicksuggest.nonsponsored",
+ },
+ {
+ green: "prefSuggestSponsored",
+ pref: "suggest.quicksuggest.sponsored",
+ },
+ {
+ green: "prefSuggestTopsites",
+ pref: "suggest.topsites",
+ },
+ ];
+
+ for (const { green, pref } of testData) {
+ Assert.equal(
+ Glean.urlbar[green].testGetValue(),
+ UrlbarPrefs.get(pref),
+ `Record ${green} when UrlbarController is initialized`
+ );
+
+ await SpecialPowers.pushPrefEnv({
+ set: [[`browser.urlbar.${pref}`, !UrlbarPrefs.get(pref)]],
+ });
+
+ Assert.equal(
+ Glean.urlbar[green].testGetValue(),
+ UrlbarPrefs.get(pref),
+ `Record ${green} when the ${pref} pref is updated`
+ );
+ }
+});
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/head-exposure.js b/browser/components/urlbar/tests/engagementTelemetry/browser/head-exposure.js
new file mode 100644
index 0000000000..f0723be701
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head-exposure.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+async function doExposureTest({
+ prefs,
+ query,
+ trigger,
+ assert,
+ select = defaultSelect,
+}) {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit();
+ await SpecialPowers.pushPrefEnv({
+ set: prefs,
+ });
+
+ await doTest(async () => {
+ await openPopup(query);
+ await select(query);
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+ await cleanupQuickSuggest();
+}
+
+async function defaultSelect(query) {
+ await selectRowByURL(`https://example.com/${query}`);
+}
+
+async function getResultByType(provider) {
+ for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
+ const detail = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
+ const telemetryType = UrlbarUtils.searchEngagementTelemetryType(
+ detail.result
+ );
+ if (telemetryType === provider) {
+ return detail.result;
+ }
+ }
+ return null;
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/head-groups.js b/browser/components/urlbar/tests/engagementTelemetry/browser/head-groups.js
new file mode 100644
index 0000000000..e86c664b46
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head-groups.js
@@ -0,0 +1,339 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+ChromeUtils.defineESModuleGetters(this, {
+ UrlbarProviderClipboard:
+ "resource:///modules/UrlbarProviderClipboard.sys.mjs",
+});
+
+async function doHeuristicsTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await openPopup("x");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doAdaptiveHistoryTest({ trigger, assert }) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.autoFill", false]],
+ });
+
+ await doTest(async browser => {
+ await PlacesTestUtils.addVisits(["https://example.com/test"]);
+ await UrlbarUtils.addToInputHistory("https://example.com/test", "examp");
+
+ await openPopup("exa");
+ await selectRowByURL("https://example.com/test");
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+}
+
+async function doSearchHistoryTest({ trigger, assert }) {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.suggest.searches", true],
+ ["browser.urlbar.maxHistoricalSearchSuggestions", 2],
+ ],
+ });
+
+ await doTest(async browser => {
+ await UrlbarTestUtils.formHistory.add(["foofoo", "foobar"]);
+
+ await openPopup("foo");
+ await selectRowByURL("http://mochi.test:8888/?terms=foofoo");
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+}
+
+async function doRecentSearchTest({ trigger, assert }) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.recentsearches.featureGate", true]],
+ });
+
+ await doTest(async browser => {
+ await UrlbarTestUtils.formHistory.add([
+ { value: "foofoo", source: Services.search.defaultEngine.name },
+ ]);
+
+ await openPopup("");
+ await selectRowByURL("http://mochi.test:8888/?terms=foofoo");
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+}
+
+async function doSearchSuggestTest({ trigger, assert }) {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.suggest.searches", true],
+ ["browser.urlbar.maxHistoricalSearchSuggestions", 2],
+ ],
+ });
+
+ await doTest(async browser => {
+ await openPopup("foo");
+ await selectRowByURL("http://mochi.test:8888/?terms=foofoo");
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+}
+
+async function doTailSearchSuggestTest({ trigger, assert }) {
+ const cleanup = await _useTailSuggestionsEngine();
+
+ await doTest(async browser => {
+ await openPopup("hello");
+ await selectRowByProvider("SearchSuggestions");
+
+ await trigger();
+ await assert();
+ });
+
+ await cleanup();
+}
+
+async function doTopPickTest({ trigger, assert }) {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit({
+ merinoSuggestions: [
+ {
+ title: "Navigational suggestion",
+ url: "https://example.com/navigational-suggestion",
+ provider: "top_picks",
+ is_sponsored: false,
+ score: 0.25,
+ block_id: 0,
+ is_top_pick: true,
+ },
+ ],
+ });
+
+ await doTest(async browser => {
+ await openPopup("navigational");
+ await selectRowByURL("https://example.com/navigational-suggestion");
+
+ await trigger();
+ await assert();
+ });
+
+ await cleanupQuickSuggest();
+}
+
+async function doTopSiteTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await addTopSites("https://example.com/");
+
+ await showResultByArrowDown();
+ await selectRowByURL("https://example.com/");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doClipboardTest({ trigger, assert }) {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.clipboard.featureGate", true],
+ ["browser.urlbar.suggest.clipboard", true],
+ ],
+ });
+ SpecialPowers.clipboardCopyString("https://example.com/clipboard");
+ await doTest(async browser => {
+ await showResultByArrowDown();
+ await selectRowByURL("https://example.com/clipboard");
+
+ await trigger();
+ await assert();
+ });
+ SpecialPowers.clipboardCopyString("");
+ UrlbarProviderClipboard.setPreviousClipboardValue("");
+ await SpecialPowers.popPrefEnv();
+}
+
+async function doRemoteTabTest({ trigger, assert }) {
+ const remoteTab = await loadRemoteTab("https://example.com");
+
+ await doTest(async browser => {
+ await openPopup("example");
+ await selectRowByProvider("RemoteTabs");
+
+ await trigger();
+ await assert();
+ });
+
+ await remoteTab.unload();
+}
+
+async function doAddonTest({ trigger, assert }) {
+ const addon = loadOmniboxAddon({ keyword: "omni" });
+ await addon.startup();
+
+ await doTest(async browser => {
+ await openPopup("omni test");
+
+ await trigger();
+ await assert();
+ });
+
+ await addon.unload();
+}
+
+async function doGeneralBookmarkTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: "https://example.com/bookmark",
+ title: "bookmark",
+ });
+
+ await openPopup("bookmark");
+ await selectRowByURL("https://example.com/bookmark");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doGeneralHistoryTest({ trigger, assert }) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.autoFill", false]],
+ });
+
+ await doTest(async browser => {
+ await PlacesTestUtils.addVisits("https://example.com/test");
+
+ await openPopup("example");
+ await selectRowByURL("https://example.com/test");
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+}
+
+async function doSuggestTest({ trigger, assert }) {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit();
+
+ await doTest(async browser => {
+ await openPopup("nonsponsored");
+ await selectRowByURL("https://example.com/nonsponsored");
+
+ await trigger();
+ await assert();
+ });
+
+ await cleanupQuickSuggest();
+}
+
+async function doAboutPageTest({ trigger, assert }) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.maxRichResults", 3]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("about:");
+ await selectRowByURL("about:robots");
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+}
+
+async function doSuggestedIndexTest({ trigger, assert }) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.unitConversion.enabled", true]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("1m to cm");
+ await selectRowByProvider("UnitConversion");
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+}
+
+/**
+ * Creates a search engine that returns tail suggestions and sets it as the
+ * default engine.
+ *
+ * @returns {Function}
+ * A cleanup function that will revert the default search engine and stop http
+ * server.
+ */
+async function _useTailSuggestionsEngine() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.search.suggest.enabled", true],
+ ["browser.urlbar.suggest.searches", true],
+ ["browser.urlbar.richSuggestions.tail", true],
+ ],
+ });
+
+ const engineName = "TailSuggestions";
+ const httpServer = new HttpServer();
+ httpServer.start(-1);
+ httpServer.registerPathHandler("/suggest", (req, resp) => {
+ const params = new URLSearchParams(req.queryString);
+ const searchStr = params.get("q");
+ const suggestions = [
+ searchStr,
+ [searchStr + "-tail"],
+ [],
+ {
+ "google:suggestdetail": [{ t: "-tail", mp: "… " }],
+ },
+ ];
+ resp.setHeader("Content-Type", "application/json", false);
+ resp.write(JSON.stringify(suggestions));
+ });
+
+ await SearchTestUtils.installSearchExtension({
+ name: engineName,
+ search_url: `http://localhost:${httpServer.identity.primaryPort}/search`,
+ suggest_url: `http://localhost:${httpServer.identity.primaryPort}/suggest`,
+ suggest_url_get_params: "?q={searchTerms}",
+ search_form: `http://localhost:${httpServer.identity.primaryPort}/search?q={searchTerms}`,
+ });
+
+ const tailEngine = Services.search.getEngineByName(engineName);
+ const originalEngine = await Services.search.getDefault();
+ Services.search.setDefault(
+ tailEngine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+
+ return async () => {
+ Services.search.setDefault(
+ originalEngine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ httpServer.stop(() => {});
+ await SpecialPowers.popPrefEnv();
+ };
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/head-interaction.js b/browser/components/urlbar/tests/engagementTelemetry/browser/head-interaction.js
new file mode 100644
index 0000000000..244e27d272
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head-interaction.js
@@ -0,0 +1,340 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+ChromeUtils.defineESModuleGetters(this, {
+ CUSTOM_SEARCH_SHORTCUTS:
+ "resource://activity-stream/lib/SearchShortcuts.sys.mjs",
+ NewTabUtils: "resource://gre/modules/NewTabUtils.sys.mjs",
+ SEARCH_SHORTCUTS: "resource://activity-stream/lib/SearchShortcuts.sys.mjs",
+ SearchService: "resource://gre/modules/SearchService.sys.mjs",
+});
+
+async function doTopsitesTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await addTopSites("https://example.com/");
+
+ await showResultByArrowDown();
+ await selectRowByURL("https://example.com/");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doTopsitesSearchTest({ trigger, assert }) {
+ await doTest(async browser => {
+ let extension = await SearchTestUtils.installSearchExtension(
+ {
+ name: "MozSearch",
+ keyword: "@test",
+ search_url: "https://example.com/",
+ search_url_get_params: "q={searchTerms}",
+ },
+ { skipUnload: true }
+ );
+
+ // Fresh profiles come with an empty set of pinned websites (pref doesn't
+ // exist). Search shortcut topsites make this test more complicated because
+ // the feature pins a new website on startup. Behaviour can vary when running
+ // with --verify so it's more predictable to clear pins entirely.
+ Services.prefs.clearUserPref("browser.newtabpage.pinned");
+ NewTabUtils.pinnedLinks.resetCache();
+
+ let entry = {
+ keyword: "@test",
+ shortURL: "example",
+ url: "https://example.com/",
+ };
+
+ // The array is used to identify sites that should be converted to
+ // a Top Site.
+ let searchShortcuts = JSON.parse(JSON.stringify(SEARCH_SHORTCUTS));
+ SEARCH_SHORTCUTS.push(entry);
+
+ // TopSitesFeed takes a list of app provided engines and determine if the
+ // engine containing an alias that matches a keyword inside of this array.
+ // If so, the list of search shortcuts in the store will be updated.
+ let customSearchShortcuts = JSON.parse(
+ JSON.stringify(CUSTOM_SEARCH_SHORTCUTS)
+ );
+ CUSTOM_SEARCH_SHORTCUTS.push(entry);
+
+ // TopSitesFeed only allows app provided engines to be included as
+ // search shortcuts.
+ // eslint-disable-next-line mozilla/valid-lazy
+ let sandbox = lazy.sinon.createSandbox();
+ sandbox
+ .stub(SearchService.prototype, "getAppProvidedEngines")
+ .resolves([{ aliases: ["@test"] }]);
+
+ let siteToPin = {
+ url: "https://example.com",
+ label: "@test",
+ searchTopSite: true,
+ };
+ NewTabUtils.pinnedLinks.pin(siteToPin, 0);
+
+ await updateTopSites(sites => {
+ return sites && sites[0] && sites[0].url == "https://example.com";
+ }, true);
+
+ BrowserTestUtils.startLoadingURIString(browser, "about:newtab");
+ await BrowserTestUtils.browserStopped(browser, "about:newtab");
+
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ ".search-shortcut .top-site-button",
+ {},
+ gBrowser.selectedBrowser
+ );
+
+ EventUtils.synthesizeKey("x");
+ await UrlbarTestUtils.promiseSearchComplete(window);
+
+ await trigger();
+ await assert();
+
+ // Clean up.
+ NewTabUtils.pinnedLinks.unpin(siteToPin);
+ SEARCH_SHORTCUTS.pop();
+ CUSTOM_SEARCH_SHORTCUTS.pop();
+ // Sanity check to ensure we're leaving the shortcuts in their default state.
+ Assert.deepEqual(
+ searchShortcuts,
+ SEARCH_SHORTCUTS,
+ "SEARCH_SHORTCUTS values"
+ );
+ Assert.deepEqual(
+ customSearchShortcuts,
+ CUSTOM_SEARCH_SHORTCUTS,
+ "CUSTOM_SEARCH_SHORTCUTS values"
+ );
+ sandbox.restore();
+ Services.prefs.clearUserPref("browser.newtabpage.pinned");
+ NewTabUtils.pinnedLinks.resetCache();
+ await extension.unload();
+ });
+}
+
+async function doTypedTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await openPopup("x");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doTypedWithResultsPopupTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await showResultByArrowDown();
+ EventUtils.synthesizeKey("x");
+ await UrlbarTestUtils.promiseSearchComplete(window);
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doPastedTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await doPaste("www.example.com");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doPastedWithResultsPopupTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await showResultByArrowDown();
+ await doPaste("x");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doReturnedRestartedRefinedTest({ trigger, assert }) {
+ const testData = [
+ {
+ firstInput: "x",
+ // Just move the focus to the URL bar after blur.
+ secondInput: null,
+ expected: "returned",
+ },
+ {
+ firstInput: "x",
+ secondInput: "x",
+ expected: "returned",
+ },
+ {
+ firstInput: "x",
+ secondInput: "y",
+ expected: "restarted",
+ },
+ {
+ firstInput: "x",
+ secondInput: "x y",
+ expected: "refined",
+ },
+ {
+ firstInput: "x y",
+ secondInput: "x",
+ expected: "refined",
+ },
+ ];
+
+ for (const { firstInput, secondInput, expected } of testData) {
+ await doTest(async browser => {
+ await openPopup(firstInput);
+ await waitForPauseImpression();
+ await doBlur();
+
+ await UrlbarTestUtils.promisePopupOpen(window, () => {
+ document.getElementById("Browser:OpenLocation").doCommand();
+ });
+ if (secondInput) {
+ for (let i = 0; i < secondInput.length; i++) {
+ EventUtils.synthesizeKey(secondInput.charAt(i));
+ }
+ }
+ await UrlbarTestUtils.promiseSearchComplete(window);
+
+ await trigger();
+ await assert(expected);
+ });
+ }
+}
+
+async function doPersistedSearchTermsTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await openPopup("x");
+ await waitForPauseImpression();
+ await doEnter();
+
+ await openPopup("x");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doPersistedSearchTermsRestartedRefinedTest({
+ enabled,
+ trigger,
+ assert,
+}) {
+ const testData = [
+ {
+ firstInput: "x",
+ // Just move the focus to the URL bar after engagement.
+ secondInput: null,
+ expected: enabled ? "persisted_search_terms" : "topsites",
+ },
+ {
+ firstInput: "x",
+ secondInput: "x",
+ expected: enabled ? "persisted_search_terms" : "typed",
+ },
+ {
+ firstInput: "x",
+ secondInput: "y",
+ expected: enabled ? "persisted_search_terms_restarted" : "typed",
+ },
+ {
+ firstInput: "x",
+ secondInput: "x y",
+ expected: enabled ? "persisted_search_terms_refined" : "typed",
+ },
+ {
+ firstInput: "x y",
+ secondInput: "x",
+ expected: enabled ? "persisted_search_terms_refined" : "typed",
+ },
+ ];
+
+ for (const { firstInput, secondInput, expected } of testData) {
+ await doTest(async browser => {
+ await openPopup(firstInput);
+ await waitForPauseImpression();
+ await doEnter();
+
+ await UrlbarTestUtils.promisePopupOpen(window, () => {
+ EventUtils.synthesizeKey("l", { accelKey: true });
+ });
+ if (secondInput) {
+ for (let i = 0; i < secondInput.length; i++) {
+ EventUtils.synthesizeKey(secondInput.charAt(i));
+ }
+ }
+ await UrlbarTestUtils.promiseSearchComplete(window);
+
+ await trigger();
+ await assert(expected);
+ });
+ }
+}
+
+async function doPersistedSearchTermsRestartedRefinedViaAbandonmentTest({
+ enabled,
+ trigger,
+ assert,
+}) {
+ const testData = [
+ {
+ firstInput: "x",
+ // Just move the focus to the URL bar after blur.
+ secondInput: null,
+ expected: enabled ? "persisted_search_terms" : "returned",
+ },
+ {
+ firstInput: "x",
+ secondInput: "x",
+ expected: enabled ? "persisted_search_terms" : "returned",
+ },
+ {
+ firstInput: "x",
+ secondInput: "y",
+ expected: enabled ? "persisted_search_terms_restarted" : "restarted",
+ },
+ {
+ firstInput: "x",
+ secondInput: "x y",
+ expected: enabled ? "persisted_search_terms_refined" : "refined",
+ },
+ {
+ firstInput: "x y",
+ secondInput: "x",
+ expected: enabled ? "persisted_search_terms_refined" : "refined",
+ },
+ ];
+
+ for (const { firstInput, secondInput, expected } of testData) {
+ await doTest(async browser => {
+ await openPopup("any search");
+ await waitForPauseImpression();
+ await doEnter();
+
+ await openPopup(firstInput);
+ await waitForPauseImpression();
+ await doBlur();
+
+ await UrlbarTestUtils.promisePopupOpen(window, () => {
+ EventUtils.synthesizeKey("l", { accelKey: true });
+ });
+ if (secondInput) {
+ for (let i = 0; i < secondInput.length; i++) {
+ EventUtils.synthesizeKey(secondInput.charAt(i));
+ }
+ }
+ await UrlbarTestUtils.promiseSearchComplete(window);
+
+ await trigger();
+ await assert(expected);
+ });
+ }
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/head-n_chars_n_words.js b/browser/components/urlbar/tests/engagementTelemetry/browser/head-n_chars_n_words.js
new file mode 100644
index 0000000000..6d4c61c7f0
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head-n_chars_n_words.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+async function doNCharsTest({ trigger, assert }) {
+ for (const input of ["x", "xx", "xx x", "xx x "]) {
+ await doTest(async browser => {
+ await openPopup(input);
+
+ await trigger();
+ await assert(input.length);
+ });
+ }
+}
+
+async function doNCharsWithOverMaxTextLengthCharsTest({ trigger, assert }) {
+ await doTest(async browser => {
+ let input = "";
+ for (let i = 0; i < UrlbarUtils.MAX_TEXT_LENGTH * 2; i++) {
+ input += "x";
+ }
+ await openPopup(input);
+
+ await trigger();
+ await assert(UrlbarUtils.MAX_TEXT_LENGTH * 2);
+ });
+}
+
+async function doNWordsTest({ trigger, assert }) {
+ for (const input of ["x", "xx", "xx x", "xx x "]) {
+ await doTest(async browser => {
+ await openPopup(input);
+
+ await trigger();
+ const splits = input.trim().split(" ");
+ await assert(splits.length);
+ });
+ }
+}
+
+async function doNWordsWithOverMaxTextLengthCharsTest({ trigger, assert }) {
+ await doTest(async browser => {
+ const word = "1234 ";
+ let input = "";
+ while (input.length < UrlbarUtils.MAX_TEXT_LENGTH * 2) {
+ input += word;
+ }
+ await openPopup(input);
+
+ await trigger();
+ await assert(UrlbarUtils.MAX_TEXT_LENGTH / word.length);
+ });
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/head-sap.js b/browser/components/urlbar/tests/engagementTelemetry/browser/head-sap.js
new file mode 100644
index 0000000000..ef95873813
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head-sap.js
@@ -0,0 +1,66 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+async function doUrlbarNewTabTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await openPopup("x");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doUrlbarTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await openPopup("x");
+ await waitForPauseImpression();
+ await doEnter();
+ await openPopup("y");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doHandoffTest({ trigger, assert }) {
+ await doTest(async browser => {
+ BrowserTestUtils.startLoadingURIString(browser, "about:newtab");
+ await BrowserTestUtils.browserStopped(browser, "about:newtab");
+ await SpecialPowers.spawn(browser, [], function () {
+ const searchInput = content.document.querySelector(".fake-editable");
+ searchInput.click();
+ });
+ EventUtils.synthesizeKey("x");
+ await UrlbarTestUtils.promiseSearchComplete(window);
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doUrlbarAddonpageTest({ trigger, assert }) {
+ const extensionData = {
+ files: {
+ "page.html": "<!DOCTYPE html>hello",
+ },
+ };
+ const extension = ExtensionTestUtils.loadExtension(extensionData);
+ await extension.startup();
+ const extensionURL = `moz-extension://${extension.uuid}/page.html`;
+
+ await doTest(async browser => {
+ const onLoad = BrowserTestUtils.browserLoaded(browser);
+ BrowserTestUtils.startLoadingURIString(browser, extensionURL);
+ await onLoad;
+ await openPopup("x");
+
+ await trigger();
+ await assert();
+ });
+
+ await extension.unload();
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/head-search_engine_default_id.js b/browser/components/urlbar/tests/engagementTelemetry/browser/head-search_engine_default_id.js
new file mode 100644
index 0000000000..c0af764e7f
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head-search_engine_default_id.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+async function doSearchEngineDefaultIdTest({ trigger, assert }) {
+ await doTest(async browser => {
+ info("Test with current engine");
+ const defaultEngine = await Services.search.getDefault();
+
+ await openPopup("x");
+ await trigger();
+ await assert(defaultEngine.telemetryId);
+ });
+
+ await doTest(async browser => {
+ info("Test with new engine");
+ const defaultEngine = await Services.search.getDefault();
+ const newEngineName = "NewDummyEngine";
+ await SearchTestUtils.installSearchExtension({
+ name: newEngineName,
+ search_url: "https://example.com/",
+ search_url_get_params: "q={searchTerms}",
+ });
+ const newEngine = await Services.search.getEngineByName(newEngineName);
+ Assert.notEqual(defaultEngine.telemetryId, newEngine.telemetryId);
+ await Services.search.setDefault(
+ newEngine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+
+ await openPopup("x");
+ await trigger();
+ await assert(newEngine.telemetryId);
+
+ await Services.search.setDefault(
+ defaultEngine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ });
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/head-search_mode.js b/browser/components/urlbar/tests/engagementTelemetry/browser/head-search_mode.js
new file mode 100644
index 0000000000..5c877da05f
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head-search_mode.js
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+async function doNotSearchModeTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await openPopup("x");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doSearchEngineTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await openPopup("x");
+ await UrlbarTestUtils.enterSearchMode(window);
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doBookmarksTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: "https://example.com/bookmark",
+ title: "bookmark",
+ });
+ await openPopup("bookmark");
+ await UrlbarTestUtils.enterSearchMode(window, {
+ source: UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
+ });
+ await selectRowByURL("https://example.com/bookmark");
+
+ await trigger();
+ await assert();
+ });
+}
+
+async function doHistoryTest({ trigger, assert }) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.autoFill", false]],
+ });
+
+ await doTest(async browser => {
+ await PlacesTestUtils.addVisits("https://example.com/test");
+ await openPopup("example");
+ await UrlbarTestUtils.enterSearchMode(window, {
+ source: UrlbarUtils.RESULT_SOURCE.HISTORY,
+ });
+ await selectRowByURL("https://example.com/test");
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+}
+
+async function doTabTest({ trigger, assert }) {
+ const tab = BrowserTestUtils.addTab(gBrowser, "https://example.com/");
+
+ await doTest(async browser => {
+ await openPopup("example");
+ await UrlbarTestUtils.enterSearchMode(window, {
+ source: UrlbarUtils.RESULT_SOURCE.TABS,
+ });
+ await selectRowByProvider("Places");
+
+ await trigger();
+ await assert();
+ });
+
+ BrowserTestUtils.removeTab(tab);
+}
+
+async function doActionsTest({ trigger, assert }) {
+ await doTest(async browser => {
+ await openPopup("add");
+ await UrlbarTestUtils.enterSearchMode(window, {
+ source: UrlbarUtils.RESULT_SOURCE.ACTIONS,
+ });
+ await selectRowByProvider("quickactions");
+
+ await trigger();
+ await assert();
+ });
+}
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/head.js b/browser/components/urlbar/tests/engagementTelemetry/browser/head.js
new file mode 100644
index 0000000000..367387b0e8
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head.js
@@ -0,0 +1,473 @@
+/* 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 = {};
+
+ChromeUtils.defineLazyGetter(lazy, "QuickSuggestTestUtils", () => {
+ const { QuickSuggestTestUtils: module } = ChromeUtils.importESModule(
+ "resource://testing-common/QuickSuggestTestUtils.sys.mjs"
+ );
+ module.init(this);
+ return module;
+});
+
+ChromeUtils.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",
+});
+
+ChromeUtils.defineLazyGetter(this, "PlacesFrecencyRecalculator", () => {
+ return Cc["@mozilla.org/places/frecency-recalculator;1"].getService(
+ Ci.nsIObserver
+ ).wrappedJSObject;
+});
+
+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() ?? [];
+ info(
+ "Asserting Glean telemetry is correct, actual events are: " +
+ JSON.stringify(telemetries)
+ );
+ 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({ ...args } = {}) {
+ return lazy.QuickSuggestTestUtils.ensureQuickSuggestInit({
+ ...args,
+ remoteSettingsRecords: [
+ {
+ 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",
+ icon: "1234",
+ },
+ {
+ 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: "Wikipedia",
+ iab_category: "5 - Education",
+ icon: "1234",
+ },
+ ],
+ },
+ {
+ 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 impression, as it is disabled by default.
+ Services.fog.setMetricsFeatureConfig(
+ JSON.stringify({
+ "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 initSearchEngineDefaultIdTest() {
+ /* import-globals-from head-search_engine_default_id.js */
+ Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-search_engine_default_id.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();
+}