Bug 1835321 - Allow any link on SERPs that don't match an ad expression to be considered a non-ad - r=Standard8

Differential Revision: https://phabricator.services.mozilla.com/D179367
This commit is contained in:
James Teow 2023-06-01 02:13:18 +00:00
Родитель f31d0a6ec2
Коммит b7663bfe8c
16 изменённых файлов: 681 добавлений и 295 удалений

Просмотреть файл

@ -67,9 +67,6 @@ class SearchProviders {
extraAdServersRegexps: p.extraAdServersRegexps.map(
r => new RegExp(r)
),
nonAdsLinkRegexps: p.nonAdsLinkRegexps?.length
? p.nonAdsLinkRegexps.map(r => new RegExp(r))
: [],
};
});
@ -388,13 +385,6 @@ class SearchAdImpression {
if (result.relatedElements?.length) {
this.#addEventListenerToElements(result.relatedElements, result.type);
}
// If an anchor doesn't match any component, and it doesn't have a non
// ads link regexp, cache the anchor so the parent process can observe
// them.
} else if (!this.#providerInfo.nonAdsLinkRegexps.length) {
this.#recordElementData(anchor, {
type: "non_ads_link",
});
}
}
}

Просмотреть файл

@ -925,9 +925,16 @@ class ContentHandler {
}
let wrappedChannel = ChannelWrapper.get(channel);
// The channel we're observing might be a redirect of a channel we've
// observed before.
if (wrappedChannel._adClickRecorded) {
lazy.logConsole.debug("Ad click already recorded");
return;
// When _adClickRecorded is false but _recordedClick is true, it means we
// recorded a non-ad link click, and it is being re-directed.
} else if (wrappedChannel._recordedClick) {
lazy.logConsole.debug("Non ad-click already recorded");
return;
}
Services.tm.dispatchToMainThread(() => {
@ -953,15 +960,35 @@ class ContentHandler {
return provider.telemetryId == providerInfo;
});
// The SERP "clicked" action is implied if a user loads another page from
// the context of a SERP. At this point, we don't know if the request is
// from a SERP but we want to avoid inspecting requests that are not
// documents, or not a top level load.
// Some channels re-direct by loading pages that return 200. The result
// is the channel will have an originURL that changes from the SERP to
// either a nonAdsRegexp or an extraAdServersRegexps. This is typical
// for loading a page in a new tab. The channel will have changed so any
// properties attached to them to record state (e.g. _recordedClick)
// won't be present.
if (
info.nonAdsLinkRegexps.some(r => r.test(originURL)) ||
info.extraAdServersRegexps.some(r => r.test(originURL))
) {
return;
}
// A click event is recorded if a user loads a resource from an
// originURL that is a SERP.
//
// Typically, we only want top level loads containing documents to avoid
// recording any event on an in-page resource a SERP might load
// (e.g. CSS files).
//
// The exception to this is if a subframe loads a resource that matches
// a non ad link. Some SERPs encode non ad search results with a URL
// that gets loaded into an iframe, which then tells the container of
// the iframe to change the location of the page.
if (
lazy.serpEventsEnabled &&
channel.isDocument &&
channel.loadInfo.isTopLevelLoad &&
!wrappedChannel._countedClick
(channel.loadInfo.isTopLevelLoad ||
info.nonAdsLinkRegexps.some(r => r.test(URL)))
) {
let start = Cu.now();
@ -1018,27 +1045,12 @@ class ContentHandler {
}
}
}
// Check if the href matches a non-ads link. Do this after looking at
// hrefToComponentMap because a link that looks like a non-ad might
// have a more specific component type.
// Default value for URLs that don't match any components categorized
// on the page.
if (!type) {
type = info.nonAdsLinkRegexps.some(r => r.test(URL))
? SearchSERPTelemetryUtils.COMPONENTS.NON_ADS_LINK
: "";
}
// The SERP may have moved onto another page that matches a SERP page
// e.g. Related Search
if (!type && isSerp) {
type = SearchSERPTelemetryUtils.COMPONENTS.NON_ADS_LINK;
}
// There might be other types of pages on a SERP that don't fall
// neatly into expected non-ad expressions or SERPs, such as Image
// Search, Maps, etc.
if (!type) {
type = info.extraPageRegexps?.some(r => r.test(URL))
? SearchSERPTelemetryUtils.COMPONENTS.NON_ADS_LINK
: "";
}
if (isSerp && isFromNewtab) {
SearchSERPTelemetry.setBrowserContentSource(
@ -1047,35 +1059,22 @@ class ContentHandler {
);
}
// Step 3: If we have a type, record an engagement.
// Exceptions:
// - Related searches on some SERPs can be encoded with a URL that
// match a nonAdsLinkRegexp. This means we'll have seen the link
// twice, once with the nonAdsLinkRegexp and again with a SERP URL
// matching a searchPageRegexp. We don't want to record the
// engagement twice, so if the origin of the request was
// nonAdsLinkRegexp, skip the categorization. The reason why we
// don't do this check earlier is because if the final URL is a
// SERP, we'll want to define the source property of the subsequent
// SERP impression.
if (type && !info.nonAdsLinkRegexps.some(r => r.test(originURL))) {
impressionIdsWithoutEngagementsSet.delete(
telemetryState.impressionId
);
Glean.serp.engagement.record({
impression_id: telemetryState.impressionId,
action: SearchSERPTelemetryUtils.ACTIONS.CLICKED,
target: type,
});
lazy.logConsole.debug("Counting click:", {
impressionId: telemetryState.impressionId,
type,
URL,
});
wrappedChannel._countedClick = true;
} else if (!type) {
lazy.logConsole.warn(`Could not find a component type for ${URL}`);
}
// Step 3: Record the engagement.
impressionIdsWithoutEngagementsSet.delete(
telemetryState.impressionId
);
Glean.serp.engagement.record({
impression_id: telemetryState.impressionId,
action: SearchSERPTelemetryUtils.ACTIONS.CLICKED,
target: type,
});
lazy.logConsole.debug("Counting click:", {
impressionId: telemetryState.impressionId,
type,
URL,
});
// Prevent re-directed channels from being examined more than once.
wrappedChannel._recordedClick = true;
}
ChromeUtils.addProfilerMarker(
"SearchSERPTelemetry._observeActivity",

Просмотреть файл

@ -99,13 +99,30 @@ tags = search-telemetry
support-files =
searchTelemetryAd_searchbox_with_content.html
searchTelemetryAd_searchbox_with_content.html^headers^
[browser_search_telemetry_engagement_non_ad.js]
tags = search-telemetry
support-files =
searchTelemetryAd_searchbox_with_content.html
searchTelemetryAd_searchbox_with_content.html^headers^
serp.css
[browser_search_telemetry_engagement_redirect.js]
tags = search-telemetry
support-files =
redirect_final.sjs
redirect_once.sjs
redirect_thrice.sjs
redirect_twice.sjs
searchTelemetryAd_adsLink_redirect.html
searchTelemetryAd_components_text.html
searchTelemetryAd_nonAdsLink_redirect.html
searchTelemetryAd_nonAdsLink_redirect.html^headers^
searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html
searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html^headers^
serp.css
[browser_search_telemetry_engagement_target.js]
tags = search-telemetry
support-files =
searchTelemetryAd_components_text.html
searchTelemetryAd_nonAdsLink_redirect.html
searchTelemetryAd_nonAdsLink_redirect.html^headers^
searchTelemetryAd_searchbox.html
searchTelemetryAd_searchbox.html^headers^
serp.css

Просмотреть файл

@ -19,9 +19,7 @@ const TEST_PROVIDER_INFO = [
codeParamName: "abc",
taggedCodes: ["ff"],
adServerAttributes: ["mozAttr"],
nonAdsLinkRegexps: [
/^https:\/\/example.com\/browser\/browser\/components\/search\/test\/browser\//,
],
nonAdsLinkRegexps: [],
extraAdServersRegexps: [/^https:\/\/example\.com\/ad/],
components: [
{

Просмотреть файл

@ -323,11 +323,8 @@ add_task(async function test_click_related_search_in_new_tab() {
BrowserTestUtils.removeTab(tab2);
});
// We consider regular expressions in nonAdsLinkRegexps and
// searchPageRegexp/extraPageRegexps as valid non ads links when recording
// an engagement event. However, if a nonAdsLinkRegexp leads to a
// searchPageRegexp/extraPageRegexps, than we risk double counting in the case
// of a re-direct occuring in a new tab.
// We consider regular expressions in nonAdsLinkRegexps and searchPageRegexp
// as valid non ads links when recording an engagement event.
add_task(async function test_click_redirect_search_in_newtab() {
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_searchbox_with_content.html");

Просмотреть файл

@ -0,0 +1,164 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* These tests load SERPs and click on links that are non ads. Non ads can have
* slightly different behavior from ads.
*/
"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: [],
extraAdServersRegexps: [/^https:\/\/example\.com\/ad/],
components: [
{
type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK,
default: 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"}`;
}
async function promiseImpressionReceived() {
return TestUtils.waitForCondition(() => {
let adImpressions = Glean.serp.adImpression.testGetValue() ?? [];
return adImpressions.length;
}, "Should have received an ad impression.");
}
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();
// Enable local telemetry recording for the duration of the tests.
await SpecialPowers.pushPrefEnv({
set: [
["browser.search.log", true],
["browser.search.serpEventTelemetry.enabled", true],
],
});
registerCleanupFunction(async () => {
SearchSERPTelemetry.overrideSearchTelemetryForTests();
resetTelemetry();
});
});
// If an anchor is a non_ads_link and it doesn't match a non-ads regular
// expression, it should still be categorize it as a non ad.
add_task(async function test_click_non_ads_link() {
await waitForIdle();
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_components_text.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
// Click a non ad.
let pageLoadPromise = BrowserTestUtils.waitForLocationChange(gBrowser);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#non_ads_link",
{},
tab.linkedBrowser
);
await pageLoadPromise;
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,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
// Reset state for other tests.
SearchSERPTelemetry.overrideSearchTelemetryForTests(TEST_PROVIDER_INFO);
await waitForIdle();
});
// Click on an non-ad element while no ads are present.
add_task(async function test_click_non_ad_with_no_ads() {
await waitForIdle();
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_searchbox.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
let browserLoadedPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser,
true,
"https://example.com/hello_world"
);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#non_ads_link",
{},
tab.linkedBrowser
);
await browserLoadedPromise;
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,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
// Reset state for other tests.
SearchSERPTelemetry.overrideSearchTelemetryForTests(TEST_PROVIDER_INFO);
await waitForIdle();
});

Просмотреть файл

@ -0,0 +1,346 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* These tests load SERPs and click on both ad and non-ad links that can be
* redirected.
*/
"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.org\/browser\/browser\/components\/search\/test\/browser\/searchTelemetryAd_nonAdsLink_redirect.html/,
],
extraAdServersRegexps: [
/^https:\/\/example\.com\/ad/,
/^https:\/\/example.org\/browser\/browser\/components\/search\/test\/browser\/searchTelemetryAd_adsLink_redirect.html/,
],
components: [
{
type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK,
default: 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"}`;
}
async function promiseImpressionReceived() {
return TestUtils.waitForCondition(() => {
let adImpressions = Glean.serp.adImpression.testGetValue() ?? [];
return adImpressions.length;
}, "Should have received an ad impression.");
}
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();
// Enable local telemetry recording for the duration of the tests.
await SpecialPowers.pushPrefEnv({
set: [
["browser.search.log", true],
["browser.search.serpEventTelemetry.enabled", true],
],
});
registerCleanupFunction(async () => {
SearchSERPTelemetry.overrideSearchTelemetryForTests();
resetTelemetry();
});
});
add_task(async function test_click_non_ads_link_redirected() {
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_components_text.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
let targetUrl = "https://example.com/hello_world";
let browserLoadedPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser,
true,
targetUrl
);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#non_ads_link_redirected",
{},
tab.linkedBrowser
);
await browserLoadedPromise;
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,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
});
// If a provider does a re-direct and we open it in a new tab, we should
// record the click and have the correct number of engagements.
add_task(async function test_click_non_ads_link_redirected_new_tab() {
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_components_text.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
let redirectUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.org"
) + "searchTelemetryAd_nonAdsLink_redirect.html";
let targetUrl = "https://example.com/hello_world";
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, targetUrl, true);
await SpecialPowers.spawn(tab.linkedBrowser, [redirectUrl], urls => {
content.document
.getElementById(["non_ads_link"])
.addEventListener("click", e => {
e.preventDefault();
content.window.open([urls], "_blank");
});
content.document.getElementById("non_ads_link").click();
});
let tab2 = await tabPromise;
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,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
BrowserTestUtils.removeTab(tab2);
});
// Some providers load a URL of a non ad within a subframe before loading the
// target website in the top level frame.
add_task(async function test_click_non_ads_link_redirect_non_top_level() {
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_components_text.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
let targetUrl = "https://example.com/hello_world";
let browserPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser,
true,
targetUrl
);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#non_ads_link_redirected_no_top_level",
{},
tab.linkedBrowser
);
await browserPromise;
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,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
});
add_task(async function test_multiple_redirects_non_ad_link() {
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_components_text.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
let targetUrl = "https://example.com/hello_world";
let browserLoadedPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser,
true,
targetUrl
);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#non_ads_link_multiple_redirects",
{},
tab.linkedBrowser
);
await browserLoadedPromise;
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,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
});
add_task(async function test_click_ad_link_redirected() {
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_components_text.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
let targetUrl = "https://example.com/hello_world";
let browserLoadedPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser,
true,
targetUrl
);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#ad_link_redirect",
{},
tab.linkedBrowser
);
await browserLoadedPromise;
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.AD_LINK,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
});
add_task(async function test_click_ad_link_redirected_new_tab() {
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_components_text.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
let targetUrl = "https://example.com/hello_world";
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, targetUrl, true);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#ad_link_redirect",
{ button: 1 },
tab.linkedBrowser
);
let tab2 = await tabPromise;
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.AD_LINK,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
BrowserTestUtils.removeTab(tab2);
});

