summaryrefslogtreecommitdiffstats
path: root/browser/components/search/test/browser/browser_search_telemetry_sources_in_content.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/search/test/browser/browser_search_telemetry_sources_in_content.js')
-rw-r--r--browser/components/search/test/browser/browser_search_telemetry_sources_in_content.js435
1 files changed, 435 insertions, 0 deletions
diff --git a/browser/components/search/test/browser/browser_search_telemetry_sources_in_content.js b/browser/components/search/test/browser/browser_search_telemetry_sources_in_content.js
new file mode 100644
index 0000000000..003b54cc8e
--- /dev/null
+++ b/browser/components/search/test/browser/browser_search_telemetry_sources_in_content.js
@@ -0,0 +1,435 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * SearchSERPTelemetry tests related to in-content sources.
+ */
+
+"use strict";
+
+const { SearchSERPTelemetry, SearchSERPTelemetryUtils } =
+ ChromeUtils.importESModule("resource:///modules/SearchSERPTelemetry.sys.mjs");
+
+const TEST_PROVIDER_INFO = [
+ {
+ telemetryId: "example",
+ searchPageRegexp:
+ /^https:\/\/example.org\/browser\/browser\/components\/search\/test\/browser\/searchTelemetry(?:Ad)?/,
+ queryParamName: "s",
+ codeParamName: "abc",
+ taggedCodes: ["ff"],
+ followOnParamNames: ["a"],
+ extraAdServersRegexps: [/^https:\/\/example\.com\/ad2?/],
+ components: [
+ {
+ type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK,
+ default: true,
+ },
+ {
+ type: SearchSERPTelemetryUtils.COMPONENTS.REFINED_SEARCH_BUTTONS,
+ included: {
+ parent: {
+ selector: ".refined-search-buttons",
+ },
+ children: [
+ {
+ selector: "a",
+ },
+ ],
+ },
+ topDown: true,
+ },
+ ],
+ },
+];
+
+function getSERPUrl(page, organic = false) {
+ let url =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.org"
+ ) + page;
+ return `${url}?s=test${organic ? "" : "&abc=ff"}`;
+}
+
+// sharedData messages are only passed to the child on idle. Therefore
+// we wait for a few idles to try and ensure the messages have been able
+// to be passed across and handled.
+async function waitForIdle() {
+ for (let i = 0; i < 10; i++) {
+ await new Promise(resolve => Services.tm.idleDispatchToMainThread(resolve));
+ }
+}
+
+add_setup(async function () {
+ SearchSERPTelemetry.overrideSearchTelemetryForTests(TEST_PROVIDER_INFO);
+ await waitForIdle();
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.search.serpEventTelemetry.enabled", true]],
+ });
+ // Enable local telemetry recording for the duration of the tests.
+ let oldCanRecord = Services.telemetry.canRecordExtended;
+ Services.telemetry.canRecordExtended = true;
+ Services.prefs.setBoolPref("browser.search.log", true);
+
+ registerCleanupFunction(async () => {
+ Services.prefs.clearUserPref("browser.search.log");
+ SearchSERPTelemetry.overrideSearchTelemetryForTests();
+ Services.telemetry.canRecordExtended = oldCanRecord;
+ resetTelemetry();
+ });
+});
+
+add_task(async function test_source_opened_in_new_tab_via_middle_click() {
+ resetTelemetry();
+ let url = getSERPUrl("searchTelemetryAd_searchbox_with_content.html");
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
+ await waitForPageWithAdImpressions();
+
+ let targetUrl =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.org"
+ ) + "searchTelemetryAd_searchbox_with_content.html?s=test+one+two+three";
+
+ let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, targetUrl, true);
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "a#related-in-page",
+ { button: 1 },
+ tab1.linkedBrowser
+ );
+ let tab2 = await tabPromise;
+
+ await TestUtils.waitForCondition(() => {
+ return Glean.serp.impression?.testGetValue()?.length == 2;
+ }, "Should have two impressions.");
+
+ assertImpressionEvents([
+ {
+ impression: {
+ provider: "example",
+ tagged: "true",
+ partner_code: "ff",
+ source: "unknown",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ engagements: [
+ {
+ action: SearchSERPTelemetryUtils.ACTIONS.CLICKED,
+ target: SearchSERPTelemetryUtils.COMPONENTS.NON_ADS_LINK,
+ },
+ ],
+ },
+ {
+ impression: {
+ provider: "example",
+ tagged: "false",
+ partner_code: "",
+ source: "opened_in_new_tab",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ },
+ ]);
+
+ BrowserTestUtils.removeTab(tab1);
+ BrowserTestUtils.removeTab(tab2);
+});
+
+add_task(async function test_source_opened_in_new_tab_via_target_blank() {
+ resetTelemetry();
+ let url = getSERPUrl("searchTelemetryAd_searchbox_with_content.html");
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
+ await waitForPageWithAdImpressions();
+
+ let targetUrl =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.org"
+ ) + "searchTelemetryAd_searchbox_with_content.html?s=test+one+two+three";
+
+ let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, targetUrl, true);
+ // Note: the anchor element with id "related-new-tab" has a target=_blank
+ // attribute.
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "a#related-new-tab",
+ {},
+ tab1.linkedBrowser
+ );
+ let tab2 = await tabPromise;
+
+ await TestUtils.waitForCondition(() => {
+ return Glean.serp.impression?.testGetValue()?.length == 2;
+ }, "Should have two impressions.");
+
+ assertImpressionEvents([
+ {
+ impression: {
+ provider: "example",
+ tagged: "true",
+ partner_code: "ff",
+ source: "unknown",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ engagements: [
+ {
+ action: SearchSERPTelemetryUtils.ACTIONS.CLICKED,
+ target: SearchSERPTelemetryUtils.COMPONENTS.NON_ADS_LINK,
+ },
+ ],
+ },
+ {
+ impression: {
+ provider: "example",
+ tagged: "false",
+ partner_code: "",
+ source: "opened_in_new_tab",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ },
+ ]);
+
+ BrowserTestUtils.removeTab(tab1);
+ BrowserTestUtils.removeTab(tab2);
+});
+
+add_task(async function test_source_opened_in_new_tab_via_context_menu() {
+ resetTelemetry();
+ let url = getSERPUrl("searchTelemetryAd_searchbox_with_content.html");
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
+ await waitForPageWithAdImpressions();
+
+ let targetUrl =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.org"
+ ) + "searchTelemetryAd_searchbox_with_content.html?s=test+one+two+three";
+
+ let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, targetUrl, true);
+
+ let contextMenu = document.getElementById("contentAreaContextMenu");
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ contextMenu,
+ "popupshown"
+ );
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "a#related-in-page",
+ {
+ button: 2,
+ type: "contextmenu",
+ },
+ tab1.linkedBrowser
+ );
+ await popupShownPromise;
+
+ let openLinkInNewTabMenuItem = contextMenu.querySelector(
+ "#context-openlinkintab"
+ );
+ contextMenu.activateItem(openLinkInNewTabMenuItem);
+
+ let tab2 = await tabPromise;
+
+ await TestUtils.waitForCondition(() => {
+ return Glean.serp.impression?.testGetValue()?.length == 2;
+ }, "Should have two impressions.");
+
+ assertImpressionEvents([
+ {
+ impression: {
+ provider: "example",
+ tagged: "true",
+ partner_code: "ff",
+ source: "unknown",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ engagements: [
+ {
+ action: SearchSERPTelemetryUtils.ACTIONS.CLICKED,
+ target: SearchSERPTelemetryUtils.COMPONENTS.NON_ADS_LINK,
+ },
+ ],
+ },
+ {
+ impression: {
+ provider: "example",
+ tagged: "false",
+ partner_code: "",
+ source: "opened_in_new_tab",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ },
+ ]);
+
+ BrowserTestUtils.removeTab(tab1);
+ BrowserTestUtils.removeTab(tab2);
+});
+
+add_task(
+ async function test_source_refinement_button_clicked_no_partner_code() {
+ resetTelemetry();
+ let url = getSERPUrl("searchTelemetryAd_searchbox_with_content.html");
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
+ await waitForPageWithAdImpressions();
+
+ let pageLoadPromise = BrowserTestUtils.waitForLocationChange(gBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "#refined-search-button",
+ {},
+ tab.linkedBrowser
+ );
+ await pageLoadPromise;
+
+ await TestUtils.waitForCondition(() => {
+ return Glean.serp.impression?.testGetValue()?.length == 2;
+ }, "Should have two impressions.");
+
+ assertImpressionEvents([
+ {
+ impression: {
+ provider: "example",
+ tagged: "true",
+ partner_code: "ff",
+ source: "unknown",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ engagements: [
+ {
+ action: SearchSERPTelemetryUtils.ACTIONS.CLICKED,
+ target: SearchSERPTelemetryUtils.COMPONENTS.REFINED_SEARCH_BUTTONS,
+ },
+ ],
+ },
+ {
+ impression: {
+ provider: "example",
+ tagged: "false",
+ partner_code: "",
+ source: "follow_on_from_refine_on_SERP",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ },
+ ]);
+
+ BrowserTestUtils.removeTab(tab);
+ }
+);
+
+add_task(
+ async function test_source_refinement_button_clicked_with_partner_code() {
+ resetTelemetry();
+ let url = getSERPUrl("searchTelemetryAd_searchbox_with_content.html");
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
+ await waitForPageWithAdImpressions();
+
+ let pageLoadPromise = BrowserTestUtils.waitForLocationChange(gBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "#refined-search-button-with-partner-code",
+ {},
+ tab.linkedBrowser
+ );
+ await pageLoadPromise;
+
+ await TestUtils.waitForCondition(() => {
+ return Glean.serp.impression?.testGetValue()?.length == 2;
+ }, "Should have two impressions.");
+
+ assertImpressionEvents([
+ {
+ impression: {
+ provider: "example",
+ tagged: "true",
+ partner_code: "ff",
+ source: "unknown",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ engagements: [
+ {
+ action: SearchSERPTelemetryUtils.ACTIONS.CLICKED,
+ target: SearchSERPTelemetryUtils.COMPONENTS.REFINED_SEARCH_BUTTONS,
+ },
+ ],
+ },
+ {
+ impression: {
+ provider: "example",
+ tagged: "true",
+ partner_code: "ff",
+ source: "follow_on_from_refine_on_SERP",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ },
+ ]);
+
+ BrowserTestUtils.removeTab(tab);
+ }
+);
+
+// When a user opens a refinement button link in a new tab, we want the
+// source to be recorded as "follow_on_from_refine_on_SERP", not
+// "opened_in_new_tab", since the refinement button click provides greater
+// context.
+add_task(async function test_refinement_button_vs_opened_in_new_tab() {
+ resetTelemetry();
+ let url = getSERPUrl("searchTelemetryAd_searchbox_with_content.html");
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
+ await waitForPageWithAdImpressions();
+
+ let targetUrl =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.org"
+ ) + "searchTelemetryAd_searchbox_with_content.html?s=test2&abc=ff";
+
+ let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, targetUrl, true);
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "#refined-search-button-with-partner-code",
+ { button: 1 },
+ tab1.linkedBrowser
+ );
+ let tab2 = await tabPromise;
+
+ await TestUtils.waitForCondition(() => {
+ return Glean.serp.impression?.testGetValue()?.length == 2;
+ }, "Should have two impressions.");
+
+ assertImpressionEvents([
+ {
+ impression: {
+ provider: "example",
+ tagged: "true",
+ partner_code: "ff",
+ source: "unknown",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ engagements: [
+ {
+ action: SearchSERPTelemetryUtils.ACTIONS.CLICKED,
+ target: SearchSERPTelemetryUtils.COMPONENTS.REFINED_SEARCH_BUTTONS,
+ },
+ ],
+ },
+ {
+ impression: {
+ provider: "example",
+ tagged: "true",
+ partner_code: "ff",
+ source: "follow_on_from_refine_on_SERP",
+ is_shopping_page: "false",
+ shopping_tab_displayed: "false",
+ },
+ },
+ ]);
+
+ BrowserTestUtils.removeTab(tab1);
+ BrowserTestUtils.removeTab(tab2);
+});