Bug 1829043 - Add actions for AboutWelcome embedded migration wizard. r=pdahiya,mconley

Add some properties to the migration wizard screen JSON to specify what
action to perform when CTAs inside the embedded migration wizard are
clicked. This lets us advance screens when the cancel or finish button
is clicked, and send telemetry when the start button is clicked. In
theory we could perform any special message actions too, but for now we
only need telemetry and screen navigation.

Differential Revision: https://phabricator.services.mozilla.com/D176358
This commit is contained in:
Shane Hughes
2023-05-08 18:23:47 +00:00
parent 53e9f0be15
commit 2c1e31da7b
8 changed files with 336 additions and 75 deletions

View File

@@ -185,7 +185,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
/* harmony import */ var _MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6);
/* harmony import */ var _LanguageSwitcher__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(11);
/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(16);
/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(17);
/* 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/. */
@@ -493,6 +493,7 @@ class WelcomeScreen extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
props
} = this;
const value = event.currentTarget.value ?? event.currentTarget.getAttribute("value");
const source = event.source || value;
let targetContent = props.content[value] || props.content.tiles || props.content.languageSwitcher;
if (!(targetContent && targetContent.action)) {
@@ -500,12 +501,12 @@ class WelcomeScreen extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
} // Send telemetry before waiting on actions
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendActionTelemetry(props.messageId, value, event.name); // Send additional telemetry if a messaging surface like feature callout is
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendActionTelemetry(props.messageId, source, event.name); // Send additional telemetry if a messaging surface like feature callout is
// dismissed via the dismiss button. Other causes of dismissal will be
// handled separately by the messaging surface's own code.
if (value === "dismiss_button" && !event.name) {
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendDismissTelemetry(props.messageId, value);
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendDismissTelemetry(props.messageId, source);
}
let {
@@ -737,6 +738,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _HeroImage__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(13);
/* harmony import */ var _OnboardingVideo__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(14);
/* harmony import */ var _AdditionalCTA__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(15);
/* harmony import */ var _EmbeddedMigrationWizard__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(16);
/* 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/. */
@@ -752,6 +754,7 @@ __webpack_require__.r(__webpack_exports__);
const MultiStageProtonScreen = props => {
const {
autoAdvance,
@@ -909,9 +912,9 @@ class ProtonScreen extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
activeMultiSelect: this.props.activeMultiSelect,
setActiveMultiSelect: this.props.setActiveMultiSelect,
handleAction: this.props.handleAction
}) : null, content.tiles && content.tiles.type === "migration-wizard" ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("migration-wizard", {
"auto-request-state": ""
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("panel-list", null)) : null);
}) : null, content.tiles && content.tiles.type === "migration-wizard" ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_EmbeddedMigrationWizard__WEBPACK_IMPORTED_MODULE_12__.EmbeddedMigrationWizard, {
handleAction: this.props.handleAction
}) : null);
}
renderNoodles() {
@@ -1863,6 +1866,59 @@ const AdditionalCTA = ({
/* 16 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "EmbeddedMigrationWizard": () => (/* binding */ EmbeddedMigrationWizard)
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* 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/. */
const EmbeddedMigrationWizard = ({
handleAction
}) => {
const ref = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)();
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
const handleBeginMigration = () => {
handleAction({
currentTarget: {
value: "migrate_start"
},
source: "primary_button"
});
};
const handleClose = () => {
handleAction({
currentTarget: {
value: "migrate_close"
}
});
};
const {
current
} = ref;
current === null || current === void 0 ? void 0 : current.addEventListener("MigrationWizard:BeginMigration", handleBeginMigration);
current === null || current === void 0 ? void 0 : current.addEventListener("MigrationWizard:Close", handleClose);
return () => {
current === null || current === void 0 ? void 0 : current.removeEventListener("MigrationWizard:BeginMigration", handleBeginMigration);
current === null || current === void 0 ? void 0 : current.removeEventListener("MigrationWizard:Close", handleClose);
};
}, []); // eslint-disable-line react-hooks/exhaustive-deps
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("migration-wizard", {
"auto-request-state": "",
ref: ref
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("panel-list", null));
};
/***/ }),
/* 17 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "BASE_PARAMS": () => (/* binding */ BASE_PARAMS),
@@ -1902,7 +1958,7 @@ function addUtmParams(url, utmTerm) {
}
/***/ }),
/* 17 */
/* 18 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
@@ -1913,7 +1969,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
/* harmony import */ var _MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16);
/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(17);
/* 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/. */
@@ -2108,7 +2164,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
/* harmony import */ var _components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
/* harmony import */ var _components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(17);
/* harmony import */ var _components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(18);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/* This Source Code Form is subject to the terms of the Mozilla Public

View File

@@ -356,6 +356,14 @@ const MR_ABOUT_WELCOME_DEFAULT = {
background:
"url('chrome://activity-stream/content/data/content/assets/mr-import.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
progress_bar: true,
migrate_start: {
action: {},
},
migrate_close: {
action: {
navigate: true,
},
},
secondary_button: {
label: {
string_id: "mr2022-onboarding-secondary-skip-button-label",

View File

@@ -0,0 +1,38 @@
/* 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 React, { useEffect, useRef } from "react";
export const EmbeddedMigrationWizard = ({ handleAction }) => {
const ref = useRef();
useEffect(() => {
const handleBeginMigration = () => {
handleAction({
currentTarget: { value: "migrate_start" },
source: "primary_button",
});
};
const handleClose = () => {
handleAction({ currentTarget: { value: "migrate_close" } });
};
const { current } = ref;
current?.addEventListener(
"MigrationWizard:BeginMigration",
handleBeginMigration
);
current?.addEventListener("MigrationWizard:Close", handleClose);
return () => {
current?.removeEventListener(
"MigrationWizard:BeginMigration",
handleBeginMigration
);
current?.removeEventListener("MigrationWizard:Close", handleClose);
};
}, []); // eslint-disable-line react-hooks/exhaustive-deps
return (
<migration-wizard auto-request-state="" ref={ref}>
<panel-list />
</migration-wizard>
);
};

View File

@@ -338,6 +338,7 @@ export class WelcomeScreen extends React.PureComponent {
let { props } = this;
const value =
event.currentTarget.value ?? event.currentTarget.getAttribute("value");
const source = event.source || value;
let targetContent =
props.content[value] ||
props.content.tiles ||
@@ -347,13 +348,13 @@ export class WelcomeScreen extends React.PureComponent {
return;
}
// Send telemetry before waiting on actions
AboutWelcomeUtils.sendActionTelemetry(props.messageId, value, event.name);
AboutWelcomeUtils.sendActionTelemetry(props.messageId, source, event.name);
// Send additional telemetry if a messaging surface like feature callout is
// dismissed via the dismiss button. Other causes of dismissal will be
// handled separately by the messaging surface's own code.
if (value === "dismiss_button" && !event.name) {
AboutWelcomeUtils.sendDismissTelemetry(props.messageId, value);
AboutWelcomeUtils.sendDismissTelemetry(props.messageId, source);
}
let { action } = targetContent;

View File

@@ -18,6 +18,7 @@ import { CTAParagraph } from "./CTAParagraph";
import { HeroImage } from "./HeroImage";
import { OnboardingVideo } from "./OnboardingVideo";
import { AdditionalCTA } from "./AdditionalCTA";
import { EmbeddedMigrationWizard } from "./EmbeddedMigrationWizard";
export const MultiStageProtonScreen = props => {
const { autoAdvance, handleAction, order } = props;
@@ -227,9 +228,7 @@ export class ProtonScreen extends React.PureComponent {
/>
) : null}
{content.tiles && content.tiles.type === "migration-wizard" ? (
<migration-wizard auto-request-state="">
<panel-list />
</migration-wizard>
<EmbeddedMigrationWizard handleAction={this.props.handleAction} />
) : null}
</React.Fragment>
);

View File

@@ -1166,8 +1166,15 @@ These record the telemetry metrics during the Firefox onboarding experience.
"locale": "en-US",
"experiments": {},
"release_channel": "default",
"addon_version": "20200330194034"
"message_id": ["DEFAULT_ABOUTWELCOME" | "DEFAULT_ABOUTWELCOME_AW_GET_STARTED" | "DEFAULT_ABOUTWELCOME_SITES" | "DEFAULT_ABOUTWELCOME_AW_IMPORT_SETTINGS" | "DEFAULT_ABOUTWELCOME_AW_CHOOSE_THEME", "RTAMO_DEFAULT_WELCOME"],
"addon_version": "20200330194034",
"message_id": [
| "DEFAULT_ABOUTWELCOME"
| "DEFAULT_ABOUTWELCOME_AW_GET_STARTED"
| "DEFAULT_ABOUTWELCOME_SITES"
| "DEFAULT_ABOUTWELCOME_AW_IMPORT_SETTINGS"
| "DEFAULT_ABOUTWELCOME_AW_CHOOSE_THEME"
| "RTAMO_DEFAULT_WELCOME"
],
"event": "IMPRESSION",
"browser_session_id": "e7e52665-7db3-f348-9918-e93160eb2ef3",
"event_context": { "page": "about:welcome" },
@@ -1192,8 +1199,13 @@ These record the telemetry metrics during the Firefox onboarding experience.
"locale": "en-US",
"experiments": {},
"release_channel": "default",
"addon_version": "20200330194034"
"message_id": ["DEFAULT_ABOUTWELCOME_AW_GET_STARTED" | "DEFAULT_ABOUTWELCOME_AW_IMPORT_SETTINGS" | "DEFAULT_ABOUTWELCOME_AW_CHOOSE_THEME" | "RTAMO_DEFAULT_WELCOME"],
"addon_version": "20200330194034",
"message_id": [
| "DEFAULT_ABOUTWELCOME_AW_GET_STARTED"
| "DEFAULT_ABOUTWELCOME_AW_IMPORT_SETTINGS"
| "DEFAULT_ABOUTWELCOME_AW_CHOOSE_THEME"
| "RTAMO_DEFAULT_WELCOME"
],
"event": "CLICK_BUTTION",
"browser_session_id": "e7e52665-7db3-f348-9918-e93160eb2ef3",
"event_context": { "page": "about:welcome", "source": ["primary_button" | "secondary_button"] },
@@ -1218,7 +1230,7 @@ These record the telemetry metrics during the Firefox onboarding experience.
"locale": "en-US",
"experiments": {},
"release_channel": "default",
"addon_version": "20200330194034"
"addon_version": "20200330194034",
"message_id": "RTAMO_DEFAULT_WELCOME",
"event": "INSTALL",
"browser_session_id": "e7e52665-7db3-f348-9918-e93160eb2ef3",
@@ -1235,6 +1247,26 @@ These record the telemetry metrics during the Firefox onboarding experience.
}
```
### Onboarding embedded migration interactions
```js
{
"client_id": "26288a14-5cc4-d14f-ae0a-bb01ef45be9c",
"version": "76.0a1",
"locale": "en-US",
"experiments": {},
"release_channel": "default",
"addon_version": "20200330194034",
"message_id": "MR_WELCOME_DEFAULT_0_AW_IMPORT_SETTINGS_EMBEDDED",
"event": "CLICK_BUTTION",
"browser_session_id": "e7e52665-7db3-f348-9918-e93160eb2ef3",
"event_context": {
"page": "about:welcome",
"source": ["primary_button" | "migrate_close"],
}
}
```
### Onboarding session end ping
```js
@@ -1244,12 +1276,19 @@ These record the telemetry metrics during the Firefox onboarding experience.
"locale": "en-US",
"experiments": {},
"release_channel": "default",
"addon_version": "20200330194034"
"addon_version": "20200330194034",
"message_id": "DEFAULT_ABOUTWELCOME",
"event": "SESSION_END",
"browser_session_id": "e7e52665-7db3-f348-9918-e93160eb2ef3",
"event_context": { "page": "about:welcome", "reason":
["welcome-window-closed" | "welcome-tab-closed" | "app-shut-down" | "address-bar-navigated"]},
"event_context": {
"page": "about:welcome",
"reason": [
| "welcome-window-closed"
| "welcome-tab-closed"
| "app-shut-down"
| "address-bar-navigated"
]
},
"attribution": {
"source": "mozilla.org",
"medium": "referral",

View File

@@ -203,6 +203,14 @@ module.exports = function(config) {
functions: 0,
branches: 0,
},
"content-src/aboutwelcome/components/EmbeddedMigrationWizard.jsx": {
// This file is covered by the mochitest: browser_aboutwelcome_multistage_mr.js
// Can't be unit tested because it relies on the migration-wizard custom element
statements: 0,
lines: 0,
functions: 0,
branches: 0,
},
"content-src/aboutwelcome/**/*.jsx": {
statements: 62,
lines: 60,