Просмотреть файл

@ -22,7 +22,7 @@ const TEST_PROVIDER_INFO = [
taggedCodes: ["ff"],
adServerAttributes: ["mozAttr"],
nonAdsLinkRegexps: [
/^https:\/\/example.org\/browser\/browser\/components\/search\/test\/browser\/searchTelemetryAd_nonAdsLink_redirect/,
/^https:\/\/example.org\/browser\/browser\/components\/search\/test\/browser\/searchTelemetryAd_nonAdsLink_redirect.html/,
],
extraAdServersRegexps: [/^https:\/\/example\.com\/ad/],
components: [
@ -190,112 +190,6 @@ add_task(async function test_click_second_ad_in_component() {
BrowserTestUtils.removeTab(tab);
});
// If a provider does a re-direct and we open it in a new tab, we should
// record the click and have the correct number of engagements.
add_task(async function test_click_non_ads_link_redirected_new_tab() {
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_components_text.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
let redirectUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.org"
) + "searchTelemetryAd_nonAdsLink_redirect.html";
let targetUrl = "https://example.com/hello_world";
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, targetUrl, true);
await SpecialPowers.spawn(tab.linkedBrowser, [redirectUrl], urls => {
content.document
.getElementById(["non_ads_link"])
.addEventListener("click", e => {
e.preventDefault();
content.window.open([urls], "_blank");
});
content.document.getElementById("non_ads_link").click();
});
let tab2 = await tabPromise;
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,
},
],
},
]);
BrowserTestUtils.removeTab(tab2);
BrowserTestUtils.removeTab(tab);
});
// If a provider does a re-direct in the same tab, we may not be able to
// determine the component based on the URLs on the page, because the initial
// redirect URL won't be known, and by the time the page is loaded, the cached
// data might be invalidated. So this should use regular expressions to make
// an inference.
add_task(async function test_click_non_ads_link_redirected() {
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_components_text.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
let redirectUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.org"
) + "searchTelemetryAd_nonAdsLink_redirect.html";
let targetUrl = "https://example.com/hello_world";
let browserLoadedPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser,
true,
targetUrl
);
await SpecialPowers.spawn(tab.linkedBrowser, [redirectUrl], urls => {
content.document
.getElementById(["non_ads_link"])
.setAttribute("href", [urls]);
content.document.getElementById("non_ads_link").click();
});
await browserLoadedPromise;
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,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
});
// If a provider appends query parameters to a link after the page has been
// parsed, we should still be able to record the click.
add_task(async function test_click_ads_link_modified() {
@ -337,54 +231,6 @@ add_task(async function test_click_ads_link_modified() {
BrowserTestUtils.removeTab(tab);
});
// If an anchor is a non_ads_link and we don't have a matching regular
// expression, we should still be categorize it as non ads.
add_task(async function test_click_non_ads_link() {
SearchSERPTelemetry.overrideSearchTelemetryForTests(
TEST_PROVIDER_INFO_NO_NON_ADS_REGEXP
);
await waitForIdle();
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_components_text.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
// Click a non ad.
let pageLoadPromise = BrowserTestUtils.waitForLocationChange(gBrowser);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#non_ads_link",
{},
tab.linkedBrowser
);
await pageLoadPromise;
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,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
// Reset state for other tests.
SearchSERPTelemetry.overrideSearchTelemetryForTests(TEST_PROVIDER_INFO);
await waitForIdle();
});
// Search box is a special case which has to be tracked in the child process.
add_task(async function test_click_and_submit_incontent_searchbox() {
resetTelemetry();
@ -531,58 +377,6 @@ add_task(async function test_click_carousel_expand() {
BrowserTestUtils.removeTab(tab);
});
// Click on an non-ad element while no ads are present.
add_task(async function test_click_non_ad_with_no_ads() {
// Use a provider that doesn't a stored non-ads regexp.
SearchSERPTelemetry.overrideSearchTelemetryForTests(
TEST_PROVIDER_INFO_NO_NON_ADS_REGEXP
);
await waitForIdle();
resetTelemetry();
let url = getSERPUrl("searchTelemetryAd_searchbox.html");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await waitForPageWithAdImpressions();
let browserLoadedPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser,
true,
"https://example.com/hello_world"
);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#non_ads_link",
{},
tab.linkedBrowser
);
await browserLoadedPromise;
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,
},
],
},
]);
BrowserTestUtils.removeTab(tab);
// Reset state for other tests.
SearchSERPTelemetry.overrideSearchTelemetryForTests(TEST_PROVIDER_INFO);
await waitForIdle();
});
// This test clicks a link that has apostrophes in the both the path and list
// of query parameters, and uses search telemetry with no nonAdsRegexps defined,
// which will force us to cache every non ads link in a map and pass it back to

