Backed out changeset 893b697b0ad7 (bug 1923868) for causing bc failures @nsMacDockSupport.mm. CLOSED TREE

This commit is contained in:
Adi 2024-11-22 05:40:59 +02:00
parent 4e744046fe
commit 2d6125b505
16 changed files with 33 additions and 488 deletions

View File

@ -137,9 +137,6 @@ export class AboutWelcomeChild extends JSWindowActorChild {
Cu.exportFunction(this.AWNewScreen.bind(this), window, { Cu.exportFunction(this.AWNewScreen.bind(this), window, {
defineAs: "AWNewScreen", defineAs: "AWNewScreen",
}); });
Cu.exportFunction(this.AWGetUnhandledCampaignAction.bind(this), window, {
defineAs: "AWGetUnhandledCampaignAction",
});
} }
/** /**
@ -392,12 +389,6 @@ export class AboutWelcomeChild extends JSWindowActorChild {
return this.wrapPromise(this.sendQuery("AWPage:NEW_SCREEN", screenId)); return this.wrapPromise(this.sendQuery("AWPage:NEW_SCREEN", screenId));
} }
AWGetUnhandledCampaignAction() {
return this.sendQueryAndCloneForContent(
"AWPage:GET_UNHANDLED_CAMPAIGN_ACTION"
);
}
/** /**
* @param {{type: string, detail?: any}} event * @param {{type: string, detail?: any}} event
* @override * @override

View File

@ -34,8 +34,6 @@ ChromeUtils.defineLazyGetter(
); );
const DID_SEE_ABOUT_WELCOME_PREF = "trailhead.firstrun.didSeeAboutWelcome"; const DID_SEE_ABOUT_WELCOME_PREF = "trailhead.firstrun.didSeeAboutWelcome";
const DID_HANDLE_CAMAPAIGN_ACTION_PREF =
"trailhead.firstrun.didHandleCampaignAction";
const AWTerminate = { const AWTerminate = {
WINDOW_CLOSED: "welcome-window-closed", WINDOW_CLOSED: "welcome-window-closed",
TAB_CLOSED: "welcome-tab-closed", TAB_CLOSED: "welcome-tab-closed",
@ -262,28 +260,6 @@ export class AboutWelcomeParent extends JSWindowActorParent {
case "AWPage:SEND_TO_DEVICE_EMAILS_SUPPORTED": { case "AWPage:SEND_TO_DEVICE_EMAILS_SUPPORTED": {
return lazy.BrowserUtils.sendToDeviceEmailsSupported(); return lazy.BrowserUtils.sendToDeviceEmailsSupported();
} }
case "AWPage:GET_UNHANDLED_CAMPAIGN_ACTION": {
if (
!Services.prefs.getBoolPref(DID_HANDLE_CAMAPAIGN_ACTION_PREF, false)
) {
return lazy.AWScreenUtils.getUnhandledCampaignAction();
}
break;
}
case "AWPage:HANDLE_CAMPAIGN_ACTION": {
if (
!Services.prefs.getBoolPref(DID_HANDLE_CAMAPAIGN_ACTION_PREF, false)
) {
lazy.SpecialMessageActions.handleAction({ type: data }, browser);
try {
Services.prefs.setBoolPref(DID_HANDLE_CAMAPAIGN_ACTION_PREF, true);
} catch (e) {
lazy.log.debug(`Fails to set ${DID_HANDLE_CAMAPAIGN_ACTION_PREF}.`);
}
return true;
}
break;
}
default: default:
lazy.log.debug(`Unexpected event ${type} was not handled.`); lazy.log.debug(`Unexpected event ${type} was not handled.`);
} }

View File

@ -59,23 +59,6 @@ export const MultiStageAboutWelcome = props => {
didFilter.current = true; didFilter.current = true;
// After completing screen filtering, trigger any unhandled campaign
// action present in the attribution campaign data. This updates the
// "trailhead.firstrun.didHandleCampaignAction" preference, marking the
// actions as complete to prevent them from being handled on subsequent
// visits to about:welcome. Do not await getting the action to avoid
// blocking the thread.
window
.AWGetUnhandledCampaignAction?.()
.then(action => {
if (typeof action === "string") {
AboutWelcomeUtils.handleCampaignAction(action, props.message_id);
}
})
.catch(error => {
console.error("Failed to get unhandled campaign action:", error);
});
const screenInitials = filteredScreens const screenInitials = filteredScreens
.map(({ id }) => id?.split("_")[1]?.[0]) .map(({ id }) => id?.split("_")[1]?.[0])
.join(""); .join("");

View File

@ -70,13 +70,6 @@ export const AboutWelcomeUtils = {
getLoadingStrategyFor(url) { getLoadingStrategyFor(url) {
return url?.startsWith("http") ? "lazy" : "eager"; return url?.startsWith("http") ? "lazy" : "eager";
}, },
handleCampaignAction(action, messageId) {
window.AWSendToParent("HANDLE_CAMPAIGN_ACTION", action).then(handled => {
if (handled) {
this.sendActionTelemetry(messageId, "CAMPAIGN_ACTION");
}
});
},
}; };
export const DEFAULT_RTAMO_CONTENT = { export const DEFAULT_RTAMO_CONTENT = {

View File

@ -100,13 +100,6 @@ const AboutWelcomeUtils = {
getLoadingStrategyFor(url) { getLoadingStrategyFor(url) {
return url?.startsWith("http") ? "lazy" : "eager"; return url?.startsWith("http") ? "lazy" : "eager";
}, },
handleCampaignAction(action, messageId) {
window.AWSendToParent("HANDLE_CAMPAIGN_ACTION", action).then(handled => {
if (handled) {
this.sendActionTelemetry(messageId, "CAMPAIGN_ACTION");
}
});
},
}; };
const DEFAULT_RTAMO_CONTENT = { const DEFAULT_RTAMO_CONTENT = {
@ -222,20 +215,6 @@ const MultiStageAboutWelcome = props => {
// e.g. if AW_LANGUAGE_MISMATCH exists, use it from existing screens // e.g. if AW_LANGUAGE_MISMATCH exists, use it from existing screens
setScreens(filteredScreens.map(filtered => screens.find(s => s.id === filtered.id) ?? filtered)); setScreens(filteredScreens.map(filtered => screens.find(s => s.id === filtered.id) ?? filtered));
didFilter.current = true; didFilter.current = true;
// After completing screen filtering, trigger any unhandled campaign
// action present in the attribution campaign data. This updates the
// "trailhead.firstrun.didHandleCampaignAction" preference, marking the
// actions as complete to prevent them from being handled on subsequent
// visits to about:welcome. Do not await getting the action to avoid
// blocking the thread.
window.AWGetUnhandledCampaignAction?.().then(action => {
if (typeof action === "string") {
_lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.handleCampaignAction(action, props.message_id);
}
}).catch(error => {
console.error("Failed to get unhandled campaign action:", error);
});
const screenInitials = filteredScreens.map(({ const screenInitials = filteredScreens.map(({
id id
}) => id?.split("_")[1]?.[0]).join(""); }) => id?.split("_")[1]?.[0]).join("");

View File

@ -42,20 +42,6 @@ export const AWScreenUtils = {
return true; return true;
}, },
/**
* Returns the string identifier of an unhandled campaign action, if
* applicable otherwise false.
*
* @returns {string|boolean}
*/
async getUnhandledCampaignAction() {
const UNHANDLED_CAMPAIGN_ACTION_TARGETING = "unhandledCampaignAction";
let result = await lazy.ASRouter.evaluateExpression({
expression: UNHANDLED_CAMPAIGN_ACTION_TARGETING,
context: lazy.ASRouterTargeting.Environment,
});
return result?.evaluationStatus?.result || false;
},
/** /**
* Filter out screens whose targeting do not match. * Filter out screens whose targeting do not match.
* *

View File

@ -90,7 +90,7 @@ const MR_ABOUT_WELCOME_DEFAULT = {
{ {
id: "AW_EASY_SETUP_NEEDS_DEFAULT_AND_PIN", id: "AW_EASY_SETUP_NEEDS_DEFAULT_AND_PIN",
targeting: targeting:
"doesAppNeedPin && (unhandledCampaignAction != 'SET_DEFAULT_BROWSER') && 'browser.shell.checkDefaultBrowser'|preferenceValue && !isDefaultBrowser", "doesAppNeedPin && 'browser.shell.checkDefaultBrowser'|preferenceValue && !isDefaultBrowser",
content: { content: {
position: "split", position: "split",
split_narrow_bkg_position: "-60px", split_narrow_bkg_position: "-60px",
@ -224,7 +224,7 @@ const MR_ABOUT_WELCOME_DEFAULT = {
{ {
id: "AW_EASY_SETUP_NEEDS_DEFAULT", id: "AW_EASY_SETUP_NEEDS_DEFAULT",
targeting: targeting:
"!doesAppNeedPin && (unhandledCampaignAction != 'SET_DEFAULT_BROWSER') && 'browser.shell.checkDefaultBrowser'|preferenceValue && !isDefaultBrowser", "!doesAppNeedPin && 'browser.shell.checkDefaultBrowser'|preferenceValue && !isDefaultBrowser",
content: { content: {
position: "split", position: "split",
split_narrow_bkg_position: "-60px", split_narrow_bkg_position: "-60px",
@ -335,7 +335,7 @@ const MR_ABOUT_WELCOME_DEFAULT = {
{ {
id: "AW_EASY_SETUP_NEEDS_PIN", id: "AW_EASY_SETUP_NEEDS_PIN",
targeting: targeting:
"doesAppNeedPin && (!'browser.shell.checkDefaultBrowser'|preferenceValue || isDefaultBrowser || (unhandledCampaignAction == 'SET_DEFAULT_BROWSER'))", "doesAppNeedPin && (!'browser.shell.checkDefaultBrowser'|preferenceValue || isDefaultBrowser)",
content: { content: {
position: "split", position: "split",
split_narrow_bkg_position: "-60px", split_narrow_bkg_position: "-60px",
@ -457,7 +457,7 @@ const MR_ABOUT_WELCOME_DEFAULT = {
{ {
id: "AW_EASY_SETUP_ONLY_IMPORT", id: "AW_EASY_SETUP_ONLY_IMPORT",
targeting: targeting:
"!doesAppNeedPin && (!'browser.shell.checkDefaultBrowser'|preferenceValue || isDefaultBrowser || (unhandledCampaignAction == 'SET_DEFAULT_BROWSER'))", "!doesAppNeedPin && (!'browser.shell.checkDefaultBrowser'|preferenceValue || isDefaultBrowser)",
content: { content: {
position: "split", position: "split",
split_narrow_bkg_position: "-60px", split_narrow_bkg_position: "-60px",

View File

@ -14,13 +14,6 @@ run-if = [
] ]
skip-if = ["os == 'win' && msix"] # These tests rely on the ability to write postSigningData, which we can't do in MSIX builds. https://bugzilla.mozilla.org/show_bug.cgi?id=1805911 skip-if = ["os == 'win' && msix"] # These tests rely on the ability to write postSigningData, which we can't do in MSIX builds. https://bugzilla.mozilla.org/show_bug.cgi?id=1805911
["browser_aboutwelcome_campaign_actions.js"]
run-if = [
"os == 'win'", # installation attribution is only available on Windows and macOS
"os == 'mac'", # installation attribution is only available on Windows and macOS
]
skip-if = ["os == 'win' && msix"] # Attribution code cannot be written for MSIX builds
["browser_aboutwelcome_configurable_ui.js"] ["browser_aboutwelcome_configurable_ui.js"]
["browser_aboutwelcome_fxa_signin_flow.js"] ["browser_aboutwelcome_fxa_signin_flow.js"]

View File

@ -1,90 +0,0 @@
"use strict";
const { ASRouter } = ChromeUtils.importESModule(
"resource:///modules/asrouter/ASRouter.sys.mjs"
);
const { AttributionCode } = ChromeUtils.importESModule(
"resource:///modules/AttributionCode.sys.mjs"
);
const { SpecialMessageActions } = ChromeUtils.importESModule(
"resource://messaging-system/lib/SpecialMessageActions.sys.mjs"
);
const TEST_ATTRIBUTION_DATA = {
campaign: "set_default_browser",
};
const DID_HANDLE_CAMAPAIGN_ACTION_PREF =
"trailhead.firstrun.didHandleCampaignAction";
const TEST_PROTON_CONTENT = [
{
id: "AW_STEP1",
content: {
title: "Step 1",
primary_button: {
label: "Next",
action: {
navigate: true,
},
},
},
},
];
add_task(async function test_unhandled_campaign_action() {
const sandbox = sinon.createSandbox();
const handleActionStub = sandbox
.stub(SpecialMessageActions, "handleAction")
.resolves();
await AttributionCode.deleteFileAsync();
await ASRouter.forceAttribution(TEST_ATTRIBUTION_DATA);
AttributionCode._clearCache();
const data = await AttributionCode.getAttrDataAsync();
Assert.equal(
data.campaign,
"set_default_browser",
"Attribution campaign should be set"
);
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"about:welcome",
true
);
await TestUtils.waitForCondition(() => handleActionStub.called);
Assert.equal(
handleActionStub.firstCall.args[0].type,
"SET_DEFAULT_BROWSER",
"Set default special message action is called"
);
Assert.equal(
Services.prefs.getBoolPref(DID_HANDLE_CAMAPAIGN_ACTION_PREF, false),
true,
"Set default campaign action handled pref is set to true"
);
handleActionStub.reset();
// Open a new about:welcome tab to ensure the action does not run again
let tab2 = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"about:welcome",
true
);
sinon.assert.notCalled(handleActionStub);
registerCleanupFunction(async () => {
BrowserTestUtils.removeTab(tab);
BrowserTestUtils.removeTab(tab2);
await ASRouter.forceAttribution("");
Services.prefs.clearUserPref(DID_HANDLE_CAMAPAIGN_ACTION_PREF);
sandbox.restore();
});
});

View File

@ -11,31 +11,6 @@ const { AWScreenUtils } = ChromeUtils.importESModule(
const sandbox = sinon.createSandbox(); const sandbox = sinon.createSandbox();
const mockAddonAndLocaleAPIs = getAddonAndLocalAPIsMocker(this, sandbox); const mockAddonAndLocaleAPIs = getAddonAndLocalAPIsMocker(this, sandbox);
add_task(function initSandbox() { add_task(function initSandbox() {
sandbox
.stub(AWScreenUtils, "evaluateScreenTargeting")
// Renders easy setup import screen as first screen to prevent pin/default dialog boxes breaking tests
.withArgs(
"!doesAppNeedPin && (!'browser.shell.checkDefaultBrowser'|preferenceValue || isDefaultBrowser || (unhandledCampaignAction == 'SET_DEFAULT_BROWSER'))"
)
.resolves(true)
.withArgs(
`("messaging-system-action.showEmbeddedImport" |preferenceValue == true) && useEmbeddedMigrationWizard`
)
.resolves(true)
.withArgs(
"doesAppNeedPin && (unhandledCampaignAction != 'SET_DEFAULT_BROWSER') && 'browser.shell.checkDefaultBrowser'|preferenceValue && !isDefaultBrowser"
)
.resolves(false)
.withArgs(
"!doesAppNeedPin && (unhandledCampaignAction != 'SET_DEFAULT_BROWSER') && 'browser.shell.checkDefaultBrowser'|preferenceValue && !isDefaultBrowser"
)
.resolves(false)
.withArgs(
"doesAppNeedPin && (!'browser.shell.checkDefaultBrowser'|preferenceValue || isDefaultBrowser || (unhandledCampaignAction == 'SET_DEFAULT_BROWSER'))"
)
.resolves(false)
.withArgs("isDeviceMigration")
.resolves(false);
registerCleanupFunction(() => { registerCleanupFunction(() => {
sandbox.restore(); sandbox.restore();
}); });
@ -74,13 +49,27 @@ async function openAboutWelcome() {
["browser.aboutwelcome.transitions", false], ["browser.aboutwelcome.transitions", false],
["intl.multilingual.aboutWelcome.languageMismatchEnabled", true] ["intl.multilingual.aboutWelcome.languageMismatchEnabled", true]
); );
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
await SpecialPowers.popPrefEnv();
});
await setAboutWelcomePref(true); await setAboutWelcomePref(true);
sandbox
.stub(AWScreenUtils, "evaluateScreenTargeting")
.resolves(true)
// Renders easy setup import screen as first screen to prevent pin/default dialog boxes breaking tests
.withArgs(
"doesAppNeedPin && 'browser.shell.checkDefaultBrowser'|preferenceValue && !isDefaultBrowser"
)
.resolves(false)
.withArgs(
"!doesAppNeedPin && 'browser.shell.checkDefaultBrowser'|preferenceValue && !isDefaultBrowser"
)
.resolves(false)
.withArgs(
"doesAppNeedPin && (!'browser.shell.checkDefaultBrowser'|preferenceValue || isDefaultBrowser)"
)
.resolves(false)
.withArgs("isDeviceMigration")
.resolves(false);
info("Opening about:welcome"); info("Opening about:welcome");
let tab = await BrowserTestUtils.openNewForegroundTab( let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, gBrowser,
@ -503,9 +492,6 @@ add_task(async function test_aboutwelcome_languageSwitcher_noMatch() {
add_task(async function test_aboutwelcome_languageSwitcher_bidiNotSupported() { add_task(async function test_aboutwelcome_languageSwitcher_bidiNotSupported() {
sandbox.restore(); sandbox.restore();
await pushPrefs(["intl.multilingual.liveReloadBidirectional", false]); await pushPrefs(["intl.multilingual.liveReloadBidirectional", false]);
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
});
const { mockable } = mockAddonAndLocaleAPIs({ const { mockable } = mockAddonAndLocaleAPIs({
systemLocale: "ar-EG", // Arabic (Egypt) systemLocale: "ar-EG", // Arabic (Egypt)
@ -539,9 +525,6 @@ add_task(
async function test_aboutwelcome_languageSwitcher_bidiNotSupported_noLangPacks() { async function test_aboutwelcome_languageSwitcher_bidiNotSupported_noLangPacks() {
sandbox.restore(); sandbox.restore();
await pushPrefs(["intl.multilingual.liveReloadBidirectional", false]); await pushPrefs(["intl.multilingual.liveReloadBidirectional", false]);
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
});
const { resolveLangPacks, mockable } = mockAddonAndLocaleAPIs({ const { resolveLangPacks, mockable } = mockAddonAndLocaleAPIs({
systemLocale: "ar-EG", // Arabic (Egypt) systemLocale: "ar-EG", // Arabic (Egypt)
@ -573,12 +556,9 @@ add_task(
/** /**
* Test when bidi live reloading is supported. * Test when bidi live reloading is supported.
*/ */
add_task(async function test_aboutwelcome_languageSwitcher_bidiSupported() { add_task(async function test_aboutwelcome_languageSwitcher_bidiNotSupported() {
sandbox.restore(); sandbox.restore();
await pushPrefs(["intl.multilingual.liveReloadBidirectional", true]); await pushPrefs(["intl.multilingual.liveReloadBidirectional", true]);
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
});
const { resolveLangPacks, mockable } = mockAddonAndLocaleAPIs({ const { resolveLangPacks, mockable } = mockAddonAndLocaleAPIs({
systemLocale: "ar-EG", // Arabic (Egypt) systemLocale: "ar-EG", // Arabic (Egypt)

View File

@ -86,7 +86,7 @@ add_task(async function test_aboutwelcome_easy_setup_screen_impression() {
.stub(AWScreenUtils, "evaluateScreenTargeting") .stub(AWScreenUtils, "evaluateScreenTargeting")
.resolves(false) .resolves(false)
.withArgs( .withArgs(
"doesAppNeedPin && (unhandledCampaignAction != 'SET_DEFAULT_BROWSER') && 'browser.shell.checkDefaultBrowser'|preferenceValue && !isDefaultBrowser" "doesAppNeedPin && 'browser.shell.checkDefaultBrowser'|preferenceValue && !isDefaultBrowser"
) )
.resolves(true) .resolves(true)
.withArgs("isDeviceMigration") .withArgs("isDeviceMigration")

View File

@ -137,19 +137,4 @@ describe("AWScreenUtils", () => {
assert.equal(addScreenImpressionStub.firstCall.args[0].id, testScreen.id); assert.equal(addScreenImpressionStub.firstCall.args[0].id, testScreen.id);
}); });
}); });
describe("getUnhandledCampaignAction", () => {
it("Should call evaluateExpression", () => {
const evaluateExpressionStub = sandbox.stub(
ASRouter,
"evaluateExpression"
);
AWScreenUtils.getUnhandledCampaignAction();
assert.calledOnce(evaluateExpressionStub);
assert.equal(
evaluateExpressionStub.firstCall.args[0].expression,
"unhandledCampaignAction"
);
});
});
}); });