View File

@@ -10,6 +10,9 @@ const { AboutWelcomeTelemetry } = ChromeUtils.import(
const { AWScreenUtils } = ChromeUtils.import(
"resource://activity-stream/lib/AWScreenUtils.jsm"
);
const { InternalTestingProfileMigrator } = ChromeUtils.importESModule(
"resource:///modules/InternalTestingProfileMigrator.sys.mjs"
);
async function clickVisibleButton(browser, selector) {
// eslint-disable-next-line no-shadow
@@ -367,6 +370,37 @@ add_task(async function test_aboutwelcome_embedded_migration() {
set: [["browser.migrate.internal-testing.enabled", true]],
});
const sandbox = sinon.createSandbox();
sandbox
.stub(InternalTestingProfileMigrator.prototype, "getResources")
.callsFake(() =>
Promise.resolve([
{
type: MigrationUtils.resourceTypes.BOOKMARKS,
migrate: () => {},
},
])
);
sandbox.stub(MigrationUtils, "_importQuantities").value({
bookmarks: 123,
history: 123,
logins: 123,
});
const migrated = new Promise(resolve => {
sandbox
.stub(InternalTestingProfileMigrator.prototype, "migrate")
.callsFake((aResourceTypes, aStartup, aProfile, aProgressCallback) => {
aProgressCallback(MigrationUtils.resourceTypes.BOOKMARKS);
Services.obs.notifyObservers(null, "Migration:Ended");
resolve();
});
});
let telemetrySpy = sandbox.spy(
AboutWelcomeTelemetry.prototype,
"sendTelemetry"
);
const TEST_CONTENT = [
{
id: "AW_IMPORT_SETTINGS_EMBEDDED",
@@ -380,6 +414,12 @@ add_task(async function test_aboutwelcome_embedded_migration() {
background:
"url('chrome://activity-stream/content/data/content/assets/mr-import.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
progress_bar: true,
migrate_start: {
action: {},
},
migrate_close: {
action: { navigate: true },
},
secondary_button: {
label: {
string_id: "mr2022-onboarding-secondary-skip-button-label",
@@ -391,6 +431,31 @@ add_task(async function test_aboutwelcome_embedded_migration() {
},
},
},
{
id: "AW_STEP2",
content: {
position: "split",
split_narrow_bkg_position: "-228px",
background:
"url('chrome://activity-stream/content/data/content/assets/mr-gratitude.svg') var(--mr-secondary-position) no-repeat, var(--mr-screen-background-color)",
progress_bar: true,
logo: {},
title: {
string_id: "mr2022-onboarding-gratitude-title",
},
subtitle: {
string_id: "mr2022-onboarding-gratitude-subtitle",
},
primary_button: {
label: {
string_id: "mr2022-onboarding-gratitude-primary-button-label",
},
action: {
navigate: true,
},
},
},
},
];
await setAboutWelcomeMultiStage(JSON.stringify(TEST_CONTENT)); // NB: calls SpecialPowers.pushPrefEnv
@@ -410,68 +475,115 @@ add_task(async function test_aboutwelcome_embedded_migration() {
// Do a basic test to make sure that the <migration-wizard> is on the right
// page and the <panel-list> can open.
await SpecialPowers.spawn(browser, [], async () => {
const { MigrationWizardConstants } = ChromeUtils.importESModule(
"chrome://browser/content/migration/migration-wizard-constants.mjs"
);
await SpecialPowers.spawn(
browser,
[`panel-item[key="${InternalTestingProfileMigrator.key}"]`],
async menuitemSelector => {
const { MigrationWizardConstants } = ChromeUtils.importESModule(
"chrome://browser/content/migration/migration-wizard-constants.mjs"
);
let wizard = content.document.querySelector("migration-wizard");
let shadow = wizard.openOrClosedShadowRoot;
let deck = shadow.querySelector("#wizard-deck");
// It's unlikely but possible that the deck might not yet be showing the
// selection page yet, in which case we wait for that page to appear.
if (deck.selectedViewName !== MigrationWizardConstants.PAGES.SELECTION) {
await ContentTaskUtils.waitForMutationCondition(
deck,
{ attributeFilter: ["selected-view"] },
() => {
return (
deck.getAttribute("selected-view") ===
`page-${MigrationWizardConstants.PAGES.SELECTION}`
);
}
);
}
Assert.ok(true, "Selection page is being shown in the migration wizard.");
// Now let's make sure that the <panel-list> can appear.
let panelList = wizard.querySelector("panel-list");
Assert.ok(panelList, "Found the <panel-list>.");
// The "shown" event from the panel-list is coming from a lower level
// of privilege than where we're executing this SpecialPowers.spawn
// task. In order to properly listen for it, we have to ask
// ContentTaskUtils.waitForEvent to listen for untrusted events.
let shown = ContentTaskUtils.waitForEvent(
panelList,
"shown",
false /* capture */,
null /* checkFn */,
true /* wantsUntrusted */
);
let selector = shadow.querySelector("#browser-profile-selector");
selector.click();
await shown;
let panelRect = panelList.getBoundingClientRect();
let selectorRect = selector.getBoundingClientRect();
// Recalculate the <panel-list> rect top value relative to the top-left
// of the selectorRect. We expect the <panel-list> to be tightly anchored
// to the bottom of the <button>, so we expect this new value to be 0.
let panelTopLeftRelativeToAnchorTopLeft =
panelRect.top - selectorRect.top - selectorRect.height;
Assert.equal(
panelTopLeftRelativeToAnchorTopLeft,
0,
"Panel should be tightly anchored to the bottom of the button shadow node."
);
let panelItem = wizard.querySelector(menuitemSelector);
panelItem.click();
let importButton = shadow.querySelector("#import");
importButton.click();
}
);
await migrated;
Assert.ok(
telemetrySpy.calledWithMatch({
event: "CLICK_BUTTON",
event_context: { source: "primary_button", page: "about:welcome" },
message_id: sinon.match.string,
}),
"Should have sent telemetry for clicking the 'Import' button."
);
await SpecialPowers.spawn(browser, [], async () => {
let wizard = content.document.querySelector("migration-wizard");
let shadow = wizard.openOrClosedShadowRoot;
let deck = shadow.querySelector("#wizard-deck");
// It's unlikely but possible that the deck might not yet be showing the
// selection page yet, in which case we wait for that page to appear.
if (deck.selectedViewName !== MigrationWizardConstants.PAGES.SELECTION) {
await ContentTaskUtils.waitForMutationCondition(
deck,
{ attributeFilter: ["selected-view"] },
() => {
return (
deck.getAttribute("selected-view") ===
`page-${MigrationWizardConstants.PAGES.SELECTION}`
);
}
);
}
Assert.ok(true, "Selection page is being shown in the migration wizard.");
// Now let's make sure that the <panel-list> can appear.
let panelList = wizard.querySelector("panel-list");
Assert.ok(panelList, "Found the <panel-list>.");
// The "shown" event from the panel-list is coming from a lower level
// of privilege than where we're executing this SpecialPowers.spawn
// task. In order to properly listen for it, we have to ask
// ContentTaskUtils.waitForEvent to listen for untrusted events.
let shown = ContentTaskUtils.waitForEvent(
panelList,
"shown",
false /* capture */,
null /* checkFn */,
true /* wantsUntrusted */
let continueButton = shadow.querySelector(
"div[name='page-progress'] .continue-button"
);
let selector = shadow.querySelector("#browser-profile-selector");
selector.click();
await shown;
let panelRect = panelList.getBoundingClientRect();
let selectorRect = selector.getBoundingClientRect();
// Recalculate the <panel-list> rect top value relative to the top-left
// of the selectorRect. We expect the <panel-list> to be tightly anchored
// to the bottom of the <button>, so we expect this new value to be 0.
let panelTopLeftRelativeToAnchorTopLeft =
panelRect.top - selectorRect.top - selectorRect.height;
Assert.equal(
panelTopLeftRelativeToAnchorTopLeft,
0,
"Panel should be tightly anchored to the bottom of the button shadow node."
continueButton.click();
await ContentTaskUtils.waitForCondition(
() => content.document.querySelector("main.AW_STEP2"),
"Waiting for step 2 to render"
);
});
Assert.ok(
telemetrySpy.calledWithMatch({
event: "CLICK_BUTTON",
event_context: { source: "migrate_close", page: "about:welcome" },
message_id: sinon.match.string,
}),
"Should have sent telemetry for clicking the 'Continue' button."
);
// cleanup
await SpecialPowers.popPrefEnv(); // for the InternalTestingProfileMigrator.
await SpecialPowers.popPrefEnv(); // for setAboutWelcomeMultiStage
await cleanup();
sandbox.restore();
let migrator = await MigrationUtils.getMigrator(
InternalTestingProfileMigrator.key
);
migrator.flushResourceCache();
});