зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1593358 - Wait to move extension cards while list is active r=rpl,Gijs
Differential Revision: https://phabricator.services.mozilla.com/D51700 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
fc6c868f4a
Коммит
3ad260c258
|
@ -122,6 +122,13 @@ const PRIVATE_BROWSING_PERMS = {
|
|||
origins: [],
|
||||
};
|
||||
|
||||
function shouldSkipAnimations() {
|
||||
return (
|
||||
document.body.hasAttribute("skip-animations") ||
|
||||
window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
||||
);
|
||||
}
|
||||
|
||||
const AddonCardListenerHandler = {
|
||||
ADDON_EVENTS: new Set([
|
||||
"onDisabled",
|
||||
|
@ -2430,6 +2437,8 @@ class AddonCard extends HTMLElement {
|
|||
switch (action) {
|
||||
case "toggle-disabled":
|
||||
this.recordActionEvent(addon.userDisabled ? "enable" : "disable");
|
||||
// Keep the checked state the same until the add-on's state changes.
|
||||
e.target.checked = !addon.userDisabled;
|
||||
if (addon.userDisabled) {
|
||||
if (shouldShowPermissionsPrompt(addon)) {
|
||||
await showPermissionsPrompt(addon);
|
||||
|
@ -2439,10 +2448,6 @@ class AddonCard extends HTMLElement {
|
|||
} else {
|
||||
await addon.disable();
|
||||
}
|
||||
if (e.mozInputSource == MouseEvent.MOZ_SOURCE_KEYBOARD) {
|
||||
// Refocus the button, since the card might've moved and lost focus.
|
||||
e.target.focus();
|
||||
}
|
||||
break;
|
||||
case "ask-to-activate":
|
||||
if (hasPermission(addon, "ask-to-activate")) {
|
||||
|
@ -3129,6 +3134,8 @@ class AddonList extends HTMLElement {
|
|||
super();
|
||||
this.sections = [];
|
||||
this.pendingUninstallAddons = new Set();
|
||||
this._addonsToUpdate = new Set();
|
||||
this._userFocusListenersAdded = false;
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
|
@ -3321,9 +3328,7 @@ class AddonList extends HTMLElement {
|
|||
return;
|
||||
}
|
||||
|
||||
let insertSection = this.sections.findIndex(({ filterFn }) =>
|
||||
filterFn(addon)
|
||||
);
|
||||
let insertSection = this._addonSectionIndex(addon);
|
||||
|
||||
// Don't add the add-on if it doesn't go in a section.
|
||||
if (insertSection == -1) {
|
||||
|
@ -3352,24 +3357,144 @@ class AddonList extends HTMLElement {
|
|||
}
|
||||
|
||||
updateAddon(addon) {
|
||||
if (!this.getCard(addon)) {
|
||||
// Try to add the add-on right away.
|
||||
this.addAddon(addon);
|
||||
} else if (this._addonSectionIndex(addon) == -1) {
|
||||
// Try to remove the add-on right away.
|
||||
this._updateAddon(addon);
|
||||
} else if (this.isUserFocused) {
|
||||
// Queue up a change for when the focus is cleared.
|
||||
this.updateLater(addon);
|
||||
} else {
|
||||
// Not currently focused, make the change now.
|
||||
this.withCardAnimation(() => this._updateAddon(addon));
|
||||
}
|
||||
}
|
||||
|
||||
updateLater(addon) {
|
||||
this._addonsToUpdate.add(addon);
|
||||
this._addUserFocusListeners();
|
||||
}
|
||||
|
||||
_addUserFocusListeners() {
|
||||
if (this._userFocusListenersAdded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._userFocusListenersAdded = true;
|
||||
this.addEventListener("mouseleave", this);
|
||||
this.addEventListener("hidden", this, true);
|
||||
this.addEventListener("focusout", this);
|
||||
}
|
||||
|
||||
_removeUserFocusListeners() {
|
||||
if (!this._userFocusListenersAdded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeEventListener("mouseleave", this);
|
||||
this.removeEventListener("hidden", this, true);
|
||||
this.removeEventListener("focusout", this);
|
||||
this._userFocusListenersAdded = false;
|
||||
}
|
||||
|
||||
get hasMenuOpen() {
|
||||
return !!this.querySelector("panel-list[open]");
|
||||
}
|
||||
|
||||
get isUserFocused() {
|
||||
return this.matches(":hover, :focus-within") || this.hasMenuOpen;
|
||||
}
|
||||
|
||||
update() {
|
||||
if (this._addonsToUpdate.size) {
|
||||
this.withCardAnimation(() => {
|
||||
for (let addon of this._addonsToUpdate) {
|
||||
this._updateAddon(addon);
|
||||
}
|
||||
this._addonsToUpdate = new Set();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_getChildCoords() {
|
||||
let results = new Map();
|
||||
for (let child of this.querySelectorAll("addon-card")) {
|
||||
results.set(child, child.getBoundingClientRect());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
withCardAnimation(changeFn) {
|
||||
if (shouldSkipAnimations()) {
|
||||
changeFn();
|
||||
return;
|
||||
}
|
||||
|
||||
let origChildCoords = this._getChildCoords();
|
||||
|
||||
changeFn();
|
||||
|
||||
let newChildCoords = this._getChildCoords();
|
||||
let cards = this.querySelectorAll("addon-card");
|
||||
let transitionCards = [];
|
||||
for (let card of cards) {
|
||||
let orig = origChildCoords.get(card);
|
||||
let moved = newChildCoords.get(card);
|
||||
let changeY = moved.y - (orig || moved).y;
|
||||
let cardEl = card.firstElementChild;
|
||||
|
||||
if (changeY != 0) {
|
||||
cardEl.style.transform = `translateY(${changeY * -1}px)`;
|
||||
transitionCards.push(card);
|
||||
}
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
for (let card of transitionCards) {
|
||||
card.firstElementChild.style.transition = "transform 125ms";
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
for (let card of transitionCards) {
|
||||
let cardEl = card.firstElementChild;
|
||||
cardEl.style.transform = "";
|
||||
cardEl.addEventListener("transitionend", function handler(e) {
|
||||
if (e.target == cardEl && e.propertyName == "transform") {
|
||||
cardEl.style.transition = "";
|
||||
cardEl.removeEventListener("transitionend", handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_addonSectionIndex(addon) {
|
||||
return this.sections.findIndex(s => s.filterFn(addon));
|
||||
}
|
||||
|
||||
_updateAddon(addon) {
|
||||
let card = this.getCard(addon);
|
||||
if (card) {
|
||||
let sectionIndex = this.sections.findIndex(s => s.filterFn(addon));
|
||||
let sectionIndex = this._addonSectionIndex(addon);
|
||||
if (sectionIndex != -1) {
|
||||
// Move the card, if needed. This will allow an animation between
|
||||
// page sections and provides clearer events for testing.
|
||||
if (card.parentNode.getAttribute("section") != sectionIndex) {
|
||||
let { activeElement } = document;
|
||||
let refocus = card.contains(activeElement);
|
||||
let oldSection = card.parentNode;
|
||||
this.insertCardInto(card, sectionIndex);
|
||||
this.updateSectionIfEmpty(oldSection);
|
||||
if (refocus) {
|
||||
activeElement.focus();
|
||||
}
|
||||
this.sendEvent("move", { id: addon.id });
|
||||
}
|
||||
} else {
|
||||
this.removeAddon(addon);
|
||||
}
|
||||
} else {
|
||||
// Add the add-on, this will do nothing if it shouldn't be in the list.
|
||||
this.addAddon(addon);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3468,6 +3593,13 @@ class AddonList extends HTMLElement {
|
|||
this.removePendingUninstallBar(addon);
|
||||
this.removeAddon(addon);
|
||||
}
|
||||
|
||||
handleEvent(e) {
|
||||
if (!this.isUserFocused || (e.type == "mouseleave" && !this.hasMenuOpen)) {
|
||||
this._removeUserFocusListeners();
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
customElements.define("addon-list", AddonList);
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ generated-files =
|
|||
[browser_CTP_plugins.js]
|
||||
tags = blocklist
|
||||
[browser_about_debugging_link.js]
|
||||
[browser_addon_list_reordering.js]
|
||||
[browser_bug523784.js]
|
||||
skip-if = (!debug && os == 'win') #Bug 1489496
|
||||
[browser_bug567137.js]
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
|
||||
function assertInSection(card, sectionName, msg) {
|
||||
let section = card.closest("section");
|
||||
let heading = section.querySelector(".list-section-heading");
|
||||
is(
|
||||
card.ownerDocument.l10n.getAttributes(heading).id,
|
||||
`extension-${sectionName}-heading`,
|
||||
msg
|
||||
);
|
||||
}
|
||||
|
||||
function waitForAnimationFrame(win) {
|
||||
return new Promise(resolve => win.requestAnimationFrame(resolve));
|
||||
}
|
||||
|
||||
async function clickEnableToggle(card) {
|
||||
let isDisabled = card.addon.userDisabled;
|
||||
let addonEvent = isDisabled ? "onEnabled" : "onDisabled";
|
||||
let addonStateChanged = AddonTestUtils.promiseAddonEvent(addonEvent);
|
||||
let win = card.ownerGlobal;
|
||||
let button = card.querySelector(".extension-enable-button");
|
||||
|
||||
// Centre the button since "start" could be behind the sticky header.
|
||||
button.scrollIntoView({ block: "center" });
|
||||
EventUtils.synthesizeMouseAtCenter(button, { type: "mousemove" }, win);
|
||||
EventUtils.synthesizeMouseAtCenter(button, {}, win);
|
||||
|
||||
await addonStateChanged;
|
||||
await waitForAnimationFrame(win);
|
||||
}
|
||||
|
||||
function mouseOver(el) {
|
||||
let win = el.ownerGlobal;
|
||||
el.scrollIntoView({ block: "center" });
|
||||
EventUtils.synthesizeMouseAtCenter(el, { type: "mousemove" }, win);
|
||||
return waitForAnimationFrame(win);
|
||||
}
|
||||
|
||||
function mouseOutOfList(win) {
|
||||
return mouseOver(win.document.querySelector(".header-name"));
|
||||
}
|
||||
|
||||
function pressKey(win, key) {
|
||||
EventUtils.synthesizeKey(key, {}, win);
|
||||
return waitForAnimationFrame(win);
|
||||
}
|
||||
|
||||
function waitForTransitionEnd(...els) {
|
||||
return Promise.all(
|
||||
els.map(el =>
|
||||
BrowserTestUtils.waitForEvent(el, "transitionend", false, e => {
|
||||
let cardEl = el.firstElementChild;
|
||||
return e.target == cardEl && e.propertyName == "transform";
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function testReordering() {
|
||||
let addonIds = [
|
||||
"one@mochi.test",
|
||||
"two@mochi.test",
|
||||
"three@mochi.test",
|
||||
"four@mochi.test",
|
||||
"five@mochi.test",
|
||||
];
|
||||
let extensions = addonIds.map(id =>
|
||||
ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: id,
|
||||
applications: { gecko: { id } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
})
|
||||
);
|
||||
|
||||
await Promise.all(extensions.map(ext => ext.startup()));
|
||||
|
||||
let win = await loadInitialView("extension", { withAnimations: true });
|
||||
|
||||
let cardOne = getAddonCard(win, "one@mochi.test");
|
||||
ok(!cardOne.addon.userDisabled, "extension one is enabled");
|
||||
assertInSection(cardOne, "enabled", "cardOne is initially in Enabled");
|
||||
|
||||
await clickEnableToggle(cardOne);
|
||||
|
||||
ok(cardOne.addon.userDisabled, "extension one is now disabled");
|
||||
assertInSection(cardOne, "enabled", "cardOne is still in Enabled");
|
||||
|
||||
let cardThree = getAddonCard(win, "three@mochi.test");
|
||||
ok(!cardThree.addon.userDisabled, "extension three is enabled");
|
||||
assertInSection(cardThree, "enabled", "cardThree is initially in Enabled");
|
||||
|
||||
await clickEnableToggle(cardThree);
|
||||
|
||||
ok(cardThree.addon.userDisabled, "extension three is now disabled");
|
||||
assertInSection(cardThree, "enabled", "cardThree is still in Enabled");
|
||||
|
||||
let transitionsEnded = waitForTransitionEnd(cardOne, cardThree);
|
||||
await mouseOutOfList(win);
|
||||
await transitionsEnded;
|
||||
|
||||
assertInSection(cardOne, "disabled", "cardOne has moved to disabled");
|
||||
assertInSection(cardThree, "disabled", "cardThree has moved to disabled");
|
||||
|
||||
await clickEnableToggle(cardThree);
|
||||
await clickEnableToggle(cardOne);
|
||||
|
||||
assertInSection(cardOne, "disabled", "cardOne is still in disabled");
|
||||
assertInSection(cardThree, "disabled", "cardThree is still in disabled");
|
||||
|
||||
info("Opening a more options menu");
|
||||
let panel = cardThree.querySelector("panel-list");
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
cardThree.querySelector('[action="more-options"]'),
|
||||
{},
|
||||
win
|
||||
);
|
||||
|
||||
await BrowserTestUtils.waitForEvent(panel, "shown");
|
||||
await mouseOutOfList(win);
|
||||
|
||||
assertInSection(cardOne, "disabled", "cardOne stays in disabled, menu open");
|
||||
assertInSection(cardThree, "disabled", "cardThree stays in disabled");
|
||||
|
||||
transitionsEnded = waitForTransitionEnd(cardOne, cardThree);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
win.document.querySelector(".header-name"),
|
||||
{},
|
||||
win
|
||||
);
|
||||
await transitionsEnded;
|
||||
|
||||
assertInSection(cardOne, "enabled", "cardOne is now in enabled");
|
||||
assertInSection(cardThree, "enabled", "cardThree is now in enabled");
|
||||
|
||||
let cardOneToggle = cardOne.querySelector(".extension-enable-button");
|
||||
cardOneToggle.scrollIntoView({ block: "center" });
|
||||
cardOneToggle.focus();
|
||||
await pressKey(win, " ");
|
||||
await waitForAnimationFrame(win);
|
||||
|
||||
let cardThreeToggle = cardThree.querySelector(".extension-enable-button");
|
||||
let addonList = win.document.querySelector("addon-list");
|
||||
// Tab down to cardThreeToggle.
|
||||
while (
|
||||
addonList.contains(win.document.activeElement) &&
|
||||
win.document.activeElement !== cardThreeToggle
|
||||
) {
|
||||
await pressKey(win, "VK_TAB");
|
||||
}
|
||||
await pressKey(win, " ");
|
||||
|
||||
assertInSection(cardOne, "enabled", "cardOne is still in enabled");
|
||||
assertInSection(cardThree, "enabled", "cardThree is still in enabled");
|
||||
|
||||
transitionsEnded = waitForTransitionEnd(cardOne, cardThree);
|
||||
win.document.querySelector('[action="page-options"]').focus();
|
||||
await transitionsEnded;
|
||||
assertInSection(
|
||||
cardOne,
|
||||
"disabled",
|
||||
"cardOne is now in the disabled section"
|
||||
);
|
||||
assertInSection(
|
||||
cardThree,
|
||||
"disabled",
|
||||
"cardThree is now in the disabled section"
|
||||
);
|
||||
|
||||
// Ensure an uninstalled extension is removed right away.
|
||||
// Hover a card in the middle of the list.
|
||||
await mouseOver(getAddonCard(win, "two@mochi.test"));
|
||||
await cardOne.addon.uninstall(true);
|
||||
ok(!cardOne.parentNode, "cardOne has been removed from the document");
|
||||
|
||||
await closeView(win);
|
||||
await Promise.all(extensions.map(ext => ext.unload()));
|
||||
});
|
|
@ -15,9 +15,6 @@ var GMPScope = ChromeUtils.import(
|
|||
|
||||
const TEST_DATE = new Date(2013, 0, 1, 12);
|
||||
|
||||
var gManagerWindow;
|
||||
var gCategoryUtilities;
|
||||
|
||||
var gMockAddons = [];
|
||||
|
||||
for (let plugin of GMPScope.GMP_PLUGINS) {
|
||||
|
@ -53,35 +50,20 @@ MockGMPInstallManager.prototype = {
|
|||
},
|
||||
};
|
||||
|
||||
function openDetailsView(aId) {
|
||||
let view = get_current_view(gManagerWindow);
|
||||
Assert.equal(
|
||||
view.id,
|
||||
"html-view",
|
||||
"Should be in the list view to use this function"
|
||||
);
|
||||
|
||||
let item = get_addon_element(gManagerWindow, aId);
|
||||
function openDetailsView(win, id) {
|
||||
let item = getAddonCard(win, id);
|
||||
Assert.ok(item, "Should have got add-on element.");
|
||||
is_element_visible(item, "Add-on element should be visible.");
|
||||
|
||||
item.scrollIntoView();
|
||||
EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, item.ownerGlobal);
|
||||
EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, item.ownerGlobal);
|
||||
|
||||
return new Promise(resolve => {
|
||||
wait_for_view_load(gManagerWindow, resolve);
|
||||
});
|
||||
let loaded = waitForViewLoad(win);
|
||||
EventUtils.synthesizeMouseAtCenter(item, {}, item.ownerGlobal);
|
||||
return loaded;
|
||||
}
|
||||
|
||||
async function initializeState() {
|
||||
add_task(async function initializeState() {
|
||||
gPrefs.setBoolPref(GMPScope.GMPPrefs.KEY_LOGGING_DUMP, true);
|
||||
gPrefs.setIntPref(GMPScope.GMPPrefs.KEY_LOGGING_LEVEL, 0);
|
||||
|
||||
gManagerWindow = await open_manager();
|
||||
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
|
||||
registerCleanupFunction(async function() {
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.clearUserPref(
|
||||
|
@ -142,14 +124,16 @@ async function initializeState() {
|
|||
}
|
||||
await GMPScope.GMPProvider.shutdown();
|
||||
GMPScope.GMPProvider.startup();
|
||||
}
|
||||
});
|
||||
|
||||
async function testNotInstalledDisabled() {
|
||||
Assert.ok(gCategoryUtilities.isTypeVisible("plugin"), "Plugin tab visible.");
|
||||
await gCategoryUtilities.openType("plugin");
|
||||
add_task(async function testNotInstalledDisabled() {
|
||||
let win = await loadInitialView("extension");
|
||||
|
||||
Assert.ok(isCategoryVisible(win, "plugin"), "Plugin tab visible.");
|
||||
await switchView(win, "plugin");
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
let addonCard = get_addon_element(gManagerWindow, addon.id);
|
||||
let addonCard = getAddonCard(win, addon.id);
|
||||
Assert.ok(addonCard, "Got add-on element:" + addon.id);
|
||||
|
||||
is(
|
||||
|
@ -161,18 +145,20 @@ async function testNotInstalledDisabled() {
|
|||
let cardMessage = addonCard.querySelector("message-bar.addon-card-message");
|
||||
is_element_hidden(cardMessage, "Warning notification is hidden");
|
||||
}
|
||||
}
|
||||
|
||||
async function testNotInstalledDisabledDetails() {
|
||||
await closeView(win);
|
||||
});
|
||||
|
||||
add_task(async function testNotInstalledDisabledDetails() {
|
||||
let win = await loadInitialView("plugin");
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
await openDetailsView(addon.id);
|
||||
let doc = gManagerWindow.document;
|
||||
|
||||
let addonCard = get_addon_element(gManagerWindow, addon.id);
|
||||
await openDetailsView(win, addon.id);
|
||||
let addonCard = getAddonCard(win, addon.id);
|
||||
ok(addonCard, "Got add-on element: " + addon.id);
|
||||
|
||||
is(
|
||||
doc.l10n.getAttributes(addonCard.addonNameEl).id,
|
||||
win.document.l10n.getAttributes(addonCard.addonNameEl).id,
|
||||
"addon-name-disabled",
|
||||
"The addon name should include a disabled postfix"
|
||||
);
|
||||
|
@ -182,17 +168,21 @@ async function testNotInstalledDisabledDetails() {
|
|||
let cardMessage = addonCard.querySelector("message-bar.addon-card-message");
|
||||
is_element_hidden(cardMessage, "Warning notification is hidden");
|
||||
|
||||
await gCategoryUtilities.openType("plugin");
|
||||
await switchView(win, "plugin");
|
||||
}
|
||||
}
|
||||
|
||||
async function testNotInstalled() {
|
||||
await closeView(win);
|
||||
});
|
||||
|
||||
add_task(async function testNotInstalled() {
|
||||
let win = await loadInitialView("plugin");
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id),
|
||||
true
|
||||
);
|
||||
let item = get_addon_element(gManagerWindow, addon.id);
|
||||
let item = getAddonCard(win, addon.id);
|
||||
Assert.ok(item, "Got add-on element:" + addon.id);
|
||||
|
||||
let warningMessageBar = await BrowserTestUtils.waitForCondition(() => {
|
||||
|
@ -214,13 +204,17 @@ async function testNotInstalled() {
|
|||
);
|
||||
pluginOptions.querySelector("panel-list").open = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function testNotInstalledDetails() {
|
||||
await closeView(win);
|
||||
});
|
||||
|
||||
add_task(async function testNotInstalledDetails() {
|
||||
let win = await loadInitialView("plugin");
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
await openDetailsView(addon.id);
|
||||
await openDetailsView(win, addon.id);
|
||||
|
||||
const addonCard = get_addon_element(gManagerWindow, addon.id);
|
||||
const addonCard = getAddonCard(win, addon.id);
|
||||
let el = addonCard.querySelector("[action=update-check]");
|
||||
is_element_visible(el, "Check for Updates action is visible");
|
||||
|
||||
|
@ -231,11 +225,15 @@ async function testNotInstalledDetails() {
|
|||
}, "Wait for the addon card message to be updated");
|
||||
is_element_visible(warningMessageBar, "Warning notification is visible");
|
||||
|
||||
await gCategoryUtilities.openType("plugin");
|
||||
await switchView(win, "plugin");
|
||||
}
|
||||
}
|
||||
|
||||
async function testInstalled() {
|
||||
await closeView(win);
|
||||
});
|
||||
|
||||
add_task(async function testInstalled() {
|
||||
let win = await loadInitialView("plugin");
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.setIntPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, addon.id),
|
||||
|
@ -250,7 +248,7 @@ async function testInstalled() {
|
|||
"1.2.3.4"
|
||||
);
|
||||
|
||||
let item = get_addon_element(gManagerWindow, addon.id);
|
||||
let item = getAddonCard(win, addon.id);
|
||||
Assert.ok(item, "Got add-on element.");
|
||||
|
||||
is(item.parentNode.getAttribute("section"), "0", "Should be enabled");
|
||||
|
@ -266,13 +264,17 @@ async function testInstalled() {
|
|||
);
|
||||
pluginOptions.querySelector("panel-list").open = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function testInstalledDetails() {
|
||||
await closeView(win);
|
||||
});
|
||||
|
||||
add_task(async function testInstalledDetails() {
|
||||
let win = await loadInitialView("plugin");
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
await openDetailsView(addon.id);
|
||||
await openDetailsView(win, addon.id);
|
||||
|
||||
let card = get_addon_element(gManagerWindow, addon.id);
|
||||
let card = getAddonCard(win, addon.id);
|
||||
ok(card, "Got add-on element:" + addon.id);
|
||||
|
||||
is_element_visible(
|
||||
|
@ -280,14 +282,18 @@ async function testInstalledDetails() {
|
|||
"Find updates link is visible"
|
||||
);
|
||||
|
||||
await gCategoryUtilities.openType("plugin");
|
||||
await switchView(win, "plugin");
|
||||
}
|
||||
}
|
||||
|
||||
async function testInstalledGlobalEmeDisabled() {
|
||||
await closeView(win);
|
||||
});
|
||||
|
||||
add_task(async function testInstalledGlobalEmeDisabled() {
|
||||
let win = await loadInitialView("plugin");
|
||||
gPrefs.setBoolPref(GMPScope.GMPPrefs.KEY_EME_ENABLED, false);
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
let item = get_addon_element(gManagerWindow, addon.id);
|
||||
let item = getAddonCard(win, addon.id);
|
||||
if (addon.isEME) {
|
||||
is(item.parentNode.getAttribute("section"), "1", "Should be disabled");
|
||||
// Open the options menu (needed to check the disabled buttons).
|
||||
|
@ -305,10 +311,12 @@ async function testInstalledGlobalEmeDisabled() {
|
|||
Assert.ok(item, "Got add-on element.");
|
||||
}
|
||||
}
|
||||
gPrefs.setBoolPref(GMPScope.GMPPrefs.KEY_EME_ENABLED, true);
|
||||
}
|
||||
|
||||
async function testPreferencesButton() {
|
||||
gPrefs.setBoolPref(GMPScope.GMPPrefs.KEY_EME_ENABLED, true);
|
||||
await closeView(win);
|
||||
});
|
||||
|
||||
add_task(async function testPreferencesButton() {
|
||||
let prefValues = [
|
||||
{ enabled: false, version: "" },
|
||||
{ enabled: false, version: "1.2.3.4" },
|
||||
|
@ -317,15 +325,12 @@ async function testPreferencesButton() {
|
|||
];
|
||||
|
||||
for (let preferences of prefValues) {
|
||||
dump(
|
||||
info(
|
||||
"Testing preferences button with pref settings: " +
|
||||
JSON.stringify(preferences) +
|
||||
"\n"
|
||||
JSON.stringify(preferences)
|
||||
);
|
||||
for (let addon of gMockAddons) {
|
||||
await close_manager(gManagerWindow);
|
||||
gManagerWindow = await open_manager();
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
let win = await loadInitialView("plugin");
|
||||
gPrefs.setCharPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id),
|
||||
preferences.version
|
||||
|
@ -335,8 +340,7 @@ async function testPreferencesButton() {
|
|||
preferences.enabled
|
||||
);
|
||||
|
||||
await gCategoryUtilities.openType("plugin");
|
||||
let item = get_addon_element(gManagerWindow, addon.id);
|
||||
let item = getAddonCard(win, addon.id);
|
||||
|
||||
// Open the options menu (needed to check the more options action is enabled).
|
||||
const pluginOptions = item.querySelector("plugin-options");
|
||||
|
@ -350,12 +354,17 @@ async function testPreferencesButton() {
|
|||
);
|
||||
moreOptions.click();
|
||||
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
await waitForViewLoad(win);
|
||||
|
||||
item = getAddonCard(win, addon.id);
|
||||
ok(item, "The right view is loaded");
|
||||
|
||||
await closeView(win);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function testUpdateButton() {
|
||||
add_task(async function testUpdateButton() {
|
||||
gPrefs.clearUserPref(GMPScope.GMPPrefs.KEY_UPDATE_LAST_CHECK);
|
||||
|
||||
let originalInstallManager = GMPScope.GMPInstallManager;
|
||||
|
@ -366,20 +375,24 @@ async function testUpdateButton() {
|
|||
configurable: true,
|
||||
});
|
||||
|
||||
let win = await loadInitialView("plugin");
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
await gCategoryUtilities.openType("plugin");
|
||||
let item = get_addon_element(gManagerWindow, addon.id);
|
||||
let item = getAddonCard(win, addon.id);
|
||||
|
||||
gInstalledAddonId = "";
|
||||
gInstallDeferred = Promise.defer();
|
||||
|
||||
let loaded = waitForViewLoad(win);
|
||||
item.querySelector("[action=expand]").click();
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
let detail = get_addon_element(gManagerWindow, addon.id);
|
||||
await loaded;
|
||||
let detail = getAddonCard(win, addon.id);
|
||||
detail.querySelector("[action=update-check]").click();
|
||||
|
||||
await gInstallDeferred.promise;
|
||||
Assert.equal(gInstalledAddonId, addon.id);
|
||||
|
||||
await switchView(win, "plugin");
|
||||
}
|
||||
Object.defineProperty(GMPScope, "GMPInstallManager", {
|
||||
value: originalInstallManager,
|
||||
|
@ -387,9 +400,11 @@ async function testUpdateButton() {
|
|||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
async function testEmeSupport() {
|
||||
await closeView(win);
|
||||
});
|
||||
|
||||
add_task(async function testEmeSupport() {
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.clearUserPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id)
|
||||
|
@ -398,9 +413,10 @@ async function testEmeSupport() {
|
|||
await GMPScope.GMPProvider.shutdown();
|
||||
GMPScope.GMPProvider.startup();
|
||||
|
||||
let win = await loadInitialView("plugin");
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
await gCategoryUtilities.openType("plugin");
|
||||
let item = get_addon_element(gManagerWindow, addon.id);
|
||||
let item = getAddonCard(win, addon.id);
|
||||
if (addon.id == GMPScope.EME_ADOBE_ID) {
|
||||
if (AppConstants.isPlatformAndVersionAtLeast("win", "6")) {
|
||||
Assert.ok(item, "Adobe EME supported, found add-on element.");
|
||||
|
@ -428,6 +444,8 @@ async function testEmeSupport() {
|
|||
}
|
||||
}
|
||||
|
||||
await closeView(win);
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VISIBLE, addon.id),
|
||||
|
@ -440,27 +458,4 @@ async function testEmeSupport() {
|
|||
}
|
||||
await GMPScope.GMPProvider.shutdown();
|
||||
GMPScope.GMPProvider.startup();
|
||||
}
|
||||
|
||||
async function testCleanupState() {
|
||||
await SpecialPowers.popPrefEnv();
|
||||
await close_manager(gManagerWindow);
|
||||
}
|
||||
|
||||
// This function run the sequence of all the gmpProvider tests
|
||||
// under the same initializeStateOptions (which will enable or disable
|
||||
// the HTML about:addons views).
|
||||
add_task(async function test_gmpProvider(initializeStateOptions) {
|
||||
await initializeState();
|
||||
await testNotInstalledDisabled();
|
||||
await testNotInstalledDisabledDetails();
|
||||
await testNotInstalled();
|
||||
await testNotInstalledDetails();
|
||||
await testInstalled();
|
||||
await testInstalledDetails();
|
||||
await testInstalledGlobalEmeDisabled();
|
||||
await testPreferencesButton();
|
||||
await testUpdateButton();
|
||||
await testEmeSupport();
|
||||
await testCleanupState();
|
||||
});
|
||||
|
|
|
@ -366,10 +366,11 @@ add_task(async function testMouseSupport() {
|
|||
});
|
||||
|
||||
add_task(async function testKeyboardSupport() {
|
||||
let id = "test@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test extension",
|
||||
applications: { gecko: { id: "test@mochi.test" } },
|
||||
applications: { gecko: { id } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
@ -424,19 +425,32 @@ add_task(async function testKeyboardSupport() {
|
|||
tab({ shiftKey: true });
|
||||
isFocused(disableButton, "The disable toggle is focused");
|
||||
is(card.parentNode, enabledSection, "The card is in the enabled section");
|
||||
let disabled = BrowserTestUtils.waitForEvent(list, "move");
|
||||
space();
|
||||
await disabled;
|
||||
// Wait for the add-on state to change.
|
||||
let [disabledAddon] = await AddonTestUtils.promiseAddonEvent("onDisabled");
|
||||
is(disabledAddon.id, id, "The right add-on was disabled");
|
||||
is(
|
||||
card.parentNode,
|
||||
enabledSection,
|
||||
"The card is still in the enabled section"
|
||||
);
|
||||
isFocused(disableButton, "The disable button is still focused");
|
||||
let moved = BrowserTestUtils.waitForEvent(list, "move");
|
||||
// Click outside the list to clear any focus.
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
doc.querySelector(".header-name"),
|
||||
{},
|
||||
win
|
||||
);
|
||||
await moved;
|
||||
is(
|
||||
card.parentNode,
|
||||
disabledSection,
|
||||
"The card is now in the disabled section"
|
||||
"The card moved when keyboard focus left the list"
|
||||
);
|
||||
isFocused(disableButton, "The disable button is still focused");
|
||||
|
||||
// Remove the add-on.
|
||||
tab();
|
||||
isFocused(moreOptionsButton, "The more options button is focused again");
|
||||
moreOptionsButton.focus();
|
||||
shown = BrowserTestUtils.waitForEvent(moreOptionsMenu, "shown");
|
||||
space();
|
||||
is(moreOptionsMenu.open, true, "The menu is open");
|
||||
|
@ -928,6 +942,10 @@ add_task(async function testDisabledDimming() {
|
|||
|
||||
let win = await loadInitialView("extension");
|
||||
let doc = win.document;
|
||||
let pageHeader = doc.querySelector("addon-page-header");
|
||||
|
||||
// Ensure there's no focus on the list.
|
||||
EventUtils.synthesizeMouseAtCenter(pageHeader, {}, win);
|
||||
|
||||
const checkOpacity = (card, expected, msg) => {
|
||||
let { opacity } = card.ownerGlobal.getComputedStyle(card.firstElementChild);
|
||||
|
@ -944,18 +962,25 @@ add_task(async function testDisabledDimming() {
|
|||
checkOpacity(card, "1", "The opacity is 1 when enabled");
|
||||
|
||||
// Disable the add-on, check again.
|
||||
let list = doc.querySelector("addon-list");
|
||||
let moved = BrowserTestUtils.waitForEvent(list, "move");
|
||||
await addon.disable();
|
||||
await moved;
|
||||
|
||||
let disabledSection = getSection(doc, "disabled");
|
||||
is(card.parentNode, disabledSection, "The card is in the disabled section");
|
||||
checkOpacity(card, "0.6", "The opacity is dimmed when disabled");
|
||||
|
||||
// Click on the menu button, this should un-dim the card.
|
||||
let transitionEnded = waitForTransition(card);
|
||||
card.panel.open = true;
|
||||
let moreOptionsButton = card.querySelector(".more-options-button");
|
||||
EventUtils.synthesizeMouseAtCenter(moreOptionsButton, {}, win);
|
||||
await transitionEnded;
|
||||
checkOpacity(card, "1", "The opacity is 1 when the menu is open");
|
||||
|
||||
// Close the menu, opacity should return.
|
||||
transitionEnded = waitForTransition(card);
|
||||
card.panel.open = false;
|
||||
EventUtils.synthesizeMouseAtCenter(pageHeader, {}, win);
|
||||
await transitionEnded;
|
||||
checkOpacity(card, "0.6", "The card is dimmed again");
|
||||
|
||||
|
|
|
@ -1637,7 +1637,7 @@ function assertAboutAddonsTelemetryEvents(events, filters = {}) {
|
|||
}
|
||||
|
||||
/* HTML view helpers */
|
||||
async function loadInitialView(type) {
|
||||
async function loadInitialView(type, opts) {
|
||||
// Force the first page load to be the view we want.
|
||||
let viewId = type == "discover" ? "discover/" : `list/${type}`;
|
||||
Services.prefs.setCharPref(PREF_UI_LASTCATEGORY, `addons://${viewId}`);
|
||||
|
@ -1646,6 +1646,9 @@ async function loadInitialView(type) {
|
|||
|
||||
let browser = managerWindow.document.getElementById("html-view-browser");
|
||||
let win = browser.contentWindow;
|
||||
if (!opts || !opts.withAnimations) {
|
||||
win.document.body.setAttribute("skip-animations", "");
|
||||
}
|
||||
win.managerWindow = managerWindow;
|
||||
return win;
|
||||
}
|
||||
|
@ -1662,6 +1665,10 @@ function switchView(win, type) {
|
|||
return new CategoryUtilities(win.managerWindow).openType(type);
|
||||
}
|
||||
|
||||
function isCategoryVisible(win, type) {
|
||||
return new CategoryUtilities(win.managerWindow).isTypeVisible(type);
|
||||
}
|
||||
|
||||
function mockPromptService() {
|
||||
let { prompt } = Services;
|
||||
let promptService = {
|
||||
|
|
Загрузка…
Ссылка в новой задаче