firefox-desktop/browser/components/search/test/unit/test_urlTelemetry_generic.js
2025-03-05 19:56:11 +01:00

472 lines
14 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
ChromeUtils.defineESModuleGetters(this, {
BrowserSearchTelemetry:
"moz-src:///browser/components/search/BrowserSearchTelemetry.sys.mjs",
NetUtil: "resource://gre/modules/NetUtil.sys.mjs",
SearchSERPTelemetry:
"moz-src:///browser/components/search/SearchSERPTelemetry.sys.mjs",
SearchSERPTelemetryUtils:
"moz-src:///browser/components/search/SearchSERPTelemetry.sys.mjs",
TelemetryTestUtils: "resource://testing-common/TelemetryTestUtils.sys.mjs",
sinon: "resource://testing-common/Sinon.sys.mjs",
});
const TEST_PROVIDER_INFO = [
{
telemetryId: "example",
searchPageRegexp: /^https:\/\/www\.example\.com\/search/,
queryParamNames: ["q"],
codeParamName: "abc",
taggedCodes: ["ff", "tb"],
expectedOrganicCodes: ["baz"],
organicCodes: ["foo"],
followOnParamNames: ["a"],
extraAdServersRegexps: [/^https:\/\/www\.example\.com\/ad2/],
shoppingTab: {
regexp: "&site=shop",
},
components: [
{
type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK,
default: true,
},
],
},
{
telemetryId: "example2",
searchPageRegexp: /^https:\/\/www\.example2\.com\/search/,
queryParamNames: ["a", "q"],
codeParamName: "abc",
taggedCodes: ["ff", "tb"],
expectedOrganicCodes: ["baz"],
organicCodes: ["foo"],
followOnParamNames: ["a"],
extraAdServersRegexps: [/^https:\/\/www\.example\.com\/ad2/],
components: [
{
type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK,
default: true,
},
],
},
{
telemetryId: "example3",
searchPageRegexp: /^https:\/\/www\.example3\.com\/search/,
queryParamNames: ["a", "q"],
codeParamName: "abc",
taggedCodes: ["ff", "tb"],
expectedOrganicCodes: ["baz"],
organicCodes: ["foo"],
followOnParamNames: ["a"],
followOnCookies: [
{
host: "www.example3.com",
name: "_dummyCookieName",
codeParamName: "abc",
extraCodePrefixes: ["xyz"],
extraCodeParamName: "dummyExtraCodeParamName",
},
],
extraAdServersRegexps: [/^https:\/\/www\.example\.com\/ad2/],
components: [
{
type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK,
default: true,
},
],
},
{
telemetryId: "example4",
searchPageRegexp: /^https:\/\/www\.example4\.com\/search/,
queryParamNames: ["a", "q"],
codeParamName: "abc",
taggedCodes: ["ff", "tb"],
expectedOrganicCodes: ["baz"],
organicCodes: ["foo"],
followOnParamNames: ["a"],
followOnCookies: [
{
host: "www.example4.com",
name: "_dummyCookieName",
codeParamName: "abc",
extraCodePrefixes: ["xyz"],
extraCodeParamName: "dummyExtraCodeParamName",
},
],
extraAdServersRegexps: [/^https:\/\/www\.example\.com\/ad2/],
components: [
{
type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK,
default: true,
},
],
},
];
const TESTS = [
{
title: "Tagged search",
trackingUrl: "https://www.example.com/search?q=test&abc=ff",
expectedSearchCountEntry: "example:tagged:ff",
expectedAdKey: "example:tagged",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example",
tagged: "true",
partner_code: "ff",
source: "unknown",
is_shopping_page: "false",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
{
title: "Tagged search with shopping",
trackingUrl: "https://www.example.com/search?q=test&abc=ff&site=shop",
expectedSearchCountEntry: "example:tagged:ff",
expectedAdKey: "example:tagged",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example",
tagged: "true",
partner_code: "ff",
source: "unknown",
is_shopping_page: "true",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
{
title: "Tagged follow-on",
trackingUrl: "https://www.example.com/search?q=test&abc=tb&a=next",
expectedSearchCountEntry: "example:tagged-follow-on:tb",
expectedAdKey: "example:tagged-follow-on",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example",
tagged: "true",
partner_code: "tb",
source: "unknown",
is_shopping_page: "false",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
{
setUp() {
Services.cookies.removeAll();
Services.cookies.add(
"www.example3.com",
"/",
"_dummyCookieName",
"abc=tb&def=ghi",
false,
false,
false,
Date.now() + 1000 * 60 * 60,
{},
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SCHEME_HTTPS
);
},
tearDown() {
Services.cookies.removeAll();
},
title: "Tagged follow-on with cookie",
trackingUrl:
"https://www.example3.com/search?q=test&a=next&dummyExtraCodeParamName=xyz",
expectedSearchCountEntry: "example3:tagged-follow-on:tb",
expectedAdKey: "example3:tagged-follow-on",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example3",
tagged: "true",
partner_code: "tb",
source: "unknown",
is_shopping_page: "false",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
{
setUp() {
Services.cookies.removeAll();
Services.cookies.add(
"www.example4.com",
"/",
"_dummyCookieName",
"abc=tb&def=ghi",
false,
false,
false,
Date.now() + 1000 * 60 * 60,
{},
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SCHEME_HTTPS
);
},
tearDown() {
Services.cookies.removeAll();
},
title:
"Tagged follow-on with cookie and unexpected extraCodeParam casing in URL",
trackingUrl:
"https://www.example4.com/search?q=test&a=next&DUMMYEXTRACODEPARAMNAME=xyz",
expectedSearchCountEntry: "example4:tagged-follow-on:tb",
expectedAdKey: "example4:tagged-follow-on",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example4",
tagged: "true",
partner_code: "tb",
source: "unknown",
is_shopping_page: "false",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
{
title: "Organic search matched code",
trackingUrl: "https://www.example.com/search?q=test&abc=foo",
expectedSearchCountEntry: "example:organic:foo",
expectedAdKey: "example:organic",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example",
tagged: "false",
partner_code: "foo",
source: "unknown",
is_shopping_page: "false",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
{
title: "Organic search non-matched code",
trackingUrl: "https://www.example.com/search?q=test&abc=ff123",
expectedSearchCountEntry: "example:organic:other",
expectedAdKey: "example:organic",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example",
tagged: "false",
partner_code: "other",
source: "unknown",
is_shopping_page: "false",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
{
title: "Organic search non-matched code 2",
trackingUrl: "https://www.example.com/search?q=test&abc=foo123",
expectedSearchCountEntry: "example:organic:other",
expectedAdKey: "example:organic",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example",
tagged: "false",
partner_code: "other",
source: "unknown",
is_shopping_page: "false",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
{
title: "Organic search expected organic matched code",
trackingUrl: "https://www.example.com/search?q=test&abc=baz",
expectedSearchCountEntry: "example:organic:none",
expectedAdKey: "example:organic",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example",
tagged: "false",
partner_code: "",
source: "unknown",
is_shopping_page: "false",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
{
title: "Organic search no codes",
trackingUrl: "https://www.example.com/search?q=test",
expectedSearchCountEntry: "example:organic:none",
expectedAdKey: "example:organic",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example",
tagged: "false",
partner_code: "",
source: "unknown",
is_shopping_page: "false",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
{
title: "Different engines using the same adUrl",
trackingUrl: "https://www.example2.com/search?q=test",
expectedSearchCountEntry: "example2:organic:none",
expectedAdKey: "example2:organic",
adUrls: ["https://www.example.com/ad2"],
nonAdUrls: ["https://www.example.com/ad3"],
impression: {
provider: "example2",
tagged: "false",
partner_code: "",
source: "unknown",
is_shopping_page: "false",
is_private: "false",
shopping_tab_displayed: "false",
is_signed_in: "false",
},
},
];
/**
* This function is primarily for testing the Ad URL regexps that are triggered
* when a URL is clicked on. These regexps are also used for the `withads`
* probe. However, we test the adclicks route as that is easier to hit.
*
* @param {string} serpUrl
* The url to simulate where the page the click came from.
* @param {string} adUrl
* The ad url to simulate being clicked.
* @param {string} [expectedAdKey]
* The expected key to be logged for the scalar. Omit if no scalar should be
* logged.
*/
async function testAdUrlClicked(serpUrl, adUrl, expectedAdKey) {
info(`Testing Ad URL: ${adUrl}`);
let channel = NetUtil.newChannel({
uri: NetUtil.newURI(adUrl),
triggeringPrincipal: Services.scriptSecurityManager.createContentPrincipal(
NetUtil.newURI(serpUrl),
{}
),
loadUsingSystemPrincipal: true,
});
SearchSERPTelemetry._contentHandler.observeActivity(
channel,
Ci.nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION,
Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE
);
// Since the content handler takes a moment to allow the channel information
// to settle down, wait the same amount of time here.
await new Promise(resolve => Services.tm.dispatchToMainThread(resolve));
const scalars = TelemetryTestUtils.getProcessScalars("parent", true, true);
if (!expectedAdKey) {
Assert.ok(
!("browser.search.adclicks.unknown" in scalars),
"Should not have recorded an ad click"
);
} else {
TelemetryTestUtils.assertKeyedScalar(
scalars,
"browser.search.adclicks.unknown",
expectedAdKey,
1
);
}
}
do_get_profile();
add_setup(async function () {
Services.fog.initializeFOG();
await SearchSERPTelemetry.init();
SearchSERPTelemetry.overrideSearchTelemetryForTests(TEST_PROVIDER_INFO);
sinon.stub(BrowserSearchTelemetry, "shouldRecordSearchCount").returns(true);
registerCleanupFunction(async () => {
sinon.restore();
});
});
add_task(async function test_parsing_search_urls() {
for (const test of TESTS) {
info(`Running ${test.title}`);
if (test.setUp) {
test.setUp();
}
let browser = {
getTabBrowser: () => {},
// There is no concept of browsing in unit tests, so assume in tests that we
// are not in private browsing mode. We have browser tests that check when
// private browsing is used.
contentPrincipal: {
originAttributes: {
privateBrowsingId: 0,
},
},
};
SearchSERPTelemetry.updateTrackingStatus(browser, test.trackingUrl);
SearchSERPTelemetry.reportPageImpression(
{
url: test.trackingUrl,
shoppingTabDisplayed: false,
},
browser
);
let scalars = TelemetryTestUtils.getProcessScalars("parent", true, true);
TelemetryTestUtils.assertKeyedScalar(
scalars,
"browser.search.content.unknown",
test.expectedSearchCountEntry,
1
);
if ("adUrls" in test) {
for (const adUrl of test.adUrls) {
await testAdUrlClicked(test.trackingUrl, adUrl, test.expectedAdKey);
}
for (const nonAdUrls of test.nonAdUrls) {
await testAdUrlClicked(test.trackingUrl, nonAdUrls);
}
}
let recordedEvents = Glean.serp.impression.testGetValue();
Assert.equal(
recordedEvents.length,
1,
"should only see one impression event"
);
// To allow deep equality.
test.impression.impression_id = recordedEvents[0].extra.impression_id;
Assert.deepEqual(recordedEvents[0].extra, test.impression);
if (test.tearDown) {
test.tearDown();
}
// We need to clear Glean events so they don't accumulate for each iteration.
Services.fog.testResetFOG();
}
});