tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 6cbd287424755e3f5f8f4e9b7a62be569d476be5
parent 1f62a4baa46b33515d562911e17ed5b901c5cca2
Author: Nathan Barrett <nbarrett@mozilla.com>
Date:   Thu, 13 Nov 2025 19:25:42 +0000

Bug 1988552 - Set up attribution actor pair r=thecount,home-newtab-reviewers,mconley

Differential Revision: https://phabricator.services.mozilla.com/D265622

Diffstat:
Mbrowser/extensions/newtab/lib/ActivityStream.sys.mjs | 2++
Abrowser/extensions/newtab/lib/NewTabActorRegistry.sys.mjs | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/extensions/newtab/lib/NewTabAttributionFeed.sys.mjs | 17+++++++++--------
Mbrowser/extensions/newtab/lib/NewTabAttributionService.sys.mjs | 23+++++++++++++++--------
Abrowser/extensions/newtab/lib/actors/NewTabAttributionChild.sys.mjs | 13+++++++++++++
Abrowser/extensions/newtab/lib/actors/NewTabAttributionParent.sys.mjs | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/extensions/newtab/test/browser/browser.toml | 2++
Abrowser/extensions/newtab/test/browser/browser_attribution_actor.js | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/extensions/newtab/test/unit/lib/ActivityStream.test.js | 1+
Mbrowser/extensions/newtab/test/xpcshell/test_NewTabAttributionFeed.js | 9+++++++--
Mbrowser/extensions/newtab/test/xpcshell/test_NewTabAttributionService.js | 66+++++++++++++++++++++++++++++++++---------------------------------
11 files changed, 566 insertions(+), 51 deletions(-)

