summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/tests/quicksuggest/browser/browser_telemetry_navigationalSuggestions.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/urlbar/tests/quicksuggest/browser/browser_telemetry_navigationalSuggestions.js')
-rw-r--r--browser/components/urlbar/tests/quicksuggest/browser/browser_telemetry_navigationalSuggestions.js353
1 files changed, 353 insertions, 0 deletions
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_telemetry_navigationalSuggestions.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_telemetry_navigationalSuggestions.js
new file mode 100644
index 0000000000..defb9bb76d
--- /dev/null
+++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_telemetry_navigationalSuggestions.js
@@ -0,0 +1,353 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * This file tests primary telemetry for navigational suggestions, a.k.a.
+ * navigational top picks.
+ */
+
+"use strict";
+
+const { TELEMETRY_SCALARS } = UrlbarProviderQuickSuggest;
+
+const MERINO_SUGGESTION = {
+ 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,
+};
+
+const suggestion_type = "navigational";
+const index = 1;
+const position = index + 1;
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ // `bestMatch.enabled` must be set to show nav suggestions with the best
+ // match UI treatment.
+ ["browser.urlbar.bestMatch.enabled", true],
+ // Disable tab-to-search since like best match it's also shown with
+ // `suggestedIndex` = 1.
+ ["browser.urlbar.suggest.engines", false],
+ ],
+ });
+
+ await setUpTelemetryTest({
+ merinoSuggestions: [MERINO_SUGGESTION],
+ });
+});
+
+// Clicks the heuristic when a nav suggestion is not matched
+add_task(async function notMatched_clickHeuristic() {
+ await doTest({
+ suggestion: null,
+ shouldBeShown: false,
+ pickRowIndex: 0,
+ scalars: {
+ [TELEMETRY_SCALARS.IMPRESSION_NAV_NOTMATCHED]: "search_engine",
+ [TELEMETRY_SCALARS.CLICK_NAV_NOTMATCHED]: "search_engine",
+ },
+ events: [],
+ });
+});
+
+// Clicks a non-heuristic row when a nav suggestion is not matched
+add_task(async function notMatched_clickOther() {
+ await PlacesTestUtils.addVisits("http://mochi.test:8888/example");
+ await doTest({
+ suggestion: null,
+ shouldBeShown: false,
+ pickRowIndex: 1,
+ scalars: {
+ [TELEMETRY_SCALARS.IMPRESSION_NAV_NOTMATCHED]: "search_engine",
+ },
+ events: [],
+ });
+});
+
+// Clicks the heuristic when a nav suggestion is shown
+add_task(async function shown_clickHeuristic() {
+ await doTest({
+ suggestion: MERINO_SUGGESTION,
+ shouldBeShown: true,
+ pickRowIndex: 0,
+ scalars: {
+ [TELEMETRY_SCALARS.IMPRESSION_NAV_SHOWN]: "search_engine",
+ [TELEMETRY_SCALARS.CLICK_NAV_SHOWN_HEURISTIC]: "search_engine",
+ },
+ events: [
+ {
+ category: QuickSuggest.TELEMETRY_EVENT_CATEGORY,
+ method: "engagement",
+ object: "impression_only",
+ extra: {
+ suggestion_type,
+ match_type: "best-match",
+ position: position.toString(),
+ source: "merino",
+ },
+ },
+ ],
+ });
+});
+
+// Clicks the nav suggestion
+add_task(async function shown_clickNavSuggestion() {
+ await doTest({
+ suggestion: MERINO_SUGGESTION,
+ shouldBeShown: true,
+ pickRowIndex: index,
+ scalars: {
+ [TELEMETRY_SCALARS.IMPRESSION_NAV_SHOWN]: "search_engine",
+ [TELEMETRY_SCALARS.CLICK_NAV_SHOWN_NAV]: "search_engine",
+ "urlbar.picked.navigational": "1",
+ },
+ events: [
+ {
+ category: QuickSuggest.TELEMETRY_EVENT_CATEGORY,
+ method: "engagement",
+ object: "click",
+ extra: {
+ suggestion_type,
+ match_type: "best-match",
+ position: position.toString(),
+ source: "merino",
+ },
+ },
+ ],
+ });
+});
+
+// Clicks a non-heuristic non-nav-suggestion row when the nav suggestion is
+// shown
+add_task(async function shown_clickOther() {
+ await PlacesTestUtils.addVisits("http://mochi.test:8888/example");
+ await doTest({
+ suggestion: MERINO_SUGGESTION,
+ shouldBeShown: true,
+ pickRowIndex: 2,
+ scalars: {
+ [TELEMETRY_SCALARS.IMPRESSION_NAV_SHOWN]: "search_engine",
+ },
+ events: [
+ {
+ category: QuickSuggest.TELEMETRY_EVENT_CATEGORY,
+ method: "engagement",
+ object: "impression_only",
+ extra: {
+ suggestion_type,
+ match_type: "best-match",
+ position: position.toString(),
+ source: "merino",
+ },
+ },
+ ],
+ });
+});
+
+// Clicks the heuristic when it dupes the nav suggestion
+add_task(async function duped_clickHeuristic() {
+ // Add enough visits to example.com so it autofills.
+ for (let i = 0; i < 5; i++) {
+ await PlacesTestUtils.addVisits("https://example.com/");
+ }
+
+ // Set the nav suggestion's URL to the same URL, example.com.
+ let suggestion = {
+ ...MERINO_SUGGESTION,
+ url: "https://example.com/",
+ };
+
+ await doTest({
+ suggestion,
+ shouldBeShown: false,
+ pickRowIndex: 0,
+ scalars: {
+ [TELEMETRY_SCALARS.IMPRESSION_NAV_SUPERCEDED]: "autofill_origin",
+ [TELEMETRY_SCALARS.CLICK_NAV_SUPERCEDED]: "autofill_origin",
+ },
+ events: [],
+ });
+});
+
+// Clicks a non-heuristic row when the heuristic dupes the nav suggestion
+add_task(async function duped_clickOther() {
+ // Add enough visits to example.com so it autofills.
+ for (let i = 0; i < 5; i++) {
+ await PlacesTestUtils.addVisits("https://example.com/");
+ }
+
+ // Set the nav suggestion's URL to the same URL, example.com.
+ let suggestion = {
+ ...MERINO_SUGGESTION,
+ url: "https://example.com/",
+ };
+
+ // Add a visit to another URL so it appears in the search below.
+ await PlacesTestUtils.addVisits("https://example.com/some-other-url");
+
+ await doTest({
+ suggestion,
+ shouldBeShown: false,
+ pickRowIndex: 1,
+ scalars: {
+ [TELEMETRY_SCALARS.IMPRESSION_NAV_SUPERCEDED]: "autofill_origin",
+ },
+ events: [],
+ });
+});
+
+// Telemetry specific to nav suggestions should not be recorded when the
+// `recordNavigationalSuggestionTelemetry` Nimbus variable is false.
+add_task(async function recordNavigationalSuggestionTelemetry_false() {
+ await doTest({
+ valueOverrides: {
+ recordNavigationalSuggestionTelemetry: false,
+ },
+ suggestion: MERINO_SUGGESTION,
+ shouldBeShown: true,
+ pickRowIndex: index,
+ scalars: {},
+ events: [
+ // The legacy engagement event should still be recorded as it is for all
+ // quick suggest results.
+ {
+ category: QuickSuggest.TELEMETRY_EVENT_CATEGORY,
+ method: "engagement",
+ object: "click",
+ extra: {
+ suggestion_type,
+ match_type: "best-match",
+ position: position.toString(),
+ source: "merino",
+ },
+ },
+ ],
+ });
+});
+
+// Telemetry specific to nav suggestions should not be recorded when the
+// `recordNavigationalSuggestionTelemetry` Nimbus variable is left out.
+add_task(async function recordNavigationalSuggestionTelemetry_undefined() {
+ await doTest({
+ valueOverrides: {},
+ suggestion: MERINO_SUGGESTION,
+ shouldBeShown: true,
+ pickRowIndex: index,
+ scalars: {},
+ events: [
+ // The legacy engagement event should still be recorded as it is for all
+ // quick suggest results.
+ {
+ category: QuickSuggest.TELEMETRY_EVENT_CATEGORY,
+ method: "engagement",
+ object: "click",
+ extra: {
+ suggestion_type,
+ match_type: "best-match",
+ position: position.toString(),
+ source: "merino",
+ },
+ },
+ ],
+ });
+});
+
+/**
+ * Does the following:
+ *
+ * 1. Sets up a Merino nav suggestion
+ * 2. Enrolls in a Nimbus experiment with the specified variables
+ * 3. Does a search
+ * 4. Makes sure the nav suggestion is or isn't shown as expected
+ * 5. Clicks a specified row
+ * 6. Makes sure the expected telemetry is recorded
+ *
+ * @param {object} options
+ * Options object
+ * @param {object} options.suggestion
+ * The nav suggestion or null if Merino shouldn't serve one.
+ * @param {boolean} options.shouldBeShown
+ * Whether the nav suggestion is expected to be shown.
+ * @param {number} options.pickRowIndex
+ * The index of the row to pick.
+ * @param {object} options.scalars
+ * An object that specifies the nav suggest keyed scalars that are expected to
+ * be recorded.
+ * @param {Array} options.events
+ * An object that specifies the legacy engagement events that are expected to
+ * be recorded.
+ * @param {object} options.valueOverrides
+ * The Nimbus variables to use.
+ */
+async function doTest({
+ suggestion,
+ shouldBeShown,
+ pickRowIndex,
+ scalars,
+ events,
+ valueOverrides = {
+ recordNavigationalSuggestionTelemetry: true,
+ },
+}) {
+ MerinoTestUtils.server.response.body.suggestions = suggestion
+ ? [suggestion]
+ : [];
+
+ Services.telemetry.clearEvents();
+ let { spy, spyCleanup } = QuickSuggestTestUtils.createTelemetryPingSpy();
+
+ await QuickSuggestTestUtils.withExperiment({
+ valueOverrides,
+ callback: async () => {
+ await BrowserTestUtils.withNewTab("about:blank", async () => {
+ gURLBar.focus();
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "example",
+ fireInputEvent: true,
+ });
+
+ if (shouldBeShown) {
+ await QuickSuggestTestUtils.assertIsQuickSuggest({
+ window,
+ index,
+ url: suggestion.url,
+ isBestMatch: true,
+ isSponsored: false,
+ });
+ } else {
+ await QuickSuggestTestUtils.assertNoQuickSuggestResults(window);
+ }
+
+ let loadPromise = BrowserTestUtils.browserLoaded(
+ gBrowser.selectedBrowser
+ );
+ if (pickRowIndex > 0) {
+ info("Arrowing down to row index " + pickRowIndex);
+ EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: pickRowIndex });
+ }
+ info("Pressing Enter and waiting for page load");
+ EventUtils.synthesizeKey("KEY_Enter");
+ await loadPromise;
+ });
+ },
+ });
+
+ info("Checking scalars");
+ QuickSuggestTestUtils.assertScalars(scalars);
+
+ info("Checking events");
+ QuickSuggestTestUtils.assertEvents(events);
+
+ info("Checking pings");
+ QuickSuggestTestUtils.assertPings(spy, []);
+
+ await spyCleanup();
+ await PlacesUtils.history.clear();
+ MerinoTestUtils.server.response.body.suggestions = [MERINO_SUGGESTION];
+}