Просмотреть файл

@ -0,0 +1,9 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
function handleRequest(request, response) {
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", "https://example.com/hello_world", false);
}

Просмотреть файл

@ -0,0 +1,9 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
function handleRequest(request, response) {
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", "redirect_final.sjs", false);
}

Просмотреть файл

@ -0,0 +1,9 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
function handleRequest(request, response) {
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", "redirect_twice.sjs", false);
}

Просмотреть файл

@ -0,0 +1,9 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
function handleRequest(request, response) {
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", "redirect_once.sjs", false);
}

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page will do a redirect</title>
<meta content="0;url=https://example.com/hello_world" http-equiv="refresh">
</head>
<body>
</body>
</html>

Просмотреть файл

@ -15,7 +15,6 @@
<a href="https://example.com/ad/1">
<h2>Example Result</h2>
</a>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod.</p>
<span><a href="https://example.com/ad/2">Ad link that says there are 10 Locations nearby</a></span>
<div class="multi-col">
<div>
@ -47,10 +46,9 @@
</div>
<div class="moz_ad">
<h5 test-label>ad_link</h5>
<a href="https://example.com/ad/7">
<a id="ad_link_redirect" href="https://example.org/browser/browser/components/search/test/browser/searchTelemetryAd_adsLink_redirect.html">
<h2>Example Shop</h2>
</a>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod.</p>
<div class="factrow">
<a href="https://example.com/ad/8">Home Page</a>
<a href="https://example.com/ad/9">Products</a>
@ -62,23 +60,23 @@
<a href="https://example.com/ad/11">
<h2>Example Shop</h2>
</a>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod.</p>
<div class="factrow">
<a href="https://example.com/ad/12">Home Page</a>
<a href="https://example.com/ad/13">Products</a>
<a href="https://example.com/ad/14">Sales</a>
</div>
</div>
<div>
<h5 test-label>non_ads_link</h5>
<a id="non_ads_link" href="https://example.com/browser/browser/components/search/test/browser/cacheable.html">
<h2>Example of a cached non ad</h2>
</a>
</div>
<div>
<h5 test-label>non_ads_link</h5>
Example of a cached non ad
</a><br />
<a id="non_ads_link_redirected" href="https://example.org/browser/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect.html">
Example of a redirected non ad link
</a><br />
<a id="non_ads_link_redirected_no_top_level" href="#">
Example of a redirected non ad link that isn't initially top level loaded
</a><br />
<a id="non_ads_link_multiple_redirects" href="https://example.com/browser/browser/components/search/test/browser/redirect_thrice.sjs">
Example of a redirected non ad link that's redirected multiple times
</a><br />
<a id="non_ads_link_with_special_characters_in_path" href="https://example.com/path'?hello_world&foo=bar's">
<h2>Example of a non ad</h2>
Example of a non ad with special characters in path
</a>
</div>
</div>
@ -96,5 +94,19 @@
</div>
</div>
</section>
<iframe style="display: none;"></iframe>
<script>
window.addEventListener("message", (event) => {
if (event.origin == "https://example.org") {
window.location.href = event.data;
}
});
document.getElementById("non_ads_link_redirected_no_top_level")
.addEventListener("click", (event) => {
event.preventDefault();
let iframe = document.querySelector("iframe");
iframe.src = "https://example.org/browser/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html";
});
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page will do a redirect without doing it in a top load</title>
<!-- <meta content="0;url=https://example.com/hello_world" http-equiv="refresh"> -->
<script>
let parentWindow = window.parent;
let url = "https://example.com/hello_world";
parentWindow.postMessage(url, "*");
</script>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -0,0 +1,4 @@
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Content-Type: text/html; charset=ISO-8859-1