summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/tests/engagementTelemetry/browser
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/urlbar/tests/engagementTelemetry/browser')
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser.ini52
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_groups.js202
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction.js58
-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_mode.js54
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_tips.js88
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_edge_cases.js218
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_groups.js259
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction.js87
-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_mode.js63
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_selected_result.js920
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_tips.js175
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_type.js151
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_exposure.js107
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_groups.js223
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction.js63
-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_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.js54
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head-exposure.js47
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head-groups.js294
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head-interaction.js238
-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_mode.js93
-rw-r--r--browser/components/urlbar/tests/engagementTelemetry/browser/head.js458
38 files changed, 4792 insertions, 0 deletions
diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser.ini b/browser/components/urlbar/tests/engagementTelemetry/browser/browser.ini
new file mode 100644
index 0000000000..762173562d
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser.ini
@@ -0,0 +1,52 @@
+# 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-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
+ ../../ext/browser/head.js
+ ../../ext/api.js
+ ../../ext/schema.json
+skip-if =
+ os == "win" && os_version == "6.1" # Skip on Azure - frequent failure
+
+[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_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_mode.js]
+[browser_glean_telemetry_engagement_selected_result.js]
+support-files =
+ ../../../../search/test/browser/trendingSuggestionEngine.sjs
+[browser_glean_telemetry_engagement_tips.js]
+[browser_glean_telemetry_engagement_type.js]
+[browser_glean_telemetry_exposure.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_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..6341a21a1a
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_groups.js
@@ -0,0 +1,202 @@
+/* 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
+
+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 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,rs_adm_sponsored,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 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: "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..0462833008
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_interaction.js
@@ -0,0 +1,58 @@
+/* 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() {
+ // TODO: https://bugzilla.mozilla.org/show_bug.cgi?id=1804010
+ // 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_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..f773b0fb28
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_tips.js
@@ -0,0 +1,88 @@
+/* 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 () {
+ Services.fog.setMetricsFeatureConfig(
+ JSON.stringify({ "urlbar.abandonment": false })
+ );
+
+ 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 () {
+ Services.fog.setMetricsFeatureConfig("{}");
+ 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, () => {
+ EventUtils.synthesizeMouseAtCenter(browser, {});
+ });
+
+ assertAbandonmentTelemetry([{ results: "tip_persist" }]);
+ });
+});
+
+add_task(async function mouse_down_without_tip() {
+ await doTest(async browser => {
+ EventUtils.synthesizeMouseAtCenter(browser, {});
+
+ 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..d7b2e775b8
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_edge_cases.js
@@ -0,0 +1,218 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test edge cases for engagement.
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/ext/browser/head.js",
+ this
+);
+
+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 = PromiseUtils.defer();
+ }
+
+ 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 = PromiseUtils.defer();
+ }
+
+ 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]],
+ });
+
+ // Update chunkResultsDelayMs to delay the call to notifyResults.
+ const originalChuldResultDelayMs =
+ UrlbarProvidersManager._chunkResultsDelayMs;
+ UrlbarProvidersManager._chunkResultsDelayMs = 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._chunkResultsDelayMs = originalChuldResultDelayMs;
+ };
+ 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"),
+ () =>
+ EventUtils.synthesizeMouseAtCenter(
+ document.getElementById("customizableui-special-spring2"),
+ {}
+ ),
+ ];
+
+ 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..9060835562
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_groups.js
@@ -0,0 +1,259 @@
+/* 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
+
+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 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,rs_adm_sponsored,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 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: "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..9de0de8953
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_interaction.js
@@ -0,0 +1,87 @@
+/* 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() {
+ // TODO: https://bugzilla.mozilla.org/show_bug.cgi?id=1804010
+ // 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_mode.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_search_mode.js
new file mode 100644
index 0000000000..62f87f0664
--- /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-row[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..c19c511ccc
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_selected_result.js
@@ -0,0 +1,920 @@
+/* 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
+// - provider
+// - results
+
+// This test has many subtests and can time out in verify mode.
+requestLongerTimeout(5);
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/ext/browser/head.js",
+ this
+);
+
+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: "",
+ 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: "",
+ 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 openPopup("exa");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "autofill_origin",
+ selected_result_subtype: "",
+ 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 openPopup("https://example.com/test");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "autofill_url",
+ selected_result_subtype: "",
+ 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: "",
+ 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: "",
+ 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: "",
+ 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: "",
+ 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: "",
+ 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: "",
+ 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: "",
+ 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-row[data-key=addons]");
+ await onLoad;
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "action",
+ selected_result_subtype: "addons",
+ 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: "",
+ 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: "",
+ 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: "",
+ 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: "",
+ 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: "",
+ 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: "",
+ provider: "calculator",
+ results: "search_engine,calc",
+ },
+ ]);
+ });
+
+ 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: "",
+ 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.loadURIString(
+ 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: "",
+ provider: "UrlbarProviderContextualSearch",
+ results: "search_engine,site_specific_contextual_search",
+ },
+ ]);
+
+ await extension.unload();
+ });
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function selected_result_experimental_addon() {
+ const extension = await loadExtension({
+ background: async () => {
+ browser.experiments.urlbar.addDynamicResultType("testDynamicType");
+ browser.experiments.urlbar.addDynamicViewTemplate("testDynamicType", {
+ children: [
+ {
+ name: "text",
+ tag: "span",
+ attributes: {
+ role: "button",
+ },
+ },
+ ],
+ });
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "active";
+ }, "testProvider");
+ browser.urlbar.onResultsRequested.addListener(query => {
+ return [
+ {
+ type: "dynamic",
+ source: "local",
+ payload: {
+ dynamicType: "testDynamicType",
+ },
+ },
+ ];
+ }, "testProvider");
+ browser.experiments.urlbar.onViewUpdateRequested.addListener(payload => {
+ return {
+ text: {
+ textContent: "This is a dynamic result.",
+ },
+ };
+ }, "testProvider");
+ },
+ });
+
+ await TestUtils.waitForCondition(
+ () =>
+ UrlbarProvidersManager.getProvider("testProvider") &&
+ UrlbarResult.getDynamicResultType("testDynamicType"),
+ "Waiting for provider and dynamic type to be registered"
+ );
+
+ await doTest(async browser => {
+ await openPopup("test");
+ EventUtils.synthesizeKey("KEY_ArrowDown");
+ await UrlbarTestUtils.promisePopupClose(window, () =>
+ EventUtils.synthesizeKey("KEY_Enter")
+ );
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "experimental_addon",
+ selected_result_subtype: "",
+ provider: "testProvider",
+ results: "search_engine,experimental_addon",
+ },
+ ]);
+ });
+
+ await extension.unload();
+});
+
+add_task(async function selected_result_adm_sponsored() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit();
+
+ await doTest(async browser => {
+ await openPopup("sponsored");
+ await selectRowByURL("https://example.com/sponsored");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "rs_adm_sponsored",
+ selected_result_subtype: "",
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,rs_adm_sponsored",
+ },
+ ]);
+ });
+
+ cleanupQuickSuggest();
+});
+
+add_task(async function selected_result_adm_nonsponsored() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit();
+
+ await doTest(async browser => {
+ await openPopup("nonsponsored");
+ await selectRowByURL("https://example.com/nonsponsored");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "rs_adm_nonsponsored",
+ selected_result_subtype: "",
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,rs_adm_nonsponsored",
+ },
+ ]);
+ });
+
+ cleanupQuickSuggest();
+});
+
+add_task(async function selected_result_input_field() {
+ const expected = [
+ {
+ selected_result: "input_field",
+ selected_result_subtype: "",
+ 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();
+
+ await doTest(async browser => {
+ await openPopup(MerinoTestUtils.WEATHER_KEYWORD);
+ await selectRowByProvider("Weather");
+ await doEnter();
+
+ assertEngagementTelemetry([
+ {
+ selected_result: "weather",
+ selected_result_subtype: "",
+ provider: "Weather",
+ results: "search_engine,weather",
+ },
+ ]);
+ });
+
+ 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: "",
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,merino_top_picks",
+ },
+ ]);
+ });
+
+ 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: "",
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,merino_wikipedia",
+ },
+ ]);
+ });
+
+ 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: "",
+ 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: "",
+ 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: "",
+ 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: "",
+ provider: "UrlbarProviderQuickSuggest",
+ results: "search_engine,merino_amo",
+ },
+ ]);
+ });
+
+ cleanupQuickSuggest();
+ await SpecialPowers.popPrefEnv();
+});
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..104e292788
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_tips.js
@@ -0,0 +1,175 @@
+/* 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
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+ PromiseUtils: "resource://gre/modules/PromiseUtils.sys.mjs",
+});
+
+add_setup(async function () {
+ makeProfileResettable();
+
+ Services.fog.setMetricsFeatureConfig(
+ JSON.stringify({ "urlbar.engagement": false })
+ );
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.quickactions.enabled", false]],
+ });
+
+ registerCleanupFunction(async function () {
+ Services.fog.setMetricsFeatureConfig("{}");
+ 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 = PromiseUtils.defer();
+ 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() {
+ await doInterventionTest(
+ SEARCH_STRINGS.CLEAR,
+ "intervention_clear",
+ "chrome://browser/content/sanitize.xhtml",
+ [
+ {
+ 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..b2b2233b52
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_type.js
@@ -0,0 +1,151 @@
+/* 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
+
+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({
+ // eslint-disable-next-line mozilla/valid-lazy
+ config: lazy.QuickSuggestTestUtils.BEST_MATCH_CONFIG,
+ });
+
+ for (const isBestMatchTest of [true, false]) {
+ const prefs = isBestMatchTest
+ ? [
+ ["browser.urlbar.bestMatch.enabled", true],
+ ["browser.urlbar.bestMatch.blockingEnabled", true],
+ ["browser.urlbar.quicksuggest.blockingEnabled", false],
+ ]
+ : [
+ ["browser.urlbar.bestMatch.enabled", false],
+ ["browser.urlbar.bestMatch.blockingEnabled", false],
+ ["browser.urlbar.quicksuggest.blockingEnabled", true],
+ ];
+ await SpecialPowers.pushPrefEnv({ set: prefs });
+
+ await doTest(async browser => {
+ await openPopup("sponsored");
+
+ const originalResultCount = UrlbarTestUtils.getResultCount(window);
+ await selectRowByURL("https://example.com/sponsored");
+ if (UrlbarPrefs.get("resultMenu")) {
+ UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "D");
+ } else {
+ doClickSubButton(".urlbarView-button-block");
+ }
+ 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 SpecialPowers.popPrefEnv();
+ }
+
+ cleanupQuickSuggest();
+});
+
+add_task(async function engagement_type_help() {
+ const cleanupQuickSuggest = await ensureQuickSuggestInit();
+
+ for (const isBestMatchTest of [true, false]) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.bestMatch.enabled", isBestMatchTest]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("sponsored");
+ await selectRowByURL("https://example.com/sponsored");
+ const onTabOpened = BrowserTestUtils.waitForNewTab(gBrowser);
+ if (UrlbarPrefs.get("resultMenu")) {
+ UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "L");
+ } else {
+ doClickSubButton(".urlbarView-button-help");
+ }
+ const tab = await onTabOpened;
+ BrowserTestUtils.removeTab(tab);
+
+ assertEngagementTelemetry([{ engagement_type: "help" }]);
+ });
+
+ await SpecialPowers.popPrefEnv();
+ }
+
+ 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..7529f29455
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_exposure.js
@@ -0,0 +1,107 @@
+/* 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", "rs_adm_sponsored"],
+ ["browser.urlbar.showExposureResults", true],
+ ],
+ query: SPONSORED_QUERY,
+ trigger: () => doClick(),
+ assert: () => assertExposureTelemetry([{ results: "rs_adm_sponsored" }]),
+ });
+});
+
+add_task(async function exposureSponsoredOnAbandonment() {
+ await doExposureTest({
+ prefs: [
+ ["browser.urlbar.exposureResults", "rs_adm_sponsored"],
+ ["browser.urlbar.showExposureResults", true],
+ ],
+ query: SPONSORED_QUERY,
+ trigger: () => doBlur(),
+ assert: () => assertExposureTelemetry([{ results: "rs_adm_sponsored" }]),
+ });
+});
+
+add_task(async function exposureFilter() {
+ await doExposureTest({
+ prefs: [
+ ["browser.urlbar.exposureResults", "rs_adm_sponsored"],
+ ["browser.urlbar.showExposureResults", false],
+ ],
+ query: SPONSORED_QUERY,
+ select: async () => {
+ // assert that the urlbar has no results
+ Assert.equal(await getResultByType("rs_adm_sponsored"), null);
+ },
+ trigger: () => doBlur(),
+ assert: () => assertExposureTelemetry([{ results: "rs_adm_sponsored" }]),
+ });
+});
+
+add_task(async function innerQueryExposure() {
+ await doExposureTest({
+ prefs: [
+ ["browser.urlbar.exposureResults", "rs_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: "rs_adm_sponsored" }]),
+ });
+});
+
+add_task(async function innerQueryInvertedExposure() {
+ await doExposureTest({
+ prefs: [
+ ["browser.urlbar.exposureResults", "rs_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: "rs_adm_sponsored" }]),
+ });
+});
+
+add_task(async function multipleProviders() {
+ await doExposureTest({
+ prefs: [
+ [
+ "browser.urlbar.exposureResults",
+ "rs_adm_sponsored,rs_adm_nonsponsored",
+ ],
+ ["browser.urlbar.showExposureResults", true],
+ ],
+ query: NONSPONSORED_QUERY,
+ trigger: () => doClick(),
+ assert: () => assertExposureTelemetry([{ results: "rs_adm_nonsponsored" }]),
+ });
+});
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..199460e312
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_groups.js
@@ -0,0 +1,223 @@
+/* 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
+
+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 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,rs_adm_sponsored,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 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: "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..f783bf766c
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_interaction.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 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() {
+ // TODO: https://bugzilla.mozilla.org/show_bug.cgi?id=1804010
+ // assertImpressionTelemetry([{ 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_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..6760385841
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_record_preferences.js
@@ -0,0 +1,54 @@
+/* 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 prefSuggestTopsites() {
+ Assert.equal(
+ Glean.urlbar.prefSuggestTopsites.testGetValue(),
+ UrlbarPrefs.get("suggest.topsites"),
+ "Record prefSuggestTopsites when UrlbarController is initialized"
+ );
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.suggest.topsites", !UrlbarPrefs.get("suggest.topsites")],
+ ],
+ });
+ Assert.equal(
+ Glean.urlbar.prefSuggestTopsites.testGetValue(),
+ UrlbarPrefs.get("suggest.topsites"),
+ "Record prefSuggestTopsites when the suggest.topsites 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..4ce2c6f869
--- /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();
+ 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..b34221d749
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head-groups.js
@@ -0,0 +1,294 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+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 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({
+ // eslint-disable-next-line mozilla/valid-lazy
+ config: lazy.QuickSuggestTestUtils.BEST_MATCH_CONFIG,
+ });
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.bestMatch.enabled", true]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("sponsored");
+ await selectRowByURL("https://example.com/sponsored");
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+ 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 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 SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.bestMatch.enabled", false]],
+ });
+
+ await doTest(async browser => {
+ await openPopup("nonsponsored");
+ await selectRowByURL("https://example.com/nonsponsored");
+
+ await trigger();
+ await assert();
+ });
+
+ await SpecialPowers.popPrefEnv();
+ 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..6bc0fd3b0e
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head-interaction.js
@@ -0,0 +1,238 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+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 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..be4e852b1c
--- /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.loadURIString(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.loadURIString(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_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..fa623deb5c
--- /dev/null
+++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head.js
@@ -0,0 +1,458 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/browser/head-common.js",
+ this
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+ QuickSuggest: "resource:///modules/QuickSuggest.sys.mjs",
+});
+
+const lazy = {};
+
+XPCOMUtils.defineLazyGetter(lazy, "QuickSuggestTestUtils", () => {
+ const { QuickSuggestTestUtils: module } = ChromeUtils.importESModule(
+ "resource://testing-common/QuickSuggestTestUtils.sys.mjs"
+ );
+ module.init(this);
+ return module;
+});
+
+XPCOMUtils.defineLazyGetter(this, "MerinoTestUtils", () => {
+ const { MerinoTestUtils: module } = ChromeUtils.importESModule(
+ "resource://testing-common/MerinoTestUtils.sys.mjs"
+ );
+ module.init(this);
+ return module;
+});
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.sys.mjs",
+ sinon: "resource://testing-common/Sinon.sys.mjs",
+});
+
+async function addTopSites(url) {
+ for (let i = 0; i < 5; i++) {
+ await PlacesTestUtils.addVisits(url);
+ }
+ await updateTopSites(sites => {
+ return sites && sites[0] && sites[0].url == url;
+ });
+}
+
+function assertAbandonmentTelemetry(expectedExtraList) {
+ _assertGleanTelemetry("abandonment", expectedExtraList);
+}
+
+function assertEngagementTelemetry(expectedExtraList) {
+ _assertGleanTelemetry("engagement", expectedExtraList);
+}
+
+function assertImpressionTelemetry(expectedExtraList) {
+ _assertGleanTelemetry("impression", expectedExtraList);
+}
+
+function assertExposureTelemetry(expectedExtraList) {
+ _assertGleanTelemetry("exposure", expectedExtraList);
+}
+
+function _assertGleanTelemetry(telemetryName, expectedExtraList) {
+ const telemetries = Glean.urlbar[telemetryName].testGetValue() ?? [];
+ Assert.equal(
+ telemetries.length,
+ expectedExtraList.length,
+ "Telemetry event length matches expected event length."
+ );
+
+ for (let i = 0; i < telemetries.length; i++) {
+ const telemetry = telemetries[i];
+ Assert.equal(telemetry.category, "urlbar");
+ Assert.equal(telemetry.name, telemetryName);
+
+ const expectedExtra = expectedExtraList[i];
+ for (const key of Object.keys(expectedExtra)) {
+ Assert.equal(
+ telemetry.extra[key],
+ expectedExtra[key],
+ `${key} is correct`
+ );
+ }
+ }
+}
+
+async function ensureQuickSuggestInit({
+ merinoSuggestions = undefined,
+ config = undefined,
+} = {}) {
+ return lazy.QuickSuggestTestUtils.ensureQuickSuggestInit({
+ config,
+ merinoSuggestions,
+ remoteSettingsResults: [
+ {
+ type: "data",
+ attachment: [
+ {
+ id: 1,
+ url: "https://example.com/sponsored",
+ title: "Sponsored suggestion",
+ keywords: ["sponsored"],
+ click_url: "https://example.com/click",
+ impression_url: "https://example.com/impression",
+ advertiser: "TestAdvertiser",
+ iab_category: "22 - Shopping",
+ },
+ {
+ id: 2,
+ url: `https://example.com/nonsponsored`,
+ title: "Non-sponsored suggestion",
+ keywords: ["nonsponsored"],
+ click_url: "https://example.com/click",
+ impression_url: "https://example.com/impression",
+ advertiser: "TestAdvertiser",
+ iab_category: "5 - Education",
+ },
+ ],
+ },
+ {
+ type: "weather",
+ weather: MerinoTestUtils.WEATHER_RS_DATA,
+ },
+ ],
+ });
+}
+
+async function doBlur() {
+ await UrlbarTestUtils.promisePopupClose(window, () => {
+ gURLBar.blur();
+ });
+}
+
+async function doClick() {
+ const selected = UrlbarTestUtils.getSelectedRow(window);
+ const onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ EventUtils.synthesizeMouseAtCenter(selected, {});
+ await onLoad;
+}
+
+async function doClickSubButton(selector) {
+ const selected = UrlbarTestUtils.getSelectedElement(window);
+ const button = selected.closest(".urlbarView-row").querySelector(selector);
+ EventUtils.synthesizeMouseAtCenter(button, {});
+}
+
+async function doDropAndGo(data) {
+ const onLoad = BrowserTestUtils.browserLoaded(browser);
+ EventUtils.synthesizeDrop(
+ document.getElementById("back-button"),
+ gURLBar.inputField,
+ [[{ type: "text/plain", data }]],
+ "copy",
+ window
+ );
+ await onLoad;
+}
+
+async function doEnter(modifier = {}) {
+ const onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ EventUtils.synthesizeKey("KEY_Enter", modifier);
+ await onLoad;
+}
+
+async function doPaste(data) {
+ await SimpleTest.promiseClipboardChange(data, () => {
+ clipboardHelper.copyString(data);
+ });
+
+ gURLBar.focus();
+ gURLBar.select();
+ document.commandDispatcher
+ .getControllerForCommand("cmd_paste")
+ .doCommand("cmd_paste");
+ await UrlbarTestUtils.promiseSearchComplete(window);
+}
+
+async function doPasteAndGo(data) {
+ await SimpleTest.promiseClipboardChange(data, () => {
+ clipboardHelper.copyString(data);
+ });
+ const inputBox = gURLBar.querySelector("moz-input-box");
+ const contextMenu = inputBox.menupopup;
+ const onPopup = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {
+ type: "contextmenu",
+ button: 2,
+ });
+ await onPopup;
+ const onLoad = BrowserTestUtils.browserLoaded(browser);
+ const menuitem = inputBox.getMenuItem("paste-and-go");
+ contextMenu.activateItem(menuitem);
+ await onLoad;
+}
+
+async function doTest(testFn) {
+ await Services.fog.testFlushAllChildren();
+ Services.fog.testResetFOG();
+ // Enable recording telemetry for abandonment, engagement and impression.
+ Services.fog.setMetricsFeatureConfig(
+ JSON.stringify({
+ "urlbar.abandonment": true,
+ "urlbar.engagement": true,
+ "urlbar.impression": true,
+ })
+ );
+
+ gURLBar.controller.engagementEvent.reset();
+ await PlacesUtils.history.clear();
+ await PlacesUtils.bookmarks.eraseEverything();
+ await PlacesTestUtils.clearHistoryVisits();
+ await PlacesTestUtils.clearInputHistory();
+ await UrlbarTestUtils.formHistory.clear(window);
+ await QuickSuggest.blockedSuggestions.clear();
+ await QuickSuggest.blockedSuggestions._test_readyPromise;
+ await updateTopSites(() => true);
+
+ try {
+ await BrowserTestUtils.withNewTab(gBrowser, testFn);
+ } finally {
+ Services.fog.setMetricsFeatureConfig("{}");
+ }
+}
+
+async function initGroupTest() {
+ /* import-globals-from head-groups.js */
+ Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-groups.js",
+ this
+ );
+ await setup();
+}
+
+async function initInteractionTest() {
+ /* import-globals-from head-interaction.js */
+ Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-interaction.js",
+ this
+ );
+ await setup();
+}
+
+async function initNCharsAndNWordsTest() {
+ /* import-globals-from head-n_chars_n_words.js */
+ Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-n_chars_n_words.js",
+ this
+ );
+ await setup();
+}
+
+async function initSapTest() {
+ /* import-globals-from head-sap.js */
+ Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-sap.js",
+ this
+ );
+ await setup();
+}
+
+async function initSearchModeTest() {
+ /* import-globals-from head-search_mode.js */
+ Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-search_mode.js",
+ this
+ );
+ await setup();
+}
+
+async function initExposureTest() {
+ /* import-globals-from head-exposure.js */
+ Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-exposure.js",
+ this
+ );
+ await setup();
+}
+
+function loadOmniboxAddon({ keyword }) {
+ return ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["tabs"],
+ omnibox: {
+ keyword,
+ },
+ },
+ background() {
+ /* global browser */
+ browser.omnibox.setDefaultSuggestion({
+ description: "doit",
+ });
+ browser.omnibox.onInputEntered.addListener(() => {
+ browser.tabs.update({ url: "https://example.com/" });
+ });
+ browser.omnibox.onInputChanged.addListener((text, suggest) => {
+ suggest([]);
+ });
+ },
+ });
+}
+
+async function loadRemoteTab(url) {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.suggest.searches", false],
+ ["browser.urlbar.maxHistoricalSearchSuggestions", 0],
+ ["browser.urlbar.autoFill", false],
+ ["services.sync.username", "fake"],
+ ["services.sync.syncedTabs.showRemoteTabs", true],
+ ],
+ });
+
+ const REMOTE_TAB = {
+ id: "test",
+ type: "client",
+ lastModified: 1492201200,
+ name: "test",
+ clientType: "desktop",
+ tabs: [
+ {
+ type: "tab",
+ title: "tesrt",
+ url,
+ icon: UrlbarUtils.ICON.DEFAULT,
+ client: "test",
+ lastUsed: Math.floor(Date.now() / 1000),
+ },
+ ],
+ };
+
+ const sandbox = lazy.sinon.createSandbox();
+ // eslint-disable-next-line no-undef
+ const syncedTabs = SyncedTabs;
+ const originalSyncedTabsInternal = syncedTabs._internal;
+ syncedTabs._internal = {
+ isConfiguredToSyncTabs: true,
+ hasSyncedThisSession: true,
+ getTabClients() {
+ return Promise.resolve([]);
+ },
+ syncTabs() {
+ return Promise.resolve();
+ },
+ };
+ const weaveXPCService = Cc["@mozilla.org/weave/service;1"].getService(
+ Ci.nsISupports
+ ).wrappedJSObject;
+ const oldWeaveServiceReady = weaveXPCService.ready;
+ weaveXPCService.ready = true;
+ sandbox
+ .stub(syncedTabs._internal, "getTabClients")
+ .callsFake(() => Promise.resolve(Cu.cloneInto([REMOTE_TAB], {})));
+
+ return {
+ async unload() {
+ sandbox.restore();
+ weaveXPCService.ready = oldWeaveServiceReady;
+ syncedTabs._internal = originalSyncedTabsInternal;
+ // Reset internal cache in UrlbarProviderRemoteTabs.
+ Services.obs.notifyObservers(null, "weave:engine:sync:finish", "tabs");
+ await SpecialPowers.popPrefEnv();
+ },
+ };
+}
+
+async function openPopup(input) {
+ await UrlbarTestUtils.promisePopupOpen(window, async () => {
+ await UrlbarTestUtils.inputIntoURLBar(window, input);
+ });
+ await UrlbarTestUtils.promiseSearchComplete(window);
+}
+
+async function selectRowByURL(url) {
+ for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
+ const detail = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
+ if (detail.url === url) {
+ UrlbarTestUtils.setSelectedRowIndex(window, i);
+ return;
+ }
+ }
+}
+
+async function selectRowByProvider(provider) {
+ for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
+ const detail = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
+ if (detail.result.providerName === provider) {
+ UrlbarTestUtils.setSelectedRowIndex(window, i);
+ break;
+ }
+ }
+}
+
+async function selectRowByType(type) {
+ for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
+ const detail = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
+ if (detail.result.payload.type === type) {
+ UrlbarTestUtils.setSelectedRowIndex(window, i);
+ return;
+ }
+ }
+}
+
+async function setup() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.searchEngagementTelemetry.enabled", true],
+ ["browser.urlbar.quickactions.enabled", true],
+ ["browser.urlbar.quickactions.minimumSearchString", 0],
+ ["browser.urlbar.suggest.quickactions", true],
+ ["browser.urlbar.shortcuts.quickactions", true],
+ [
+ "browser.urlbar.searchEngagementTelemetry.pauseImpressionIntervalMs",
+ 100,
+ ],
+ ],
+ });
+
+ const engine = await SearchTestUtils.promiseNewSearchEngine({
+ url: "chrome://mochitests/content/browser/browser/components/urlbar/tests/browser/searchSuggestionEngine.xml",
+ });
+ const originalDefaultEngine = await Services.search.getDefault();
+ await Services.search.setDefault(
+ engine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ await Services.search.moveEngine(engine, 0);
+
+ registerCleanupFunction(async function () {
+ await SpecialPowers.popPrefEnv();
+ await Services.search.setDefault(
+ originalDefaultEngine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ });
+}
+
+async function setupNimbus(variables) {
+ return lazy.UrlbarTestUtils.initNimbusFeature(variables);
+}
+
+async function showResultByArrowDown() {
+ gURLBar.value = "";
+ gURLBar.select();
+ await UrlbarTestUtils.promisePopupOpen(window, () => {
+ EventUtils.synthesizeKey("KEY_ArrowDown");
+ });
+ await UrlbarTestUtils.promiseSearchComplete(window);
+}
+
+async function waitForPauseImpression() {
+ await new Promise(r =>
+ setTimeout(
+ r,
+ UrlbarPrefs.get("searchEngagementTelemetry.pauseImpressionIntervalMs")
+ )
+ );
+ await Services.fog.testFlushAllChildren();
+}