diff options
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.js | 353 |
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]; +} |