diff --git a/browser/extensions/newtab/lib/ActivityStream.sys.mjs b/browser/extensions/newtab/lib/ActivityStream.sys.mjs @@ -28,6 +28,7 @@ ChromeUtils.defineESModuleGetters(lazy, { HighlightsFeed: "resource://newtab/lib/HighlightsFeed.sys.mjs", ListsFeed: "resource://newtab/lib/Widgets/ListsFeed.sys.mjs", NewTabAttributionFeed: "resource://newtab/lib/NewTabAttributionFeed.sys.mjs", + NewTabActorRegistry: "resource://newtab/lib/NewTabActorRegistry.sys.mjs", NewTabInit: "resource://newtab/lib/NewTabInit.sys.mjs", NewTabMessaging: "resource://newtab/lib/NewTabMessaging.sys.mjs", NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs", @@ -1580,6 +1581,7 @@ export class ActivityStream { this._defaultPrefs.init(); Services.obs.addObserver(this, "intl:app-locales-changed"); Services.obs.addObserver(this, "browser-search-engine-modified"); + lazy.NewTabActorRegistry.init(); // Bug 1969587: Because our pref system does not support async getValue(), // we mirror the value of the BROWSER_URLBAR_PLACEHOLDERNAME pref into diff --git a/browser/extensions/newtab/lib/NewTabActorRegistry.sys.mjs b/browser/extensions/newtab/lib/NewTabActorRegistry.sys.mjs @@ -0,0 +1,61 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { ActorManagerParent } from "resource://gre/modules/ActorManagerParent.sys.mjs"; + +let attributionActorRegister = null; +let attributionActorUnregister = null; + +/** + * Fission-compatible JSWindowActor implementations. + * Detailed documentation of these options is in dom/docs/ipc/jsactors.rst, + * available at https://firefox-source-docs.mozilla.org/dom/ipc/jsactors.html + */ +const JSWINDOWACTORS = { + Attribution: { + parent: { + esModuleURI: + "resource://newtab/lib/actors/NewTabAttributionParent.sys.mjs", + }, + child: { + esModuleURI: + "resource://newtab/lib/actors/NewTabAttributionChild.sys.mjs", + events: { + FirefoxConversionNotification: { capture: true, wantUntrusted: true }, + }, + }, + allFrames: true, + matches: ["https://*/*", "about:newtab", "about:home"], + onAddActor(register, unregister) { + attributionActorRegister = register; + attributionActorUnregister = unregister; + }, + }, +}; + +export const NewTabActorRegistry = { + init() { + ActorManagerParent.addJSWindowActors(JSWINDOWACTORS); + }, + + /** + * Registers the Attribution actor to handle conversion events from advertiser websites. + * Called by NewTabAttributionFeed when attribution is enabled. + */ + registerAttributionActor() { + if (attributionActorRegister) { + attributionActorRegister(); + } + }, + + /** + * Unregisters the Attribution actor. + * Called by NewTabAttributionFeed when attribution is disabled. + */ + unregisterAttributionActor() { + if (attributionActorUnregister) { + attributionActorUnregister(); + } + }, +}; diff --git a/browser/extensions/newtab/lib/NewTabAttributionFeed.sys.mjs b/browser/extensions/newtab/lib/NewTabAttributionFeed.sys.mjs @@ -7,8 +7,9 @@ const lazy = {}; import { actionTypes as at } from "resource://newtab/common/Actions.mjs"; ChromeUtils.defineESModuleGetters(lazy, { - NewTabAttributionService: + newTabAttributionService: "resource://newtab/lib/NewTabAttributionService.sys.mjs", + NewTabActorRegistry: "resource://newtab/lib/NewTabActorRegistry.sys.mjs", }); const PREF_SYSTEM_ATTRIBUTION = "discoverystream.attribution.enabled"; @@ -66,17 +67,17 @@ export class NewTabAttributionFeed { } async init() { - this.attributionService = new lazy.NewTabAttributionService(); this.loaded = true; + lazy.NewTabActorRegistry.registerAttributionActor(); } uninit() { - this.attributionService = null; this.loaded = false; + lazy.NewTabActorRegistry.unregisterAttributionActor(); } async onPlacesHistoryCleared() { - await this.attributionService?.onAttributionReset(); + await lazy.newTabAttributionService.onAttributionReset(); } async onPrefChangedAction(action) { @@ -123,12 +124,12 @@ export class NewTabAttributionFeed { const item = action?.data || {}; if (item.attribution) { if (item.type === "impression") { - await this.attributionService.onAttributionEvent( + await lazy.newTabAttributionService.onAttributionEvent( "view", item.attribution ); } else if (item.type === "click") { - await this.attributionService.onAttributionEvent( + await lazy.newTabAttributionService.onAttributionEvent( "click", item.attribution ); @@ -140,7 +141,7 @@ export class NewTabAttributionFeed { if (this.loaded && this.isEnabled()) { const item = action?.data?.tiles?.[0] || {}; if (item.attribution) { - await this.attributionService.onAttributionEvent( + await lazy.newTabAttributionService.onAttributionEvent( "view", item.attribution ); @@ -151,7 +152,7 @@ export class NewTabAttributionFeed { if (this.loaded && this.isEnabled()) { const item = action?.data?.value || {}; if (item.attribution) { - await this.attributionService.onAttributionEvent( + await lazy.newTabAttributionService.onAttributionEvent( "click", item.attribution ); diff --git a/browser/extensions/newtab/lib/NewTabAttributionService.sys.mjs b/browser/extensions/newtab/lib/NewTabAttributionService.sys.mjs @@ -7,7 +7,7 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { IndexedDB: "resource://gre/modules/IndexedDB.sys.mjs", - DAPTelemetrySender: "resource://gre/modules/DAPTelemetrySender.sys.mjs", + DAPSender: "resource://gre/modules/DAPSender.sys.mjs", }); const MAX_CONVERSIONS = 5; @@ -18,7 +18,7 @@ const CONVERSION_RESET_MILLI = 7 * DAY_IN_MILLI; /** * */ -export class NewTabAttributionService { +class NewTabAttributionService { /** * @typedef { 'view' | 'click' | 'default' } matchType - Available matching methodologies for conversion events. * @@ -46,13 +46,13 @@ export class NewTabAttributionService { * @property {number} conversions - Number of conversions that have occurred in the budget period. * @property {number} nextReset - Timestamp in milliseconds for the end of the period this budget applies to. */ - #dapTelemetrySenderInternal; + #dapSenderInternal; #dateProvider; // eslint-disable-next-line no-unused-private-class-members #testDapOptions; - constructor({ dapTelemetrySender, dateProvider, testDapOptions } = {}) { - this.#dapTelemetrySenderInternal = dapTelemetrySender; + constructor({ dapSender, dateProvider, testDapOptions } = {}) { + this.#dapSenderInternal = dapSender; this.#dateProvider = dateProvider ?? Date; this.#testDapOptions = testDapOptions; @@ -68,8 +68,8 @@ export class NewTabAttributionService { }; } - get #dapTelemetrySender() { - return this.#dapTelemetrySenderInternal || lazy.DAPTelemetrySender; + get #dapSender() { + return this.#dapSenderInternal || lazy.DAPSender; } #now() { @@ -205,7 +205,7 @@ export class NewTabAttributionService { } await this.#updateBudget(budget, budgetSpend, partnerId); - await this.#dapTelemetrySender.sendDAPMeasurement( + await this.#dapSender.sendDAPMeasurement( conversion.task, measurement, {} @@ -403,3 +403,10 @@ export class NewTabAttributionService { return this.models[type] ?? this.models.default; } } + +const newTabAttributionService = new NewTabAttributionService(); + +export { + newTabAttributionService, + NewTabAttributionService as NewTabAttributionServiceClass, +}; diff --git a/browser/extensions/newtab/lib/actors/NewTabAttributionChild.sys.mjs b/browser/extensions/newtab/lib/actors/NewTabAttributionChild.sys.mjs @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +export class AttributionChild extends JSWindowActorChild { + handleEvent(event) { + if (event.type !== "FirefoxConversionNotification") { + return; + } + + this.sendAsyncMessage("AttributionEvent", { detail: event.detail }); + } +} diff --git a/browser/extensions/newtab/lib/actors/NewTabAttributionParent.sys.mjs b/browser/extensions/newtab/lib/actors/NewTabAttributionParent.sys.mjs @@ -0,0 +1,171 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// eslint-disable-next-line mozilla/use-static-import +const { newTabAttributionService } = ChromeUtils.importESModule( + "resource://newtab/lib/NewTabAttributionService.sys.mjs" +); + +const lazy = {}; + +ChromeUtils.defineLazyGetter(lazy, "logConsole", function () { + return console.createInstance({ + prefix: "NewTabAttributionParent", + maxLogLevel: "Warn", + }); +}); + +/** + * Allowed fields in the conversion event payload from advertisers. + * - partnerId: Mozilla-generated UUID associated with the advertiser + * - impressionType: How attribution should be determined (view/click/default) + * - lookbackDays: Number of days in the past to look for an attributable interaction (1, 7, 14, or 30) + */ +const CONVERSION_KEYS = new Set([ + "partnerId", + "impressionType", + "lookbackDays", +]); + +/** + * Checks if an object is a plain object (not null, not an array, not a function). + * This is necessary because JSWindowActor messages use structured clones, + * which have a different prototypes than normal objects + * + * @param {object} obj - The value to check. + * @returns {boolean} True if obj is a plain object, false otherwise. + */ +function isPlainObject(obj) { + return ( + typeof obj === "object" && + obj !== null && + !Array.isArray(obj) && + Object.prototype.toString.call(obj) === "[object Object]" + ); +} + +// RS collection: https://bugzilla.mozilla.org/show_bug.cgi?id=1994040 +// TODO: connect to RS collection when created +let gAllowList = new Set([]); + +/** + * Parent-side JSWindowActor for handling attribution conversion events. + * + * This actor receives FirefoxConversionNotification custom events from advertiser websites + * + * Upon successful validation, the conversion data is passed to NewTabAttributionService + */ +export class AttributionParent extends JSWindowActorParent { + /** + * TEST-ONLY: Override the allowlist from a test. + * + * @param {Array<string>} origins - Array of origin strings to allow. + */ + setAllowListForTest(origins = []) { + gAllowList = new Set(origins); + } + + /** + * Validates a conversion event payload from an advertiser. + * Ensures all required fields are present, correctly typed, and within valid ranges. + * + * @param {*} data - The conversion data to validate. + * @returns {object|null} The validated conversion data object, or null if validation fails. + * + * Validation checks: + * - Must be a plain object + * - Must contain only allowed keys (partnerId, impressionType, lookbackDays) + * - partnerId: must be a non-empty string + * - impressionType: must be a string + * - lookbackDays: must be a positive number + */ + validateConversion(data) { + // confirm that data is an object + if (!isPlainObject(data)) { + return null; + } + + // Check that only allowed keys are present + for (const key of Object.keys(data)) { + if (!CONVERSION_KEYS.has(key)) { + return null; + } + } + + // Validate required fields are present + if ( + !data.partnerId || + !data.impressionType || + data.lookbackDays === undefined + ) { + return null; + } + + // Validate types + if (typeof data.partnerId !== "string") { + return null; + } + + if (typeof data.impressionType !== "string") { + return null; + } + + if (typeof data.lookbackDays !== "number" || data.lookbackDays <= 0) { + return null; + } + + return data; + } + + /** + * Receives and processes conversion event messages from the child actor. + * This method is called when a FirefoxConversionNotification custom event is triggered + * on an advertiser's website. + * + * @param {object} message - The message from the child actor. + * @param {object} message.data - The message data. + * @param {object} message.data.detail - The custom event detail. + * @param {object} message.data.detail.conversion - The conversion payload. + * @returns {Promise} + */ + async receiveMessage(message) { + let principal = this.manager.documentPrincipal; + + // Only accept conversion events from secure origins (HTTPS) + if (!principal.isOriginPotentiallyTrustworthy) { + lazy.logConsole.error( + `AttributionParent: conversion events must be sent over HTTPS` + ); + return; + } + + // Only accept conversion events from allowlisted origins + if (!gAllowList.has(principal.originNoSuffix)) { + lazy.logConsole.error( + `AttributionParent: conversion events must come from the allow list` + ); + return; + } + + const { detail } = message.data || {}; + + if (detail) { + const validatedConversion = this.validateConversion(detail); + + if (!validatedConversion) { + lazy.logConsole.error( + `AttributionParent: rejected invalid conversion payload from ${principal}` + ); + return; + } + + const { partnerId, lookbackDays, impressionType } = validatedConversion; + await newTabAttributionService.onAttributionConversion( + partnerId, + lookbackDays, + impressionType + ); + } + } +} diff --git a/browser/extensions/newtab/test/browser/browser.toml b/browser/extensions/newtab/test/browser/browser.toml @@ -33,6 +33,8 @@ skip-if = ["os == 'win' && os_version == '11.26100' && verify-standalone"] ["browser_as_render.js"] +["browser_attribution_actor.js"] + ["browser_context_menu_item.js"] ["browser_customize_menu_content.js"] diff --git a/browser/extensions/newtab/test/browser/browser_attribution_actor.js b/browser/extensions/newtab/test/browser/browser_attribution_actor.js @@ -0,0 +1,252 @@ +/* Public Domain — http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + sinon: "resource://testing-common/Sinon.sys.mjs", + NewTabActorRegistry: "resource://newtab/lib/NewTabActorRegistry.sys.mjs", + newTabAttributionService: + "resource://newtab/lib/NewTabAttributionService.sys.mjs", + NewTabAttributionServiceClass: + "resource://newtab/lib/NewTabAttributionService.sys.mjs", +}); + +const { DAPSender } = ChromeUtils.importESModule( + "resource://gre/modules/DAPSender.sys.mjs" +); + +let sandbox; +let dapStub; +let conversionStub; + +async function resetDatabase() { + await newTabAttributionService.onAttributionReset(); +} + +async function viewImpression({ partnerId, allocation }) { + await newTabAttributionService.onAttributionEvent("view", { + partner_id: partnerId, + conversion: { + task_id: allocation.task_id, + vdaf: allocation.vdaf, + bits: allocation.bits, + length: allocation.length, + time_precision: allocation.time_precision, + default_measurement: allocation.default_measurement, + index: allocation.index, + }, + }); +} + +const TEST_URL = "https://example.com/"; + +async function getParentActor(browser) { + return browser.browsingContext.currentWindowGlobal.getActor("Attribution"); +} + +/** + * Helper to dispatch a FirefoxConversionNotification event in the content process. + * + * @param {Browser} browser - The browser element + * @param {object} detail - The detail object to pass to the event + */ +async function dispatchAttributionEvent(browser, detail) { + await SpecialPowers.spawn(browser, [detail], function (contentDetail) { + let event = new content.CustomEvent("FirefoxConversionNotification", { + detail: contentDetail, + bubbles: true, + }); + content.dispatchEvent(event); + }); +} + +add_setup(async function () { + // enable gating so registry will register the actor + await SpecialPowers.pushPrefEnv({ + set: [ + [ + "browser.newtabpage.activity-stream.discoverystream.attribution.enabled", + true, + ], + ["browser.newtabpage.activity-stream.feeds.topsites", true], + ["browser.newtabpage.activity-stream.feeds.system.topsites", true], + ["browser.newtabpage.activity-stream.showSponsoredTopSites", true], + ["browser.newtabpage.activity-stream.unifiedAds.tiles.enabled", true], + ["browser.newtab.preload", false], + ["browser.newtabpage.activity-stream.prerender", false], + ], + }); + + sandbox = sinon.createSandbox(); + dapStub = sandbox.stub(DAPSender, "sendDAPMeasurement"); + conversionStub = sandbox.stub( + NewTabAttributionServiceClass.prototype, + "onAttributionConversion" + ); + + registerCleanupFunction(async () => { + await resetDatabase(); + sandbox.restore(); + await SpecialPowers.popPrefEnv(); + }); +}); + +/** + * Helper to reset the allowlist before each test. + */ +async function setAllowList(allowList = []) { + // Open a temporary tab to get an actor and reset the allowlist + await BrowserTestUtils.withNewTab(TEST_URL, async browser => { + const parent = await getParentActor(browser); + parent.setAllowListForTest(allowList); + }); +} + +/** + * Reset test state before each test. + */ +async function resetTestState() { + await resetDatabase(); + await setAllowList(); + if (conversionStub) { + conversionStub.resetHistory(); + } +} + +/** + * Test that onAttributionConversion is called with a valid payload + * from an allowlisted origin. + */ +add_task(async function test_parent_calls_onAttributionConversion() { + await resetTestState(); + dapStub.resetHistory(); + + const partnerId = "expedia"; + const lookbackDays = 7; + const impressionType = "view"; + + const allocation = { + task_id: "task-123", + vdaf: "sum", + bits: 8, + length: 4, + time_precision: 1, + default_measurement: 0, + index: 2, + }; + + await viewImpression({ partnerId, allocation }); + + await BrowserTestUtils.withNewTab(TEST_URL, async browser => { + const parent = await getParentActor(browser); + const origin = parent.manager.documentPrincipal.originNoSuffix; + parent.setAllowListForTest([origin]); + + await dispatchAttributionEvent(browser, { + partnerId, + lookbackDays, + impressionType, + }); + + Assert.ok( + conversionStub.calledOnce, + "onAttributionConversion was called once" + ); + Assert.ok( + conversionStub.calledWith(partnerId, lookbackDays, impressionType), + "onAttributionConversion was called with correct arguments" + ); + }); +}); + +/** + * Test that onAttributionConversion is NOT called when origin + * is not in allowlist. + */ +add_task(async function test_parent_blocks_non_allowlisted_origin() { + await resetTestState(); + + const partnerId = "expedia"; + const lookbackDays = 7; + const impressionType = "view"; + + await BrowserTestUtils.withNewTab(TEST_URL, async browser => { + await dispatchAttributionEvent(browser, { + partnerId, + lookbackDays, + impressionType, + }); + Assert.ok(!conversionStub.called, "onAttributionConversion was not called"); + }); +}); + +/** + * Test that onAttributionConversion is NOT called with invalid + * conversion data (extra keys). + */ +add_task(async function test_parent_blocks_invalid_conversion_extra_keys() { + await resetTestState(); + + await BrowserTestUtils.withNewTab(TEST_URL, async browser => { + const parent = await getParentActor(browser); + const origin = parent.manager.documentPrincipal.originNoSuffix; + parent.setAllowListForTest([origin]); + + await dispatchAttributionEvent(browser, { + partnerId: "expedia", + lookbackDays: 7, + impressionType: "view", + extraKey: "should-be-rejected", // Invalid extra key + }); + + Assert.ok(!conversionStub.called, "onAttributionConversion was not called"); + }); +}); + +/** + * Test that onAttributionConversion is NOT called when conversion + * is not an object. + */ +add_task(async function test_parent_blocks_non_object_conversion() { + await resetTestState(); + + await BrowserTestUtils.withNewTab(TEST_URL, async browser => { + const parent = await getParentActor(browser); + const origin = parent.manager.documentPrincipal.originNoSuffix; + parent.setAllowListForTest([origin]); + + // Test with string + await dispatchAttributionEvent(browser, "not-an-object"); + + Assert.ok(!conversionStub.called, "onAttributionConversion was not called"); + + // Test with array + await dispatchAttributionEvent(browser, ["array"]); + + Assert.ok(!conversionStub.called, "onAttributionConversion was not called"); + }); +}); + +/** + * Test that onAttributionConversion is NOT called when + * message.data.detail is missing. + */ +add_task(async function test_parent_blocks_missing_detail() { + await resetTestState(); + + await BrowserTestUtils.withNewTab(TEST_URL, async browser => { + const parent = await getParentActor(browser); + const origin = parent.manager.documentPrincipal.originNoSuffix; + parent.setAllowListForTest([origin]); + + // Test with undefined detail + await dispatchAttributionEvent(browser, undefined); + + Assert.ok(!conversionStub.called, "onAttributionConversion was not called"); + + // Test with empty detail object + await dispatchAttributionEvent(browser, {}); + + Assert.ok(!conversionStub.called, "onAttributionConversion was not called"); + }); +}); diff --git a/browser/extensions/newtab/test/unit/lib/ActivityStream.test.js b/browser/extensions/newtab/test/unit/lib/ActivityStream.test.js @@ -41,6 +41,7 @@ describe("ActivityStream", () => { DEFAULT_SITES, AboutPreferences, DefaultPrefs, + NewTabActorRegistry: { init: () => {} }, NewTabInit, SectionsFeed, RecommendationProvider, diff --git a/browser/extensions/newtab/test/xpcshell/test_NewTabAttributionFeed.js b/browser/extensions/newtab/test/xpcshell/test_NewTabAttributionFeed.js @@ -6,6 +6,8 @@ ChromeUtils.defineESModuleGetters(this, { actionTypes: "resource://newtab/common/Actions.mjs", NewTabAttributionFeed: "resource://newtab/lib/NewTabAttributionFeed.sys.mjs", + newTabAttributionService: + "resource://newtab/lib/NewTabAttributionService.sys.mjs", sinon: "resource://testing-common/Sinon.sys.mjs", }); @@ -82,9 +84,9 @@ add_task(async function test_events_when_enabled() { Assert.ok(feed.loaded); const onAttributionEvent = sinon - .stub(feed.attributionService, "onAttributionEvent") + .stub(newTabAttributionService, "onAttributionEvent") .resolves(); - const onReset = sinon.stub(feed.attributionService, "onAttributionReset"); + const onReset = sinon.stub(newTabAttributionService, "onAttributionReset"); const attribution = { campaignId: "bar", creativeId: "bar" }; @@ -125,6 +127,9 @@ add_task(async function test_events_when_enabled() { // History cleared await feed.onAction({ type: actionTypes.PLACES_HISTORY_CLEARED }); Assert.ok(onReset.calledOnce); + + onAttributionEvent.restore(); + onReset.restore(); }); add_task(async function test_pref_changed_trigger_init() { diff --git a/browser/extensions/newtab/test/xpcshell/test_NewTabAttributionService.js b/browser/extensions/newtab/test/xpcshell/test_NewTabAttributionService.js @@ -4,7 +4,7 @@ https://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; ChromeUtils.defineESModuleGetters(this, { - NewTabAttributionService: + NewTabAttributionServiceClass: "resource://newtab/lib/NewTabAttributionService.sys.mjs", }); @@ -41,7 +41,7 @@ class MockDateProvider { } } -class MockDAPTelemetrySender { +class MockDAPSender { constructor() { this.receivedMeasurements = []; } @@ -104,9 +104,9 @@ add_setup(async function () { }); add_task(async function testSuccessfulConversion() { - const mockSender = new MockDAPTelemetrySender(); - const privateAttribution = new NewTabAttributionService({ - dapTelemetrySender: mockSender, + const mockSender = new MockDAPSender(); + const privateAttribution = new NewTabAttributionServiceClass({ + dapSender: mockSender, }); const partnerIdentifier = "partner_identifier"; @@ -153,9 +153,9 @@ add_task(async function testSuccessfulConversion() { }); add_task(async function testConversionWithoutImpression() { - const mockSender = new MockDAPTelemetrySender(); - const privateAttribution = new NewTabAttributionService({ - dapTelemetrySender: mockSender, + const mockSender = new MockDAPSender(); + const privateAttribution = new NewTabAttributionServiceClass({ + dapSender: mockSender, }); const partnerIdentifier = "partner_identifier_no_impression"; @@ -170,9 +170,9 @@ add_task(async function testConversionWithoutImpression() { }); add_task(async function testConversionWithInvalidLookbackDays() { - const mockSender = new MockDAPTelemetrySender(); - const privateAttribution = new NewTabAttributionService({ - dapTelemetrySender: mockSender, + const mockSender = new MockDAPSender(); + const privateAttribution = new NewTabAttributionServiceClass({ + dapSender: mockSender, }); const partnerIdentifier = "partner_identifier"; @@ -201,10 +201,10 @@ add_task(async function testConversionWithInvalidLookbackDays() { }); add_task(async function testSelectionByLastView() { - const mockSender = new MockDAPTelemetrySender(); + const mockSender = new MockDAPSender(); const mockDateProvider = new MockDateProvider(); - const privateAttribution = new NewTabAttributionService({ - dapTelemetrySender: mockSender, + const privateAttribution = new NewTabAttributionServiceClass({ + dapSender: mockSender, dateProvider: mockDateProvider, }); @@ -268,10 +268,10 @@ add_task(async function testSelectionByLastView() { }); add_task(async function testSelectionByLastClick() { - const mockSender = new MockDAPTelemetrySender(); + const mockSender = new MockDAPSender(); const mockDateProvider = new MockDateProvider(); - const privateAttribution = new NewTabAttributionService({ - dapTelemetrySender: mockSender, + const privateAttribution = new NewTabAttributionServiceClass({ + dapSender: mockSender, dateProvider: mockDateProvider, }); @@ -335,10 +335,10 @@ add_task(async function testSelectionByLastClick() { }); add_task(async function testSelectionByLastTouch() { - const mockSender = new MockDAPTelemetrySender(); + const mockSender = new MockDAPSender(); const mockDateProvider = new MockDateProvider(); - const privateAttribution = new NewTabAttributionService({ - dapTelemetrySender: mockSender, + const privateAttribution = new NewTabAttributionServiceClass({ + dapSender: mockSender, dateProvider: mockDateProvider, }); @@ -389,10 +389,10 @@ add_task(async function testSelectionByLastTouch() { }); add_task(async function testSelectionByPartnerId() { - const mockSender = new MockDAPTelemetrySender(); + const mockSender = new MockDAPSender(); const mockDateProvider = new MockDateProvider(); - const privateAttribution = new NewTabAttributionService({ - dapTelemetrySender: mockSender, + const privateAttribution = new NewTabAttributionServiceClass({ + dapSender: mockSender, dateProvider: mockDateProvider, }); @@ -444,10 +444,10 @@ add_task(async function testSelectionByPartnerId() { }); add_task(async function testExpiredImpressions() { - const mockSender = new MockDAPTelemetrySender(); + const mockSender = new MockDAPSender(); const mockDateProvider = new MockDateProvider(); - const privateAttribution = new NewTabAttributionService({ - dapTelemetrySender: mockSender, + const privateAttribution = new NewTabAttributionServiceClass({ + dapSender: mockSender, dateProvider: mockDateProvider, }); @@ -482,9 +482,9 @@ add_task(async function testExpiredImpressions() { }); add_task(async function testConversionBudget() { - const mockSender = new MockDAPTelemetrySender(); - const privateAttribution = new NewTabAttributionService({ - dapTelemetrySender: mockSender, + const mockSender = new MockDAPSender(); + const privateAttribution = new NewTabAttributionServiceClass({ + dapSender: mockSender, }); const partnerIdentifier = "partner_identifier_budget"; @@ -532,9 +532,9 @@ add_task(async function testConversionBudget() { }); add_task(async function testHistogramSize() { - const mockSender = new MockDAPTelemetrySender(); - const privateAttribution = new NewTabAttributionService({ - dapTelemetrySender: mockSender, + const mockSender = new MockDAPSender(); + const privateAttribution = new NewTabAttributionServiceClass({ + dapSender: mockSender, }); const partnerIdentifier = "partner_identifier_bad_settings"; @@ -574,7 +574,7 @@ add_task(async function testWithRealDAPSender() { const mockServer = new MockServer(); mockServer.start(); - const privateAttribution = new NewTabAttributionService(); + const privateAttribution = new NewTabAttributionServiceClass(); const partnerIdentifier = "partner_identifier_real_dap"; const conversionSettings = {