fune/browser/base/content/test/webextensions/browser_extension_sideloading.js
Phil Ringnalda 25fd452953 Backed out 5 changesets (bug 1197420) for test_ext_permissions.js and test_chrome_ext_permissions.html timeouts on Fennec
CLOSED TREE

Backed out changeset 8a0125e00903 (bug 1197420)
Backed out changeset 925e3a9499ee (bug 1197420)
Backed out changeset 46e135035f10 (bug 1197420)
Backed out changeset 440bab141509 (bug 1197420)
Backed out changeset 3e690bbe8b5a (bug 1197420)
2017-03-24 20:43:24 -07:00

333 lines
11 KiB
JavaScript

const {AddonManagerPrivate} = Cu.import("resource://gre/modules/AddonManager.jsm", {});
// MockAddon mimics the AddonInternal interface and MockProvider implements
// just enough of the AddonManager provider interface to make it look like
// we have sideloaded webextensions so the sideloading flow can be tested.
// MockAddon -> callback
let setCallbacks = new Map();
class MockAddon {
constructor(props) {
this._userDisabled = false;
this.pendingOperations = 0;
this.type = "extension";
for (let name in props) {
if (name == "userDisabled") {
this._userDisabled = props[name];
}
this[name] = props[name];
}
}
markAsSeen() {
this.seen = true;
}
get userDisabled() {
return this._userDisabled;
}
set userDisabled(val) {
this._userDisabled = val;
AddonManagerPrivate.callAddonListeners(val ? "onDisabled" : "onEnabled", this);
let fn = setCallbacks.get(this);
if (fn) {
setCallbacks.delete(this);
fn(val);
}
return val;
}
get permissions() {
return this._userDisabled ? AddonManager.PERM_CAN_ENABLE : AddonManager.PERM_CAN_DISABLE;
}
}
class MockProvider {
constructor(...addons) {
this.addons = new Set(addons);
}
startup() { }
shutdown() { }
getAddonByID(id, callback) {
for (let addon of this.addons) {
if (addon.id == id) {
callback(addon);
return;
}
}
callback(null);
}
getAddonsByTypes(types, callback) {
let addons = [];
if (!types || types.includes("extension")) {
addons = [...this.addons];
}
callback(addons);
}
}
function promiseSetDisabled(addon) {
return new Promise(resolve => {
setCallbacks.set(addon, resolve);
});
}
let cleanup;
add_task(function* () {
// ICON_URL wouldn't ever appear as an actual webextension icon, but
// we're just mocking out the addon here, so all we care about is that
// that it propagates correctly to the popup.
const ICON_URL = "chrome://mozapps/skin/extensions/category-extensions.svg";
const DEFAULT_ICON_URL = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
const ID1 = "addon1@tests.mozilla.org";
let mock1 = new MockAddon({
id: ID1,
name: "Test 1",
userDisabled: true,
seen: false,
userPermissions: {
permissions: ["history"],
hosts: ["https://*/*"],
},
iconURL: ICON_URL,
});
const ID2 = "addon2@tests.mozilla.org";
let mock2 = new MockAddon({
id: ID2,
name: "Test 2",
userDisabled: true,
seen: false,
userPermissions: {
permissions: [],
hosts: [],
},
});
const ID3 = "addon3@tests.mozilla.org";
let mock3 = new MockAddon({
id: ID3,
name: "Test 3",
isWebExtension: true,
userDisabled: true,
seen: false,
userPermissions: {
permissions: [],
hosts: ["<all_urls>"],
}
});
const ID4 = "addon4@tests.mozilla.org";
let mock4 = new MockAddon({
id: ID4,
name: "Test 4",
isWebExtension: true,
userDisabled: true,
seen: false,
userPermissions: {
permissions: [],
hosts: ["<all_urls>"],
}
});
let provider = new MockProvider(mock1, mock2, mock3, mock4);
AddonManagerPrivate.registerProvider(provider, [{
id: "extension",
name: "Extensions",
uiPriority: 4000,
flags: AddonManager.TYPE_UI_VIEW_LIST |
AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL,
}]);
testCleanup = async function() {
AddonManagerPrivate.unregisterProvider(provider);
// clear out ExtensionsUI state about sideloaded extensions so
// subsequent tests don't get confused.
ExtensionsUI.sideloaded.clear();
ExtensionsUI.emit("change");
};
// Navigate away from the starting page to force about:addons to load
// in a new tab during the tests below.
gBrowser.selectedBrowser.loadURI("about:robots");
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
registerCleanupFunction(function*() {
// Return to about:blank when we're done
gBrowser.selectedBrowser.loadURI("about:blank");
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
});
hookExtensionsTelemetry();
let changePromise = new Promise(resolve => {
ExtensionsUI.on("change", function listener() {
ExtensionsUI.off("change", listener);
resolve();
});
});
ExtensionsUI._checkForSideloaded();
yield changePromise;
// Check for the addons badge on the hamburger menu
let menuButton = document.getElementById("PanelUI-menu-button");
is(menuButton.getAttribute("badge-status"), "addon-alert", "Should have addon alert badge");
// Find the menu entries for sideloaded extensions
yield PanelUI.show();
let addons = document.getElementById("PanelUI-footer-addons");
is(addons.children.length, 4, "Have 4 menu entries for sideloaded extensions");
// Click the first sideloaded extension
let popupPromise = promisePopupNotificationShown("addon-webext-permissions");
addons.children[0].click();
// When we get the permissions prompt, we should be at the extensions
// list in about:addons
let panel = yield popupPromise;
is(gBrowser.currentURI.spec, "about:addons", "Foreground tab is at about:addons");
const VIEW = "addons://list/extension";
let win = gBrowser.selectedBrowser.contentWindow;
ok(!win.gViewController.isLoading, "about:addons view is fully loaded");
is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
// Check the contents of the notification, then choose "Cancel"
checkNotification(panel, ICON_URL, [
["webextPerms.hostDescription.allUrls"],
["webextPerms.description.history"],
]);
let disablePromise = promiseSetDisabled(mock1);
panel.secondaryButton.click();
let value = yield disablePromise;
is(value, true, "Addon should remain disabled");
let [addon1, addon2, addon3, addon4] = yield AddonManager.getAddonsByIDs([ID1, ID2, ID3, ID4]);
ok(addon1.seen, "Addon should be marked as seen");
is(addon1.userDisabled, true, "Addon 1 should still be disabled");
is(addon2.userDisabled, true, "Addon 2 should still be disabled");
is(addon3.userDisabled, true, "Addon 3 should still be disabled");
is(addon4.userDisabled, true, "Addon 4 should still be disabled");
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
// Should still have 3 entries in the hamburger menu
yield PanelUI.show();
addons = document.getElementById("PanelUI-footer-addons");
is(addons.children.length, 3, "Have 3 menu entries for sideloaded extensions");
// Click the second sideloaded extension and wait for the notification
popupPromise = promisePopupNotificationShown("addon-webext-permissions");
addons.children[0].click();
panel = yield popupPromise;
// Again we should be at the extentions list in about:addons
is(gBrowser.currentURI.spec, "about:addons", "Foreground tab is at about:addons");
win = gBrowser.selectedBrowser.contentWindow;
ok(!win.gViewController.isLoading, "about:addons view is fully loaded");
is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
// Check the notification contents.
checkNotification(panel, DEFAULT_ICON_URL, []);
// This time accept the install.
disablePromise = promiseSetDisabled(mock2);
panel.button.click();
value = yield disablePromise;
is(value, false, "Addon should be set to enabled");
[addon1, addon2, addon3, addon4] = yield AddonManager.getAddonsByIDs([ID1, ID2, ID3, ID4]);
is(addon1.userDisabled, true, "Addon 1 should still be disabled");
is(addon2.userDisabled, false, "Addon 2 should now be enabled");
is(addon3.userDisabled, true, "Addon 3 should still be disabled");
is(addon4.userDisabled, true, "Addon 4 should still be disabled");
// Should still have 2 entries in the hamburger menu
yield PanelUI.show();
addons = document.getElementById("PanelUI-footer-addons");
is(addons.children.length, 2, "Have 2 menu entries for sideloaded extensions");
// Close the hamburger menu and go directly to the addons manager
yield PanelUI.hide();
win = yield BrowserOpenAddonsMgr(VIEW);
let list = win.document.getElementById("addon-list");
// Make sure XBL bindings are applied
list.clientHeight;
let item = list.children.find(_item => _item.value == ID3);
ok(item, "Found entry for sideloaded extension in about:addons");
item.scrollIntoView({behavior: "instant"});
ok(is_visible(item._enableBtn), "Enable button is visible for sideloaded extension");
ok(is_hidden(item._disableBtn), "Disable button is not visible for sideloaded extension");
// When clicking enable we should see the permissions notification
popupPromise = promisePopupNotificationShown("addon-webext-permissions");
BrowserTestUtils.synthesizeMouseAtCenter(item._enableBtn, {},
gBrowser.selectedBrowser);
panel = yield popupPromise;
checkNotification(panel, DEFAULT_ICON_URL, [["webextPerms.hostDescription.allUrls"]]);
// Accept the permissions
disablePromise = promiseSetDisabled(mock3);
panel.button.click();
value = yield disablePromise;
is(value, false, "userDisabled should be set on addon 3");
addon3 = yield AddonManager.getAddonByID(ID3);
is(addon3.userDisabled, false, "Addon 3 should be enabled");
// Should still have 1 entry in the hamburger menu
yield PanelUI.show();
addons = document.getElementById("PanelUI-footer-addons");
is(addons.children.length, 1, "Have 1 menu entry for sideloaded extensions");
// Close the hamburger menu and go to the detail page for this addon
yield PanelUI.hide();
win = yield BrowserOpenAddonsMgr(`addons://detail/${encodeURIComponent(ID4)}`);
let button = win.document.getElementById("detail-enable-btn");
// When clicking enable we should see the permissions notification
popupPromise = promisePopupNotificationShown("addon-webext-permissions");
BrowserTestUtils.synthesizeMouseAtCenter(button, {},
gBrowser.selectedBrowser);
panel = yield popupPromise;
checkNotification(panel, DEFAULT_ICON_URL, [["webextPerms.hostDescription.allUrls"]]);
// Accept the permissions
disablePromise = promiseSetDisabled(mock4);
panel.button.click();
value = yield disablePromise;
is(value, false, "userDisabled should be set on addon 4");
addon4 = yield AddonManager.getAddonByID(ID4);
is(addon4.userDisabled, false, "Addon 4 should be enabled");
// We should have recorded 1 cancelled followed by 3 accepted sideloads.
expectTelemetry(["sideloadRejected", "sideloadAccepted", "sideloadAccepted", "sideloadAccepted"]);
isnot(menuButton.getAttribute("badge-status"), "addon-alert", "Should no longer have addon alert badge");
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
});