View File

@ -12,13 +12,6 @@ import { shallow, mount } from "enzyme";
import { AboutWelcomeDefaults } from "modules/AboutWelcomeDefaults.sys.mjs"; import { AboutWelcomeDefaults } from "modules/AboutWelcomeDefaults.sys.mjs";
import { AboutWelcomeUtils } from "content-src/lib/aboutwelcome-utils.mjs"; import { AboutWelcomeUtils } from "content-src/lib/aboutwelcome-utils.mjs";
const spinEventLoop = async () => {
// Spin the event loop to allow the useEffect hooks to execute,
// any promises to resolve, and re-rendering to happen after the
// promises have updated the state/props
await new Promise(resolve => setTimeout(resolve, 0));
};
describe("MultiStageAboutWelcome module", () => { describe("MultiStageAboutWelcome module", () => {
let globals; let globals;
let sandbox; let sandbox;
@ -37,7 +30,6 @@ describe("MultiStageAboutWelcome module", () => {
AWEvaluateScreenTargeting: () => {}, AWEvaluateScreenTargeting: () => {},
AWGetSelectedTheme: () => Promise.resolve("automatic"), AWGetSelectedTheme: () => Promise.resolve("automatic"),
AWGetInstalledAddons: () => Promise.resolve(["test-addon-id"]), AWGetInstalledAddons: () => Promise.resolve(["test-addon-id"]),
AWGetUnhandledCampaignAction: () => Promise.resolve(false),
AWSendEventTelemetry: () => {}, AWSendEventTelemetry: () => {},
AWSendToParent: () => {}, AWSendToParent: () => {},
AWWaitForMigrationClose: () => Promise.resolve(), AWWaitForMigrationClose: () => Promise.resolve(),
@ -61,7 +53,10 @@ describe("MultiStageAboutWelcome module", () => {
it("should pass activeTheme and initialTheme props to WelcomeScreen", async () => { it("should pass activeTheme and initialTheme props to WelcomeScreen", async () => {
let wrapper = mount(<MultiStageAboutWelcome {...DEFAULT_PROPS} />); let wrapper = mount(<MultiStageAboutWelcome {...DEFAULT_PROPS} />);
await spinEventLoop(); // Spin the event loop to allow the useEffect hooks to execute,
// any promises to resolve, and re-rendering to happen after the
// promises have updated the state/props
await new Promise(resolve => setTimeout(resolve, 0));
// sync up enzyme's representation with the real DOM // sync up enzyme's representation with the real DOM
wrapper.update(); wrapper.update();
@ -75,7 +70,10 @@ describe("MultiStageAboutWelcome module", () => {
it("should fetch a list of installed Addons", async () => { it("should fetch a list of installed Addons", async () => {
let wrapper = mount(<MultiStageAboutWelcome {...DEFAULT_PROPS} />); let wrapper = mount(<MultiStageAboutWelcome {...DEFAULT_PROPS} />);
await spinEventLoop(); // Spin the event loop to allow the useEffect hooks to execute,
// any promises to resolve, and re-rendering to happen after the
// promises have updated the state/props
await new Promise(resolve => setTimeout(resolve, 0));
// sync up enzyme's representation with the real DOM // sync up enzyme's representation with the real DOM
wrapper.update(); wrapper.update();
@ -1134,103 +1132,6 @@ describe("MultiStageAboutWelcome module", () => {
AboutWelcomeUtils.handleUserAction.resetHistory(); AboutWelcomeUtils.handleUserAction.resetHistory();
} }
}); });
it("Should handle a campaign action when applicable", async () => {
let actionSpy = sandbox.spy(AboutWelcomeUtils, "handleCampaignAction");
let telemetrySpy = sandbox.spy(
AboutWelcomeUtils,
"sendActionTelemetry"
);
globals.set("AWGetUnhandledCampaignAction", () =>
Promise.resolve("SET_DEFAULT_BROWSER")
);
// Return true when "HANDLE_CAMPAIGN_ACTION" is sent to parent
globals.set("AWSendToParent", () => Promise.resolve(true));
const screens = [
{
content: {
title: "test title",
},
},
];
const TEST_PROPS = {
defaultScreens: screens,
message_id: "DEFAULT_ABOUTWELCOME",
startScreen: 0,
};
let wrapper = mount(<MultiStageAboutWelcome {...TEST_PROPS} />);
await spinEventLoop();
wrapper.update();
assert.calledOnce(actionSpy);
// If campaign is handled, we should send telemetry
assert.calledOnce(telemetrySpy);
assert.equal(telemetrySpy.firstCall.args[1], "CAMPAIGN_ACTION");
globals.restore();
});
it("Should not handle a campaign action when the action has already been handled", async () => {
let actionSpy = sandbox.spy(AboutWelcomeUtils, "handleCampaignAction");
let telemetrySpy = sandbox.spy(
AboutWelcomeUtils,
"sendActionTelemetry"
);
globals.set("AWGetUnhandledCampaignAction", () =>
Promise.resolve(false)
);
const screens = [
{
content: {
title: "test title",
},
},
];
const TEST_PROPS = {
defaultScreens: screens,
message_id: "DEFAULT_ABOUTWELCOME",
startScreen: 0,
};
let wrapper = mount(<MultiStageAboutWelcome {...TEST_PROPS} />);
await spinEventLoop();
wrapper.update();
assert.notCalled(actionSpy);
assert.notCalled(telemetrySpy);
globals.restore();
});
it("Should not send telemetrty when campaign action handling fails", async () => {
let actionSpy = sandbox.spy(AboutWelcomeUtils, "handleCampaignAction");
let telemetrySpy = sandbox.spy(
AboutWelcomeUtils,
"sendActionTelemetry"
);
globals.set("AWGetUnhandledCampaignAction", () =>
Promise.resolve("SET_DEFAULT_BROWSER")
);
// Return undefined when "HANDLE_CAMPAIGN_ACTION" is sent to parent as
// though "AWPage:HANDLE_CAMPAIGN_ACTION" case did not return true due
// to failure executing action or the campaign handled pref being true
globals.set("AWSendToParent", () => Promise.resolve(undefined));
const screens = [
{
content: {
title: "test title",
},
},
];
const TEST_PROPS = {
defaultScreens: screens,
message_id: "DEFAULT_ABOUTWELCOME",
startScreen: 0,
};
let wrapper = mount(<MultiStageAboutWelcome {...TEST_PROPS} />);
await spinEventLoop();
wrapper.update();
assert.calledOnce(actionSpy);
// If campaign handling fails, we should not send telemetry
assert.notCalled(telemetrySpy);
globals.restore();
});
}); });
describe("#handleUserAction", () => { describe("#handleUserAction", () => {

View File

@ -49,7 +49,6 @@ Please note that some targeting attributes require stricter controls on the tele
* [isMajorUpgrade](#ismajorupgrade) * [isMajorUpgrade](#ismajorupgrade)
* [isMSIX](#ismsix) * [isMSIX](#ismsix)
* [isRTAMO](#isrtamo) * [isRTAMO](#isrtamo)
* [unhandledCampaignAction](#unhandledCampaignAction)
* [launchOnLoginEnabled](#launchonloginenabled) * [launchOnLoginEnabled](#launchonloginenabled)
* [locale](#locale) * [locale](#locale)
* [localeLanguageCode](#localelanguagecode) * [localeLanguageCode](#localelanguagecode)
@ -1042,10 +1041,6 @@ A boolean. `true` when both the current install and current profile support crea
A boolean. `true` when the `toolkit.profiles.storeID` pref has a value. Indicates that the profile is part of a profile group managed by the `SelectableProfileService`, and the user has used the multiple profiles feature. `false` otherwise. A boolean. `true` when the `toolkit.profiles.storeID` pref has a value. Indicates that the profile is part of a profile group managed by the `SelectableProfileService`, and the user has used the multiple profiles feature. `false` otherwise.
### `unhandledCampaignAction`
A string. A special message action to be executed on first-run. For example, `"SET_DEFAULT_BROWSER"` when the user selected to set as default via the [install marketing page](https://www.mozilla.org/firefox/new/) and set default has not yet been automatically triggered, `null` otherwise.
### `isMSIX` ### `isMSIX`
A boolean. `true` when hasPackageId is `true` on Windows, `false` otherwise. A boolean. `true` when hasPackageId is `true` on Windows, `false` otherwise.

View File

@ -176,12 +176,6 @@ XPCOMUtils.defineLazyPreferenceGetter(
"toolkit.profiles.storeID", "toolkit.profiles.storeID",
null null
); );
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"didHandleCampaignAction",
"trailhead.firstrun.didHandleCampaignAction",
false
);
XPCOMUtils.defineLazyServiceGetters(lazy, { XPCOMUtils.defineLazyServiceGetters(lazy, {
AUS: ["@mozilla.org/updates/update-service;1", "nsIApplicationUpdateService"], AUS: ["@mozilla.org/updates/update-service;1", "nsIApplicationUpdateService"],
@ -264,39 +258,6 @@ function CacheListAttachedOAuthClients() {
}; };
} }
function CacheUnhandledCampaignAction() {
return {
_lastUpdated: 0,
_value: null,
expire() {
this._lastUpdated = 0;
this._value = null;
},
get() {
const now = Date.now();
// Don't get cached value until the action has been handled to ensure
// proper screen targeting in about:welcome
if (
now - this._lastUpdated >= FRECENT_SITES_UPDATE_INTERVAL ||
!lazy.didHandleCampaignAction
) {
this._value = null;
if (!lazy.didHandleCampaignAction) {
const attributionData =
lazy.AttributionCode.getCachedAttributionData();
const ALLOWED_CAMPAIGN_ACTIONS = ["SET_DEFAULT_BROWSER"];
const campaign = attributionData?.campaign?.toUpperCase();
if (campaign && ALLOWED_CAMPAIGN_ACTIONS.includes(campaign)) {
this._value = campaign;
}
}
this._lastUpdated = now;
}
return this._value;
},
};
}
function CheckBrowserNeedsUpdate( function CheckBrowserNeedsUpdate(
updateInterval = FRECENT_SITES_UPDATE_INTERVAL updateInterval = FRECENT_SITES_UPDATE_INTERVAL
) { ) {
@ -365,7 +326,6 @@ export const QueryCache = {
RecentBookmarks: new CachedTargetingGetter("getRecentBookmarks"), RecentBookmarks: new CachedTargetingGetter("getRecentBookmarks"),
ListAttachedOAuthClients: new CacheListAttachedOAuthClients(), ListAttachedOAuthClients: new CacheListAttachedOAuthClients(),
UserMonthlyActivity: new CachedTargetingGetter("getUserMonthlyActivity"), UserMonthlyActivity: new CachedTargetingGetter("getUserMonthlyActivity"),
UnhandledCampaignAction: new CacheUnhandledCampaignAction(),
}, },
getters: { getters: {
doesAppNeedPin: new CachedTargetingGetter( doesAppNeedPin: new CachedTargetingGetter(
@ -1106,17 +1066,6 @@ const TargetingGetters = {
return attributionData?.campaign === "migration"; return attributionData?.campaign === "migration";
}, },
/**
* Whether the user opted into a special message action represented by an
* installer attribution campaign and this choice still needs to be honored.
* @return {string} A special message action to be executed on first-run. For
* example, `"SET_DEFAULT_BROWSER"` when the user selected to set as default
* via the install marketing page and set default has not yet been
* automatically triggered, 'null' otherwise.
*/
get unhandledCampaignAction() {
return QueryCache.queries.UnhandledCampaignAction.get();
},
/** /**
* The values of the height and width available to the browser to display * The values of the height and width available to the browser to display
* web content. The available height and width are each calculated taking * web content. The available height and width are each calculated taking

View File

@ -1859,79 +1859,3 @@ add_task(
); );
} }
); );
add_task(async function check_unhandledCampaignAction() {
is(
typeof ASRouterTargeting.Environment.unhandledCampaignAction,
"object",
"Should return an object" // is null unless an unhandled action is present
);
const DID_HANDLE_CAMAPAIGN_ACTION_PREF =
"trailhead.firstrun.didHandleCampaignAction";
const TEST_CASES = [
{
title: "unsupported open_url campaign action",
attributionData: {
campaign: "open_url",
},
expected: null,
after: () => {
QueryCache.queries.UnhandledCampaignAction.expire();
},
},
{
title: "supported and unhandled set default browser campaign action",
attributionData: {
campaign: "set_default_browser",
},
expected: "SET_DEFAULT_BROWSER",
after: () => {
QueryCache.queries.UnhandledCampaignAction.expire();
},
},
{
title: "supported and handled set default browser campaign action",
attributionData: {
campaign: "set_default_browser",
},
expected: null,
before: async () => {
await pushPrefs([DID_HANDLE_CAMAPAIGN_ACTION_PREF, true]);
},
after: () => {
Services.prefs.clearUserPref(DID_HANDLE_CAMAPAIGN_ACTION_PREF);
QueryCache.queries.UnhandledCampaignAction.expire();
},
},
];
const sandbox = sinon.createSandbox();
registerCleanupFunction(async () => {
sandbox.restore();
});
const stub = sandbox.stub(AttributionCode, "getCachedAttributionData");
for (const {
title,
attributionData,
expected,
before,
after,
} of TEST_CASES) {
if (before) {
await before();
}
stub.returns(attributionData);
is(
ASRouterTargeting.Environment.unhandledCampaignAction,
expected,
`${title} - Expected unhandledCampaignAction to have the expected value`
);
if (after) {
after();
}
}
});