Bug 1957729 - Show data collection permissions in the update prompt. r=rpl,fluent-reviewers,bolsson
Differential Revision: https://phabricator.services.mozilla.com/D244067
This commit is contained in:
@@ -237,7 +237,11 @@ export var ExtensionsUI = {
|
|||||||
let strings = this._buildStrings(info);
|
let strings = this._buildStrings(info);
|
||||||
|
|
||||||
// If this is an update with no promptable permissions, just apply it
|
// If this is an update with no promptable permissions, just apply it
|
||||||
if (info.type == "update" && !strings.msgs.length) {
|
if (
|
||||||
|
info.type == "update" &&
|
||||||
|
!strings.msgs.length &&
|
||||||
|
!strings.dataCollectionPermissions?.msg
|
||||||
|
) {
|
||||||
info.resolve();
|
info.resolve();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -283,7 +287,7 @@ export var ExtensionsUI = {
|
|||||||
let strings = this._buildStrings(info);
|
let strings = this._buildStrings(info);
|
||||||
|
|
||||||
// If we don't prompt for any new permissions, just apply it
|
// If we don't prompt for any new permissions, just apply it
|
||||||
if (!strings.msgs.length) {
|
if (!strings.msgs.length && !strings.dataCollectionPermissions?.msg) {
|
||||||
info.resolve();
|
info.resolve();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1304,6 +1304,8 @@ export class ExtensionData {
|
|||||||
* Returns additional permissions that extensions is requesting based on its
|
* Returns additional permissions that extensions is requesting based on its
|
||||||
* manifest. For now, this is host_permissions (and content scripts) in mv3,
|
* manifest. For now, this is host_permissions (and content scripts) in mv3,
|
||||||
* and the "technicalAndInteraction" optional data collection permission.
|
* and the "technicalAndInteraction" optional data collection permission.
|
||||||
|
*
|
||||||
|
* @returns {null | Permissions}
|
||||||
*/
|
*/
|
||||||
getRequestedPermissions() {
|
getRequestedPermissions() {
|
||||||
if (this.type !== "extension") {
|
if (this.type !== "extension") {
|
||||||
@@ -1336,7 +1338,9 @@ export class ExtensionData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns optional permissions from the manifest, including host permissions
|
* Returns optional permissions from the manifest, including host permissions
|
||||||
* if originControls is true.
|
* if originControls is true, and optional data collection (if enabled).
|
||||||
|
*
|
||||||
|
* @returns {null | Permissions}
|
||||||
*/
|
*/
|
||||||
get manifestOptionalPermissions() {
|
get manifestOptionalPermissions() {
|
||||||
if (this.type !== "extension") {
|
if (this.type !== "extension") {
|
||||||
@@ -1353,11 +1357,14 @@ export class ExtensionData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Bug 1955990 - add support for data collection permissions.
|
const data_collection = lazy.dataCollectionPermissionsEnabled
|
||||||
|
? this.getDataCollectionPermissions().optional
|
||||||
|
: [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
permissions: Array.from(permissions),
|
permissions: Array.from(permissions),
|
||||||
origins: Array.from(origins),
|
origins: Array.from(origins),
|
||||||
|
data_collection,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1413,6 +1420,9 @@ export class ExtensionData {
|
|||||||
permissions: newPermissions.permissions.filter(
|
permissions: newPermissions.permissions.filter(
|
||||||
perm => !oldPermissions.permissions.includes(perm)
|
perm => !oldPermissions.permissions.includes(perm)
|
||||||
),
|
),
|
||||||
|
data_collection: newPermissions.data_collection.filter(
|
||||||
|
perm => newPermissions.data_collection.includes(perm) && perm !== "none"
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1431,6 +1441,9 @@ export class ExtensionData {
|
|||||||
permissions: oldPermissions.permissions.filter(perm =>
|
permissions: oldPermissions.permissions.filter(perm =>
|
||||||
newPermissions.permissions.includes(perm)
|
newPermissions.permissions.includes(perm)
|
||||||
),
|
),
|
||||||
|
data_collection: oldPermissions.data_collection.filter(
|
||||||
|
perm => newPermissions.data_collection.includes(perm) && perm !== "none"
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2865,7 +2878,10 @@ export class ExtensionData {
|
|||||||
permissions.data_collection?.length
|
permissions.data_collection?.length
|
||||||
) {
|
) {
|
||||||
result.dataCollectionPermissions =
|
result.dataCollectionPermissions =
|
||||||
this._formatDataCollectionPermissions(permissions.data_collection);
|
this._formatDataCollectionPermissions(
|
||||||
|
permissions.data_collection,
|
||||||
|
type
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2945,10 +2961,17 @@ export class ExtensionData {
|
|||||||
: "webext-perms-sideload-text-no-perms"
|
: "webext-perms-sideload-text-no-perms"
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "update":
|
case "update": {
|
||||||
headerId = "webext-perms-update-text";
|
if (!lazy.dataCollectionPermissionsEnabled) {
|
||||||
|
headerId = "webext-perms-update-text";
|
||||||
|
} else {
|
||||||
|
headerId = hasDataCollectionOnly
|
||||||
|
? "webext-perms-update-data-collection-only-text"
|
||||||
|
: "webext-perms-update-data-collection-text";
|
||||||
|
}
|
||||||
acceptId = "webext-perms-update-accept";
|
acceptId = "webext-perms-update-accept";
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case "optional":
|
case "optional":
|
||||||
headerId = "webext-perms-optional-perms-header";
|
headerId = "webext-perms-optional-perms-header";
|
||||||
acceptId = "webext-perms-optional-perms-allow";
|
acceptId = "webext-perms-optional-perms-allow";
|
||||||
@@ -2981,7 +3004,7 @@ export class ExtensionData {
|
|||||||
* @returns {{msg: string, collectsTechnicalAndInteractionData: boolean}} An
|
* @returns {{msg: string, collectsTechnicalAndInteractionData: boolean}} An
|
||||||
* object with information about data collection permissions for the UI.
|
* object with information about data collection permissions for the UI.
|
||||||
*/
|
*/
|
||||||
static _formatDataCollectionPermissions(dataPermissions) {
|
static _formatDataCollectionPermissions(dataPermissions, type) {
|
||||||
const dataCollectionPermissions = {};
|
const dataCollectionPermissions = {};
|
||||||
const permissions = new Set(dataPermissions);
|
const permissions = new Set(dataPermissions);
|
||||||
|
|
||||||
@@ -3011,8 +3034,17 @@ export class ExtensionData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let id;
|
||||||
|
switch (type) {
|
||||||
|
case "update":
|
||||||
|
id = "webext-perms-description-data-some-update";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
id = "webext-perms-description-data-some";
|
||||||
|
}
|
||||||
|
|
||||||
const fluentIdAndArgs = {
|
const fluentIdAndArgs = {
|
||||||
id: "webext-perms-description-data-some",
|
id,
|
||||||
args: {
|
args: {
|
||||||
permissions: new Intl.ListFormat(undefined, {
|
permissions: new Intl.ListFormat(undefined, {
|
||||||
style: "narrow",
|
style: "narrow",
|
||||||
|
|||||||
@@ -14,6 +14,17 @@ webext-perms-description-data-none = The developer says this extension doesn’t
|
|||||||
# $permissions (String): a list of data collection permissions formatted with `Intl.ListFormat` using the "narrow" style.
|
# $permissions (String): a list of data collection permissions formatted with `Intl.ListFormat` using the "narrow" style.
|
||||||
webext-perms-description-data-some = The developer says this extension collects: { $permissions }.
|
webext-perms-description-data-some = The developer says this extension collects: { $permissions }.
|
||||||
|
|
||||||
|
# Variables:
|
||||||
|
# $permissions (String): a list of data collection permissions formatted with `Intl.ListFormat` using the "narrow" style.
|
||||||
|
webext-perms-description-data-some-update = The developer says the extension will collect: { $permissions }.
|
||||||
|
# Variables:
|
||||||
|
# $extension (String): replaced with the localized name of the extension.
|
||||||
|
webext-perms-update-data-collection-text = { $extension } has been updated. You must approve new settings before the updated version will install. Choosing “Cancel” will maintain your current extension version. This extension will have permission to:
|
||||||
|
|
||||||
|
# Variables:
|
||||||
|
# $extension (String): replaced with the localized name of the extension.
|
||||||
|
webext-perms-update-data-collection-only-text = { $extension } has been updated. You must approve new settings before the updated version will install. Choosing “Cancel” will maintain your current extension version.
|
||||||
|
|
||||||
## Short form to be used in lists or in a string (`webext-perms-description-data-some`)
|
## Short form to be used in lists or in a string (`webext-perms-description-data-some`)
|
||||||
## that formats some of these permissions below using `Intl.ListFormat`.
|
## that formats some of these permissions below using `Intl.ListFormat`.
|
||||||
##
|
##
|
||||||
|
|||||||
@@ -1248,7 +1248,11 @@ var AddonManagerInternal = {
|
|||||||
let difference = lazy.Extension.comparePermissions(oldPerms, newPerms);
|
let difference = lazy.Extension.comparePermissions(oldPerms, newPerms);
|
||||||
|
|
||||||
// If there are no new permissions, just go ahead with the update
|
// If there are no new permissions, just go ahead with the update
|
||||||
if (!difference.origins.length && !difference.permissions.length) {
|
if (
|
||||||
|
!difference.origins.length &&
|
||||||
|
!difference.permissions.length &&
|
||||||
|
!difference.data_collection.length
|
||||||
|
) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,11 @@ function installPromptHandler(info) {
|
|||||||
let difference = Extension.comparePermissions(oldPerms, newPerms);
|
let difference = Extension.comparePermissions(oldPerms, newPerms);
|
||||||
|
|
||||||
// If there are no new permissions, just proceed
|
// If there are no new permissions, just proceed
|
||||||
if (!difference.origins.length && !difference.permissions.length) {
|
if (
|
||||||
|
!difference.origins.length &&
|
||||||
|
!difference.permissions.length &&
|
||||||
|
!difference.data_collection.length
|
||||||
|
) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ const { AddonTestUtils } = ChromeUtils.importESModule(
|
|||||||
"resource://testing-common/AddonTestUtils.sys.mjs"
|
"resource://testing-common/AddonTestUtils.sys.mjs"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ChromeUtils.defineESModuleGetters(this, {
|
||||||
|
PERMISSION_L10N: "resource://gre/modules/ExtensionPermissionMessages.sys.mjs",
|
||||||
|
});
|
||||||
|
|
||||||
AddonTestUtils.initMochitest(this);
|
AddonTestUtils.initMochitest(this);
|
||||||
|
|
||||||
const server = AddonTestUtils.createHttpServer();
|
const server = AddonTestUtils.createHttpServer();
|
||||||
@@ -49,6 +53,7 @@ add_setup(async function () {
|
|||||||
function createTestExtension({
|
function createTestExtension({
|
||||||
id = "test-pending-update@test",
|
id = "test-pending-update@test",
|
||||||
newManifest = {},
|
newManifest = {},
|
||||||
|
oldManifest = {},
|
||||||
}) {
|
}) {
|
||||||
function background() {
|
function background() {
|
||||||
browser.runtime.onUpdateAvailable.addListener(() => {
|
browser.runtime.onUpdateAvailable.addListener(() => {
|
||||||
@@ -64,6 +69,7 @@ function createTestExtension({
|
|||||||
|
|
||||||
const manifest = {
|
const manifest = {
|
||||||
name: "Test Pending Update",
|
name: "Test Pending Update",
|
||||||
|
...oldManifest,
|
||||||
browser_specific_settings: {
|
browser_specific_settings: {
|
||||||
gecko: { id, update_url },
|
gecko: { id, update_url },
|
||||||
},
|
},
|
||||||
@@ -72,7 +78,16 @@ function createTestExtension({
|
|||||||
|
|
||||||
let extension = ExtensionTestUtils.loadExtension({
|
let extension = ExtensionTestUtils.loadExtension({
|
||||||
background,
|
background,
|
||||||
manifest,
|
manifest: {
|
||||||
|
...oldManifest,
|
||||||
|
...manifest,
|
||||||
|
browser_specific_settings: {
|
||||||
|
gecko: {
|
||||||
|
...(oldManifest.browser_specific_settings?.gecko ?? {}),
|
||||||
|
...manifest.browser_specific_settings.gecko,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
// Use permanent so the add-on can be updated.
|
// Use permanent so the add-on can be updated.
|
||||||
useAddonManager: "permanent",
|
useAddonManager: "permanent",
|
||||||
});
|
});
|
||||||
@@ -309,3 +324,270 @@ add_task(async function test_pending_update_no_prompted_permission() {
|
|||||||
await closeView(win);
|
await closeView(win);
|
||||||
await extension.unload();
|
await extension.unload();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
add_task(async function test_pending_update_with_prompted_permission() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [["extensions.dataCollectionPermissions.enabled", true]],
|
||||||
|
});
|
||||||
|
|
||||||
|
const TEST_CASES = [
|
||||||
|
{
|
||||||
|
title: "With data collection",
|
||||||
|
data_collection_permissions: {
|
||||||
|
required: ["locationInfo"],
|
||||||
|
},
|
||||||
|
verifyDialog(popupContentEl, { extensionId }) {
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.querySelector(".popup-notification-description")
|
||||||
|
.textContent,
|
||||||
|
PERMISSION_L10N.formatValueSync(
|
||||||
|
"webext-perms-update-data-collection-only-text",
|
||||||
|
{ extension: extensionId }
|
||||||
|
),
|
||||||
|
"Expected header string without perms"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.permsListEl.childElementCount,
|
||||||
|
1,
|
||||||
|
"Expected a permission entry in the list"
|
||||||
|
);
|
||||||
|
Assert.ok(
|
||||||
|
popupContentEl.permsListEl.querySelector(
|
||||||
|
"li.webext-data-collection-perm-granted"
|
||||||
|
),
|
||||||
|
"Expected data collection item"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.permsListEl.firstChild.textContent,
|
||||||
|
PERMISSION_L10N.formatValueSync(
|
||||||
|
"webext-perms-description-data-some-update",
|
||||||
|
{
|
||||||
|
permissions: "location",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"Expected formatted data collection permission string"
|
||||||
|
);
|
||||||
|
Assert.ok(
|
||||||
|
popupContentEl.hasAttribute("learnmoreurl"),
|
||||||
|
"Expected a learn more link"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "With data collection and required permission",
|
||||||
|
permissions: ["bookmarks"],
|
||||||
|
data_collection_permissions: {
|
||||||
|
required: ["locationInfo", "healthInfo"],
|
||||||
|
},
|
||||||
|
verifyDialog(popupContentEl, { extensionId }) {
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.querySelector(".popup-notification-description")
|
||||||
|
.textContent,
|
||||||
|
PERMISSION_L10N.formatValueSync(
|
||||||
|
"webext-perms-update-data-collection-text",
|
||||||
|
{ extension: extensionId }
|
||||||
|
),
|
||||||
|
"Expected header string with perms"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.permsListEl.childElementCount,
|
||||||
|
2,
|
||||||
|
"Expected two permission entries in the list"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.permsListEl.firstChild.textContent,
|
||||||
|
PERMISSION_L10N.formatValueSync("webext-perms-description-bookmarks"),
|
||||||
|
"Expected formatted permission string"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.permsListEl.lastChild.textContent,
|
||||||
|
PERMISSION_L10N.formatValueSync(
|
||||||
|
"webext-perms-description-data-some-update",
|
||||||
|
{
|
||||||
|
permissions: "location, health information",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"Expected formatted data collection permission string"
|
||||||
|
);
|
||||||
|
Assert.ok(
|
||||||
|
popupContentEl.hasAttribute("learnmoreurl"),
|
||||||
|
"Expected a learn more link"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "With data collection changing from required to optional",
|
||||||
|
permissions: ["bookmarks"],
|
||||||
|
old_data_collection_permissions: {
|
||||||
|
required: ["bookmarksInfo"],
|
||||||
|
},
|
||||||
|
data_collection_permissions: {
|
||||||
|
required: ["locationInfo", "healthInfo"],
|
||||||
|
optional: ["bookmarksInfo"],
|
||||||
|
},
|
||||||
|
verifyDialog(popupContentEl, { extensionId }) {
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.querySelector(".popup-notification-description")
|
||||||
|
.textContent,
|
||||||
|
PERMISSION_L10N.formatValueSync(
|
||||||
|
"webext-perms-update-data-collection-text",
|
||||||
|
{ extension: extensionId }
|
||||||
|
),
|
||||||
|
"Expected header string with perms"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.permsListEl.childElementCount,
|
||||||
|
2,
|
||||||
|
"Expected two permission entries in the list"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.permsListEl.childNodes[0].textContent,
|
||||||
|
PERMISSION_L10N.formatValueSync("webext-perms-description-bookmarks"),
|
||||||
|
"Expected formatted bookmarks permission string"
|
||||||
|
);
|
||||||
|
Assert.equal(
|
||||||
|
popupContentEl.permsListEl.childNodes[1].textContent,
|
||||||
|
PERMISSION_L10N.formatValueSync(
|
||||||
|
"webext-perms-description-data-some-update",
|
||||||
|
{
|
||||||
|
permissions: "location, health information",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"Expected formatted data collection permission string"
|
||||||
|
);
|
||||||
|
Assert.ok(
|
||||||
|
popupContentEl.hasAttribute("learnmoreurl"),
|
||||||
|
"Expected a learn more link"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const {
|
||||||
|
title,
|
||||||
|
permissions,
|
||||||
|
data_collection_permissions,
|
||||||
|
old_data_collection_permissions,
|
||||||
|
verifyDialog,
|
||||||
|
} of TEST_CASES) {
|
||||||
|
info(title);
|
||||||
|
|
||||||
|
const id = `@${title.toLowerCase().replaceAll(/[^\w]+/g, "-")}`;
|
||||||
|
const { extension } = createTestExtension({
|
||||||
|
id,
|
||||||
|
oldManifest: {
|
||||||
|
browser_specific_settings: {
|
||||||
|
gecko: {
|
||||||
|
...(old_data_collection_permissions
|
||||||
|
? { data_collection_permissions: old_data_collection_permissions }
|
||||||
|
: {}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
newManifest: {
|
||||||
|
name: id,
|
||||||
|
permissions,
|
||||||
|
browser_specific_settings: {
|
||||||
|
gecko: {
|
||||||
|
id,
|
||||||
|
data_collection_permissions,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await extension.startup();
|
||||||
|
await extension.awaitMessage("bgpage-ready");
|
||||||
|
const win = await loadInitialView("extension");
|
||||||
|
|
||||||
|
const dialogPromise = promisePopupNotificationShown(
|
||||||
|
"addon-webext-permissions"
|
||||||
|
);
|
||||||
|
// This `promptPromise` is retrieving data from the prompt internals, while
|
||||||
|
// the `dialogPromise` will return the actual dialog element.
|
||||||
|
const promptPromise = promisePermissionPrompt(id);
|
||||||
|
win.checkForUpdates();
|
||||||
|
const [popupContentEl, infoProps] = await Promise.all([
|
||||||
|
dialogPromise,
|
||||||
|
promptPromise,
|
||||||
|
]);
|
||||||
|
|
||||||
|
verifyDialog(popupContentEl, { extensionId: id });
|
||||||
|
|
||||||
|
// Confirm the update, and proceed.
|
||||||
|
const waitForManagementUpdate = new Promise(resolve => {
|
||||||
|
const { Management } = ChromeUtils.importESModule(
|
||||||
|
"resource://gre/modules/Extension.sys.mjs"
|
||||||
|
);
|
||||||
|
Management.once("update", resolve);
|
||||||
|
});
|
||||||
|
infoProps.resolve();
|
||||||
|
await promiseUpdateAvailable(extension);
|
||||||
|
await completePostponedUpdate({ id, win });
|
||||||
|
// Ensure that the bootstrap scope update method has been executed
|
||||||
|
// successfully and emitted the update Management event.
|
||||||
|
info("Wait for the Management update to be emitted");
|
||||||
|
await waitForManagementUpdate;
|
||||||
|
|
||||||
|
await closeView(win);
|
||||||
|
await extension.unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
await SpecialPowers.popPrefEnv();
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_pending_update_with_no_prompted_permission() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [["extensions.dataCollectionPermissions.enabled", true]],
|
||||||
|
});
|
||||||
|
|
||||||
|
const TEST_CASES = [
|
||||||
|
{
|
||||||
|
title: "No data collection",
|
||||||
|
data_collection_permissions: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Explicit no data collection",
|
||||||
|
data_collection_permissions: {
|
||||||
|
required: ["none"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Optional data collection",
|
||||||
|
data_collection_permissions: {
|
||||||
|
optional: ["technicalAndInteraction"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const { title, data_collection_permissions } of TEST_CASES) {
|
||||||
|
info(title);
|
||||||
|
|
||||||
|
const id = `@${title.toLowerCase().replaceAll(/[^\w]+/g, "-")}`;
|
||||||
|
const { extension } = createTestExtension({
|
||||||
|
id,
|
||||||
|
newManifest: {
|
||||||
|
name: id,
|
||||||
|
browser_specific_settings: {
|
||||||
|
gecko: {
|
||||||
|
id,
|
||||||
|
data_collection_permissions,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await extension.startup();
|
||||||
|
await extension.awaitMessage("bgpage-ready");
|
||||||
|
let win = await loadInitialView("extension");
|
||||||
|
|
||||||
|
win.checkForUpdates();
|
||||||
|
await promiseUpdateAvailable(extension);
|
||||||
|
await completePostponedUpdate({ id, win });
|
||||||
|
|
||||||
|
await closeView(win);
|
||||||
|
await extension.unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
await SpecialPowers.popPrefEnv();
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user