diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /browser/components/newtab/test/browser/browser_aboutwelcome_multistage_default.js | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | browser/components/newtab/test/browser/browser_aboutwelcome_multistage_default.js | 736 |
1 files changed, 736 insertions, 0 deletions
diff --git a/browser/components/newtab/test/browser/browser_aboutwelcome_multistage_default.js b/browser/components/newtab/test/browser/browser_aboutwelcome_multistage_default.js new file mode 100644 index 0000000000..9d578db93d --- /dev/null +++ b/browser/components/newtab/test/browser/browser_aboutwelcome_multistage_default.js @@ -0,0 +1,736 @@ +"use strict"; +const { SpecialMessageActions } = ChromeUtils.importESModule( + "resource://messaging-system/lib/SpecialMessageActions.sys.mjs" +); + +const DID_SEE_ABOUT_WELCOME_PREF = "trailhead.firstrun.didSeeAboutWelcome"; + +const TEST_DEFAULT_CONTENT = [ + { + id: "AW_STEP1", + content: { + position: "split", + title: "Step 1", + primary_button: { + label: "Next", + action: { + navigate: true, + }, + }, + secondary_button: { + label: "link", + }, + secondary_button_top: { + label: "link top", + action: { + type: "SHOW_FIREFOX_ACCOUNTS", + data: { entrypoint: "test" }, + }, + }, + help_text: { + text: "Here's some sample help text", + }, + }, + }, + { + id: "AW_STEP2", + content: { + position: "center", + title: "Step 2", + primary_button: { + label: "Next", + action: { + navigate: true, + }, + }, + secondary_button: { + label: "link", + }, + has_noodles: true, + }, + }, + { + id: "AW_STEP3", + content: { + title: "Step 3", + tiles: { + type: "theme", + action: { + theme: "<event>", + }, + data: [ + { + theme: "automatic", + label: "theme-1", + tooltip: "test-tooltip", + }, + { + theme: "dark", + label: "theme-2", + }, + ], + }, + primary_button: { + label: "Next", + action: { + navigate: true, + }, + }, + secondary_button: { + label: "Import", + action: { + type: "SHOW_MIGRATION_WIZARD", + data: { source: "chrome" }, + }, + }, + }, + }, + { + id: "AW_STEP4", + auto_advance: "primary_button", + content: { + title: "Step 4", + primary_button: { + label: "Next", + action: { + navigate: true, + }, + }, + secondary_button: { + label: "link", + }, + }, + }, +]; + +const TEST_DEFAULT_JSON = JSON.stringify(TEST_DEFAULT_CONTENT); + +async function openAboutWelcome() { + await setAboutWelcomePref(true); + await setAboutWelcomeMultiStage(TEST_DEFAULT_JSON); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:welcome", + true + ); + registerCleanupFunction(() => { + BrowserTestUtils.removeTab(tab); + }); + return tab.linkedBrowser; +} + +/** + * Test the multistage welcome default UI + */ +add_task(async function test_multistage_aboutwelcome_default() { + const sandbox = sinon.createSandbox(); + let browser = await openAboutWelcome(); + let aboutWelcomeActor = await getAboutWelcomeParent(browser); + // Stub AboutWelcomeParent Content Message Handler + sandbox.spy(aboutWelcomeActor, "onContentMessage"); + registerCleanupFunction(() => { + sandbox.restore(); + }); + + await test_screen_content( + browser, + "multistage step 1", + // Expected selectors: + [ + "main.AW_STEP1", + "div.onboardingContainer", + "div.section-secondary", + "span.attrib-text", + "div.secondary-cta.top", + "div.steps", + "div.indicator.current", + ], + // Unexpected selectors: + [ + "main.AW_STEP2", + "main.AW_STEP3", + "main.dialog-initial", + "main.dialog-last", + ] + ); + + await onButtonClick(browser, "button.primary"); + + const { callCount } = aboutWelcomeActor.onContentMessage; + ok(callCount >= 1, `${callCount} Stub was called`); + let clickCall; + for (let i = 0; i < callCount; i++) { + const call = aboutWelcomeActor.onContentMessage.getCall(i); + info(`Call #${i}: ${call.args[0]} ${JSON.stringify(call.args[1])}`); + if (call.calledWithMatch("", { event: "CLICK_BUTTON" })) { + clickCall = call; + } + } + + Assert.ok( + clickCall.args[1].message_id === "MR_WELCOME_DEFAULT_0_AW_STEP1", + "AboutWelcome MR message id joined with screen id" + ); + + await test_screen_content( + browser, + "multistage step 2", + // Expected selectors: + [ + "main.AW_STEP2", + "div.onboardingContainer", + "div.section-main", + "div.steps", + "div.indicator.current", + "main.with-noodles", + ], + // Unexpected selectors: + [ + "main.AW_STEP1", + "main.AW_STEP3", + "div.section-secondary", + "main.dialog-last", + ] + ); + + await onButtonClick(browser, "button.primary"); + + // No 3rd screen to go to for win7. + if (win7Content) return; + + await test_screen_content( + browser, + "multistage step 3", + // Expected selectors: + [ + "main.AW_STEP3", + "div.onboardingContainer", + "div.section-main", + "div.tiles-theme-container", + "div.steps", + "div.indicator.current", + ], + // Unexpected selectors: + [ + "main.AW_STEP2", + "main.AW_STEP1", + "div.section-secondary", + "main.dialog-initial", + "main.with-noodles", + "main.dialog-last", + ] + ); + + await onButtonClick(browser, "button.primary"); + + await test_screen_content( + browser, + "multistage step 4", + // Expected selectors: + [ + "main.AW_STEP4.screen-1", + "main.AW_STEP4.dialog-last", + "div.onboardingContainer", + ], + // Unexpected selectors: + [ + "main.AW_STEP2", + "main.AW_STEP1", + "main.AW_STEP3", + "div.steps", + "main.dialog-initial", + "main.AW_STEP4.screen-0", + "main.AW_STEP4.screen-2", + "main.AW_STEP4.screen-3", + ] + ); +}); + +/** + * Test navigating back/forward between screens + */ +add_task(async function test_Multistage_About_Welcome_navigation() { + let browser = await openAboutWelcome(); + + await onButtonClick(browser, "button.primary"); + await TestUtils.waitForCondition(() => browser.canGoBack); + browser.goBack(); + + await test_screen_content( + browser, + "multistage step 1", + // Expected selectors: + [ + "div.onboardingContainer", + "main.AW_STEP1", + "div.secondary-cta", + "div.secondary-cta.top", + "button[value='secondary_button']", + "button[value='secondary_button_top']", + ], + // Unexpected selectors: + ["main.AW_STEP2", "main.AW_STEP3"] + ); + + await document.getElementById("forward-button").click(); +}); + +/** + * Test the multistage welcome UI primary button action + */ +add_task(async function test_AWMultistage_Primary_Action() { + let browser = await openAboutWelcome(); + let aboutWelcomeActor = await getAboutWelcomeParent(browser); + const sandbox = sinon.createSandbox(); + sandbox.spy(aboutWelcomeActor, "onContentMessage"); + registerCleanupFunction(() => { + sandbox.restore(); + }); + + await onButtonClick(browser, "button.primary"); + const { callCount } = aboutWelcomeActor.onContentMessage; + ok(callCount >= 1, `${callCount} Stub was called`); + + let clickCall; + let performanceCall; + for (let i = 0; i < callCount; i++) { + const call = aboutWelcomeActor.onContentMessage.getCall(i); + info(`Call #${i}: ${call.args[0]} ${JSON.stringify(call.args[1])}`); + if (call.calledWithMatch("", { event: "CLICK_BUTTON" })) { + clickCall = call; + } else if ( + call.calledWithMatch("", { + event_context: { mountStart: sinon.match.number }, + }) + ) { + performanceCall = call; + } + } + + // For some builds, we can stub fast enough to catch the performance + if (performanceCall) { + Assert.equal( + performanceCall.args[0], + "AWPage:TELEMETRY_EVENT", + "send telemetry event" + ); + Assert.equal( + performanceCall.args[1].event, + "IMPRESSION", + "performance impression event recorded in telemetry" + ); + Assert.equal( + typeof performanceCall.args[1].event_context.domComplete, + "number", + "numeric domComplete recorded in telemetry" + ); + Assert.equal( + typeof performanceCall.args[1].event_context.domInteractive, + "number", + "numeric domInteractive recorded in telemetry" + ); + Assert.equal( + typeof performanceCall.args[1].event_context.mountStart, + "number", + "numeric mountStart recorded in telemetry" + ); + Assert.equal( + performanceCall.args[1].message_id, + "MR_WELCOME_DEFAULT", + "MessageId sent in performance event telemetry" + ); + } + + Assert.equal( + clickCall.args[0], + "AWPage:TELEMETRY_EVENT", + "send telemetry event" + ); + Assert.equal( + clickCall.args[1].event, + "CLICK_BUTTON", + "click button event recorded in telemetry" + ); + Assert.equal( + clickCall.args[1].event_context.source, + "primary_button", + "primary button click source recorded in telemetry" + ); + Assert.equal( + clickCall.args[1].message_id, + "MR_WELCOME_DEFAULT_0_AW_STEP1", + "MessageId sent in click event telemetry" + ); +}); + +add_task(async function test_AWMultistage_Secondary_Open_URL_Action() { + if (win7Content) return; + let browser = await openAboutWelcome(); + let aboutWelcomeActor = await getAboutWelcomeParent(browser); + const sandbox = sinon.createSandbox(); + // Stub AboutWelcomeParent Content Message Handler + sandbox.stub(aboutWelcomeActor, "onContentMessage").resolves(null); + registerCleanupFunction(() => { + sandbox.restore(); + }); + + await onButtonClick(browser, "button[value='secondary_button_top']"); + const { callCount } = aboutWelcomeActor.onContentMessage; + ok( + callCount >= 2, + `${callCount} Stub called twice to handle FxA open URL and Telemetry` + ); + + let actionCall; + let eventCall; + for (let i = 0; i < callCount; i++) { + const call = aboutWelcomeActor.onContentMessage.getCall(i); + info(`Call #${i}: ${call.args[0]} ${JSON.stringify(call.args[1])}`); + if (call.calledWithMatch("SPECIAL")) { + actionCall = call; + } else if (call.calledWithMatch("", { event: "CLICK_BUTTON" })) { + eventCall = call; + } + } + + Assert.equal( + actionCall.args[0], + "AWPage:SPECIAL_ACTION", + "Got call to handle special action" + ); + Assert.equal( + actionCall.args[1].type, + "SHOW_FIREFOX_ACCOUNTS", + "Special action SHOW_FIREFOX_ACCOUNTS event handled" + ); + Assert.equal( + actionCall.args[1].data.extraParams.utm_term, + "aboutwelcome-default-screen", + "UTMTerm set in FxA URL" + ); + Assert.equal( + actionCall.args[1].data.entrypoint, + "test", + "EntryPoint set in FxA URL" + ); + Assert.equal( + eventCall.args[0], + "AWPage:TELEMETRY_EVENT", + "Got call to handle Telemetry event" + ); + Assert.equal( + eventCall.args[1].event, + "CLICK_BUTTON", + "click button event recorded in Telemetry" + ); + Assert.equal( + eventCall.args[1].event_context.source, + "secondary_button_top", + "secondary_top button click source recorded in Telemetry" + ); +}); + +add_task(async function test_AWMultistage_Themes() { + // No theme screen to test for win7. + if (win7Content) return; + + let browser = await openAboutWelcome(); + let aboutWelcomeActor = await getAboutWelcomeParent(browser); + + const sandbox = sinon.createSandbox(); + sandbox.spy(aboutWelcomeActor, "onContentMessage"); + + registerCleanupFunction(() => { + sandbox.restore(); + }); + await onButtonClick(browser, "button.primary"); + + await test_screen_content( + browser, + "multistage proton step 2", + // Expected selectors: + ["main.AW_STEP2"], + // Unexpected selectors: + ["main.AW_STEP1"] + ); + await onButtonClick(browser, "button.primary"); + + await ContentTask.spawn(browser, "Themes", async () => { + await ContentTaskUtils.waitForCondition( + () => content.document.querySelector("label.theme"), + "Theme Icons" + ); + let themes = content.document.querySelectorAll("label.theme"); + Assert.equal(themes.length, 2, "Two themes displayed"); + }); + + await onButtonClick(browser, "input[value=automatic]"); + + const { callCount } = aboutWelcomeActor.onContentMessage; + ok(callCount >= 1, `${callCount} Stub was called`); + + let actionCall; + let eventCall; + for (let i = 0; i < callCount; i++) { + const call = aboutWelcomeActor.onContentMessage.getCall(i); + info(`Call #${i}: ${call.args[0]} ${JSON.stringify(call.args[1])}`); + if (call.calledWithMatch("SELECT_THEME")) { + actionCall = call; + } else if (call.calledWithMatch("", { event: "CLICK_BUTTON" })) { + eventCall = call; + } + } + + Assert.equal( + actionCall.args[0], + "AWPage:SELECT_THEME", + "Got call to handle select theme" + ); + Assert.equal( + actionCall.args[1], + "AUTOMATIC", + "Theme value passed as AUTOMATIC" + ); + Assert.equal( + eventCall.args[0], + "AWPage:TELEMETRY_EVENT", + "Got call to handle Telemetry event when theme tile clicked" + ); + Assert.equal( + eventCall.args[1].event, + "CLICK_BUTTON", + "click button event recorded in Telemetry" + ); + Assert.equal( + eventCall.args[1].event_context.source, + "automatic", + "automatic click source recorded in Telemetry" + ); +}); + +add_task(async function test_AWMultistage_can_restore_theme() { + const { XPIProvider } = ChromeUtils.import( + "resource://gre/modules/addons/XPIProvider.jsm" + ); + const sandbox = sinon.createSandbox(); + registerCleanupFunction(() => sandbox.restore()); + + const fakeAddons = []; + class FakeAddon { + constructor({ id = "default-theme@mozilla.org", isActive = false } = {}) { + this.id = id; + this.isActive = isActive; + } + enable() { + for (let addon of fakeAddons) { + addon.isActive = false; + } + this.isActive = true; + } + } + fakeAddons.push( + new FakeAddon({ id: "fake-theme-1@mozilla.org", isActive: true }), + new FakeAddon({ id: "fake-theme-2@mozilla.org" }) + ); + + let browser = await openAboutWelcome(); + let aboutWelcomeActor = await getAboutWelcomeParent(browser); + + sandbox.stub(XPIProvider, "getAddonsByTypes").resolves(fakeAddons); + sandbox + .stub(XPIProvider, "getAddonByID") + .callsFake(id => fakeAddons.find(addon => addon.id === id)); + sandbox.spy(aboutWelcomeActor, "onContentMessage"); + + // Test that the active theme ID is stored in LIGHT_WEIGHT_THEMES + await aboutWelcomeActor.receiveMessage({ + name: "AWPage:GET_SELECTED_THEME", + }); + Assert.equal( + await aboutWelcomeActor.onContentMessage.lastCall.returnValue, + "automatic", + `Should return "automatic" for non-built-in theme` + ); + + await aboutWelcomeActor.receiveMessage({ + name: "AWPage:SELECT_THEME", + data: "AUTOMATIC", + }); + Assert.equal( + XPIProvider.getAddonByID.lastCall.args[0], + fakeAddons[0].id, + `LIGHT_WEIGHT_THEMES.AUTOMATIC should be ${fakeAddons[0].id}` + ); + + // Enable a different theme... + fakeAddons[1].enable(); + // And test that AWGetSelectedTheme updates the active theme ID + await aboutWelcomeActor.receiveMessage({ + name: "AWPage:GET_SELECTED_THEME", + }); + await aboutWelcomeActor.receiveMessage({ + name: "AWPage:SELECT_THEME", + data: "AUTOMATIC", + }); + Assert.equal( + XPIProvider.getAddonByID.lastCall.args[0], + fakeAddons[1].id, + `LIGHT_WEIGHT_THEMES.AUTOMATIC should be ${fakeAddons[1].id}` + ); +}); + +add_task(async function test_AWMultistage_Import() { + // No import screen to test for win7. + if (win7Content) return; + let browser = await openAboutWelcome(); + let aboutWelcomeActor = await getAboutWelcomeParent(browser); + + // Click twice to advance to screen 3 + await onButtonClick(browser, "button.primary"); + await test_screen_content( + browser, + "multistage proton step 2", + // Expected selectors: + ["main.AW_STEP2"], + // Unexpected selectors: + ["main.AW_STEP1"] + ); + await onButtonClick(browser, "button.primary"); + + const sandbox = sinon.createSandbox(); + sandbox.stub(SpecialMessageActions, "handleAction"); + sandbox.spy(aboutWelcomeActor, "onContentMessage"); + + registerCleanupFunction(() => { + sandbox.restore(); + }); + + await test_screen_content( + browser, + "multistage proton step 2", + // Expected selectors: + ["main.AW_STEP3"], + // Unexpected selectors: + ["main.AW_STEP2"] + ); + + await onButtonClick(browser, "button[value='secondary_button']"); + const { callCount } = aboutWelcomeActor.onContentMessage; + + let actionCall; + let eventCall; + for (let i = 0; i < callCount; i++) { + const call = aboutWelcomeActor.onContentMessage.getCall(i); + info(`Call #${i}: ${call.args[0]} ${JSON.stringify(call.args[1])}`); + if (call.calledWithMatch("SPECIAL")) { + actionCall = call; + } else if (call.calledWithMatch("", { event: "CLICK_BUTTON" })) { + eventCall = call; + } + } + + Assert.equal( + actionCall.args[0], + "AWPage:SPECIAL_ACTION", + "Got call to handle special action" + ); + Assert.equal( + actionCall.args[1].type, + "SHOW_MIGRATION_WIZARD", + "Special action SHOW_MIGRATION_WIZARD event handled" + ); + Assert.equal( + actionCall.args[1].data.source, + "chrome", + "Source passed to event handler" + ); + Assert.equal( + eventCall.args[0], + "AWPage:TELEMETRY_EVENT", + "Got call to handle Telemetry event" + ); +}); + +add_task(async function test_updatesPrefOnAWOpen() { + Services.prefs.setBoolPref(DID_SEE_ABOUT_WELCOME_PREF, false); + await setAboutWelcomePref(true); + + await openAboutWelcome(); + await TestUtils.waitForCondition( + () => + Services.prefs.getBoolPref(DID_SEE_ABOUT_WELCOME_PREF, false) === true, + "Updated pref to seen AW" + ); + Services.prefs.clearUserPref(DID_SEE_ABOUT_WELCOME_PREF); +}); + +add_setup(async function () { + const sandbox = sinon.createSandbox(); + // This needs to happen before any about:welcome page opens + sandbox.stub(FxAccounts.config, "promiseMetricsFlowURI").resolves(""); + await setAboutWelcomeMultiStage(""); + + registerCleanupFunction(() => { + sandbox.restore(); + }); +}); + +add_task(async function test_FxA_metricsFlowURI() { + let browser = await openAboutWelcome(); + + await ContentTask.spawn(browser, {}, async () => { + Assert.ok( + await ContentTaskUtils.waitForCondition( + () => content.document.querySelector("div.onboardingContainer"), + "Wait for about:welcome to load" + ), + "about:welcome loaded" + ); + }); + + Assert.ok(FxAccounts.config.promiseMetricsFlowURI.called, "Stub was called"); + Assert.equal( + FxAccounts.config.promiseMetricsFlowURI.firstCall.args[0], + "aboutwelcome", + "Called by AboutWelcomeParent" + ); + + SpecialPowers.popPrefEnv(); +}); + +add_task(async function test_send_aboutwelcome_as_page_in_event_telemetry() { + const sandbox = sinon.createSandbox(); + let browser = await openAboutWelcome(); + let aboutWelcomeActor = await getAboutWelcomeParent(browser); + sandbox.spy(aboutWelcomeActor, "onContentMessage"); + + await onButtonClick(browser, "button.primary"); + + const { callCount } = aboutWelcomeActor.onContentMessage; + ok(callCount >= 1, `${callCount} Stub was called`); + + let eventCall; + for (let i = 0; i < callCount; i++) { + const call = aboutWelcomeActor.onContentMessage.getCall(i); + info(`Call #${i}: ${call.args[0]} ${JSON.stringify(call.args[1])}`); + if (call.calledWithMatch("", { event: "CLICK_BUTTON" })) { + eventCall = call; + } + } + + Assert.equal( + eventCall.args[1].event, + "CLICK_BUTTON", + "Event telemetry sent on primary button press" + ); + Assert.equal( + eventCall.args[1].event_context.page, + "about:welcome", + "Event context page set to 'about:welcome' in event telemetry" + ); + + registerCleanupFunction(() => { + sandbox.restore(); + }); +}); |