From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- ...wser_search_telemetry_engagement_cached_serp.js | 239 +++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 browser/components/search/test/browser/browser_search_telemetry_engagement_cached_serp.js (limited to 'browser/components/search/test/browser/browser_search_telemetry_engagement_cached_serp.js') diff --git a/browser/components/search/test/browser/browser_search_telemetry_engagement_cached_serp.js b/browser/components/search/test/browser/browser_search_telemetry_engagement_cached_serp.js new file mode 100644 index 0000000000..26ebea5a56 --- /dev/null +++ b/browser/components/search/test/browser/browser_search_telemetry_engagement_cached_serp.js @@ -0,0 +1,239 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * These tests check when a SERP retrieves data from the BFCache as SERPs + * typically set their response headers with Cache-Control as private. + */ + +"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\/searchTelemetryAd_/, + queryParamName: "s", + codeParamName: "abc", + taggedCodes: ["ff"], + adServerAttributes: ["mozAttr"], + nonAdsLinkRegexps: [/^https:\/\/example.com/], + extraAdServersRegexps: [/^https:\/\/example\.com\/ad/], + components: [ + { + type: SearchSERPTelemetryUtils.COMPONENTS.INCONTENT_SEARCHBOX, + included: { + parent: { + selector: "form", + }, + children: [ + { + selector: "input", + }, + ], + related: { + selector: "div", + }, + }, + topDown: true, + }, + { + type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK, + default: true, + }, + ], + }, +]; + +function getSERPUrl(page, term) { + let url = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.org" + ) + page; + return `${url}?s=${term}`; +} + +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.log", true], + ["browser.search.serpEventTelemetry.enabled", true], + ], + }); + + registerCleanupFunction(async () => { + SearchSERPTelemetry.overrideSearchTelemetryForTests(); + resetTelemetry(); + }); +}); + +async function goBack(tab, callback = async () => {}) { + info("Go back."); + let pageShowPromise = BrowserTestUtils.waitForContentEvent( + tab.linkedBrowser, + "pageshow" + ); + tab.linkedBrowser.goBack(); + await pageShowPromise; + await callback(); +} + +async function goForward(tab, callback = async () => {}) { + info("Go forward."); + let pageShowPromise = BrowserTestUtils.waitForContentEvent( + tab.linkedBrowser, + "pageshow" + ); + tab.linkedBrowser.goForward(); + await pageShowPromise; + await callback(); +} + +// This test loads a cached SERP and checks returning to it and interacting +// with elements on the page don't count the events more than once. +// This is a proxy for ensuring we remove event listeners. +add_task(async function test_cached_serp() { + resetTelemetry(); + let url = getSERPUrl("searchTelemetryAd_searchbox.html"); + info("Load search page."); + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url); + await waitForPageWithAdImpressions(); + + for (let index = 0; index < 3; ++index) { + info("Load non-search page."); + let loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser, true); + BrowserTestUtils.loadURIString( + tab.linkedBrowser, + "https://www.example.com" + ); + await loadPromise; + await goBack(tab, async () => { + await waitForPageWithAdImpressions(); + }); + } + + info("Click on searchbox."); + await BrowserTestUtils.synthesizeMouseAtCenter( + "input", + {}, + tab.linkedBrowser + ); + + await Services.fog.testFlushAllChildren(); + let engagements = Glean.serp.engagement.testGetValue() ?? []; + Assert.equal( + engagements.length, + 1, + "There should be 1 engagement event recorded." + ); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_back_and_forward_serp_to_serp() { + await SpecialPowers.pushPrefEnv({ + // This has to be disabled or else using back and forward in the test won't + // trigger responses in the network listener in SearchSERPTelemetry. The + // page will still load from a BFCache. + set: [["fission.bfcacheInParent", false]], + }); + resetTelemetry(); + + let url = getSERPUrl("searchTelemetryAd_searchbox.html"); + info("Load search page."); + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url); + await waitForPageWithAdImpressions(); + + let loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false); + info("Click on a suggested search term."); + BrowserTestUtils.synthesizeMouseAtCenter("#suggest", {}, tab.linkedBrowser); + await loadPromise; + await waitForPageWithAdImpressions(); + + for (let index = 0; index < 3; ++index) { + info("Return to first search page."); + await goBack(tab, async () => { + await waitForPageWithAdImpressions(); + }); + info("Return to second search page."); + await goForward(tab, async () => { + await waitForPageWithAdImpressions(); + }); + } + + await Services.fog.testFlushAllChildren(); + let engagements = Glean.serp.engagement.testGetValue() ?? []; + let abandonments = Glean.serp.abandonment.testGetValue() ?? []; + Assert.equal(engagements.length, 1, "There should be 1 engagement."); + Assert.equal(abandonments.length, 6, "There should be 6 abandonments."); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async function test_back_and_forward_content_to_serp_to_serp() { + await SpecialPowers.pushPrefEnv({ + // This has to be disabled or else using back and forward in the test won't + // trigger responses in the network listener in SearchSERPTelemetry. The + // page will still load from a BFCache. + set: [["fission.bfcacheInParent", false]], + }); + resetTelemetry(); + + info("Load non-search page."); + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "https://www.example.com/" + ); + + info("Load search page."); + let url = getSERPUrl("searchTelemetryAd_searchbox.html"); + let loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser, true); + BrowserTestUtils.loadURIString(tab.linkedBrowser, url); + await loadPromise; + await waitForPageWithAdImpressions(); + + loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false); + info("Click on a suggested search term."); + BrowserTestUtils.synthesizeMouseAtCenter("#suggest", {}, tab.linkedBrowser); + await loadPromise; + await waitForPageWithAdImpressions(); + + info("Return to first search page."); + await goBack(tab, async () => { + await waitForPageWithAdImpressions(); + }); + + info("Return to non-search page."); + await goBack(tab); + + info("Return to first search page."); + await goForward(tab, async () => { + await waitForPageWithAdImpressions(); + }); + + info("Return to second search page."); + await goForward(tab, async () => { + await waitForPageWithAdImpressions(); + }); + + await Services.fog.testFlushAllChildren(); + let engagements = Glean.serp.engagement.testGetValue() ?? []; + let abandonments = Glean.serp.abandonment.testGetValue() ?? []; + Assert.equal(engagements.length, 1, "There should be 1 engagement."); + Assert.equal(abandonments.length, 3, "There should be 3 abandonments."); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); -- cgit v1.2.3