Bug 1531964 - Permissions tab on add-on details page r=rpl,flod

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Mark Striemer 2019-05-16 14:14:29 +00:00
parent 2748936152
commit 40e016aded
6 changed files with 175 additions and 6 deletions

View File

@ -391,6 +391,7 @@ preferences-addon-button =
}
details-addon-button = Details
release-notes-addon-button = Release Notes
permissions-addon-button = Permissions
addons-enabled-heading = Enabled
addons-disabled-heading = Disabled
@ -452,3 +453,5 @@ recent-updates-heading = Recent Updates
release-notes-loading = Loading…
release-notes-error = Sorry, but there was an error loading the release notes.
addon-permissions-empty = This extension doesnt require any permissions

View File

@ -362,6 +362,10 @@ panel-item-separator[hidden] {
text-decoration: none;
}
addon-permissions-list > .addon-detail-row:first-of-type {
border-top: none;
}
.deck-tab-group {
border-bottom: 1px solid var(--grey-90-a20);
border-top: 1px solid var(--grey-90-a20);

View File

@ -87,6 +87,7 @@
<template name="addon-details">
<div class="deck-tab-group">
<named-deck-button deck="details-deck" name="details" data-l10n-id="details-addon-button"></named-deck-button>
<named-deck-button deck="details-deck" name="permissions" data-l10n-id="permissions-addon-button"></named-deck-button>
<named-deck-button deck="details-deck" name="release-notes" data-l10n-id="release-notes-addon-button"></named-deck-button>
</div>
<named-deck id="details-deck">
@ -156,6 +157,7 @@
</div>
</div>
</section>
<addon-permissions-list name="permissions"></addon-permissions-list>
<update-release-notes name="release-notes"></update-release-notes>
</named-deck>
</template>

View File

@ -18,6 +18,15 @@ XPCOMUtils.defineLazyModuleGetters(this, {
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
});
XPCOMUtils.defineLazyGetter(this, "browserBundle", () => {
return Services.strings.createBundle(
"chrome://browser/locale/browser.properties");
});
XPCOMUtils.defineLazyGetter(this, "brandBundle", () => {
return Services.strings.createBundle(
"chrome://branding/locale/brand.properties");
});
XPCOMUtils.defineLazyPreferenceGetter(
this, "allowPrivateBrowsingByDefault",
"extensions.allowPrivateBrowsingByDefault", true);
@ -753,6 +762,49 @@ class UpdateReleaseNotes extends HTMLElement {
}
customElements.define("update-release-notes", UpdateReleaseNotes);
class AddonPermissionsList extends HTMLElement {
setAddon(addon) {
this.addon = addon;
this.render();
}
render() {
let appName = brandBundle.GetStringFromName("brandShortName");
let {msgs} = Extension.formatPermissionStrings({
permissions: this.addon.userPermissions,
appName,
}, browserBundle);
this.textContent = "";
if (msgs.length > 0) {
// Add a row for each permission message.
for (let msg of msgs) {
let row = document.createElement("div");
row.classList.add("addon-detail-row", "permission-info");
row.textContent = msg;
this.appendChild(row);
}
} else {
let emptyMessage = document.createElement("div");
emptyMessage.classList.add("addon-detail-row");
document.l10n.setAttributes(emptyMessage, "addon-permissions-empty");
this.appendChild(emptyMessage);
}
// Add a learn more link.
let learnMoreRow = document.createElement("div");
learnMoreRow.classList.add("addon-detail-row");
let learnMoreLink = document.createElement("a");
learnMoreLink.setAttribute("target", "_blank");
learnMoreLink.href = SUPPORT_URL + "extension-permissions";
learnMoreLink.textContent =
browserBundle.GetStringFromName("webextPerms.learnMore");
learnMoreRow.appendChild(learnMoreLink);
this.appendChild(learnMoreRow);
}
}
customElements.define("addon-permissions-list", AddonPermissionsList);
class AddonDetails extends HTMLElement {
connectedCallback() {
@ -793,6 +845,8 @@ class AddonDetails extends HTMLElement {
// Hide tab buttons that won't have any content.
let getButtonByName =
name => this.tabGroup.querySelector(`[name="${name}"]`);
let permsBtn = getButtonByName("permissions");
permsBtn.hidden = addon.type != "extension";
let notesBtn = getButtonByName("release-notes");
notesBtn.hidden = !this.releaseNotesUri;
@ -828,6 +882,10 @@ class AddonDetails extends HTMLElement {
this.deck = this.querySelector("named-deck");
this.tabGroup = this.querySelector(".deck-tab-group");
// Set the add-on for the permissions section.
this.permissionsList = this.querySelector("addon-permissions-list");
this.permissionsList.setAddon(addon);
// Full description.
let description = this.querySelector(".addon-detail-description");
if (addon.getFullDescription) {

View File

@ -61,6 +61,26 @@ function checkOptions(doc, options, expectedOptions) {
}
}
function assertDeckHeadingHidden(group) {
ok(group.hidden, "The tab group is hidden");
for (let button of group.children) {
ok(button.offsetHeight == 0, `The ${button.name} is hidden`);
}
}
function assertDeckHeadingButtons(group, visibleButtons) {
ok(!group.hidden, "The tab group is shown");
ok(group.children.length >= visibleButtons.length,
`There should be at least ${visibleButtons.length} buttons`);
for (let button of group.children) {
if (visibleButtons.includes(button.name)) {
ok(!button.hidden, `The ${button.name} is shown`);
} else {
ok(button.hidden, `The ${button.name} is hidden`);
}
}
}
async function hasPrivateAllowed(id) {
let perms = await ExtensionPermissions.get(id);
return perms.permissions.includes("internal:privateBrowsingAllowed");
@ -83,6 +103,10 @@ add_task(async function enableHtmlViews() {
type: "extension",
contributionURL: "http://foo.com",
averageRating: 4.279,
userPermissions: {
origins: ["<all_urls>", "file://*/*"],
permissions: ["alarms", "contextMenus", "tabs", "webNavigation"],
},
reviewCount: 5,
reviewURL: "http://example.com/reviews",
homepageURL: "http://example.com/addon1",
@ -93,6 +117,10 @@ add_task(async function enableHtmlViews() {
name: "Test add-on 2",
creator: {name: "I made it"},
description: "Short description",
userPermissions: {
origins: [],
permissions: ["alarms", "contextMenus"],
},
type: "extension",
}, {
id: "theme1@mochi.test",
@ -284,6 +312,10 @@ add_task(async function testFullDetails() {
is(preview.hidden, true, "The preview is hidden");
let details = card.querySelector("addon-details");
// Check all the deck buttons are hidden.
assertDeckHeadingButtons(details.tabGroup, ["details", "permissions"]);
let desc = details.querySelector(".addon-detail-description");
is(desc.innerHTML, "Longer description<br>With brs!",
"The full description replaces newlines with <br>");
@ -291,7 +323,8 @@ add_task(async function testFullDetails() {
let contrib = details.querySelector(".addon-detail-contribute");
ok(contrib, "The contribution section is visible");
let rows = Array.from(details.querySelectorAll(".addon-detail-row"));
let rows = Array.from(
card.querySelectorAll('[name="details"] .addon-detail-row'));
// Auto updates.
let row = rows.shift();
@ -396,13 +429,17 @@ add_task(async function testMinimalExtension() {
card = getAddonCard(doc, "addon2@mochi.test");
let details = card.querySelector("addon-details");
// Check all the deck buttons are hidden.
assertDeckHeadingButtons(details.tabGroup, ["details", "permissions"]);
let desc = details.querySelector(".addon-detail-description");
is(desc.textContent, "", "There is no full description");
let contrib = details.querySelector(".addon-detail-contribute");
ok(!contrib, "There is no contribution element");
let rows = Array.from(details.querySelectorAll(".addon-detail-row"));
let rows = Array.from(
card.querySelectorAll('[name="details"] .addon-detail-row'));
// Automatic updates.
let row = rows.shift();
@ -454,7 +491,11 @@ add_task(async function testDefaultTheme() {
ok(preview, "There is a preview");
is(preview.hidden, true, "The preview is hidden");
let rows = Array.from(card.querySelectorAll(".addon-detail-row"));
// Check all the deck buttons are hidden.
assertDeckHeadingHidden(card.details.tabGroup);
let rows = Array.from(
card.querySelectorAll('[name="details"] .addon-detail-row'));
// Author.
let author = rows.shift();
@ -508,7 +549,11 @@ add_task(async function testStaticTheme() {
is(preview.height, "90", "The height is set");
is(preview.hidden, false, "The preview is visible");
let rows = Array.from(card.querySelectorAll(".addon-detail-row"));
// Check all the deck buttons are hidden.
assertDeckHeadingHidden(card.details.tabGroup);
let rows = Array.from(
card.querySelectorAll('[name="details"] .addon-detail-row'));
// Automatic updates.
let row = rows.shift();
@ -621,3 +666,61 @@ add_task(async function testPrivateBrowsingAllowedListView() {
await extension.unload();
await closeView(win);
});
add_task(async function testPermissions() {
async function runTest(id, permissions) {
let win = await loadInitialView("extension");
let doc = win.document;
let card = getAddonCard(doc, id);
ok(!card.hasAttribute("expanded"), "The list card is not expanded");
let loaded = waitForViewLoad(win);
card.querySelector('[action="expand"]').click();
await loaded;
card = getAddonCard(doc, id);
let {deck, tabGroup} = card.details;
// Check all the deck buttons are hidden.
assertDeckHeadingButtons(tabGroup, ["details", "permissions"]);
let permsBtn = tabGroup.querySelector('[name="permissions"]');
let permsShown = BrowserTestUtils.waitForEvent(deck, "view-changed");
permsBtn.click();
await permsShown;
let permsSection = card.querySelector("addon-permissions-list");
let rows = Array.from(permsSection.querySelectorAll(".addon-detail-row"));
info("Check displayed permissions");
if (permissions) {
for (let name in permissions) {
// Check the permission-info class to make sure it's for a permission.
let row = rows.shift();
ok(row.classList.contains("permission-info"),
`There's a row for ${name}`);
}
} else {
let row = rows.shift();
is(doc.l10n.getAttributes(row).id, "addon-permissions-empty",
"There's a message when no permissions are shown");
}
info("Check learn more link");
let row = rows.shift();
is(row.children.length, 1, "There's one child for learn more");
let link = row.firstElementChild;
let rootUrl = Services.urlFormatter.formatURLPref("app.support.baseURL");
let url = rootUrl + "extension-permissions";
is(link.href, url, "The URL is set");
is(link.getAttribute("target"), "_blank", "The link opens in a new tab");
await closeView(win);
}
info("Check permissions for add-on with permission message");
await runTest("addon1@mochi.test", ["<all_urls>", "tabs", "webNavigation"]);
info("Check permissions for add-on without permission messages");
await runTest("addon2@mochi.test");
});

View File

@ -218,8 +218,7 @@ function assertUpdateState({
`The update check button is ${shown ? "hidden" : "shown"}`);
let {tabGroup} = card.details;
is(tabGroup.hidden, !releaseNotes,
`The tab group is ${releaseNotes ? "shown" : "hidden"}`);
is(tabGroup.hidden, false, "The tab group is shown");
let notesBtn = tabGroup.querySelector('[name="release-notes"]');
is(notesBtn.hidden, !releaseNotes,
`The release notes button is ${releaseNotes ? "shown" : "hidden"}`);