зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1561435 - Format toolkit/mozapps/, a=automatic-formatting
# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D36057 --HG-- extra : source : fc2db4029f7eeae4942b42ca0b23873f150012b2
This commit is contained in:
Родитель
b503616295
Коммит
584e273f90
|
@ -28,16 +28,18 @@ const LAST_DIR_PREF = "browser.download.lastDir";
|
|||
const SAVE_PER_SITE_PREF = LAST_DIR_PREF + ".savePerSite";
|
||||
const nsIFile = Ci.nsIFile;
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "DownloadLastDir" ];
|
||||
var EXPORTED_SYMBOLS = ["DownloadLastDir"];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let nonPrivateLoadContext = Cu.createLoadContext();
|
||||
let privateLoadContext = Cu.createPrivateLoadContext();
|
||||
|
||||
var observer = {
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver",
|
||||
"nsISupportsWeakReference"]),
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
"nsIObserver",
|
||||
"nsISupportsWeakReference",
|
||||
]),
|
||||
|
||||
observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
|
@ -46,12 +48,14 @@ var observer = {
|
|||
break;
|
||||
case "browser:purge-session-history":
|
||||
gDownloadLastDirFile = null;
|
||||
if (Services.prefs.prefHasUserValue(LAST_DIR_PREF))
|
||||
if (Services.prefs.prefHasUserValue(LAST_DIR_PREF)) {
|
||||
Services.prefs.clearUserPref(LAST_DIR_PREF);
|
||||
}
|
||||
// Ensure that purging session history causes both the session-only PB cache
|
||||
// and persistent prefs to be cleared.
|
||||
let cps2 = Cc["@mozilla.org/content-pref/service;1"].
|
||||
getService(Ci.nsIContentPrefService2);
|
||||
let cps2 = Cc["@mozilla.org/content-pref/service;1"].getService(
|
||||
Ci.nsIContentPrefService2
|
||||
);
|
||||
|
||||
cps2.removeByName(LAST_DIR_PREF, nonPrivateLoadContext);
|
||||
cps2.removeByName(LAST_DIR_PREF, privateLoadContext);
|
||||
|
@ -82,14 +86,13 @@ function isContentPrefEnabled() {
|
|||
var gDownloadLastDirFile = readLastDirPref();
|
||||
|
||||
function DownloadLastDir(aWindow) {
|
||||
let loadContext = aWindow.docShell
|
||||
.QueryInterface(Ci.nsILoadContext);
|
||||
let loadContext = aWindow.docShell.QueryInterface(Ci.nsILoadContext);
|
||||
// Need this in case the real thing has gone away by the time we need it.
|
||||
// We only care about the private browsing state. All the rest of the
|
||||
// load context isn't of interest to the content pref service.
|
||||
this.fakeContext = loadContext.usePrivateBrowsing ?
|
||||
privateLoadContext :
|
||||
nonPrivateLoadContext;
|
||||
this.fakeContext = loadContext.usePrivateBrowsing
|
||||
? privateLoadContext
|
||||
: nonPrivateLoadContext;
|
||||
}
|
||||
|
||||
DownloadLastDir.prototype = {
|
||||
|
@ -97,19 +100,25 @@ DownloadLastDir.prototype = {
|
|||
return this.fakeContext.usePrivateBrowsing;
|
||||
},
|
||||
// compat shims
|
||||
get file() { return this._getLastFile(); },
|
||||
set file(val) { this.setFile(null, val); },
|
||||
get file() {
|
||||
return this._getLastFile();
|
||||
},
|
||||
set file(val) {
|
||||
this.setFile(null, val);
|
||||
},
|
||||
cleanupPrivateFile() {
|
||||
gDownloadLastDirFile = null;
|
||||
},
|
||||
|
||||
_getLastFile() {
|
||||
if (gDownloadLastDirFile && !gDownloadLastDirFile.exists())
|
||||
if (gDownloadLastDirFile && !gDownloadLastDirFile.exists()) {
|
||||
gDownloadLastDirFile = null;
|
||||
}
|
||||
|
||||
if (this.isPrivate()) {
|
||||
if (!gDownloadLastDirFile)
|
||||
if (!gDownloadLastDirFile) {
|
||||
gDownloadLastDirFile = readLastDirPref();
|
||||
}
|
||||
return gDownloadLastDirFile;
|
||||
}
|
||||
return readLastDirPref();
|
||||
|
@ -123,18 +132,20 @@ DownloadLastDir.prototype = {
|
|||
}
|
||||
|
||||
let uri = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
|
||||
let cps2 = Cc["@mozilla.org/content-pref/service;1"]
|
||||
.getService(Ci.nsIContentPrefService2);
|
||||
let cps2 = Cc["@mozilla.org/content-pref/service;1"].getService(
|
||||
Ci.nsIContentPrefService2
|
||||
);
|
||||
let result = null;
|
||||
cps2.getByDomainAndName(uri, LAST_DIR_PREF, this.fakeContext, {
|
||||
handleResult: aResult => result = aResult,
|
||||
handleResult: aResult => (result = aResult),
|
||||
handleCompletion(aReason) {
|
||||
let file = plainPrefFile;
|
||||
if (aReason == Ci.nsIContentPrefCallback2.COMPLETE_OK &&
|
||||
result instanceof Ci.nsIContentPref) {
|
||||
if (
|
||||
aReason == Ci.nsIContentPrefCallback2.COMPLETE_OK &&
|
||||
result instanceof Ci.nsIContentPref
|
||||
) {
|
||||
try {
|
||||
file = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsIFile);
|
||||
file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.initWithPath(result.value);
|
||||
} catch (e) {
|
||||
file = plainPrefFile;
|
||||
|
@ -148,18 +159,21 @@ DownloadLastDir.prototype = {
|
|||
setFile(aURI, aFile) {
|
||||
if (aURI && isContentPrefEnabled()) {
|
||||
let uri = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
|
||||
let cps2 = Cc["@mozilla.org/content-pref/service;1"]
|
||||
.getService(Ci.nsIContentPrefService2);
|
||||
if (aFile instanceof Ci.nsIFile)
|
||||
let cps2 = Cc["@mozilla.org/content-pref/service;1"].getService(
|
||||
Ci.nsIContentPrefService2
|
||||
);
|
||||
if (aFile instanceof Ci.nsIFile) {
|
||||
cps2.set(uri, LAST_DIR_PREF, aFile.path, this.fakeContext);
|
||||
else
|
||||
} else {
|
||||
cps2.removeByDomainAndName(uri, LAST_DIR_PREF, this.fakeContext);
|
||||
}
|
||||
}
|
||||
if (this.isPrivate()) {
|
||||
if (aFile instanceof Ci.nsIFile)
|
||||
if (aFile instanceof Ci.nsIFile) {
|
||||
gDownloadLastDirFile = aFile.clone();
|
||||
else
|
||||
} else {
|
||||
gDownloadLastDirFile = null;
|
||||
}
|
||||
} else if (aFile instanceof Ci.nsIFile) {
|
||||
Services.prefs.setComplexValue(LAST_DIR_PREF, nsIFile, aFile);
|
||||
} else if (Services.prefs.prefHasUserValue(LAST_DIR_PREF)) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "DownloadUtils" ];
|
||||
var EXPORTED_SYMBOLS = ["DownloadUtils"];
|
||||
|
||||
/**
|
||||
* This module provides the DownloadUtils object which contains useful methods
|
||||
|
@ -37,20 +37,26 @@ var EXPORTED_SYMBOLS = [ "DownloadUtils" ];
|
|||
* convertTimeUnits(double aSecs)
|
||||
*/
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm"
|
||||
);
|
||||
|
||||
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
||||
|
||||
var localeNumberFormatCache = new Map();
|
||||
function getLocaleNumberFormat(fractionDigits) {
|
||||
if (!localeNumberFormatCache.has(fractionDigits)) {
|
||||
localeNumberFormatCache.set(fractionDigits,
|
||||
new Services.intl.NumberFormat(undefined,
|
||||
{ maximumFractionDigits: fractionDigits,
|
||||
minimumFractionDigits: fractionDigits }));
|
||||
localeNumberFormatCache.set(
|
||||
fractionDigits,
|
||||
new Services.intl.NumberFormat(undefined, {
|
||||
maximumFractionDigits: fractionDigits,
|
||||
minimumFractionDigits: fractionDigits,
|
||||
})
|
||||
);
|
||||
}
|
||||
return localeNumberFormatCache.get(fractionDigits);
|
||||
}
|
||||
|
@ -85,7 +91,7 @@ Object.defineProperty(this, "gBundle", {
|
|||
enumerable: true,
|
||||
get() {
|
||||
delete this.gBundle;
|
||||
return this.gBundle = Services.strings.createBundle(kDownloadProperties);
|
||||
return (this.gBundle = Services.strings.createBundle(kDownloadProperties));
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -109,18 +115,33 @@ var DownloadUtils = {
|
|||
* Last time remaining in seconds or Infinity for unknown
|
||||
* @return A pair: [download status text, new value of "last seconds"]
|
||||
*/
|
||||
getDownloadStatus: function DU_getDownloadStatus(aCurrBytes, aMaxBytes,
|
||||
aSpeed, aLastSec) {
|
||||
let [transfer, timeLeft, newLast, normalizedSpeed]
|
||||
= this._deriveTransferRate(aCurrBytes, aMaxBytes, aSpeed, aLastSec);
|
||||
getDownloadStatus: function DU_getDownloadStatus(
|
||||
aCurrBytes,
|
||||
aMaxBytes,
|
||||
aSpeed,
|
||||
aLastSec
|
||||
) {
|
||||
let [
|
||||
transfer,
|
||||
timeLeft,
|
||||
newLast,
|
||||
normalizedSpeed,
|
||||
] = this._deriveTransferRate(aCurrBytes, aMaxBytes, aSpeed, aLastSec);
|
||||
|
||||
let [rate, unit] = DownloadUtils.convertByteUnits(normalizedSpeed);
|
||||
|
||||
let status;
|
||||
if (rate === "Infinity") {
|
||||
// Infinity download speed doesn't make sense. Show a localized phrase instead.
|
||||
let params = [transfer, gBundle.GetStringFromName(gStr.infiniteRate), timeLeft];
|
||||
status = gBundle.formatStringFromName(gStr.statusFormatInfiniteRate, params);
|
||||
let params = [
|
||||
transfer,
|
||||
gBundle.GetStringFromName(gStr.infiniteRate),
|
||||
timeLeft,
|
||||
];
|
||||
status = gBundle.formatStringFromName(
|
||||
gStr.statusFormatInfiniteRate,
|
||||
params
|
||||
);
|
||||
} else {
|
||||
let params = [transfer, rate, unit, timeLeft];
|
||||
status = gBundle.formatStringFromName(gStr.statusFormat, params);
|
||||
|
@ -144,11 +165,18 @@ var DownloadUtils = {
|
|||
* Last time remaining in seconds or Infinity for unknown
|
||||
* @return A pair: [download status text, new value of "last seconds"]
|
||||
*/
|
||||
getDownloadStatusNoRate:
|
||||
function DU_getDownloadStatusNoRate(aCurrBytes, aMaxBytes, aSpeed,
|
||||
aLastSec) {
|
||||
let [transfer, timeLeft, newLast]
|
||||
= this._deriveTransferRate(aCurrBytes, aMaxBytes, aSpeed, aLastSec);
|
||||
getDownloadStatusNoRate: function DU_getDownloadStatusNoRate(
|
||||
aCurrBytes,
|
||||
aMaxBytes,
|
||||
aSpeed,
|
||||
aLastSec
|
||||
) {
|
||||
let [transfer, timeLeft, newLast] = this._deriveTransferRate(
|
||||
aCurrBytes,
|
||||
aMaxBytes,
|
||||
aSpeed,
|
||||
aLastSec
|
||||
);
|
||||
|
||||
let params = [transfer, timeLeft];
|
||||
let status = gBundle.formatStringFromName(gStr.statusFormatNoRate, params);
|
||||
|
@ -169,19 +197,25 @@ var DownloadUtils = {
|
|||
* @return A triple: [amount transferred string, time remaining string,
|
||||
* new value of "last seconds"]
|
||||
*/
|
||||
_deriveTransferRate: function DU__deriveTransferRate(aCurrBytes,
|
||||
aMaxBytes, aSpeed,
|
||||
aLastSec) {
|
||||
if (aMaxBytes == null)
|
||||
_deriveTransferRate: function DU__deriveTransferRate(
|
||||
aCurrBytes,
|
||||
aMaxBytes,
|
||||
aSpeed,
|
||||
aLastSec
|
||||
) {
|
||||
if (aMaxBytes == null) {
|
||||
aMaxBytes = -1;
|
||||
if (aSpeed == null)
|
||||
}
|
||||
if (aSpeed == null) {
|
||||
aSpeed = -1;
|
||||
if (aLastSec == null)
|
||||
}
|
||||
if (aLastSec == null) {
|
||||
aLastSec = Infinity;
|
||||
}
|
||||
|
||||
// Calculate the time remaining if we have valid values
|
||||
let seconds = (aSpeed > 0) && (aMaxBytes > 0) ?
|
||||
(aMaxBytes - aCurrBytes) / aSpeed : -1;
|
||||
let seconds =
|
||||
aSpeed > 0 && aMaxBytes > 0 ? (aMaxBytes - aCurrBytes) / aSpeed : -1;
|
||||
|
||||
let transfer = DownloadUtils.getTransferTotal(aCurrBytes, aMaxBytes);
|
||||
let [timeLeft, newLast] = DownloadUtils.getTimeLeft(seconds, aLastSec);
|
||||
|
@ -200,8 +234,9 @@ var DownloadUtils = {
|
|||
* @return The transfer progress text
|
||||
*/
|
||||
getTransferTotal: function DU_getTransferTotal(aCurrBytes, aMaxBytes) {
|
||||
if (aMaxBytes == null)
|
||||
if (aMaxBytes == null) {
|
||||
aMaxBytes = -1;
|
||||
}
|
||||
|
||||
let [progress, progressUnits] = DownloadUtils.convertByteUnits(aCurrBytes);
|
||||
let [total, totalUnits] = DownloadUtils.convertByteUnits(aMaxBytes);
|
||||
|
@ -210,25 +245,13 @@ var DownloadUtils = {
|
|||
let name, values;
|
||||
if (aMaxBytes < 0) {
|
||||
name = gStr.transferNoTotal;
|
||||
values = [
|
||||
progress,
|
||||
progressUnits,
|
||||
];
|
||||
values = [progress, progressUnits];
|
||||
} else if (progressUnits == totalUnits) {
|
||||
name = gStr.transferSameUnits;
|
||||
values = [
|
||||
progress,
|
||||
total,
|
||||
totalUnits,
|
||||
];
|
||||
values = [progress, total, totalUnits];
|
||||
} else {
|
||||
name = gStr.transferDiffUnits;
|
||||
values = [
|
||||
progress,
|
||||
progressUnits,
|
||||
total,
|
||||
totalUnits,
|
||||
];
|
||||
values = [progress, progressUnits, total, totalUnits];
|
||||
}
|
||||
|
||||
return gBundle.formatStringFromName(name, values);
|
||||
|
@ -248,20 +271,25 @@ var DownloadUtils = {
|
|||
*/
|
||||
getTimeLeft: function DU_getTimeLeft(aSeconds, aLastSec) {
|
||||
let nf = new Services.intl.NumberFormat();
|
||||
if (aLastSec == null)
|
||||
if (aLastSec == null) {
|
||||
aLastSec = Infinity;
|
||||
}
|
||||
|
||||
if (aSeconds < 0)
|
||||
if (aSeconds < 0) {
|
||||
return [gBundle.GetStringFromName(gStr.timeUnknown), aLastSec];
|
||||
}
|
||||
|
||||
// Try to find a cached lastSec for the given second
|
||||
aLastSec = gCachedLast.reduce((aResult, aItem) =>
|
||||
aItem[0] == aSeconds ? aItem[1] : aResult, aLastSec);
|
||||
aLastSec = gCachedLast.reduce(
|
||||
(aResult, aItem) => (aItem[0] == aSeconds ? aItem[1] : aResult),
|
||||
aLastSec
|
||||
);
|
||||
|
||||
// Add the current second/lastSec pair unless we have too many
|
||||
gCachedLast.push([aSeconds, aLastSec]);
|
||||
if (gCachedLast.length > kCachedLastMaxSize)
|
||||
if (gCachedLast.length > kCachedLastMaxSize) {
|
||||
gCachedLast.shift();
|
||||
}
|
||||
|
||||
// Apply smoothing only if the new time isn't a huge change -- e.g., if the
|
||||
// new time is more than half the previous time; this is useful for
|
||||
|
@ -270,13 +298,14 @@ var DownloadUtils = {
|
|||
// Apply hysteresis to favor downward over upward swings
|
||||
// 30% of down and 10% of up (exponential smoothing)
|
||||
let diff = aSeconds - aLastSec;
|
||||
aSeconds = aLastSec + (diff < 0 ? .3 : .1) * diff;
|
||||
aSeconds = aLastSec + (diff < 0 ? 0.3 : 0.1) * diff;
|
||||
|
||||
// If the new time is similar, reuse something close to the last seconds,
|
||||
// but subtract a little to provide forward progress
|
||||
let diffPct = diff / aLastSec * 100;
|
||||
if (Math.abs(diff) < 5 || Math.abs(diffPct) < 5)
|
||||
aSeconds = aLastSec - (diff < 0 ? .4 : .2);
|
||||
let diffPct = (diff / aLastSec) * 100;
|
||||
if (Math.abs(diff) < 5 || Math.abs(diffPct) < 5) {
|
||||
aSeconds = aLastSec - (diff < 0 ? 0.4 : 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
// Decide what text to show for the time
|
||||
|
@ -286,23 +315,29 @@ var DownloadUtils = {
|
|||
timeLeft = gBundle.GetStringFromName(gStr.timeFewSeconds);
|
||||
} else {
|
||||
// Convert the seconds into its two largest units to display
|
||||
let [time1, unit1, time2, unit2] =
|
||||
DownloadUtils.convertTimeUnits(aSeconds);
|
||||
let [time1, unit1, time2, unit2] = DownloadUtils.convertTimeUnits(
|
||||
aSeconds
|
||||
);
|
||||
|
||||
let pair1 =
|
||||
gBundle.formatStringFromName(gStr.timePair, [nf.format(time1), unit1]);
|
||||
let pair2 =
|
||||
gBundle.formatStringFromName(gStr.timePair, [nf.format(time2), unit2]);
|
||||
let pair1 = gBundle.formatStringFromName(gStr.timePair, [
|
||||
nf.format(time1),
|
||||
unit1,
|
||||
]);
|
||||
let pair2 = gBundle.formatStringFromName(gStr.timePair, [
|
||||
nf.format(time2),
|
||||
unit2,
|
||||
]);
|
||||
|
||||
// Only show minutes for under 1 hour unless there's a few minutes left;
|
||||
// or the second pair is 0.
|
||||
if ((aSeconds < 3600 && time1 >= 4) || time2 == 0) {
|
||||
timeLeft = gBundle.formatStringFromName(gStr.timeLeftSingle,
|
||||
[pair1]);
|
||||
timeLeft = gBundle.formatStringFromName(gStr.timeLeftSingle, [pair1]);
|
||||
} else {
|
||||
// We've got 2 pairs of times to display
|
||||
timeLeft = gBundle.formatStringFromName(gStr.timeLeftDouble,
|
||||
[pair1, pair2]);
|
||||
timeLeft = gBundle.formatStringFromName(gStr.timeLeftDouble, [
|
||||
pair1,
|
||||
pair2,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,23 +377,27 @@ var DownloadUtils = {
|
|||
timeStyle: "short",
|
||||
});
|
||||
dateTimeCompact = dts.format(aDate);
|
||||
} else if (today - aDate < (MS_PER_DAY)) {
|
||||
} else if (today - aDate < MS_PER_DAY) {
|
||||
// After yesterday started, show yesterday
|
||||
dateTimeCompact = gBundle.GetStringFromName(gStr.yesterday);
|
||||
} else if (today - aDate < (6 * MS_PER_DAY)) {
|
||||
} else if (today - aDate < 6 * MS_PER_DAY) {
|
||||
// After last week started, show day of week
|
||||
dateTimeCompact = aDate.toLocaleDateString(undefined, { weekday: "long" });
|
||||
dateTimeCompact = aDate.toLocaleDateString(undefined, {
|
||||
weekday: "long",
|
||||
});
|
||||
} else {
|
||||
// Show month/day
|
||||
dateTimeCompact = aDate.toLocaleString(undefined, {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
}
|
||||
|
||||
const dtOptions = { dateStyle: "long", timeStyle: "short" };
|
||||
dateTimeFull =
|
||||
new Services.intl.DateTimeFormat(undefined, dtOptions).format(aDate);
|
||||
dateTimeFull = new Services.intl.DateTimeFormat(
|
||||
undefined,
|
||||
dtOptions
|
||||
).format(aDate);
|
||||
|
||||
return [dateTimeCompact, dateTimeFull];
|
||||
},
|
||||
|
@ -372,8 +411,9 @@ var DownloadUtils = {
|
|||
* @return A pair: [display host for the URI string, full host name]
|
||||
*/
|
||||
getURIHost: function DU_getURIHost(aURIString) {
|
||||
let idnService = Cc["@mozilla.org/network/idn-service;1"].
|
||||
getService(Ci.nsIIDNService);
|
||||
let idnService = Cc["@mozilla.org/network/idn-service;1"].getService(
|
||||
Ci.nsIIDNService
|
||||
);
|
||||
|
||||
// Get a URI that knows about its components
|
||||
let uri;
|
||||
|
@ -384,8 +424,9 @@ var DownloadUtils = {
|
|||
}
|
||||
|
||||
// Get the inner-most uri for schemes like jar:
|
||||
if (uri instanceof Ci.nsINestedURI)
|
||||
if (uri instanceof Ci.nsINestedURI) {
|
||||
uri = uri.innermostURI;
|
||||
}
|
||||
|
||||
let fullHost;
|
||||
try {
|
||||
|
@ -414,8 +455,7 @@ var DownloadUtils = {
|
|||
fullHost = displayHost;
|
||||
} else if (displayHost.length == 0) {
|
||||
// Got nothing; show the scheme (data: about: moz-icon:)
|
||||
displayHost =
|
||||
gBundle.formatStringFromName(gStr.doneScheme, [uri.scheme]);
|
||||
displayHost = gBundle.formatStringFromName(gStr.doneScheme, [uri.scheme]);
|
||||
fullHost = displayHost;
|
||||
} else if (uri.port != -1) {
|
||||
// Tack on the port if it's not the default port
|
||||
|
@ -440,7 +480,7 @@ var DownloadUtils = {
|
|||
|
||||
// Convert to next unit if it needs 4 digits (after rounding), but only if
|
||||
// we know the name of the next unit
|
||||
while ((aBytes >= 999.5) && (unitIndex < gStr.units.length - 1)) {
|
||||
while (aBytes >= 999.5 && unitIndex < gStr.units.length - 1) {
|
||||
aBytes /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
|
@ -448,7 +488,7 @@ var DownloadUtils = {
|
|||
// Get rid of insignificant bits by truncating to 1 or 0 decimal points
|
||||
// 0 -> 0; 1.2 -> 1.2; 12.3 -> 12.3; 123.4 -> 123; 234.5 -> 235
|
||||
// added in bug 462064: (unitIndex != 0) makes sure that no decimal digit for bytes appears when aBytes < 100
|
||||
let fractionDigits = (aBytes > 0) && (aBytes < 100) && (unitIndex != 0) ? 1 : 0;
|
||||
let fractionDigits = aBytes > 0 && aBytes < 100 && unitIndex != 0 ? 1 : 0;
|
||||
|
||||
// Don't try to format Infinity values using NumberFormat.
|
||||
if (aBytes === Infinity) {
|
||||
|
@ -479,7 +519,7 @@ var DownloadUtils = {
|
|||
|
||||
// Keep converting to the next unit while we have units left and the
|
||||
// current one isn't the largest unit possible
|
||||
while ((unitIndex < timeSize.length) && (time >= timeSize[unitIndex])) {
|
||||
while (unitIndex < timeSize.length && time >= timeSize[unitIndex]) {
|
||||
time /= timeSize[unitIndex];
|
||||
scale *= timeSize[unitIndex];
|
||||
unitIndex++;
|
||||
|
@ -492,8 +532,9 @@ var DownloadUtils = {
|
|||
let nextIndex = unitIndex - 1;
|
||||
|
||||
// Convert the extra time to the next largest unit
|
||||
for (let index = 0; index < nextIndex; index++)
|
||||
for (let index = 0; index < nextIndex; index++) {
|
||||
extra /= timeSize[index];
|
||||
}
|
||||
|
||||
let value2 = convertTimeUnitsValue(extra);
|
||||
let units2 = convertTimeUnitsUnits(value2, nextIndex);
|
||||
|
@ -524,10 +565,14 @@ function convertTimeUnitsValue(aTime) {
|
|||
*/
|
||||
function convertTimeUnitsUnits(aTime, aIndex) {
|
||||
// Negative index would be an invalid unit, so just give empty
|
||||
if (aIndex < 0)
|
||||
if (aIndex < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return PluralForm.get(aTime, gBundle.GetStringFromName(gStr.timeUnits[aIndex]));
|
||||
return PluralForm.get(
|
||||
aTime,
|
||||
gBundle.GetStringFromName(gStr.timeUnits[aIndex])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -5,9 +5,11 @@
|
|||
ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm", this);
|
||||
|
||||
const UCT_URI = "chrome://mozapps/content/downloads/unknownContentType.xul";
|
||||
const LOAD_URI = "http://mochi.test:8888/browser/toolkit/mozapps/downloads/tests/browser/unknownContentType_dialog_layout_data.txt";
|
||||
const LOAD_URI =
|
||||
"http://mochi.test:8888/browser/toolkit/mozapps/downloads/tests/browser/unknownContentType_dialog_layout_data.txt";
|
||||
|
||||
const DIALOG_DELAY = Services.prefs.getIntPref("security.dialog_enable_delay") + 200;
|
||||
const DIALOG_DELAY =
|
||||
Services.prefs.getIntPref("security.dialog_enable_delay") + 200;
|
||||
|
||||
let UCTObserver = {
|
||||
opened: PromiseUtils.defer(),
|
||||
|
@ -18,12 +20,16 @@ let UCTObserver = {
|
|||
|
||||
switch (aTopic) {
|
||||
case "domwindowopened":
|
||||
win.addEventListener("load", function onLoad(event) {
|
||||
// Let the dialog initialize
|
||||
SimpleTest.executeSoon(function() {
|
||||
UCTObserver.opened.resolve(win);
|
||||
});
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function onLoad(event) {
|
||||
// Let the dialog initialize
|
||||
SimpleTest.executeSoon(function() {
|
||||
UCTObserver.opened.resolve(win);
|
||||
});
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
break;
|
||||
|
||||
case "domwindowclosed":
|
||||
|
@ -45,39 +51,42 @@ function waitDelay(delay) {
|
|||
add_task(async function test_unknownContentType_delayedbutton() {
|
||||
Services.ww.registerNotification(UCTObserver);
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: LOAD_URI,
|
||||
}, async function() {
|
||||
let uctWindow = await UCTObserver.opened.promise;
|
||||
let ok = uctWindow.document.documentElement.getButton("accept");
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: LOAD_URI,
|
||||
},
|
||||
async function() {
|
||||
let uctWindow = await UCTObserver.opened.promise;
|
||||
let ok = uctWindow.document.documentElement.getButton("accept");
|
||||
|
||||
SimpleTest.is(ok.disabled, true, "button started disabled");
|
||||
SimpleTest.is(ok.disabled, true, "button started disabled");
|
||||
|
||||
await waitDelay(DIALOG_DELAY);
|
||||
await waitDelay(DIALOG_DELAY);
|
||||
|
||||
SimpleTest.is(ok.disabled, false, "button was enabled");
|
||||
SimpleTest.is(ok.disabled, false, "button was enabled");
|
||||
|
||||
let focusOutOfDialog = SimpleTest.promiseFocus(window);
|
||||
window.focus();
|
||||
await focusOutOfDialog;
|
||||
let focusOutOfDialog = SimpleTest.promiseFocus(window);
|
||||
window.focus();
|
||||
await focusOutOfDialog;
|
||||
|
||||
SimpleTest.is(ok.disabled, true, "button was disabled");
|
||||
SimpleTest.is(ok.disabled, true, "button was disabled");
|
||||
|
||||
let focusOnDialog = SimpleTest.promiseFocus(uctWindow);
|
||||
uctWindow.focus();
|
||||
await focusOnDialog;
|
||||
let focusOnDialog = SimpleTest.promiseFocus(uctWindow);
|
||||
uctWindow.focus();
|
||||
await focusOnDialog;
|
||||
|
||||
SimpleTest.is(ok.disabled, true, "button remained disabled");
|
||||
SimpleTest.is(ok.disabled, true, "button remained disabled");
|
||||
|
||||
await waitDelay(DIALOG_DELAY);
|
||||
SimpleTest.is(ok.disabled, false, "button re-enabled after delay");
|
||||
await waitDelay(DIALOG_DELAY);
|
||||
SimpleTest.is(ok.disabled, false, "button re-enabled after delay");
|
||||
|
||||
uctWindow.document.documentElement.cancelDialog();
|
||||
await UCTObserver.closed.promise;
|
||||
uctWindow.document.documentElement.cancelDialog();
|
||||
await UCTObserver.closed.promise;
|
||||
|
||||
Services.ww.unregisterNotification(UCTObserver);
|
||||
uctWindow = null;
|
||||
UCTObserver = null;
|
||||
});
|
||||
Services.ww.unregisterNotification(UCTObserver);
|
||||
uctWindow = null;
|
||||
UCTObserver = null;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -11,15 +11,19 @@
|
|||
const UCT_URI = "chrome://mozapps/content/downloads/unknownContentType.xul";
|
||||
|
||||
let tests = [
|
||||
{ // This URL will trigger the simple UI, where only the Save an Cancel buttons are available
|
||||
url: "http://mochi.test:8888/browser/toolkit/mozapps/downloads/tests/browser/unknownContentType_dialog_layout_data.pif",
|
||||
{
|
||||
// This URL will trigger the simple UI, where only the Save an Cancel buttons are available
|
||||
url:
|
||||
"http://mochi.test:8888/browser/toolkit/mozapps/downloads/tests/browser/unknownContentType_dialog_layout_data.pif",
|
||||
elements: {
|
||||
basicBox: { collapsed: false },
|
||||
normalBox: { collapsed: true },
|
||||
},
|
||||
},
|
||||
{ // This URL will trigger the full UI
|
||||
url: "http://mochi.test:8888/browser/toolkit/mozapps/downloads/tests/browser/unknownContentType_dialog_layout_data.txt",
|
||||
{
|
||||
// This URL will trigger the full UI
|
||||
url:
|
||||
"http://mochi.test:8888/browser/toolkit/mozapps/downloads/tests/browser/unknownContentType_dialog_layout_data.txt",
|
||||
elements: {
|
||||
basicBox: { collapsed: true },
|
||||
normalBox: { collapsed: false },
|
||||
|
@ -38,12 +42,16 @@ add_task(async function test_unknownContentType_dialog_layout() {
|
|||
|
||||
switch (aTopic) {
|
||||
case "domwindowopened":
|
||||
win.addEventListener("load", function onLoad(event) {
|
||||
// Let the dialog initialize
|
||||
SimpleTest.executeSoon(function() {
|
||||
UCTObserver.opened.resolve(win);
|
||||
});
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function onLoad(event) {
|
||||
// Let the dialog initialize
|
||||
SimpleTest.executeSoon(function() {
|
||||
UCTObserver.opened.resolve(win);
|
||||
});
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
break;
|
||||
|
||||
case "domwindowclosed":
|
||||
|
@ -56,27 +64,37 @@ add_task(async function test_unknownContentType_dialog_layout() {
|
|||
};
|
||||
|
||||
Services.ww.registerNotification(UCTObserver);
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: test.url,
|
||||
}, async function() {
|
||||
let uctWindow = await UCTObserver.opened.promise;
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: test.url,
|
||||
},
|
||||
async function() {
|
||||
let uctWindow = await UCTObserver.opened.promise;
|
||||
|
||||
for (let [id, props] of Object.entries(test.elements)) {
|
||||
let elem = uctWindow.dialog.dialogElement(id);
|
||||
for (let [prop, value] of Object.entries(props)) {
|
||||
SimpleTest.is(elem[prop], value,
|
||||
"Element with id " + id + " has property " +
|
||||
prop + " set to " + value);
|
||||
for (let [id, props] of Object.entries(test.elements)) {
|
||||
let elem = uctWindow.dialog.dialogElement(id);
|
||||
for (let [prop, value] of Object.entries(props)) {
|
||||
SimpleTest.is(
|
||||
elem[prop],
|
||||
value,
|
||||
"Element with id " +
|
||||
id +
|
||||
" has property " +
|
||||
prop +
|
||||
" set to " +
|
||||
value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
let focusOnDialog = SimpleTest.promiseFocus(uctWindow);
|
||||
uctWindow.focus();
|
||||
await focusOnDialog;
|
||||
let focusOnDialog = SimpleTest.promiseFocus(uctWindow);
|
||||
uctWindow.focus();
|
||||
await focusOnDialog;
|
||||
|
||||
uctWindow.document.documentElement.cancelDialog();
|
||||
uctWindow = null;
|
||||
Services.ww.unregisterNotification(UCTObserver);
|
||||
});
|
||||
uctWindow.document.documentElement.cancelDialog();
|
||||
uctWindow = null;
|
||||
Services.ww.unregisterNotification(UCTObserver);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.obs.notifyObservers(null, "quit-application");
|
||||
|
|
|
@ -2,9 +2,13 @@
|
|||
* 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 {DownloadUtils} = ChromeUtils.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
const { DownloadUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/DownloadUtils.jsm"
|
||||
);
|
||||
|
||||
const gDecimalSymbol = Number(5.4).toLocaleString().match(/\D/);
|
||||
const gDecimalSymbol = Number(5.4)
|
||||
.toLocaleString()
|
||||
.match(/\D/);
|
||||
function _(str) {
|
||||
return str.replace(/\./g, gDecimalSymbol);
|
||||
}
|
||||
|
@ -23,7 +27,19 @@ function testTransferTotal(aCurrBytes, aMaxBytes, aTransfer) {
|
|||
// Get the em-dash character because typing it directly here doesn't work :(
|
||||
var gDash = DownloadUtils.getDownloadStatus(0)[0].match(/left (.) 0 bytes/)[1];
|
||||
|
||||
var gVals = [0, 100, 2345, 55555, 982341, 23194134, 1482, 58, 9921949201, 13498132, Infinity];
|
||||
var gVals = [
|
||||
0,
|
||||
100,
|
||||
2345,
|
||||
55555,
|
||||
982341,
|
||||
23194134,
|
||||
1482,
|
||||
58,
|
||||
9921949201,
|
||||
13498132,
|
||||
Infinity,
|
||||
];
|
||||
|
||||
function testStatus(aFunc, aCurr, aMore, aRate, aTest) {
|
||||
dump("Status Test: " + [aCurr, aMore, aRate, aTest] + "\n");
|
||||
|
@ -34,18 +50,30 @@ function testStatus(aFunc, aCurr, aMore, aRate, aTest) {
|
|||
let [status, last] = aFunc(curr, max, speed);
|
||||
|
||||
if (0) {
|
||||
dump("testStatus(" + aCurr + ", " + aMore + ", " + aRate + ", [\"" +
|
||||
status.replace(gDash, "--") + "\", " + last.toFixed(3) + "]);\n");
|
||||
dump(
|
||||
"testStatus(" +
|
||||
aCurr +
|
||||
", " +
|
||||
aMore +
|
||||
", " +
|
||||
aRate +
|
||||
', ["' +
|
||||
status.replace(gDash, "--") +
|
||||
'", ' +
|
||||
last.toFixed(3) +
|
||||
"]);\n"
|
||||
);
|
||||
}
|
||||
|
||||
// Make sure the status text matches
|
||||
Assert.equal(status, _(aTest[0].replace(/--/, gDash)));
|
||||
|
||||
// Make sure the lastSeconds matches
|
||||
if (last == Infinity)
|
||||
if (last == Infinity) {
|
||||
Assert.equal(last, aTest[1]);
|
||||
else
|
||||
Assert.ok(Math.abs(last - aTest[1]) < .1);
|
||||
} else {
|
||||
Assert.ok(Math.abs(last - aTest[1]) < 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
function testURI(aURI, aDisp, aHost) {
|
||||
|
@ -58,7 +86,6 @@ function testURI(aURI, aDisp, aHost) {
|
|||
Assert.equal(host, aHost);
|
||||
}
|
||||
|
||||
|
||||
function testGetReadableDates(aDate, aCompactValue) {
|
||||
const now = new Date(2000, 11, 31, 11, 59, 59);
|
||||
|
||||
|
@ -69,35 +96,52 @@ function testGetReadableDates(aDate, aCompactValue) {
|
|||
function testAllGetReadableDates() {
|
||||
// This test cannot depend on the current date and time, or the date format.
|
||||
// It depends on being run with the English localization, however.
|
||||
const today_11_30 = new Date(2000, 11, 31, 11, 30, 15);
|
||||
const today_12_30 = new Date(2000, 11, 31, 12, 30, 15);
|
||||
const today_11_30 = new Date(2000, 11, 31, 11, 30, 15);
|
||||
const today_12_30 = new Date(2000, 11, 31, 12, 30, 15);
|
||||
const yesterday_11_30 = new Date(2000, 11, 30, 11, 30, 15);
|
||||
const yesterday_12_30 = new Date(2000, 11, 30, 12, 30, 15);
|
||||
const twodaysago = new Date(2000, 11, 29, 11, 30, 15);
|
||||
const sixdaysago = new Date(2000, 11, 25, 11, 30, 15);
|
||||
const sevendaysago = new Date(2000, 11, 24, 11, 30, 15);
|
||||
const twodaysago = new Date(2000, 11, 29, 11, 30, 15);
|
||||
const sixdaysago = new Date(2000, 11, 25, 11, 30, 15);
|
||||
const sevendaysago = new Date(2000, 11, 24, 11, 30, 15);
|
||||
|
||||
let cDtf = Services.intl.DateTimeFormat;
|
||||
|
||||
testGetReadableDates(today_11_30,
|
||||
(new cDtf(undefined, {timeStyle: "short"})).format(today_11_30));
|
||||
testGetReadableDates(today_12_30,
|
||||
(new cDtf(undefined, {timeStyle: "short"})).format(today_12_30));
|
||||
testGetReadableDates(
|
||||
today_11_30,
|
||||
new cDtf(undefined, { timeStyle: "short" }).format(today_11_30)
|
||||
);
|
||||
testGetReadableDates(
|
||||
today_12_30,
|
||||
new cDtf(undefined, { timeStyle: "short" }).format(today_12_30)
|
||||
);
|
||||
|
||||
testGetReadableDates(yesterday_11_30, "Yesterday");
|
||||
testGetReadableDates(yesterday_12_30, "Yesterday");
|
||||
testGetReadableDates(twodaysago,
|
||||
twodaysago.toLocaleDateString(undefined, { weekday: "long" }));
|
||||
testGetReadableDates(sixdaysago,
|
||||
sixdaysago.toLocaleDateString(undefined, { weekday: "long" }));
|
||||
testGetReadableDates(sevendaysago,
|
||||
sevendaysago.toLocaleDateString(undefined, { month: "long" }) + " " +
|
||||
sevendaysago.getDate().toString().padStart(2, "0"));
|
||||
testGetReadableDates(
|
||||
twodaysago,
|
||||
twodaysago.toLocaleDateString(undefined, { weekday: "long" })
|
||||
);
|
||||
testGetReadableDates(
|
||||
sixdaysago,
|
||||
sixdaysago.toLocaleDateString(undefined, { weekday: "long" })
|
||||
);
|
||||
testGetReadableDates(
|
||||
sevendaysago,
|
||||
sevendaysago.toLocaleDateString(undefined, { month: "long" }) +
|
||||
" " +
|
||||
sevendaysago
|
||||
.getDate()
|
||||
.toString()
|
||||
.padStart(2, "0")
|
||||
);
|
||||
|
||||
let [, dateTimeFull] = DownloadUtils.getReadableDates(today_11_30);
|
||||
|
||||
const dtOptions = { dateStyle: "long", timeStyle: "short" };
|
||||
Assert.equal(dateTimeFull, (new cDtf(undefined, dtOptions)).format(today_11_30));
|
||||
Assert.equal(
|
||||
dateTimeFull,
|
||||
new cDtf(undefined, dtOptions).format(today_11_30)
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
@ -132,47 +176,137 @@ function run_test() {
|
|||
// First, test with rates, via getDownloadStatus...
|
||||
let statusFunc = DownloadUtils.getDownloadStatus.bind(DownloadUtils);
|
||||
|
||||
testStatus(statusFunc, 2, 1, 7, ["A few seconds left -- 2.3 of 2.4 KB (58 bytes/sec)", 1.724]);
|
||||
testStatus(statusFunc, 1, 2, 6, ["A few seconds left -- 100 bytes of 2.4 KB (1.4 KB/sec)", 1.582]);
|
||||
testStatus(statusFunc, 4, 3, 9, ["A few seconds left -- 959 KB of 1.0 MB (12.9 MB/sec)", 0.004]);
|
||||
testStatus(statusFunc, 2, 3, 8, ["A few seconds left -- 2.3 of 56.5 KB (9.2 GB/sec)", 0.000]);
|
||||
testStatus(statusFunc, 2, 1, 7, [
|
||||
"A few seconds left -- 2.3 of 2.4 KB (58 bytes/sec)",
|
||||
1.724,
|
||||
]);
|
||||
testStatus(statusFunc, 1, 2, 6, [
|
||||
"A few seconds left -- 100 bytes of 2.4 KB (1.4 KB/sec)",
|
||||
1.582,
|
||||
]);
|
||||
testStatus(statusFunc, 4, 3, 9, [
|
||||
"A few seconds left -- 959 KB of 1.0 MB (12.9 MB/sec)",
|
||||
0.004,
|
||||
]);
|
||||
testStatus(statusFunc, 2, 3, 8, [
|
||||
"A few seconds left -- 2.3 of 56.5 KB (9.2 GB/sec)",
|
||||
0.0,
|
||||
]);
|
||||
|
||||
testStatus(statusFunc, 8, 4, 3, ["17s left -- 9.2 of 9.2 GB (54.3 KB/sec)", 17.682]);
|
||||
testStatus(statusFunc, 1, 3, 2, ["23s left -- 100 bytes of 54.4 KB (2.3 KB/sec)", 23.691]);
|
||||
testStatus(statusFunc, 9, 3, 2, ["23s left -- 12.9 of 12.9 MB (2.3 KB/sec)", 23.691]);
|
||||
testStatus(statusFunc, 5, 6, 7, ["25s left -- 22.1 of 22.1 MB (58 bytes/sec)", 25.552]);
|
||||
testStatus(statusFunc, 8, 4, 3, [
|
||||
"17s left -- 9.2 of 9.2 GB (54.3 KB/sec)",
|
||||
17.682,
|
||||
]);
|
||||
testStatus(statusFunc, 1, 3, 2, [
|
||||
"23s left -- 100 bytes of 54.4 KB (2.3 KB/sec)",
|
||||
23.691,
|
||||
]);
|
||||
testStatus(statusFunc, 9, 3, 2, [
|
||||
"23s left -- 12.9 of 12.9 MB (2.3 KB/sec)",
|
||||
23.691,
|
||||
]);
|
||||
testStatus(statusFunc, 5, 6, 7, [
|
||||
"25s left -- 22.1 of 22.1 MB (58 bytes/sec)",
|
||||
25.552,
|
||||
]);
|
||||
|
||||
testStatus(statusFunc, 3, 9, 3, ["4m left -- 54.3 KB of 12.9 MB (54.3 KB/sec)", 242.969]);
|
||||
testStatus(statusFunc, 2, 3, 1, ["9m left -- 2.3 of 56.5 KB (100 bytes/sec)", 555.550]);
|
||||
testStatus(statusFunc, 4, 3, 7, ["15m left -- 959 KB of 1.0 MB (58 bytes/sec)", 957.845]);
|
||||
testStatus(statusFunc, 5, 3, 7, ["15m left -- 22.1 of 22.2 MB (58 bytes/sec)", 957.845]);
|
||||
testStatus(statusFunc, 3, 9, 3, [
|
||||
"4m left -- 54.3 KB of 12.9 MB (54.3 KB/sec)",
|
||||
242.969,
|
||||
]);
|
||||
testStatus(statusFunc, 2, 3, 1, [
|
||||
"9m left -- 2.3 of 56.5 KB (100 bytes/sec)",
|
||||
555.55,
|
||||
]);
|
||||
testStatus(statusFunc, 4, 3, 7, [
|
||||
"15m left -- 959 KB of 1.0 MB (58 bytes/sec)",
|
||||
957.845,
|
||||
]);
|
||||
testStatus(statusFunc, 5, 3, 7, [
|
||||
"15m left -- 22.1 of 22.2 MB (58 bytes/sec)",
|
||||
957.845,
|
||||
]);
|
||||
|
||||
testStatus(statusFunc, 1, 9, 2, ["1h 35m left -- 100 bytes of 12.9 MB (2.3 KB/sec)", 5756.133]);
|
||||
testStatus(statusFunc, 2, 9, 6, ["2h 31m left -- 2.3 KB of 12.9 MB (1.4 KB/sec)", 9108.051]);
|
||||
testStatus(statusFunc, 2, 4, 1, ["2h 43m left -- 2.3 of 962 KB (100 bytes/sec)", 9823.410]);
|
||||
testStatus(statusFunc, 6, 4, 7, ["4h 42m left -- 1.4 of 961 KB (58 bytes/sec)", 16936.914]);
|
||||
testStatus(statusFunc, 1, 9, 2, [
|
||||
"1h 35m left -- 100 bytes of 12.9 MB (2.3 KB/sec)",
|
||||
5756.133,
|
||||
]);
|
||||
testStatus(statusFunc, 2, 9, 6, [
|
||||
"2h 31m left -- 2.3 KB of 12.9 MB (1.4 KB/sec)",
|
||||
9108.051,
|
||||
]);
|
||||
testStatus(statusFunc, 2, 4, 1, [
|
||||
"2h 43m left -- 2.3 of 962 KB (100 bytes/sec)",
|
||||
9823.41,
|
||||
]);
|
||||
testStatus(statusFunc, 6, 4, 7, [
|
||||
"4h 42m left -- 1.4 of 961 KB (58 bytes/sec)",
|
||||
16936.914,
|
||||
]);
|
||||
|
||||
testStatus(statusFunc, 6, 9, 1, ["1d 13h left -- 1.4 KB of 12.9 MB (100 bytes/sec)", 134981.320]);
|
||||
testStatus(statusFunc, 3, 8, 3, ["2d 1h left -- 54.3 KB of 9.2 GB (54.3 KB/sec)", 178596.872]);
|
||||
testStatus(statusFunc, 1, 8, 6, ["77d 11h left -- 100 bytes of 9.2 GB (1.4 KB/sec)", 6694972.470]);
|
||||
testStatus(statusFunc, 6, 8, 7, ["1,979d 22h left -- 1.4 KB of 9.2 GB (58 bytes/sec)", 171068089.672]);
|
||||
testStatus(statusFunc, 6, 9, 1, [
|
||||
"1d 13h left -- 1.4 KB of 12.9 MB (100 bytes/sec)",
|
||||
134981.32,
|
||||
]);
|
||||
testStatus(statusFunc, 3, 8, 3, [
|
||||
"2d 1h left -- 54.3 KB of 9.2 GB (54.3 KB/sec)",
|
||||
178596.872,
|
||||
]);
|
||||
testStatus(statusFunc, 1, 8, 6, [
|
||||
"77d 11h left -- 100 bytes of 9.2 GB (1.4 KB/sec)",
|
||||
6694972.47,
|
||||
]);
|
||||
testStatus(statusFunc, 6, 8, 7, [
|
||||
"1,979d 22h left -- 1.4 KB of 9.2 GB (58 bytes/sec)",
|
||||
171068089.672,
|
||||
]);
|
||||
|
||||
testStatus(statusFunc, 0, 0, 5, ["Unknown time left -- 0 of 0 bytes (22.1 MB/sec)", Infinity]);
|
||||
testStatus(statusFunc, 0, 6, 0, ["Unknown time left -- 0 bytes of 1.4 KB (0 bytes/sec)", Infinity]);
|
||||
testStatus(statusFunc, 6, 6, 0, ["Unknown time left -- 1.4 of 2.9 KB (0 bytes/sec)", Infinity]);
|
||||
testStatus(statusFunc, 8, 5, 0, ["Unknown time left -- 9.2 of 9.3 GB (0 bytes/sec)", Infinity]);
|
||||
testStatus(statusFunc, 0, 0, 5, [
|
||||
"Unknown time left -- 0 of 0 bytes (22.1 MB/sec)",
|
||||
Infinity,
|
||||
]);
|
||||
testStatus(statusFunc, 0, 6, 0, [
|
||||
"Unknown time left -- 0 bytes of 1.4 KB (0 bytes/sec)",
|
||||
Infinity,
|
||||
]);
|
||||
testStatus(statusFunc, 6, 6, 0, [
|
||||
"Unknown time left -- 1.4 of 2.9 KB (0 bytes/sec)",
|
||||
Infinity,
|
||||
]);
|
||||
testStatus(statusFunc, 8, 5, 0, [
|
||||
"Unknown time left -- 9.2 of 9.3 GB (0 bytes/sec)",
|
||||
Infinity,
|
||||
]);
|
||||
|
||||
// With rate equal to Infinity
|
||||
testStatus(statusFunc, 0, 0, 10, ["Unknown time left -- 0 of 0 bytes (Really fast)", Infinity]);
|
||||
testStatus(statusFunc, 1, 2, 10, ["A few seconds left -- 100 bytes of 2.4 KB (Really fast)", 0]);
|
||||
testStatus(statusFunc, 0, 0, 10, [
|
||||
"Unknown time left -- 0 of 0 bytes (Really fast)",
|
||||
Infinity,
|
||||
]);
|
||||
testStatus(statusFunc, 1, 2, 10, [
|
||||
"A few seconds left -- 100 bytes of 2.4 KB (Really fast)",
|
||||
0,
|
||||
]);
|
||||
|
||||
// Now test without rates, via getDownloadStatusNoRate.
|
||||
statusFunc = DownloadUtils.getDownloadStatusNoRate.bind(DownloadUtils);
|
||||
|
||||
testStatus(statusFunc, 2, 1, 7, ["A few seconds left -- 2.3 of 2.4 KB", 1.724]);
|
||||
testStatus(statusFunc, 1, 2, 6, ["A few seconds left -- 100 bytes of 2.4 KB", 1.582]);
|
||||
testStatus(statusFunc, 4, 3, 9, ["A few seconds left -- 959 KB of 1.0 MB", 0.004]);
|
||||
testStatus(statusFunc, 2, 3, 8, ["A few seconds left -- 2.3 of 56.5 KB", 0.000]);
|
||||
testStatus(statusFunc, 2, 1, 7, [
|
||||
"A few seconds left -- 2.3 of 2.4 KB",
|
||||
1.724,
|
||||
]);
|
||||
testStatus(statusFunc, 1, 2, 6, [
|
||||
"A few seconds left -- 100 bytes of 2.4 KB",
|
||||
1.582,
|
||||
]);
|
||||
testStatus(statusFunc, 4, 3, 9, [
|
||||
"A few seconds left -- 959 KB of 1.0 MB",
|
||||
0.004,
|
||||
]);
|
||||
testStatus(statusFunc, 2, 3, 8, [
|
||||
"A few seconds left -- 2.3 of 56.5 KB",
|
||||
0.0,
|
||||
]);
|
||||
|
||||
testStatus(statusFunc, 8, 4, 3, ["17s left -- 9.2 of 9.2 GB", 17.682]);
|
||||
testStatus(statusFunc, 1, 3, 2, ["23s left -- 100 bytes of 54.4 KB", 23.691]);
|
||||
|
@ -180,29 +314,67 @@ function run_test() {
|
|||
testStatus(statusFunc, 5, 6, 7, ["25s left -- 22.1 of 22.1 MB", 25.552]);
|
||||
|
||||
testStatus(statusFunc, 3, 9, 3, ["4m left -- 54.3 KB of 12.9 MB", 242.969]);
|
||||
testStatus(statusFunc, 2, 3, 1, ["9m left -- 2.3 of 56.5 KB", 555.550]);
|
||||
testStatus(statusFunc, 2, 3, 1, ["9m left -- 2.3 of 56.5 KB", 555.55]);
|
||||
testStatus(statusFunc, 4, 3, 7, ["15m left -- 959 KB of 1.0 MB", 957.845]);
|
||||
testStatus(statusFunc, 5, 3, 7, ["15m left -- 22.1 of 22.2 MB", 957.845]);
|
||||
|
||||
testStatus(statusFunc, 1, 9, 2, ["1h 35m left -- 100 bytes of 12.9 MB", 5756.133]);
|
||||
testStatus(statusFunc, 2, 9, 6, ["2h 31m left -- 2.3 KB of 12.9 MB", 9108.051]);
|
||||
testStatus(statusFunc, 2, 4, 1, ["2h 43m left -- 2.3 of 962 KB", 9823.410]);
|
||||
testStatus(statusFunc, 1, 9, 2, [
|
||||
"1h 35m left -- 100 bytes of 12.9 MB",
|
||||
5756.133,
|
||||
]);
|
||||
testStatus(statusFunc, 2, 9, 6, [
|
||||
"2h 31m left -- 2.3 KB of 12.9 MB",
|
||||
9108.051,
|
||||
]);
|
||||
testStatus(statusFunc, 2, 4, 1, ["2h 43m left -- 2.3 of 962 KB", 9823.41]);
|
||||
testStatus(statusFunc, 6, 4, 7, ["4h 42m left -- 1.4 of 961 KB", 16936.914]);
|
||||
|
||||
testStatus(statusFunc, 6, 9, 1, ["1d 13h left -- 1.4 KB of 12.9 MB", 134981.320]);
|
||||
testStatus(statusFunc, 3, 8, 3, ["2d 1h left -- 54.3 KB of 9.2 GB", 178596.872]);
|
||||
testStatus(statusFunc, 1, 8, 6, ["77d 11h left -- 100 bytes of 9.2 GB", 6694972.470]);
|
||||
testStatus(statusFunc, 6, 8, 7, ["1,979d 22h left -- 1.4 KB of 9.2 GB", 171068089.672]);
|
||||
testStatus(statusFunc, 6, 9, 1, [
|
||||
"1d 13h left -- 1.4 KB of 12.9 MB",
|
||||
134981.32,
|
||||
]);
|
||||
testStatus(statusFunc, 3, 8, 3, [
|
||||
"2d 1h left -- 54.3 KB of 9.2 GB",
|
||||
178596.872,
|
||||
]);
|
||||
testStatus(statusFunc, 1, 8, 6, [
|
||||
"77d 11h left -- 100 bytes of 9.2 GB",
|
||||
6694972.47,
|
||||
]);
|
||||
testStatus(statusFunc, 6, 8, 7, [
|
||||
"1,979d 22h left -- 1.4 KB of 9.2 GB",
|
||||
171068089.672,
|
||||
]);
|
||||
|
||||
testStatus(statusFunc, 0, 0, 5, ["Unknown time left -- 0 of 0 bytes", Infinity]);
|
||||
testStatus(statusFunc, 0, 6, 0, ["Unknown time left -- 0 bytes of 1.4 KB", Infinity]);
|
||||
testStatus(statusFunc, 6, 6, 0, ["Unknown time left -- 1.4 of 2.9 KB", Infinity]);
|
||||
testStatus(statusFunc, 8, 5, 0, ["Unknown time left -- 9.2 of 9.3 GB", Infinity]);
|
||||
testStatus(statusFunc, 0, 0, 5, [
|
||||
"Unknown time left -- 0 of 0 bytes",
|
||||
Infinity,
|
||||
]);
|
||||
testStatus(statusFunc, 0, 6, 0, [
|
||||
"Unknown time left -- 0 bytes of 1.4 KB",
|
||||
Infinity,
|
||||
]);
|
||||
testStatus(statusFunc, 6, 6, 0, [
|
||||
"Unknown time left -- 1.4 of 2.9 KB",
|
||||
Infinity,
|
||||
]);
|
||||
testStatus(statusFunc, 8, 5, 0, [
|
||||
"Unknown time left -- 9.2 of 9.3 GB",
|
||||
Infinity,
|
||||
]);
|
||||
|
||||
testURI("http://www.mozilla.org/", "mozilla.org", "www.mozilla.org");
|
||||
testURI("http://www.city.mikasa.hokkaido.jp/", "city.mikasa.hokkaido.jp", "www.city.mikasa.hokkaido.jp");
|
||||
testURI(
|
||||
"http://www.city.mikasa.hokkaido.jp/",
|
||||
"city.mikasa.hokkaido.jp",
|
||||
"www.city.mikasa.hokkaido.jp"
|
||||
);
|
||||
testURI("data:text/html,Hello World", "data resource", "data resource");
|
||||
testURI("jar:http://www.mozilla.com/file!/magic", "mozilla.com", "www.mozilla.com");
|
||||
testURI(
|
||||
"jar:http://www.mozilla.com/file!/magic",
|
||||
"mozilla.com",
|
||||
"www.mozilla.com"
|
||||
);
|
||||
testURI("file:///C:/Cool/Stuff/", "local file", "local file");
|
||||
// Don't test for moz-icon if we don't have a protocol handler for it (e.g. b2g):
|
||||
if ("@mozilla.org/network/protocol;1?name=moz-icon" in Cc) {
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
/* 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/. */
|
||||
* 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/. */
|
||||
|
||||
/**
|
||||
* Test bug 448344 to make sure when we're in low minutes, we show both minutes
|
||||
* and seconds; but continue to show only minutes when we have plenty.
|
||||
*/
|
||||
|
||||
const {DownloadUtils} = ChromeUtils.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
const { DownloadUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/DownloadUtils.jsm"
|
||||
);
|
||||
|
||||
/**
|
||||
* Print some debug message to the console. All arguments will be printed,
|
||||
|
|
|
@ -8,17 +8,21 @@
|
|||
* "last time".
|
||||
*/
|
||||
|
||||
const {DownloadUtils} = ChromeUtils.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
const { DownloadUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/DownloadUtils.jsm"
|
||||
);
|
||||
|
||||
function run_test() {
|
||||
// Simulate having multiple downloads requesting time left
|
||||
let downloadTimes = {};
|
||||
for (let time of [1, 30, 60, 3456, 9999])
|
||||
for (let time of [1, 30, 60, 3456, 9999]) {
|
||||
downloadTimes[time] = DownloadUtils.getTimeLeft(time)[0];
|
||||
}
|
||||
|
||||
// Pretend we're a download status bar also asking for a time left, but we're
|
||||
// using a different "last sec". We need to make sure we get the same time.
|
||||
let lastSec = 314;
|
||||
for (let [time, text] of Object.entries(downloadTimes))
|
||||
for (let [time, text] of Object.entries(downloadTimes)) {
|
||||
Assert.equal(DownloadUtils.getTimeLeft(time, lastSec)[0], text);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,17 +7,27 @@
|
|||
* methods provide the same result.
|
||||
*/
|
||||
|
||||
const {DownloadUtils} = ChromeUtils.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
const { DownloadUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/DownloadUtils.jsm"
|
||||
);
|
||||
|
||||
function run_test() {
|
||||
Assert.equal(DownloadUtils.getDownloadStatus(1000, null, null, null) + "",
|
||||
DownloadUtils.getDownloadStatus(1000) + "");
|
||||
Assert.equal(DownloadUtils.getDownloadStatus(1000, null, null) + "",
|
||||
DownloadUtils.getDownloadStatus(1000, null) + "");
|
||||
Assert.equal(
|
||||
DownloadUtils.getDownloadStatus(1000, null, null, null) + "",
|
||||
DownloadUtils.getDownloadStatus(1000) + ""
|
||||
);
|
||||
Assert.equal(
|
||||
DownloadUtils.getDownloadStatus(1000, null, null) + "",
|
||||
DownloadUtils.getDownloadStatus(1000, null) + ""
|
||||
);
|
||||
|
||||
Assert.equal(DownloadUtils.getTransferTotal(1000, null) + "",
|
||||
DownloadUtils.getTransferTotal(1000) + "");
|
||||
Assert.equal(
|
||||
DownloadUtils.getTransferTotal(1000, null) + "",
|
||||
DownloadUtils.getTransferTotal(1000) + ""
|
||||
);
|
||||
|
||||
Assert.equal(DownloadUtils.getTimeLeft(1000, null) + "",
|
||||
DownloadUtils.getTimeLeft(1000) + "");
|
||||
Assert.equal(
|
||||
DownloadUtils.getTimeLeft(1000, null) + "",
|
||||
DownloadUtils.getTimeLeft(1000) + ""
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
* 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 EXPORTED_SYMBOLS = [ "AbuseReporter", "AbuseReportError" ];
|
||||
const EXPORTED_SYMBOLS = ["AbuseReporter", "AbuseReportError"];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
|
||||
const PREF_ABUSE_REPORT_URL = "extensions.abuseReport.url";
|
||||
const PREF_ABUSE_REPORT_URL = "extensions.abuseReport.url";
|
||||
|
||||
// Maximum length of the string properties sent to the API endpoint.
|
||||
const MAX_STRING_LENGTH = 255;
|
||||
|
@ -24,7 +26,11 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
Services: "resource://gre/modules/Services.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "ABUSE_REPORT_URL", PREF_ABUSE_REPORT_URL);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"ABUSE_REPORT_URL",
|
||||
PREF_ABUSE_REPORT_URL
|
||||
);
|
||||
|
||||
const PRIVATE_REPORT_PROPS = Symbol("privateReportProps");
|
||||
|
||||
|
@ -44,8 +50,7 @@ class AbuseReportError extends Error {
|
|||
throw new Error(`Unknown AbuseReportError type "${errorType}"`);
|
||||
}
|
||||
|
||||
let message = errorInfo ?
|
||||
`${errorType} - ${errorInfo}` : errorType;
|
||||
let message = errorInfo ? `${errorType} - ${errorInfo}` : errorType;
|
||||
|
||||
super(message);
|
||||
this.name = "AbuseReportError";
|
||||
|
@ -93,7 +98,7 @@ const AbuseReporter = {
|
|||
* An instance of the AbuseReport class, which represent an ongoing
|
||||
* report.
|
||||
*/
|
||||
async createAbuseReport(addonId, {reportEntryPoint} = {}) {
|
||||
async createAbuseReport(addonId, { reportEntryPoint } = {}) {
|
||||
const addon = await AddonManager.getAddonByID(addonId);
|
||||
|
||||
if (!addon) {
|
||||
|
@ -128,7 +133,7 @@ const AbuseReporter = {
|
|||
* An object that contains the collected details.
|
||||
*/
|
||||
async getReportData(addon) {
|
||||
const truncateString = (text) =>
|
||||
const truncateString = text =>
|
||||
typeof text == "string" ? text.slice(0, MAX_STRING_LENGTH) : text;
|
||||
|
||||
const data = {
|
||||
|
@ -136,7 +141,8 @@ const AbuseReporter = {
|
|||
addon_version: addon.version,
|
||||
addon_name: truncateString(addon.name),
|
||||
addon_summary: truncateString(addon.description),
|
||||
addon_install_origin: addon.sourceURI && truncateString(addon.sourceURI.spec),
|
||||
addon_install_origin:
|
||||
addon.sourceURI && truncateString(addon.sourceURI.spec),
|
||||
install_date: addon.installDate && addon.installDate.toISOString(),
|
||||
};
|
||||
|
||||
|
@ -145,7 +151,7 @@ const AbuseReporter = {
|
|||
// https://addons-server.readthedocs.io/en/latest/topics/api/abuse.html).
|
||||
let install_method = "other";
|
||||
if (addon.installTelemetryInfo) {
|
||||
const {source, method} = addon.installTelemetryInfo;
|
||||
const { source, method } = addon.installTelemetryInfo;
|
||||
switch (source) {
|
||||
case "enterprise-policy":
|
||||
case "file-url":
|
||||
|
@ -248,7 +254,7 @@ const AbuseReporter = {
|
|||
* A string that identify how the report has been triggered.
|
||||
*/
|
||||
class AbuseReport {
|
||||
constructor({addon, createErrorType, reportData, reportEntryPoint}) {
|
||||
constructor({ addon, createErrorType, reportData, reportEntryPoint }) {
|
||||
this[PRIVATE_REPORT_PROPS] = {
|
||||
aborted: false,
|
||||
abortController: new AbortController(),
|
||||
|
@ -259,7 +265,7 @@ class AbuseReport {
|
|||
}
|
||||
|
||||
recordTelemetry(errorType) {
|
||||
const {addon, reportEntryPoint} = this;
|
||||
const { addon, reportEntryPoint } = this;
|
||||
AMTelemetry.recordReportEvent({
|
||||
addonId: addon.id,
|
||||
addonType: addon.type,
|
||||
|
@ -282,15 +288,13 @@ class AbuseReport {
|
|||
* It rejects with an AbuseReportError if the report couldn't be
|
||||
* submitted for a known reason (or another Error type otherwise).
|
||||
*/
|
||||
async submit({reason, message}) {
|
||||
const {
|
||||
aborted, abortController,
|
||||
reportData,
|
||||
reportEntryPoint,
|
||||
} = this[PRIVATE_REPORT_PROPS];
|
||||
async submit({ reason, message }) {
|
||||
const { aborted, abortController, reportData, reportEntryPoint } = this[
|
||||
PRIVATE_REPORT_PROPS
|
||||
];
|
||||
|
||||
// Record telemetry event and throw an AbuseReportError.
|
||||
const rejectReportError = async (errorType, {response} = {}) => {
|
||||
const rejectReportError = async (errorType, { response } = {}) => {
|
||||
this.recordTelemetry(errorType);
|
||||
|
||||
let errorInfo;
|
||||
|
@ -325,7 +329,7 @@ class AbuseReport {
|
|||
method: "POST",
|
||||
credentials: "omit",
|
||||
referrerPolicy: "no-referrer",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
...reportData,
|
||||
report_entry_point: reportEntryPoint,
|
||||
|
@ -355,22 +359,22 @@ class AbuseReport {
|
|||
}
|
||||
|
||||
if (response.status >= 400 && response.status < 500) {
|
||||
return rejectReportError("ERROR_CLIENT", {response});
|
||||
return rejectReportError("ERROR_CLIENT", { response });
|
||||
}
|
||||
|
||||
if (response.status >= 500 && response.status < 600) {
|
||||
return rejectReportError("ERROR_SERVER", {response});
|
||||
return rejectReportError("ERROR_SERVER", { response });
|
||||
}
|
||||
|
||||
// We got an unexpected HTTP status code.
|
||||
return rejectReportError("ERROR_UNKNOWN", {response});
|
||||
return rejectReportError("ERROR_UNKNOWN", { response });
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort the report submission.
|
||||
*/
|
||||
abort() {
|
||||
const {abortController} = this[PRIVATE_REPORT_PROPS];
|
||||
const { abortController } = this[PRIVATE_REPORT_PROPS];
|
||||
abortController.abort();
|
||||
this[PRIVATE_REPORT_PROPS].aborted = true;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -31,6 +31,6 @@ var LightweightThemeManager = {
|
|||
},
|
||||
|
||||
get themeData() {
|
||||
return _fallbackThemeData || {theme: null};
|
||||
return _fallbackThemeData || { theme: null };
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,43 +10,58 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "separatePrivilegedMozillaWebContentProcess",
|
||||
"browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", false);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "extensionsWebAPITesting",
|
||||
"extensions.webapi.testing", false);
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"separatePrivilegedMozillaWebContentProcess",
|
||||
"browser.tabs.remote.separatePrivilegedMozillaWebContentProcess",
|
||||
false
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"extensionsWebAPITesting",
|
||||
"extensions.webapi.testing",
|
||||
false
|
||||
);
|
||||
|
||||
// The old XPInstall error codes
|
||||
const EXECUTION_ERROR = -203;
|
||||
const EXECUTION_ERROR = -203;
|
||||
const CANT_READ_ARCHIVE = -207;
|
||||
const USER_CANCELLED = -210;
|
||||
const DOWNLOAD_ERROR = -228;
|
||||
const UNSUPPORTED_TYPE = -244;
|
||||
const SUCCESS = 0;
|
||||
const USER_CANCELLED = -210;
|
||||
const DOWNLOAD_ERROR = -228;
|
||||
const UNSUPPORTED_TYPE = -244;
|
||||
const SUCCESS = 0;
|
||||
|
||||
const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled";
|
||||
const MSG_INSTALL_ADDON = "WebInstallerInstallAddonFromWebpage";
|
||||
const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled";
|
||||
const MSG_INSTALL_ADDON = "WebInstallerInstallAddonFromWebpage";
|
||||
const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback";
|
||||
|
||||
const MSG_PROMISE_REQUEST = "WebAPIPromiseRequest";
|
||||
const MSG_PROMISE_RESULT = "WebAPIPromiseResult";
|
||||
const MSG_INSTALL_EVENT = "WebAPIInstallEvent";
|
||||
const MSG_INSTALL_CLEANUP = "WebAPICleanup";
|
||||
const MSG_ADDON_EVENT_REQ = "WebAPIAddonEventRequest";
|
||||
const MSG_ADDON_EVENT = "WebAPIAddonEvent";
|
||||
const MSG_PROMISE_REQUEST = "WebAPIPromiseRequest";
|
||||
const MSG_PROMISE_RESULT = "WebAPIPromiseResult";
|
||||
const MSG_INSTALL_EVENT = "WebAPIInstallEvent";
|
||||
const MSG_INSTALL_CLEANUP = "WebAPICleanup";
|
||||
const MSG_ADDON_EVENT_REQ = "WebAPIAddonEventRequest";
|
||||
const MSG_ADDON_EVENT = "WebAPIAddonEvent";
|
||||
|
||||
const CHILD_SCRIPT = "resource://gre/modules/addons/Content.js";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var gSingleton = null;
|
||||
|
||||
var AddonManager, AddonManagerPrivate;
|
||||
function amManager() {
|
||||
({AddonManager, AddonManagerPrivate} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm"));
|
||||
({ AddonManager, AddonManagerPrivate } = ChromeUtils.import(
|
||||
"resource://gre/modules/AddonManager.jsm"
|
||||
));
|
||||
|
||||
Services.mm.loadFrameScript(CHILD_SCRIPT, true, true);
|
||||
Services.mm.addMessageListener(MSG_INSTALL_ENABLED, this);
|
||||
|
@ -81,14 +96,7 @@ amManager.prototype = {
|
|||
installAddonFromWebpage(aPayload, aBrowser, aCallback) {
|
||||
let retval = true;
|
||||
|
||||
const {
|
||||
mimetype,
|
||||
triggeringPrincipal,
|
||||
hash,
|
||||
icon,
|
||||
name,
|
||||
uri,
|
||||
} = aPayload;
|
||||
const { mimetype, triggeringPrincipal, hash, icon, name, uri } = aPayload;
|
||||
|
||||
if (!AddonManager.isInstallAllowed(mimetype, triggeringPrincipal)) {
|
||||
aCallback = null;
|
||||
|
@ -132,10 +140,11 @@ amManager.prototype = {
|
|||
},
|
||||
|
||||
onDownloadFailed(aInstall) {
|
||||
if (aInstall.error == AddonManager.ERROR_CORRUPT_FILE)
|
||||
if (aInstall.error == AddonManager.ERROR_CORRUPT_FILE) {
|
||||
callCallback(CANT_READ_ARCHIVE);
|
||||
else
|
||||
} else {
|
||||
callCallback(DOWNLOAD_ERROR);
|
||||
}
|
||||
},
|
||||
|
||||
onInstallFailed(aInstall) {
|
||||
|
@ -148,7 +157,12 @@ amManager.prototype = {
|
|||
});
|
||||
}
|
||||
|
||||
AddonManager.installAddonFromWebpage(mimetype, aBrowser, triggeringPrincipal, aInstall);
|
||||
AddonManager.installAddonFromWebpage(
|
||||
mimetype,
|
||||
aBrowser,
|
||||
triggeringPrincipal,
|
||||
aInstall
|
||||
);
|
||||
});
|
||||
|
||||
return retval;
|
||||
|
@ -165,7 +179,7 @@ amManager.prototype = {
|
|||
_addAddonListener(target) {
|
||||
if (!this.addonListeners.has(target)) {
|
||||
let handler = (event, id) => {
|
||||
target.sendAsyncMessage(MSG_ADDON_EVENT, {event, id});
|
||||
target.sendAsyncMessage(MSG_ADDON_EVENT, { event, id });
|
||||
};
|
||||
let listener = {
|
||||
onEnabling: addon => handler("onEnabling", addon.id),
|
||||
|
@ -176,7 +190,8 @@ amManager.prototype = {
|
|||
onInstalled: addon => handler("onInstalled", addon.id),
|
||||
onUninstalling: addon => handler("onUninstalling", addon.id),
|
||||
onUninstalled: addon => handler("onUninstalled", addon.id),
|
||||
onOperationCancelled: addon => handler("onOperationCancelled", addon.id),
|
||||
onOperationCancelled: addon =>
|
||||
handler("onOperationCancelled", addon.id),
|
||||
};
|
||||
this.addonListeners.set(target, listener);
|
||||
AddonManager.addAddonListener(listener);
|
||||
|
@ -222,20 +237,24 @@ amManager.prototype = {
|
|||
}
|
||||
|
||||
case MSG_PROMISE_REQUEST: {
|
||||
if (!extensionsWebAPITesting &&
|
||||
separatePrivilegedMozillaWebContentProcess && aMessage.target &&
|
||||
aMessage.target.remoteType != null && aMessage.target.remoteType !== "privilegedmozilla") {
|
||||
if (
|
||||
!extensionsWebAPITesting &&
|
||||
separatePrivilegedMozillaWebContentProcess &&
|
||||
aMessage.target &&
|
||||
aMessage.target.remoteType != null &&
|
||||
aMessage.target.remoteType !== "privilegedmozilla"
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let mm = aMessage.target.messageManager;
|
||||
let resolve = (value) => {
|
||||
let resolve = value => {
|
||||
mm.sendAsyncMessage(MSG_PROMISE_RESULT, {
|
||||
callbackID: payload.callbackID,
|
||||
resolve: value,
|
||||
});
|
||||
};
|
||||
let reject = (value) => {
|
||||
let reject = value => {
|
||||
mm.sendAsyncMessage(MSG_PROMISE_RESULT, {
|
||||
callbackID: payload.callbackID,
|
||||
reject: value,
|
||||
|
@ -244,7 +263,10 @@ amManager.prototype = {
|
|||
|
||||
let API = AddonManager.webAPI;
|
||||
if (payload.type in API) {
|
||||
API[payload.type](aMessage.target, ...payload.args).then(resolve, reject);
|
||||
API[payload.type](aMessage.target, ...payload.args).then(
|
||||
resolve,
|
||||
reject
|
||||
);
|
||||
} else {
|
||||
reject("Unknown Add-on API request.");
|
||||
}
|
||||
|
@ -252,9 +274,13 @@ amManager.prototype = {
|
|||
}
|
||||
|
||||
case MSG_INSTALL_CLEANUP: {
|
||||
if (!extensionsWebAPITesting &&
|
||||
separatePrivilegedMozillaWebContentProcess && aMessage.target &&
|
||||
aMessage.target.remoteType != null && aMessage.target.remoteType !== "privilegedmozilla") {
|
||||
if (
|
||||
!extensionsWebAPITesting &&
|
||||
separatePrivilegedMozillaWebContentProcess &&
|
||||
aMessage.target &&
|
||||
aMessage.target.remoteType != null &&
|
||||
aMessage.target.remoteType !== "privilegedmozilla"
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
@ -263,9 +289,13 @@ amManager.prototype = {
|
|||
}
|
||||
|
||||
case MSG_ADDON_EVENT_REQ: {
|
||||
if (!extensionsWebAPITesting &&
|
||||
separatePrivilegedMozillaWebContentProcess && aMessage.target &&
|
||||
aMessage.target.remoteType != null && aMessage.target.remoteType !== "privilegedmozilla") {
|
||||
if (
|
||||
!extensionsWebAPITesting &&
|
||||
separatePrivilegedMozillaWebContentProcess &&
|
||||
aMessage.target &&
|
||||
aMessage.target.remoteType != null &&
|
||||
aMessage.target.remoteType !== "privilegedmozilla"
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
@ -292,18 +322,24 @@ amManager.prototype = {
|
|||
classID: Components.ID("{4399533d-08d1-458c-a87a-235f74451cfa}"),
|
||||
_xpcom_factory: {
|
||||
createInstance(aOuter, aIid) {
|
||||
if (aOuter != null)
|
||||
throw Components.Exception("Component does not support aggregation",
|
||||
Cr.NS_ERROR_NO_AGGREGATION);
|
||||
if (aOuter != null) {
|
||||
throw Components.Exception(
|
||||
"Component does not support aggregation",
|
||||
Cr.NS_ERROR_NO_AGGREGATION
|
||||
);
|
||||
}
|
||||
|
||||
if (!gSingleton)
|
||||
if (!gSingleton) {
|
||||
gSingleton = new amManager();
|
||||
}
|
||||
return gSingleton.QueryInterface(aIid);
|
||||
},
|
||||
},
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.amIAddonManager,
|
||||
Ci.nsITimerCallback,
|
||||
Ci.nsIObserver]),
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.amIAddonManager,
|
||||
Ci.nsITimerCallback,
|
||||
Ci.nsIObserver,
|
||||
]),
|
||||
};
|
||||
|
||||
const BLOCKLIST_JSM = "resource://gre/modules/Blocklist.jsm";
|
||||
|
@ -319,7 +355,8 @@ BlocklistService.prototype = {
|
|||
STATE_SOFTBLOCKED: Ci.nsIBlocklistService.STATE_SOFTBLOCKED,
|
||||
STATE_BLOCKED: Ci.nsIBlocklistService.STATE_BLOCKED,
|
||||
STATE_OUTDATED: Ci.nsIBlocklistService.STATE_OUTDATED,
|
||||
STATE_VULNERABLE_UPDATE_AVAILABLE: Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE,
|
||||
STATE_VULNERABLE_UPDATE_AVAILABLE:
|
||||
Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE,
|
||||
STATE_VULNERABLE_NO_UPDATE: Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE,
|
||||
|
||||
get isLoaded() {
|
||||
|
@ -331,12 +368,18 @@ BlocklistService.prototype = {
|
|||
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
}
|
||||
if (Cu.isModuleLoaded(BLOCKLIST_JSM)) {
|
||||
return Blocklist.getPluginBlocklistState(plugin, appVersion, toolkitVersion);
|
||||
return Blocklist.getPluginBlocklistState(
|
||||
plugin,
|
||||
appVersion,
|
||||
toolkitVersion
|
||||
);
|
||||
}
|
||||
|
||||
// Blocklist module isn't loaded yet. Queue the query until it is.
|
||||
let request = {plugin, appVersion, toolkitVersion};
|
||||
let promise = new Promise(resolve => { request.resolve = resolve; });
|
||||
let request = { plugin, appVersion, toolkitVersion };
|
||||
let promise = new Promise(resolve => {
|
||||
request.resolve = resolve;
|
||||
});
|
||||
|
||||
this.pluginQueries.push(request);
|
||||
return promise;
|
||||
|
@ -351,9 +394,11 @@ BlocklistService.prototype = {
|
|||
},
|
||||
|
||||
classID: Components.ID("{66354bc9-7ed1-4692-ae1d-8da97d6b205e}"),
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsIBlocklistService,
|
||||
Ci.nsITimerCallback]),
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsIObserver,
|
||||
Ci.nsIBlocklistService,
|
||||
Ci.nsITimerCallback,
|
||||
]),
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
const XPI_CONTENT_TYPE = "application/x-xpinstall";
|
||||
const MSG_INSTALL_ADDON = "WebInstallerInstallAddonFromWebpage";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function amContentHandler() {
|
||||
}
|
||||
function amContentHandler() {}
|
||||
|
||||
amContentHandler.prototype = {
|
||||
/**
|
||||
|
@ -24,24 +23,27 @@ amContentHandler.prototype = {
|
|||
* The nsIRequest dealing with the content
|
||||
*/
|
||||
handleContent(aMimetype, aContext, aRequest) {
|
||||
if (aMimetype != XPI_CONTENT_TYPE)
|
||||
if (aMimetype != XPI_CONTENT_TYPE) {
|
||||
throw Cr.NS_ERROR_WONT_HANDLE_CONTENT;
|
||||
}
|
||||
|
||||
if (!(aRequest instanceof Ci.nsIChannel))
|
||||
if (!(aRequest instanceof Ci.nsIChannel)) {
|
||||
throw Cr.NS_ERROR_WONT_HANDLE_CONTENT;
|
||||
}
|
||||
|
||||
let uri = aRequest.URI;
|
||||
|
||||
let window = null;
|
||||
let callbacks = aRequest.notificationCallbacks ?
|
||||
aRequest.notificationCallbacks :
|
||||
aRequest.loadGroup.notificationCallbacks;
|
||||
if (callbacks)
|
||||
let callbacks = aRequest.notificationCallbacks
|
||||
? aRequest.notificationCallbacks
|
||||
: aRequest.loadGroup.notificationCallbacks;
|
||||
if (callbacks) {
|
||||
window = callbacks.getInterface(Ci.nsIDOMWindow);
|
||||
}
|
||||
|
||||
aRequest.cancel(Cr.NS_BINDING_ABORTED);
|
||||
|
||||
const {triggeringPrincipal} = aRequest.loadInfo;
|
||||
const { triggeringPrincipal } = aRequest.loadInfo;
|
||||
|
||||
let sourceHost;
|
||||
|
||||
|
@ -69,8 +71,12 @@ amContentHandler.prototype = {
|
|||
// in-content UI page, walk up to find the first frame element in a chrome
|
||||
// privileged document
|
||||
let element = window.frameElement;
|
||||
while (element && !element.ownerDocument.nodePrincipal.isSystemPrincipal)
|
||||
while (
|
||||
element &&
|
||||
!element.ownerDocument.nodePrincipal.isSystemPrincipal
|
||||
) {
|
||||
element = element.ownerGlobal.frameElement;
|
||||
}
|
||||
|
||||
if (element) {
|
||||
let listener = Cc["@mozilla.org/addons/integration;1"].getService();
|
||||
|
|
|
@ -4,19 +4,23 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
const {Log} = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Preferences } = ChromeUtils.import(
|
||||
"resource://gre/modules/Preferences.jsm"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
|
||||
const XPINSTALL_MIMETYPE = "application/x-xpinstall";
|
||||
const XPINSTALL_MIMETYPE = "application/x-xpinstall";
|
||||
|
||||
const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled";
|
||||
const MSG_INSTALL_ADDON = "WebInstallerInstallAddonFromWebpage";
|
||||
const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled";
|
||||
const MSG_INSTALL_ADDON = "WebInstallerInstallAddonFromWebpage";
|
||||
const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback";
|
||||
|
||||
|
||||
var log = Log.repository.getLogger("AddonManager.InstallTrigger");
|
||||
log.level = Log.Level[Preferences.get("extensions.logging.enabled", false) ? "Warn" : "Trace"];
|
||||
log.level =
|
||||
Log.Level[
|
||||
Preferences.get("extensions.logging.enabled", false) ? "Warn" : "Trace"
|
||||
];
|
||||
|
||||
function CallbackObject(id, callback, mediator) {
|
||||
this.id = id;
|
||||
|
@ -73,8 +77,12 @@ RemoteMediator.prototype = {
|
|||
// in-content UI page, walk up to find the first frame element in a chrome
|
||||
// privileged document
|
||||
let element = window.frameElement;
|
||||
while (element && !element.ownerDocument.nodePrincipal.isSystemPrincipal)
|
||||
while (
|
||||
element &&
|
||||
!element.ownerDocument.nodePrincipal.isSystemPrincipal
|
||||
) {
|
||||
element = element.ownerGlobal.frameElement;
|
||||
}
|
||||
|
||||
if (element) {
|
||||
let listener = Cc["@mozilla.org/addons/integration;1"].getService();
|
||||
|
@ -93,8 +101,9 @@ RemoteMediator.prototype = {
|
|||
},
|
||||
|
||||
_addCallback(callback) {
|
||||
if (!callback || typeof callback != "function")
|
||||
if (!callback || typeof callback != "function") {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let callbackID = this._windowID + "-" + ++this._lastCallbackID;
|
||||
let callbackObject = new CallbackObject(callbackID, callback, this);
|
||||
|
@ -105,9 +114,7 @@ RemoteMediator.prototype = {
|
|||
QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference]),
|
||||
};
|
||||
|
||||
|
||||
function InstallTrigger() {
|
||||
}
|
||||
function InstallTrigger() {}
|
||||
|
||||
InstallTrigger.prototype = {
|
||||
// We've declared ourselves as providing the nsIDOMGlobalPropertyInitializer
|
||||
|
@ -148,12 +155,16 @@ InstallTrigger.prototype = {
|
|||
item = { URL: item };
|
||||
}
|
||||
if (!item.URL) {
|
||||
throw new this._window.Error("Missing URL property for '" + keys[0] + "'");
|
||||
throw new this._window.Error(
|
||||
"Missing URL property for '" + keys[0] + "'"
|
||||
);
|
||||
}
|
||||
|
||||
let url = this._resolveURL(item.URL);
|
||||
if (!this._checkLoadURIFromScript(url)) {
|
||||
throw new this._window.Error("Insufficient permissions to install: " + url.spec);
|
||||
throw new this._window.Error(
|
||||
"Insufficient permissions to install: " + url.spec
|
||||
);
|
||||
}
|
||||
|
||||
let iconUrl = null;
|
||||
|
@ -182,15 +193,18 @@ InstallTrigger.prototype = {
|
|||
sourceHost,
|
||||
};
|
||||
|
||||
return this._mediator.install(installData, this._principal, callback, this._window);
|
||||
return this._mediator.install(
|
||||
installData,
|
||||
this._principal,
|
||||
callback,
|
||||
this._window
|
||||
);
|
||||
},
|
||||
|
||||
startSoftwareUpdate(url, flags) {
|
||||
let filename = Services.io.newURI(url)
|
||||
.QueryInterface(Ci.nsIURL)
|
||||
.filename;
|
||||
let filename = Services.io.newURI(url).QueryInterface(Ci.nsIURL).filename;
|
||||
let args = {};
|
||||
args[filename] = { "URL": url };
|
||||
args[filename] = { URL: url };
|
||||
return this.install(args);
|
||||
},
|
||||
|
||||
|
@ -205,9 +219,11 @@ InstallTrigger.prototype = {
|
|||
_checkLoadURIFromScript(uri) {
|
||||
let secman = Services.scriptSecurityManager;
|
||||
try {
|
||||
secman.checkLoadURIWithPrincipal(this._principal,
|
||||
uri,
|
||||
secman.DISALLOW_INHERIT_PRINCIPAL);
|
||||
secman.checkLoadURIWithPrincipal(
|
||||
this._principal,
|
||||
uri,
|
||||
secman.DISALLOW_INHERIT_PRINCIPAL
|
||||
);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
|
|
|
@ -4,19 +4,28 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Services",
|
||||
"resource://gre/modules/Services.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "WEBEXT_PERMISSION_PROMPTS",
|
||||
"extensions.webextPermissionPrompts", false);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"WEBEXT_PERMISSION_PROMPTS",
|
||||
"extensions.webextPermissionPrompts",
|
||||
false
|
||||
);
|
||||
|
||||
const MSG_PROMISE_REQUEST = "WebAPIPromiseRequest";
|
||||
const MSG_PROMISE_RESULT = "WebAPIPromiseResult";
|
||||
const MSG_INSTALL_EVENT = "WebAPIInstallEvent";
|
||||
const MSG_INSTALL_CLEANUP = "WebAPICleanup";
|
||||
const MSG_ADDON_EVENT_REQ = "WebAPIAddonEventRequest";
|
||||
const MSG_ADDON_EVENT = "WebAPIAddonEvent";
|
||||
const MSG_PROMISE_REQUEST = "WebAPIPromiseRequest";
|
||||
const MSG_PROMISE_RESULT = "WebAPIPromiseResult";
|
||||
const MSG_INSTALL_EVENT = "WebAPIInstallEvent";
|
||||
const MSG_INSTALL_CLEANUP = "WebAPICleanup";
|
||||
const MSG_ADDON_EVENT_REQ = "WebAPIAddonEventRequest";
|
||||
const MSG_ADDON_EVENT = "WebAPIAddonEvent";
|
||||
|
||||
class APIBroker {
|
||||
constructor(mm) {
|
||||
|
@ -51,7 +60,9 @@ class APIBroker {
|
|||
case MSG_INSTALL_EVENT: {
|
||||
let install = this._installMap.get(payload.id);
|
||||
if (!install) {
|
||||
let err = new Error(`Got install event for unknown install ${payload.id}`);
|
||||
let err = new Error(
|
||||
`Got install event for unknown install ${payload.id}`
|
||||
);
|
||||
Cu.reportError(err);
|
||||
return;
|
||||
}
|
||||
|
@ -80,10 +91,10 @@ class APIBroker {
|
|||
this._eventListener = callback;
|
||||
if (callback) {
|
||||
this.mm.addMessageListener(MSG_ADDON_EVENT, this);
|
||||
this.mm.sendAsyncMessage(MSG_ADDON_EVENT_REQ, {enabled: true});
|
||||
this.mm.sendAsyncMessage(MSG_ADDON_EVENT_REQ, { enabled: true });
|
||||
} else {
|
||||
this.mm.removeMessageListener(MSG_ADDON_EVENT, this);
|
||||
this.mm.sendAsyncMessage(MSG_ADDON_EVENT_REQ, {enabled: false});
|
||||
this.mm.sendAsyncMessage(MSG_ADDON_EVENT_REQ, { enabled: false });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,7 +245,8 @@ class WebAPI extends APIObject {
|
|||
// Provide the host from which the amWebAPI is being called
|
||||
// (so that we can detect if the API is being used from the disco pane,
|
||||
// AMO, testpilot or another unknown webpage).
|
||||
sourceHost: this.window.document.nodePrincipal.URI &&
|
||||
sourceHost:
|
||||
this.window.document.nodePrincipal.URI &&
|
||||
this.window.document.nodePrincipal.URI.host,
|
||||
};
|
||||
installOptions.triggeringPrincipal = this.window.document.nodePrincipal;
|
||||
|
@ -269,6 +281,10 @@ class WebAPI extends APIObject {
|
|||
}
|
||||
}
|
||||
}
|
||||
WebAPI.prototype.QueryInterface = ChromeUtils.generateQI(["nsIDOMGlobalPropertyInitializer"]);
|
||||
WebAPI.prototype.classID = Components.ID("{8866d8e3-4ea5-48b7-a891-13ba0ac15235}");
|
||||
WebAPI.prototype.QueryInterface = ChromeUtils.generateQI([
|
||||
"nsIDOMGlobalPropertyInitializer",
|
||||
]);
|
||||
WebAPI.prototype.classID = Components.ID(
|
||||
"{8866d8e3-4ea5-48b7-a891-13ba0ac15235}"
|
||||
);
|
||||
var EXPORTED_SYMBOLS = ["WebAPI"];
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -9,19 +9,28 @@
|
|||
* isDisabledUnsigned, loadReleaseNotes, openOptionsInTab,
|
||||
* promiseEvent, shouldShowPermissionsPrompt, showPermissionsPrompt */
|
||||
|
||||
const {AddonSettings} =
|
||||
ChromeUtils.import("resource://gre/modules/addons/AddonSettings.jsm");
|
||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { AddonSettings } = ChromeUtils.import(
|
||||
"resource://gre/modules/addons/AddonSettings.jsm"
|
||||
);
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this, "WEBEXT_PERMISSION_PROMPTS",
|
||||
"extensions.webextPermissionPrompts", false);
|
||||
this,
|
||||
"WEBEXT_PERMISSION_PROMPTS",
|
||||
"extensions.webextPermissionPrompts",
|
||||
false
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Extension",
|
||||
"resource://gre/modules/Extension.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Extension",
|
||||
"resource://gre/modules/Extension.jsm"
|
||||
);
|
||||
|
||||
function getBrowserElement() {
|
||||
return window.docShell.chromeEventHandler;
|
||||
|
@ -29,7 +38,7 @@ function getBrowserElement() {
|
|||
|
||||
function promiseEvent(event, target, capture = false) {
|
||||
return new Promise(resolve => {
|
||||
target.addEventListener(event, resolve, {capture, once: true});
|
||||
target.addEventListener(event, resolve, { capture, once: true });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -38,7 +47,7 @@ function attachUpdateHandler(install) {
|
|||
return;
|
||||
}
|
||||
|
||||
install.promptHandler = (info) => {
|
||||
install.promptHandler = info => {
|
||||
let oldPerms = info.existingAddon.userPermissions;
|
||||
if (!oldPerms) {
|
||||
// Updating from a legacy add-on, let it proceed
|
||||
|
@ -78,7 +87,7 @@ function attachUpdateHandler(install) {
|
|||
}
|
||||
|
||||
async function loadReleaseNotes(uri) {
|
||||
const res = await fetch(uri.spec, {credentials: "omit"});
|
||||
const res = await fetch(uri.spec, { credentials: "omit" });
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error("Error loading release notes");
|
||||
|
@ -88,8 +97,9 @@ async function loadReleaseNotes(uri) {
|
|||
const text = await res.text();
|
||||
|
||||
// Setup the content sanitizer.
|
||||
const ParserUtils = Cc["@mozilla.org/parserutils;1"]
|
||||
.getService(Ci.nsIParserUtils);
|
||||
const ParserUtils = Cc["@mozilla.org/parserutils;1"].getService(
|
||||
Ci.nsIParserUtils
|
||||
);
|
||||
const flags =
|
||||
ParserUtils.SanitizerDropMedia |
|
||||
ParserUtils.SanitizerDropNonCSSPresentation |
|
||||
|
@ -117,12 +127,12 @@ function shouldShowPermissionsPrompt(addon) {
|
|||
return false;
|
||||
}
|
||||
|
||||
const {origins, permissions} = addon.userPermissions;
|
||||
const { origins, permissions } = addon.userPermissions;
|
||||
return origins.length > 0 || permissions.length > 0;
|
||||
}
|
||||
|
||||
function showPermissionsPrompt(addon) {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
const permissions = addon.userPermissions;
|
||||
const target = getBrowserElement();
|
||||
|
||||
|
@ -130,10 +140,13 @@ function showPermissionsPrompt(addon) {
|
|||
// The user has just enabled a sideloaded extension, if the permission
|
||||
// can be changed for the extension, show the post-install panel to
|
||||
// give the user that opportunity.
|
||||
if (addon.permissions &
|
||||
AddonManager.PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS) {
|
||||
Services.obs.notifyObservers({addon, target},
|
||||
"webextension-install-notify");
|
||||
if (
|
||||
addon.permissions & AddonManager.PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS
|
||||
) {
|
||||
Services.obs.notifyObservers(
|
||||
{ addon, target },
|
||||
"webextension-install-notify"
|
||||
);
|
||||
}
|
||||
resolve();
|
||||
};
|
||||
|
@ -182,8 +195,9 @@ function isCorrectlySigned(addon) {
|
|||
}
|
||||
|
||||
function isDisabledUnsigned(addon) {
|
||||
let signingRequired = (addon.type == "locale") ?
|
||||
AddonSettings.LANGPACKS_REQUIRE_SIGNING :
|
||||
AddonSettings.REQUIRE_SIGNING;
|
||||
let signingRequired =
|
||||
addon.type == "locale"
|
||||
? AddonSettings.LANGPACKS_REQUIRE_SIGNING
|
||||
: AddonSettings.REQUIRE_SIGNING;
|
||||
return signingRequired && !isCorrectlySigned(addon);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,16 @@
|
|||
/* globals MozXULElement, Services, useHtmlViews, getHtmlBrowser, htmlBrowserLoaded */
|
||||
|
||||
{
|
||||
const ABUSE_REPORT_ENABLED = Services.prefs.getBoolPref("extensions.abuseReport.enabled", false);
|
||||
const ABUSE_REPORT_FRAME_URL = "chrome://mozapps/content/extensions/abuse-report-frame.html";
|
||||
const ABUSE_REPORT_ENABLED = Services.prefs.getBoolPref(
|
||||
"extensions.abuseReport.enabled",
|
||||
false
|
||||
);
|
||||
const ABUSE_REPORT_FRAME_URL =
|
||||
"chrome://mozapps/content/extensions/abuse-report-frame.html";
|
||||
const fm = Services.focus;
|
||||
const {AbuseReporter} = ChromeUtils.import("resource://gre/modules/AbuseReporter.jsm");
|
||||
const { AbuseReporter } = ChromeUtils.import(
|
||||
"resource://gre/modules/AbuseReporter.jsm"
|
||||
);
|
||||
|
||||
class AddonAbuseReportsXULFrame extends MozXULElement {
|
||||
constructor() {
|
||||
|
@ -33,7 +39,9 @@
|
|||
|
||||
const browser = this.querySelector("browser");
|
||||
this.promiseBrowserLoaded = new Promise(resolve => {
|
||||
browser.addEventListener("load", () => resolve(browser), {once: true});
|
||||
browser.addEventListener("load", () => resolve(browser), {
|
||||
once: true,
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("focus", this);
|
||||
|
@ -88,15 +96,19 @@
|
|||
}
|
||||
|
||||
forwardEvent(evt) {
|
||||
this.dispatchEvent(new CustomEvent(evt.type, {detail: evt.detail}));
|
||||
this.dispatchEvent(new CustomEvent(evt.type, { detail: evt.detail }));
|
||||
}
|
||||
|
||||
async openReport({addonId, reportEntryPoint}) {
|
||||
async openReport({ addonId, reportEntryPoint }) {
|
||||
if (this.report) {
|
||||
throw new Error("Ignoring new abuse report request. AbuseReport panel already open");
|
||||
throw new Error(
|
||||
"Ignoring new abuse report request. AbuseReport panel already open"
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
this.report = await AbuseReporter.createAbuseReport(addonId, {reportEntryPoint});
|
||||
this.report = await AbuseReporter.createAbuseReport(addonId, {
|
||||
reportEntryPoint,
|
||||
});
|
||||
this.update();
|
||||
} catch (err) {
|
||||
// Log the complete error in the console.
|
||||
|
@ -105,9 +117,14 @@
|
|||
// panel an error message-bar is created on the HTML about:addons page.
|
||||
const win = await this.promiseHtmlAboutAddons;
|
||||
win.document.dispatchEvent(
|
||||
new CustomEvent("abuse-report:create-error", {detail: {
|
||||
addonId, addon: err.addon, errorType: err.errorType,
|
||||
}}));
|
||||
new CustomEvent("abuse-report:create-error", {
|
||||
detail: {
|
||||
addonId,
|
||||
addon: err.addon,
|
||||
errorType: err.errorType,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,9 +156,9 @@
|
|||
}
|
||||
|
||||
async update() {
|
||||
const {report} = this;
|
||||
const { report } = this;
|
||||
if (report && report.addon && !report.errorType) {
|
||||
const {addon, reportEntryPoint} = this.report;
|
||||
const { addon, reportEntryPoint } = this.report;
|
||||
this.addonId = addon.id;
|
||||
this.reportEntryPoint = reportEntryPoint;
|
||||
|
||||
|
@ -149,9 +166,15 @@
|
|||
// embedded in the XUL browser.
|
||||
this.promiseAbuseReport.then(abuseReport => {
|
||||
this.hidden = false;
|
||||
abuseReport.addEventListener("abuse-report:updated", this, {once: true});
|
||||
abuseReport.addEventListener("abuse-report:submit", this, {once: true});
|
||||
abuseReport.addEventListener("abuse-report:cancel", this, {once: true});
|
||||
abuseReport.addEventListener("abuse-report:updated", this, {
|
||||
once: true,
|
||||
});
|
||||
abuseReport.addEventListener("abuse-report:submit", this, {
|
||||
once: true,
|
||||
});
|
||||
abuseReport.addEventListener("abuse-report:cancel", this, {
|
||||
once: true,
|
||||
});
|
||||
abuseReport.setAbuseReport(report);
|
||||
// Hide the content of the underlying about:addons page from
|
||||
// screen readers.
|
||||
|
@ -171,16 +194,27 @@
|
|||
|
||||
// Move the focus back to the top level window.
|
||||
fm.moveFocus(window, null, fm.MOVEFOCUS_ROOT, fm.FLAG_BYKEY);
|
||||
this.promiseAbuseReport.then(abuseReport => {
|
||||
abuseReport.removeEventListener("abuse-report:updated", this, {once: true});
|
||||
abuseReport.removeEventListener("abuse-report:submit", this, {once: true});
|
||||
abuseReport.removeEventListener("abuse-report:cancel", this, {once: true});
|
||||
abuseReport.setAbuseReport(null);
|
||||
}, err => {
|
||||
console.error("promiseAbuseReport rejected", err);
|
||||
}).then(() => {
|
||||
this.dispatchEvent(new CustomEvent("abuse-report:frame-hidden"));
|
||||
});
|
||||
this.promiseAbuseReport
|
||||
.then(
|
||||
abuseReport => {
|
||||
abuseReport.removeEventListener("abuse-report:updated", this, {
|
||||
once: true,
|
||||
});
|
||||
abuseReport.removeEventListener("abuse-report:submit", this, {
|
||||
once: true,
|
||||
});
|
||||
abuseReport.removeEventListener("abuse-report:cancel", this, {
|
||||
once: true,
|
||||
});
|
||||
abuseReport.setAbuseReport(null);
|
||||
},
|
||||
err => {
|
||||
console.error("promiseAbuseReport rejected", err);
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
this.dispatchEvent(new CustomEvent("abuse-report:frame-hidden"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,14 +267,17 @@
|
|||
// the custom XUL WebComponent and append it to the XUL stack element
|
||||
// (if not registered the element will be just a dummy hidden box)
|
||||
if (useHtmlViews && ABUSE_REPORT_ENABLED) {
|
||||
customElements.define("addon-abuse-report-xulframe", AddonAbuseReportsXULFrame);
|
||||
customElements.define(
|
||||
"addon-abuse-report-xulframe",
|
||||
AddonAbuseReportsXULFrame
|
||||
);
|
||||
}
|
||||
|
||||
// Helper method exported into the about:addons global, used to open the
|
||||
// abuse report panel from outside of the about:addons page
|
||||
// (e.g. triggered from the browserAction context menu).
|
||||
window.openAbuseReport = ({addonId, reportEntryPoint}) => {
|
||||
window.openAbuseReport = ({ addonId, reportEntryPoint }) => {
|
||||
const frame = document.querySelector("addon-abuse-report-xulframe");
|
||||
frame.openReport({addonId, reportEntryPoint});
|
||||
frame.openReport({ addonId, reportEntryPoint });
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,55 +5,58 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Services",
|
||||
"resource://gre/modules/Services.jsm"
|
||||
);
|
||||
|
||||
const showOnAnyType = () => false;
|
||||
const hideOnAnyType = () => true;
|
||||
const hideOnThemeType = (addonType) => addonType === "theme";
|
||||
const hideOnThemeType = addonType => addonType === "theme";
|
||||
|
||||
// The reasons string used as a key in this Map is expected to stay in sync
|
||||
// with the reasons string used in the "abuseReports.ftl" locale file and
|
||||
// the suggestions templates included in abuse-reports-xulframe.html.
|
||||
const ABUSE_REASONS = window.ABUSE_REPORT_REASONS = {
|
||||
"damage": {
|
||||
const ABUSE_REASONS = (window.ABUSE_REPORT_REASONS = {
|
||||
damage: {
|
||||
isExampleHidden: showOnAnyType,
|
||||
isReasonHidden: hideOnThemeType,
|
||||
},
|
||||
"spam": {
|
||||
spam: {
|
||||
isExampleHidden: showOnAnyType,
|
||||
isReasonHidden: showOnAnyType,
|
||||
},
|
||||
"settings": {
|
||||
settings: {
|
||||
hasSuggestions: true,
|
||||
isExampleHidden: hideOnAnyType,
|
||||
isReasonHidden: hideOnThemeType,
|
||||
},
|
||||
"deceptive": {
|
||||
deceptive: {
|
||||
isExampleHidden: showOnAnyType,
|
||||
isReasonHidden: showOnAnyType,
|
||||
},
|
||||
"broken": {
|
||||
broken: {
|
||||
hasAddonTypeL10nId: true,
|
||||
hasAddonTypeSuggestionTemplate: true,
|
||||
hasSuggestions: true,
|
||||
isExampleHidden: hideOnThemeType,
|
||||
isReasonHidden: showOnAnyType,
|
||||
},
|
||||
"policy": {
|
||||
policy: {
|
||||
hasSuggestions: true,
|
||||
isExampleHidden: hideOnAnyType,
|
||||
isReasonHidden: showOnAnyType,
|
||||
},
|
||||
"unwanted": {
|
||||
unwanted: {
|
||||
isExampleHidden: showOnAnyType,
|
||||
isReasonHidden: hideOnThemeType,
|
||||
},
|
||||
"other": {
|
||||
other: {
|
||||
isExampleHidden: hideOnAnyType,
|
||||
isReasonHidden: showOnAnyType,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
function getReasonL10nId(reason, addonType) {
|
||||
let l10nId = `abuse-report-${reason}-reason`;
|
||||
|
@ -101,9 +104,9 @@ const LEARNMORE_LINKS = {
|
|||
function formatLearnMoreURLs(containerEl) {
|
||||
for (const [linkClass, linkInfo] of Object.entries(LEARNMORE_LINKS)) {
|
||||
for (const element of containerEl.querySelectorAll(linkClass)) {
|
||||
const baseURL = linkInfo.baseURL ?
|
||||
Services.urlFormatter.formatURL(linkInfo.baseURL) :
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL");
|
||||
const baseURL = linkInfo.baseURL
|
||||
? Services.urlFormatter.formatURL(linkInfo.baseURL)
|
||||
: Services.urlFormatter.formatURLPref("app.support.baseURL");
|
||||
|
||||
element.href = baseURL + linkInfo.path;
|
||||
}
|
||||
|
@ -114,7 +117,7 @@ function formatLearnMoreURLs(containerEl) {
|
|||
function defineElementSelectorsGetters(object, propsMap) {
|
||||
const props = Object.entries(propsMap).reduce((acc, entry) => {
|
||||
const [name, selector] = entry;
|
||||
acc[name] = {get: () => object.querySelector(selector)};
|
||||
acc[name] = { get: () => object.querySelector(selector) };
|
||||
return acc;
|
||||
}, {});
|
||||
Object.defineProperties(object, props);
|
||||
|
@ -127,7 +130,7 @@ function defineElementAttributesProperties(object, propsMap) {
|
|||
const [name, attr] = entry;
|
||||
acc[name] = {
|
||||
get: () => object.getAttribute(attr),
|
||||
set: (value) => {
|
||||
set: value => {
|
||||
object.setAttribute(attr, value);
|
||||
},
|
||||
};
|
||||
|
@ -148,7 +151,7 @@ function getElements(containerEl, propsMap) {
|
|||
}
|
||||
|
||||
function dispatchCustomEvent(el, eventName, detail) {
|
||||
el.dispatchEvent(new CustomEvent(eventName, {detail}));
|
||||
el.dispatchEvent(new CustomEvent(eventName, { detail }));
|
||||
}
|
||||
|
||||
// This WebComponent extends the li item to represent an abuse report reason
|
||||
|
@ -177,7 +180,7 @@ class AbuseReasonListItem extends HTMLLIElement {
|
|||
return;
|
||||
}
|
||||
|
||||
const {reason, checked, addonType} = this;
|
||||
const { reason, checked, addonType } = this;
|
||||
|
||||
this.textContent = "";
|
||||
const content = document.importNode(this.template.content, true);
|
||||
|
@ -186,7 +189,7 @@ class AbuseReasonListItem extends HTMLLIElement {
|
|||
const reasonId = `abuse-reason-${reason}`;
|
||||
const reasonInfo = ABUSE_REASONS[reason] || {};
|
||||
|
||||
const {labelEl, descriptionEl, radioEl} = getElements(content, {
|
||||
const { labelEl, descriptionEl, radioEl } = getElements(content, {
|
||||
labelEl: "label",
|
||||
descriptionEl: ".reason-description",
|
||||
radioEl: "input[type=radio]",
|
||||
|
@ -200,13 +203,17 @@ class AbuseReasonListItem extends HTMLLIElement {
|
|||
// This reason has a different localized description based on the
|
||||
// addon type.
|
||||
document.l10n.setAttributes(
|
||||
descriptionEl, getReasonL10nId(reason, addonType));
|
||||
descriptionEl,
|
||||
getReasonL10nId(reason, addonType)
|
||||
);
|
||||
|
||||
// Show the reason example if supported for the addon type.
|
||||
if (!reasonInfo.isExampleHidden(addonType)) {
|
||||
const exampleEl = content.querySelector(".reason-example");
|
||||
document.l10n.setAttributes(
|
||||
exampleEl, `abuse-report-${reason}-example`);
|
||||
exampleEl,
|
||||
`abuse-report-${reason}-example`
|
||||
);
|
||||
exampleEl.hidden = false;
|
||||
}
|
||||
}
|
||||
|
@ -240,12 +247,12 @@ class AbuseReasonsPanel extends HTMLElement {
|
|||
return;
|
||||
}
|
||||
|
||||
const {addonType} = this;
|
||||
const { addonType } = this;
|
||||
|
||||
this.textContent = "";
|
||||
const content = document.importNode(this.template.content, true);
|
||||
|
||||
const {titleEl, listEl} = getElements(content, {
|
||||
const { titleEl, listEl } = getElements(content, {
|
||||
titleEl: ".abuse-report-title",
|
||||
listEl: "ul.abuse-report-reasons",
|
||||
});
|
||||
|
@ -255,8 +262,8 @@ class AbuseReasonsPanel extends HTMLElement {
|
|||
|
||||
// Create the randomized list of reasons.
|
||||
const reasons = Object.keys(ABUSE_REASONS)
|
||||
.filter(reason => reason !== "other")
|
||||
.sort(() => Math.random() - 0.5);
|
||||
.filter(reason => reason !== "other")
|
||||
.sort(() => Math.random() - 0.5);
|
||||
|
||||
for (const reason of reasons) {
|
||||
const reasonInfo = ABUSE_REASONS[reason];
|
||||
|
@ -299,7 +306,7 @@ class AbuseReasonSuggestions extends HTMLElement {
|
|||
}
|
||||
|
||||
update() {
|
||||
const {addonType, extensionSupportURL, reason} = this;
|
||||
const { addonType, extensionSupportURL, reason } = this;
|
||||
|
||||
if (!addonType) {
|
||||
return;
|
||||
|
@ -359,7 +366,7 @@ class AbuseSubmitPanel extends HTMLElement {
|
|||
if (!this.isConnected || !this.addonType) {
|
||||
return;
|
||||
}
|
||||
const {addonType, reason, _suggestions, _title} = this;
|
||||
const { addonType, reason, _suggestions, _title } = this;
|
||||
document.l10n.setAttributes(_title, getReasonL10nId(reason, addonType));
|
||||
_suggestions.reason = reason;
|
||||
_suggestions.addonType = addonType;
|
||||
|
@ -435,8 +442,7 @@ class AbuseReport extends HTMLElement {
|
|||
this.handleKeyboardNavigation(evt);
|
||||
break;
|
||||
case "click":
|
||||
if (evt.target === this._iconClose ||
|
||||
evt.target === this._btnCancel) {
|
||||
if (evt.target === this._iconClose || evt.target === this._btnCancel) {
|
||||
// NOTE: clear the focus on the clicked element to ensure that
|
||||
// -moz-focusring pseudo class is not still set on the element
|
||||
// when the panel is going to be shown again (See Bug 1560949).
|
||||
|
@ -468,8 +474,12 @@ class AbuseReport extends HTMLElement {
|
|||
}
|
||||
|
||||
handleKeyboardNavigation(evt) {
|
||||
if (evt.keyCode !== evt.DOM_VK_TAB ||
|
||||
evt.altKey || evt.controlKey || evt.metaKey) {
|
||||
if (
|
||||
evt.keyCode !== evt.DOM_VK_TAB ||
|
||||
evt.altKey ||
|
||||
evt.controlKey ||
|
||||
evt.metaKey
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -497,8 +507,11 @@ class AbuseReport extends HTMLElement {
|
|||
evt.stopImmediatePropagation();
|
||||
const chromeWin = window.windowRoot.ownerGlobal;
|
||||
Services.focus.moveFocus(
|
||||
chromeWin, null,
|
||||
Services.MOVEFOCUS_BACKWARD, Services.focus.FLAG_BYKEY);
|
||||
chromeWin,
|
||||
null,
|
||||
Services.MOVEFOCUS_BACKWARD,
|
||||
Services.focus.FLAG_BYKEY
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,9 +548,11 @@ class AbuseReport extends HTMLElement {
|
|||
|
||||
_linkAddonAuthor.href = this.authorURL || this.homepageURL;
|
||||
_linkAddonAuthor.textContent = this.authorName;
|
||||
document.l10n.setAttributes(_linkAddonAuthor.parentNode,
|
||||
"abuse-report-addon-authored-by",
|
||||
{"author-name": this.authorName});
|
||||
document.l10n.setAttributes(
|
||||
_linkAddonAuthor.parentNode,
|
||||
"abuse-report-addon-authored-by",
|
||||
{ "author-name": this.authorName }
|
||||
);
|
||||
|
||||
_addonIconElement.setAttribute("src", this.iconURL);
|
||||
|
||||
|
@ -551,7 +566,8 @@ class AbuseReport extends HTMLElement {
|
|||
|
||||
this.focus();
|
||||
dispatchCustomEvent(this, "abuse-report:updated", {
|
||||
addonId, panel: "reasons",
|
||||
addonId,
|
||||
panel: "reasons",
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -573,11 +589,11 @@ class AbuseReport extends HTMLElement {
|
|||
return;
|
||||
}
|
||||
if (this._reasonsPanel.hidden) {
|
||||
const {_textarea} = this;
|
||||
const { _textarea } = this;
|
||||
_textarea.focus();
|
||||
_textarea.select();
|
||||
} else {
|
||||
const {_radioCheckedReason} = this;
|
||||
const { _radioCheckedReason } = this;
|
||||
if (_radioCheckedReason) {
|
||||
_radioCheckedReason.focus();
|
||||
}
|
||||
|
@ -617,7 +633,8 @@ class AbuseReport extends HTMLElement {
|
|||
// Adjust the focused element when switching to the submit panel.
|
||||
this.focus();
|
||||
dispatchCustomEvent(this, "abuse-report:updated", {
|
||||
addonId: this.addonId, panel: "submit",
|
||||
addonId: this.addonId,
|
||||
panel: "submit",
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -632,7 +649,8 @@ class AbuseReport extends HTMLElement {
|
|||
// Adjust the focused element when switching back to the list of reasons.
|
||||
this.focus();
|
||||
dispatchCustomEvent(this, "abuse-report:updated", {
|
||||
addonId: this.addonId, panel: "reasons",
|
||||
addonId: this.addonId,
|
||||
panel: "reasons",
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -657,18 +675,18 @@ class AbuseReport extends HTMLElement {
|
|||
}
|
||||
|
||||
get homepageURL() {
|
||||
const {addon} = this;
|
||||
return addon && addon.homepageURL || this.authorURL || "";
|
||||
const { addon } = this;
|
||||
return (addon && addon.homepageURL) || this.authorURL || "";
|
||||
}
|
||||
|
||||
get authorName() {
|
||||
// The author name may be missing on some of the test extensions
|
||||
// (or for temporarily installed add-ons).
|
||||
return this.addonCreator && this.addonCreator.name || "";
|
||||
return (this.addonCreator && this.addonCreator.name) || "";
|
||||
}
|
||||
|
||||
get authorURL() {
|
||||
return this.addonCreator && this.addonCreator.url || "";
|
||||
return (this.addonCreator && this.addonCreator.url) || "";
|
||||
}
|
||||
|
||||
get iconURL() {
|
||||
|
@ -676,7 +694,7 @@ class AbuseReport extends HTMLElement {
|
|||
}
|
||||
|
||||
get supportURL() {
|
||||
return this.addon && this.addon.supportURL || this.homepageURL || "";
|
||||
return (this.addon && this.addon.supportURL) || this.homepageURL || "";
|
||||
}
|
||||
|
||||
get message() {
|
||||
|
@ -692,14 +710,21 @@ class AbuseReport extends HTMLElement {
|
|||
}
|
||||
}
|
||||
|
||||
customElements.define("abuse-report-reason-listitem",
|
||||
AbuseReasonListItem, {extends: "li"});
|
||||
customElements.define("abuse-report-reason-suggestions",
|
||||
AbuseReasonSuggestions);
|
||||
customElements.define("abuse-report-reason-listitem", AbuseReasonListItem, {
|
||||
extends: "li",
|
||||
});
|
||||
customElements.define(
|
||||
"abuse-report-reason-suggestions",
|
||||
AbuseReasonSuggestions
|
||||
);
|
||||
customElements.define("abuse-report-reasons-panel", AbuseReasonsPanel);
|
||||
customElements.define("abuse-report-submit-panel", AbuseSubmitPanel);
|
||||
customElements.define("addon-abuse-report", AbuseReport);
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
document.body.prepend(document.createElement("addon-abuse-report"));
|
||||
}, {once: true});
|
||||
window.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
document.body.prepend(document.createElement("addon-abuse-report"));
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
|
|
@ -14,66 +14,88 @@
|
|||
// Message Bars definitions.
|
||||
const ABUSE_REPORT_MESSAGE_BARS = {
|
||||
// Idle message-bar (used while the submission is still ongoing).
|
||||
"submitting": {id: "submitting", actions: ["cancel"]},
|
||||
submitting: { id: "submitting", actions: ["cancel"] },
|
||||
// Submitted report message-bar.
|
||||
"submitted": {
|
||||
id: "submitted", actionAddonTypeSuffix: true,
|
||||
actions: ["remove", "keep"], dismissable: true,
|
||||
submitted: {
|
||||
id: "submitted",
|
||||
actionAddonTypeSuffix: true,
|
||||
actions: ["remove", "keep"],
|
||||
dismissable: true,
|
||||
},
|
||||
// Submitted report message-bar (with no remove actions).
|
||||
"submitted-no-remove-action": {
|
||||
id: "submitted-noremove", dismissable: true,
|
||||
id: "submitted-noremove",
|
||||
dismissable: true,
|
||||
},
|
||||
// Submitted report and remove addon message-bar.
|
||||
"submitted-and-removed": {
|
||||
id: "removed", addonTypeSuffix: true, dismissable: true,
|
||||
id: "removed",
|
||||
addonTypeSuffix: true,
|
||||
dismissable: true,
|
||||
},
|
||||
// The "aborted report" message bar is rendered as a generic informative one,
|
||||
// because aborting a report is triggered by a user choice.
|
||||
"ERROR_ABORTED_SUBMIT": {
|
||||
id: "aborted", type: "generic", dismissable: true,
|
||||
ERROR_ABORTED_SUBMIT: {
|
||||
id: "aborted",
|
||||
type: "generic",
|
||||
dismissable: true,
|
||||
},
|
||||
// Errors message bars.
|
||||
"ERROR_ADDON_NOTFOUND": {
|
||||
id: "error", type: "error", dismissable: true,
|
||||
ERROR_ADDON_NOTFOUND: {
|
||||
id: "error",
|
||||
type: "error",
|
||||
dismissable: true,
|
||||
},
|
||||
"ERROR_CLIENT": {
|
||||
id: "error", type: "error", dismissable: true,
|
||||
ERROR_CLIENT: {
|
||||
id: "error",
|
||||
type: "error",
|
||||
dismissable: true,
|
||||
},
|
||||
"ERROR_NETWORK": {
|
||||
id: "error", actions: ["retry", "cancel"], type: "error",
|
||||
ERROR_NETWORK: {
|
||||
id: "error",
|
||||
actions: ["retry", "cancel"],
|
||||
type: "error",
|
||||
},
|
||||
"ERROR_RECENT_SUBMIT": {
|
||||
id: "error-recent-submit", actions: ["retry", "cancel"], type: "error",
|
||||
ERROR_RECENT_SUBMIT: {
|
||||
id: "error-recent-submit",
|
||||
actions: ["retry", "cancel"],
|
||||
type: "error",
|
||||
},
|
||||
"ERROR_SERVER": {
|
||||
id: "error", actions: ["retry", "cancel"], type: "error",
|
||||
ERROR_SERVER: {
|
||||
id: "error",
|
||||
actions: ["retry", "cancel"],
|
||||
type: "error",
|
||||
},
|
||||
"ERROR_UNKNOWN": {
|
||||
id: "error", actions: ["retry", "cancel"], type: "error",
|
||||
ERROR_UNKNOWN: {
|
||||
id: "error",
|
||||
actions: ["retry", "cancel"],
|
||||
type: "error",
|
||||
},
|
||||
};
|
||||
|
||||
function openAbuseReport({addonId, reportEntryPoint}) {
|
||||
document.dispatchEvent(new CustomEvent("abuse-report:new", {
|
||||
detail: {addonId, reportEntryPoint},
|
||||
}));
|
||||
function openAbuseReport({ addonId, reportEntryPoint }) {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("abuse-report:new", {
|
||||
detail: { addonId, reportEntryPoint },
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function used to create abuse report message bars in the
|
||||
// HTML about:addons page.
|
||||
function createReportMessageBar(
|
||||
definitionId, {addonId, addonName, addonType},
|
||||
{onclose, onaction} = {}
|
||||
definitionId,
|
||||
{ addonId, addonName, addonType },
|
||||
{ onclose, onaction } = {}
|
||||
) {
|
||||
const getMessageL10n = (id) => `abuse-report-messagebar-${id}`;
|
||||
const getActionL10n = (action) => getMessageL10n(`action-${action}`);
|
||||
const getMessageL10n = id => `abuse-report-messagebar-${id}`;
|
||||
const getActionL10n = action => getMessageL10n(`action-${action}`);
|
||||
|
||||
const barInfo = ABUSE_REPORT_MESSAGE_BARS[definitionId];
|
||||
if (!barInfo) {
|
||||
throw new Error(`message-bar definition not found: ${definitionId}`);
|
||||
}
|
||||
const {id, dismissable, actions, type} = barInfo;
|
||||
const { id, dismissable, actions, type } = barInfo;
|
||||
const messageEl = document.createElement("span");
|
||||
|
||||
// The message element includes an addon-name span (also filled by
|
||||
|
@ -86,18 +108,22 @@ function createReportMessageBar(
|
|||
document.l10n.setAttributes(
|
||||
messageEl,
|
||||
getMessageL10n(barInfo.addonTypeSuffix ? `${id}-${addonType}` : id),
|
||||
{"addon-name": addonName || addonId});
|
||||
{ "addon-name": addonName || addonId }
|
||||
);
|
||||
|
||||
const barActions = actions ? actions.map(action => {
|
||||
// Some of the message bars require a different per addonType
|
||||
// Fluent id for their actions.
|
||||
const actionId = barInfo.actionAddonTypeSuffix ?
|
||||
`${action}-${addonType}` : action;
|
||||
const buttonEl = document.createElement("button");
|
||||
buttonEl.addEventListener("click", () => onaction && onaction(action));
|
||||
document.l10n.setAttributes(buttonEl, getActionL10n(actionId));
|
||||
return buttonEl;
|
||||
}) : [];
|
||||
const barActions = actions
|
||||
? actions.map(action => {
|
||||
// Some of the message bars require a different per addonType
|
||||
// Fluent id for their actions.
|
||||
const actionId = barInfo.actionAddonTypeSuffix
|
||||
? `${action}-${addonType}`
|
||||
: action;
|
||||
const buttonEl = document.createElement("button");
|
||||
buttonEl.addEventListener("click", () => onaction && onaction(action));
|
||||
document.l10n.setAttributes(buttonEl, getActionL10n(actionId));
|
||||
return buttonEl;
|
||||
})
|
||||
: [];
|
||||
|
||||
const messagebar = document.createElement("message-bar");
|
||||
messagebar.setAttribute("type", type || "generic");
|
||||
|
@ -105,35 +131,40 @@ function createReportMessageBar(
|
|||
messagebar.setAttribute("dismissable", "");
|
||||
}
|
||||
messagebar.append(messageEl, ...barActions);
|
||||
messagebar.addEventListener("message-bar:close", onclose, {once: true});
|
||||
messagebar.addEventListener("message-bar:close", onclose, { once: true });
|
||||
|
||||
document.getElementById("abuse-reports-messages").append(messagebar);
|
||||
|
||||
document.dispatchEvent(new CustomEvent("abuse-report:new-message-bar", {
|
||||
detail: {definitionId, messagebar},
|
||||
}));
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("abuse-report:new-message-bar", {
|
||||
detail: { definitionId, messagebar },
|
||||
})
|
||||
);
|
||||
return messagebar;
|
||||
}
|
||||
|
||||
async function submitReport({report, reason, message}) {
|
||||
const {addon} = report;
|
||||
async function submitReport({ report, reason, message }) {
|
||||
const { addon } = report;
|
||||
const addonId = addon.id;
|
||||
const addonName = addon.name;
|
||||
const addonType = addon.type;
|
||||
|
||||
// Create a message bar while we are still submitting the report.
|
||||
const mbSubmitting = createReportMessageBar(
|
||||
"submitting", {addonId, addonName, addonType}, {
|
||||
onaction: (action) => {
|
||||
"submitting",
|
||||
{ addonId, addonName, addonType },
|
||||
{
|
||||
onaction: action => {
|
||||
if (action === "cancel") {
|
||||
report.abort();
|
||||
mbSubmitting.remove();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
await report.submit({reason, message});
|
||||
await report.submit({ reason, message });
|
||||
mbSubmitting.remove();
|
||||
|
||||
// Create a submitted message bar when the submission has been
|
||||
|
@ -152,53 +183,67 @@ async function submitReport({report, reason, message}) {
|
|||
barId = "submitted";
|
||||
}
|
||||
|
||||
const mbInfo = createReportMessageBar(barId, {
|
||||
addonId, addonName, addonType,
|
||||
}, {
|
||||
onaction: (action) => {
|
||||
mbInfo.remove();
|
||||
// action "keep" doesn't require any further action,
|
||||
// just handle "remove".
|
||||
if (action === "remove") {
|
||||
report.addon.uninstall(true);
|
||||
}
|
||||
const mbInfo = createReportMessageBar(
|
||||
barId,
|
||||
{
|
||||
addonId,
|
||||
addonName,
|
||||
addonType,
|
||||
},
|
||||
});
|
||||
{
|
||||
onaction: action => {
|
||||
mbInfo.remove();
|
||||
// action "keep" doesn't require any further action,
|
||||
// just handle "remove".
|
||||
if (action === "remove") {
|
||||
report.addon.uninstall(true);
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
// Log the complete error in the console.
|
||||
console.error("Error submitting abuse report for", addonId, err);
|
||||
mbSubmitting.remove();
|
||||
// The report has a submission error, create a error message bar which
|
||||
// may optionally allow the user to retry to submit the same report.
|
||||
const barId = err.errorType in ABUSE_REPORT_MESSAGE_BARS ?
|
||||
err.errorType : "ERROR_UNKNOWN";
|
||||
const barId =
|
||||
err.errorType in ABUSE_REPORT_MESSAGE_BARS
|
||||
? err.errorType
|
||||
: "ERROR_UNKNOWN";
|
||||
|
||||
const mbError = createReportMessageBar(barId, {
|
||||
addonId, addonName, addonType,
|
||||
}, {
|
||||
onaction: (action) => {
|
||||
mbError.remove();
|
||||
switch (action) {
|
||||
case "retry":
|
||||
submitReport({report, reason, message});
|
||||
break;
|
||||
case "cancel":
|
||||
report.abort();
|
||||
break;
|
||||
}
|
||||
const mbError = createReportMessageBar(
|
||||
barId,
|
||||
{
|
||||
addonId,
|
||||
addonName,
|
||||
addonType,
|
||||
},
|
||||
});
|
||||
{
|
||||
onaction: action => {
|
||||
mbError.remove();
|
||||
switch (action) {
|
||||
case "retry":
|
||||
submitReport({ report, reason, message });
|
||||
break;
|
||||
case "cancel":
|
||||
report.abort();
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("abuse-report:submit", ({detail}) => {
|
||||
document.addEventListener("abuse-report:submit", ({ detail }) => {
|
||||
submitReport(detail);
|
||||
});
|
||||
|
||||
document.addEventListener("abuse-report:create-error", ({detail}) => {
|
||||
const {addonId, addon, errorType} = detail;
|
||||
const barId = errorType in ABUSE_REPORT_MESSAGE_BARS ?
|
||||
errorType : "ERROR_UNKNOWN";
|
||||
document.addEventListener("abuse-report:create-error", ({ detail }) => {
|
||||
const { addonId, addon, errorType } = detail;
|
||||
const barId =
|
||||
errorType in ABUSE_REPORT_MESSAGE_BARS ? errorType : "ERROR_UNKNOWN";
|
||||
createReportMessageBar(barId, {
|
||||
addonId,
|
||||
addonName: addon && addon.name,
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
/* global MozXULElement */
|
||||
/* exported init, finish */
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var gArgs;
|
||||
|
||||
|
@ -18,17 +18,27 @@ function init() {
|
|||
var hasSoftBlocks = false;
|
||||
gArgs = window.arguments[0].wrappedJSObject;
|
||||
|
||||
document.addEventListener("dialogaccept", function() { finish(true); });
|
||||
document.addEventListener("dialogcancel", function() { finish(false); });
|
||||
document.addEventListener("dialogaccept", function() {
|
||||
finish(true);
|
||||
});
|
||||
document.addEventListener("dialogcancel", function() {
|
||||
finish(false);
|
||||
});
|
||||
|
||||
// NOTE: We use strings from the "updates.properties" bundleset to change the
|
||||
// text on the "Cancel" button to "Restart Later". (bug 523784)
|
||||
let bundle = Services.strings.
|
||||
createBundle("chrome://mozapps/locale/update/updates.properties");
|
||||
let bundle = Services.strings.createBundle(
|
||||
"chrome://mozapps/locale/update/updates.properties"
|
||||
);
|
||||
let cancelButton = document.documentElement.getButton("cancel");
|
||||
cancelButton.setAttribute("label", bundle.GetStringFromName("restartLaterButton"));
|
||||
cancelButton.setAttribute("accesskey",
|
||||
bundle.GetStringFromName("restartLaterButton.accesskey"));
|
||||
cancelButton.setAttribute(
|
||||
"label",
|
||||
bundle.GetStringFromName("restartLaterButton")
|
||||
);
|
||||
cancelButton.setAttribute(
|
||||
"accesskey",
|
||||
bundle.GetStringFromName("restartLaterButton.accesskey")
|
||||
);
|
||||
|
||||
var richlist = document.getElementById("addonList");
|
||||
var list = gArgs.list;
|
||||
|
@ -58,14 +68,24 @@ function init() {
|
|||
fragment.pack = "end";
|
||||
|
||||
if (listItem.blocked) {
|
||||
fragment.appendChild(MozXULElement.parseXULToFragment(`
|
||||
fragment.appendChild(
|
||||
MozXULElement.parseXULToFragment(
|
||||
`
|
||||
<label class="blockedLabel" value="&blocklist.blocked.label;"/>
|
||||
`, ["chrome://mozapps/locale/extensions/blocklist.dtd"]));
|
||||
`,
|
||||
["chrome://mozapps/locale/extensions/blocklist.dtd"]
|
||||
)
|
||||
);
|
||||
hasHardBlocks = true;
|
||||
} else {
|
||||
fragment.appendChild(MozXULElement.parseXULToFragment(`
|
||||
fragment.appendChild(
|
||||
MozXULElement.parseXULToFragment(
|
||||
`
|
||||
<checkbox class="disableCheckbox" checked="true" label="&blocklist.checkbox.label;"/>
|
||||
`, ["chrome://mozapps/locale/extensions/blocklist.dtd"]));
|
||||
`,
|
||||
["chrome://mozapps/locale/extensions/blocklist.dtd"]
|
||||
)
|
||||
);
|
||||
hasSoftBlocks = true;
|
||||
}
|
||||
|
||||
|
@ -74,18 +94,21 @@ function init() {
|
|||
richlist.appendChild(item);
|
||||
}
|
||||
|
||||
if (hasHardBlocks && hasSoftBlocks)
|
||||
if (hasHardBlocks && hasSoftBlocks) {
|
||||
document.getElementById("bothMessage").hidden = false;
|
||||
else if (hasHardBlocks)
|
||||
} else if (hasHardBlocks) {
|
||||
document.getElementById("hardBlockMessage").hidden = false;
|
||||
else
|
||||
} else {
|
||||
document.getElementById("softBlockMessage").hidden = false;
|
||||
}
|
||||
|
||||
var link = document.getElementById("moreInfo");
|
||||
if (list.length == 1 && list[0].url) {
|
||||
link.setAttribute("href", list[0].url);
|
||||
} else {
|
||||
var url = Services.urlFormatter.formatURLPref("extensions.blocklist.detailsURL");
|
||||
var url = Services.urlFormatter.formatURLPref(
|
||||
"extensions.blocklist.detailsURL"
|
||||
);
|
||||
link.setAttribute("href", url);
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +118,8 @@ function finish(shouldRestartNow) {
|
|||
var list = gArgs.list;
|
||||
var items = document.getElementById("addonList").childNodes;
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (!list[i].blocked)
|
||||
if (!list[i].blocked) {
|
||||
list[i].disable = items[i].querySelector(".disableCheckbox").checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -10,7 +10,7 @@ class MessageBarStackElement extends HTMLElement {
|
|||
constructor() {
|
||||
super();
|
||||
this._observer = null;
|
||||
const shadowRoot = this.attachShadow({mode: "open"});
|
||||
const shadowRoot = this.attachShadow({ mode: "open" });
|
||||
shadowRoot.append(this.constructor.template.content.cloneNode(true));
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,9 @@ class MessageBarStackElement extends HTMLElement {
|
|||
this._observer = new MutationObserver(() => {
|
||||
this._observer.disconnect();
|
||||
this.closeMessageBars();
|
||||
this._observer.observe(this, {childList: true});
|
||||
this._observer.observe(this, { childList: true });
|
||||
});
|
||||
this._observer.observe(this, {childList: true});
|
||||
this._observer.observe(this, { childList: true });
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
|
@ -35,7 +35,7 @@ class MessageBarStackElement extends HTMLElement {
|
|||
}
|
||||
|
||||
closeMessageBars() {
|
||||
const {maxMessageBarCount} = this;
|
||||
const { maxMessageBarCount } = this;
|
||||
if (maxMessageBarCount > 1) {
|
||||
// Remove the older message bars if the stack reached the
|
||||
// maximum number of message bars allowed.
|
||||
|
@ -78,11 +78,12 @@ class MessageBarStackElement extends HTMLElement {
|
|||
class MessageBarElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
const shadowRoot = this.attachShadow({mode: "open"});
|
||||
const shadowRoot = this.attachShadow({ mode: "open" });
|
||||
const content = this.constructor.template.content.cloneNode(true);
|
||||
shadowRoot.append(content);
|
||||
this._closeIcon.addEventListener(
|
||||
"click", () => this.remove(), {once: true});
|
||||
this._closeIcon.addEventListener("click", () => this.remove(), {
|
||||
once: true,
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
class NamedDeckButton extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({mode: "open"});
|
||||
this.attachShadow({ mode: "open" });
|
||||
// Include styles inline to avoid a FOUC.
|
||||
let style = document.createElement("style");
|
||||
style.textContent = `
|
||||
|
@ -72,11 +72,11 @@ class NamedDeckButton extends HTMLElement {
|
|||
|
||||
connectedCallback() {
|
||||
this.setSelectedFromDeck();
|
||||
document.addEventListener("view-changed", this, {capture: true});
|
||||
document.addEventListener("view-changed", this, { capture: true });
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
document.removeEventListener("view-changed", this, {capture: true});
|
||||
document.removeEventListener("view-changed", this, { capture: true });
|
||||
}
|
||||
|
||||
get deckId() {
|
||||
|
@ -95,7 +95,7 @@ class NamedDeckButton extends HTMLElement {
|
|||
if (e.type == "view-changed" && e.target.id == this.deckId) {
|
||||
this.setSelectedFromDeck();
|
||||
} else if (e.type == "click") {
|
||||
let {deck} = this;
|
||||
let { deck } = this;
|
||||
if (deck) {
|
||||
deck.selectedViewName = this.name;
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ class NamedDeckButton extends HTMLElement {
|
|||
}
|
||||
|
||||
setSelectedFromDeck() {
|
||||
let {deck} = this;
|
||||
let { deck } = this;
|
||||
this.selected = deck && deck.selectedViewName == this.name;
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ class NamedDeck extends HTMLElement {
|
|||
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({mode: "open"});
|
||||
this.attachShadow({ mode: "open" });
|
||||
|
||||
// Create a slot for the visible content.
|
||||
let selectedSlot = document.createElement("slot");
|
||||
|
@ -178,7 +178,7 @@ class NamedDeck extends HTMLElement {
|
|||
this.selectedViewName = firstView.getAttribute("name");
|
||||
}
|
||||
}
|
||||
this.observer.observe(this, {childList: true});
|
||||
this.observer.observe(this, { childList: true });
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
|
@ -208,7 +208,7 @@ class NamedDeck extends HTMLElement {
|
|||
* is shown.
|
||||
*/
|
||||
_setSelectedViewAttributes() {
|
||||
let {selectedViewName} = this;
|
||||
let { selectedViewName } = this;
|
||||
for (let view of this.children) {
|
||||
if (view.getAttribute("name") == selectedViewName) {
|
||||
view.slot = "selected";
|
||||
|
|
|
@ -5,32 +5,42 @@
|
|||
"use strict";
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
|
||||
const { AddonManager } = ChromeUtils.import(
|
||||
"resource://gre/modules/AddonManager.jsm"
|
||||
);
|
||||
|
||||
const PREFS = {
|
||||
"pluginFlashBlockingCheckbox":
|
||||
{ pref: "plugins.flashBlock.enabled", invert: false },
|
||||
"pluginEnableProtectedModeCheckbox":
|
||||
{ pref: "dom.ipc.plugins.flash.disable-protected-mode", invert: true },
|
||||
pluginFlashBlockingCheckbox: {
|
||||
pref: "plugins.flashBlock.enabled",
|
||||
invert: false,
|
||||
},
|
||||
pluginEnableProtectedModeCheckbox: {
|
||||
pref: "dom.ipc.plugins.flash.disable-protected-mode",
|
||||
invert: true,
|
||||
},
|
||||
};
|
||||
|
||||
async function renderPluginMetadata(id) {
|
||||
let plugin = await AddonManager.getAddonByID(id);
|
||||
if (!plugin)
|
||||
if (!plugin) {
|
||||
return;
|
||||
}
|
||||
|
||||
let libLabel = document.getElementById("pluginLibraries");
|
||||
libLabel.textContent = plugin.pluginLibraries.join(", ");
|
||||
|
||||
let typeLabel = document.getElementById("pluginMimeTypes"), types = [];
|
||||
let typeLabel = document.getElementById("pluginMimeTypes"),
|
||||
types = [];
|
||||
for (let type of plugin.pluginMimeTypes) {
|
||||
let extras = [type.description.trim(), type.suffixes].
|
||||
filter(x => x).join(": ");
|
||||
let extras = [type.description.trim(), type.suffixes]
|
||||
.filter(x => x)
|
||||
.join(": ");
|
||||
types.push(type.type + (extras ? " (" + extras + ")" : ""));
|
||||
}
|
||||
typeLabel.textContent = types.join(",\n");
|
||||
let showProtectedModePref = canDisableFlashProtectedMode(plugin);
|
||||
document.getElementById("pluginEnableProtectedMode")
|
||||
document
|
||||
.getElementById("pluginEnableProtectedMode")
|
||||
.setAttribute("collapsed", showProtectedModePref ? "" : "true");
|
||||
}
|
||||
|
||||
|
@ -48,8 +58,10 @@ function init() {
|
|||
var prefVal = Services.prefs.getBoolPref(PREFS[id].pref);
|
||||
checkbox.checked = PREFS[id].invert ? !prefVal : prefVal;
|
||||
checkbox.addEventListener("command", () => {
|
||||
Services.prefs.setBoolPref(PREFS[id].pref,
|
||||
PREFS[id].invert ? !checkbox.checked : checkbox.checked);
|
||||
Services.prefs.setBoolPref(
|
||||
PREFS[id].pref,
|
||||
PREFS[id].invert ? !checkbox.checked : checkbox.checked
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AddonManager: "resource://gre/modules/AddonManager.jsm",
|
||||
|
@ -24,14 +26,18 @@ let shortcutKeyMap = new Map();
|
|||
const templates = {};
|
||||
|
||||
function loadTemplates() {
|
||||
if (templatesLoaded) return;
|
||||
if (templatesLoaded) {
|
||||
return;
|
||||
}
|
||||
templatesLoaded = true;
|
||||
|
||||
templates.card = document.getElementById("card-template");
|
||||
templates.row = document.getElementById("shortcut-row-template");
|
||||
templates.noAddons = document.getElementById("shortcuts-no-addons");
|
||||
templates.expandRow = document.getElementById("expand-row-template");
|
||||
templates.noShortcutAddons = document.getElementById("shortcuts-no-commands-template");
|
||||
templates.noShortcutAddons = document.getElementById(
|
||||
"shortcuts-no-commands-template"
|
||||
);
|
||||
}
|
||||
|
||||
function extensionForAddonId(id) {
|
||||
|
@ -44,7 +50,7 @@ let builtInNames = new Map([
|
|||
["_execute_page_action", "shortcuts-pageAction"],
|
||||
["_execute_sidebar_action", "shortcuts-sidebarAction"],
|
||||
]);
|
||||
let getCommandDescriptionId = (command) => {
|
||||
let getCommandDescriptionId = command => {
|
||||
if (!command.description && builtInNames.has(command.name)) {
|
||||
return builtInNames.get(command.name);
|
||||
}
|
||||
|
@ -52,18 +58,75 @@ let getCommandDescriptionId = (command) => {
|
|||
};
|
||||
|
||||
const _functionKeys = [
|
||||
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
|
||||
"F1",
|
||||
"F2",
|
||||
"F3",
|
||||
"F4",
|
||||
"F5",
|
||||
"F6",
|
||||
"F7",
|
||||
"F8",
|
||||
"F9",
|
||||
"F10",
|
||||
"F11",
|
||||
"F12",
|
||||
];
|
||||
const functionKeys = new Set(_functionKeys);
|
||||
const validKeys = new Set([
|
||||
"Home", "End", "PageUp", "PageDown", "Insert", "Delete",
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
"Home",
|
||||
"End",
|
||||
"PageUp",
|
||||
"PageDown",
|
||||
"Insert",
|
||||
"Delete",
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
..._functionKeys,
|
||||
"MediaNextTrack", "MediaPlayPause", "MediaPrevTrack", "MediaStop",
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
|
||||
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||
"Up", "Down", "Left", "Right",
|
||||
"Comma", "Period", "Space",
|
||||
"MediaNextTrack",
|
||||
"MediaPlayPause",
|
||||
"MediaPrevTrack",
|
||||
"MediaStop",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z",
|
||||
"Up",
|
||||
"Down",
|
||||
"Left",
|
||||
"Right",
|
||||
"Comma",
|
||||
"Period",
|
||||
"Space",
|
||||
]);
|
||||
|
||||
/**
|
||||
|
@ -157,18 +220,25 @@ function getShortcutValue(shortcut) {
|
|||
let error;
|
||||
|
||||
function setError(input, messageId, args) {
|
||||
if (!error) error = document.querySelector(".error-message");
|
||||
if (!error) {
|
||||
error = document.querySelector(".error-message");
|
||||
}
|
||||
|
||||
let {x, y, height} = input.getBoundingClientRect();
|
||||
let { x, y, height } = input.getBoundingClientRect();
|
||||
error.style.top = `${y + window.scrollY + height - 5}px`;
|
||||
error.style.left = `${x}px`;
|
||||
document.l10n.setAttributes(
|
||||
error.querySelector(".error-message-label"), messageId, args);
|
||||
error.querySelector(".error-message-label"),
|
||||
messageId,
|
||||
args
|
||||
);
|
||||
error.style.visibility = "visible";
|
||||
}
|
||||
|
||||
function inputBlurred(e) {
|
||||
if (!error) error = document.querySelector(".error-message");
|
||||
if (!error) {
|
||||
error = document.querySelector(".error-message");
|
||||
}
|
||||
|
||||
error.style.visibility = "hidden";
|
||||
e.target.value = getShortcutValue(e.target.getAttribute("shortcut"));
|
||||
|
@ -272,7 +342,9 @@ function onShortcutChange(e) {
|
|||
|
||||
// Check if shortcut is already assigned.
|
||||
if (shortcutKeyMap.has(shortcutString)) {
|
||||
setError(input, "shortcuts-exists", {addon: getAddonName(shortcutString)});
|
||||
setError(input, "shortcuts-exists", {
|
||||
addon: getAddonName(shortcutString),
|
||||
});
|
||||
break;
|
||||
} else {
|
||||
// Update the shortcut if it isn't reserved or assigned.
|
||||
|
@ -292,10 +364,11 @@ function onShortcutChange(e) {
|
|||
input.blur();
|
||||
break;
|
||||
case ShortcutUtils.MODIFIER_REQUIRED:
|
||||
if (AppConstants.platform == "macosx")
|
||||
if (AppConstants.platform == "macosx") {
|
||||
setError(input, "shortcuts-modifier-mac");
|
||||
else
|
||||
} else {
|
||||
setError(input, "shortcuts-modifier-other");
|
||||
}
|
||||
break;
|
||||
case ShortcutUtils.INVALID_COMBINATION:
|
||||
setError(input, "shortcuts-invalid");
|
||||
|
@ -326,11 +399,13 @@ async function renderAddons(addons) {
|
|||
let extension = extensionForAddonId(addon.id);
|
||||
|
||||
// Skip this extension if it isn't a webextension.
|
||||
if (!extension) continue;
|
||||
if (!extension) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (extension.shortcuts) {
|
||||
let card = document.importNode(
|
||||
templates.card.content, true).firstElementChild;
|
||||
let card = document.importNode(templates.card.content, true)
|
||||
.firstElementChild;
|
||||
let icon = AddonManager.getPreferredIconURL(addon, 24, window);
|
||||
card.setAttribute("addon-id", addon.id);
|
||||
card.setAttribute("addon-name", addon.name);
|
||||
|
@ -342,21 +417,24 @@ async function renderAddons(addons) {
|
|||
// Sort the commands so the ones with shortcuts are at the top.
|
||||
commands.sort((a, b) => {
|
||||
// Boolean compare the shortcuts to see if they're both set or unset.
|
||||
if (!a.shortcut == !b.shortcut)
|
||||
if (!a.shortcut == !b.shortcut) {
|
||||
return 0;
|
||||
if (a.shortcut)
|
||||
}
|
||||
if (a.shortcut) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
|
||||
let {limit, allowOver} = COLLAPSE_OPTIONS;
|
||||
let { limit, allowOver } = COLLAPSE_OPTIONS;
|
||||
let willHideCommands = commands.length > limit + allowOver;
|
||||
let firstHiddenInput;
|
||||
|
||||
for (let i = 0; i < commands.length; i++) {
|
||||
let command = commands[i];
|
||||
|
||||
let row = document.importNode(templates.row.content, true).firstElementChild;
|
||||
let row = document.importNode(templates.row.content, true)
|
||||
.firstElementChild;
|
||||
|
||||
if (willHideCommands && i >= limit) {
|
||||
row.setAttribute("hide-before-expand", "true");
|
||||
|
@ -391,14 +469,14 @@ async function renderAddons(addons) {
|
|||
let row = document.importNode(templates.expandRow.content, true);
|
||||
let button = row.querySelector(".expand-button");
|
||||
let numberToShow = commands.length - limit;
|
||||
let setLabel = (type) => {
|
||||
let setLabel = type => {
|
||||
document.l10n.setAttributes(button, `shortcuts-card-${type}-button`, {
|
||||
numberToShow,
|
||||
});
|
||||
};
|
||||
|
||||
setLabel("expand");
|
||||
button.addEventListener("click", (event) => {
|
||||
button.addEventListener("click", event => {
|
||||
let expanded = card.hasAttribute("expanded");
|
||||
if (expanded) {
|
||||
card.removeAttribute("expanded");
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AddonManager: "resource://gre/modules/AddonManager.jsm",
|
||||
|
@ -38,30 +40,33 @@ XPCOMUtils.defineLazyGetter(this, "PLATFORM", () => {
|
|||
return platform;
|
||||
});
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "AddonRepository" ];
|
||||
var EXPORTED_SYMBOLS = ["AddonRepository"];
|
||||
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
|
||||
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
|
||||
const PREF_GETADDONS_CACHE_TYPES = "extensions.getAddons.cache.types";
|
||||
const PREF_GETADDONS_CACHE_ID_ENABLED = "extensions.%ID%.getAddons.cache.enabled";
|
||||
const PREF_GETADDONS_BROWSEADDONS = "extensions.getAddons.browseAddons";
|
||||
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
|
||||
const PREF_COMPAT_OVERRIDES = "extensions.getAddons.compatOverides.url";
|
||||
const PREF_GETADDONS_BROWSESEARCHRESULTS = "extensions.getAddons.search.browseURL";
|
||||
const PREF_GETADDONS_DB_SCHEMA = "extensions.getAddons.databaseSchema";
|
||||
const PREF_GET_LANGPACKS = "extensions.getAddons.langpacks.url";
|
||||
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
|
||||
const PREF_GETADDONS_CACHE_TYPES = "extensions.getAddons.cache.types";
|
||||
const PREF_GETADDONS_CACHE_ID_ENABLED =
|
||||
"extensions.%ID%.getAddons.cache.enabled";
|
||||
const PREF_GETADDONS_BROWSEADDONS = "extensions.getAddons.browseAddons";
|
||||
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
|
||||
const PREF_COMPAT_OVERRIDES = "extensions.getAddons.compatOverides.url";
|
||||
const PREF_GETADDONS_BROWSESEARCHRESULTS =
|
||||
"extensions.getAddons.search.browseURL";
|
||||
const PREF_GETADDONS_DB_SCHEMA = "extensions.getAddons.databaseSchema";
|
||||
const PREF_GET_LANGPACKS = "extensions.getAddons.langpacks.url";
|
||||
|
||||
const PREF_METADATA_LASTUPDATE = "extensions.getAddons.cache.lastUpdate";
|
||||
const PREF_METADATA_UPDATETHRESHOLD_SEC = "extensions.getAddons.cache.updateThreshold";
|
||||
const PREF_METADATA_LASTUPDATE = "extensions.getAddons.cache.lastUpdate";
|
||||
const PREF_METADATA_UPDATETHRESHOLD_SEC =
|
||||
"extensions.getAddons.cache.updateThreshold";
|
||||
const DEFAULT_METADATA_UPDATETHRESHOLD_SEC = 172800; // two days
|
||||
|
||||
const DEFAULT_CACHE_TYPES = "extension,theme,locale,dictionary";
|
||||
|
||||
const FILE_DATABASE = "addons.json";
|
||||
const DB_SCHEMA = 5;
|
||||
const DB_MIN_JSON_SCHEMA = 5;
|
||||
const DB_BATCH_TIMEOUT_MS = 50;
|
||||
const FILE_DATABASE = "addons.json";
|
||||
const DB_SCHEMA = 5;
|
||||
const DB_MIN_JSON_SCHEMA = 5;
|
||||
const DB_BATCH_TIMEOUT_MS = 50;
|
||||
|
||||
const BLANK_DB = function() {
|
||||
return {
|
||||
|
@ -71,9 +76,9 @@ const BLANK_DB = function() {
|
|||
};
|
||||
};
|
||||
|
||||
const TOOLKIT_ID = "toolkit@mozilla.org";
|
||||
const TOOLKIT_ID = "toolkit@mozilla.org";
|
||||
|
||||
const {Log} = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const LOGGER_ID = "addons.repository";
|
||||
|
||||
// Create a new logger for use by the Addons Repository
|
||||
|
@ -81,25 +86,30 @@ const LOGGER_ID = "addons.repository";
|
|||
var logger = Log.repository.getLogger(LOGGER_ID);
|
||||
|
||||
function convertHTMLToPlainText(html) {
|
||||
if (!html)
|
||||
if (!html) {
|
||||
return html;
|
||||
var converter = Cc["@mozilla.org/widget/htmlformatconverter;1"].
|
||||
createInstance(Ci.nsIFormatConverter);
|
||||
}
|
||||
var converter = Cc[
|
||||
"@mozilla.org/widget/htmlformatconverter;1"
|
||||
].createInstance(Ci.nsIFormatConverter);
|
||||
|
||||
var input = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
var input = Cc["@mozilla.org/supports-string;1"].createInstance(
|
||||
Ci.nsISupportsString
|
||||
);
|
||||
input.data = html.replace(/\n/g, "<br>");
|
||||
|
||||
var output = {};
|
||||
converter.convert("text/html", input, "text/unicode", output);
|
||||
|
||||
if (output.value instanceof Ci.nsISupportsString)
|
||||
if (output.value instanceof Ci.nsISupportsString) {
|
||||
return output.value.data.replace(/\r\n/g, "\n");
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
async function getAddonsToCache(aIds) {
|
||||
let types = Preferences.get(PREF_GETADDONS_CACHE_TYPES) || DEFAULT_CACHE_TYPES;
|
||||
let types =
|
||||
Preferences.get(PREF_GETADDONS_CACHE_TYPES) || DEFAULT_CACHE_TYPES;
|
||||
|
||||
types = types.split(",");
|
||||
|
||||
|
@ -109,8 +119,9 @@ async function getAddonsToCache(aIds) {
|
|||
for (let [i, addon] of addons.entries()) {
|
||||
var preference = PREF_GETADDONS_CACHE_ID_ENABLED.replace("%ID%", aIds[i]);
|
||||
// If the preference doesn't exist caching is enabled by default
|
||||
if (!Preferences.get(preference, true))
|
||||
if (!Preferences.get(preference, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The add-ons manager may not know about this ID yet if it is a pending
|
||||
// install. In that case we'll just cache it regardless
|
||||
|
@ -190,7 +201,7 @@ AddonSearchResult.prototype = {
|
|||
return this.icons && this.icons[32];
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* The URLs of the add-on's icons, as an object with icon size as key
|
||||
*/
|
||||
icons: null,
|
||||
|
@ -255,9 +266,9 @@ AddonSearchResult.prototype = {
|
|||
|
||||
for (let property of Object.keys(this)) {
|
||||
let value = this[property];
|
||||
if (property.startsWith("_") ||
|
||||
typeof(value) === "function")
|
||||
if (property.startsWith("_") || typeof value === "function") {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
switch (property) {
|
||||
|
@ -279,8 +290,9 @@ AddonSearchResult.prototype = {
|
|||
|
||||
for (let property of Object.keys(this._unsupportedProperties)) {
|
||||
let value = this._unsupportedProperties[property];
|
||||
if (!property.startsWith("_"))
|
||||
if (!property.startsWith("_")) {
|
||||
json[property] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
|
@ -305,7 +317,7 @@ var AddonRepository = {
|
|||
*/
|
||||
get homepageURL() {
|
||||
let url = this._formatURLPref(PREF_GETADDONS_BROWSEADDONS, {});
|
||||
return (url != null) ? url : "about:blank";
|
||||
return url != null ? url : "about:blank";
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -320,7 +332,7 @@ var AddonRepository = {
|
|||
let url = this._formatURLPref(PREF_GETADDONS_BROWSESEARCHRESULTS, {
|
||||
TERMS: aSearchTerms,
|
||||
});
|
||||
return (url != null) ? url : "about:blank";
|
||||
return url != null ? url : "about:blank";
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -346,8 +358,11 @@ var AddonRepository = {
|
|||
},
|
||||
|
||||
isMetadataStale() {
|
||||
let threshold = Services.prefs.getIntPref(PREF_METADATA_UPDATETHRESHOLD_SEC, DEFAULT_METADATA_UPDATETHRESHOLD_SEC);
|
||||
return (this.metadataAge() > threshold);
|
||||
let threshold = Services.prefs.getIntPref(
|
||||
PREF_METADATA_UPDATETHRESHOLD_SEC,
|
||||
DEFAULT_METADATA_UPDATETHRESHOLD_SEC
|
||||
);
|
||||
return this.metadataAge() > threshold;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -421,7 +436,8 @@ var AddonRepository = {
|
|||
*/
|
||||
_clearCache() {
|
||||
return AddonDatabase.delete().then(() =>
|
||||
AddonManagerPrivate.updateAddonRepositoryData());
|
||||
AddonManagerPrivate.updateAddonRepositoryData()
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -442,7 +458,7 @@ var AddonRepository = {
|
|||
* the API call(s).
|
||||
*/
|
||||
_fetchPaged(ids, pref, handler) {
|
||||
let startURL = this._formatURLPref(pref, {IDS: ids.join(",")});
|
||||
let startURL = this._formatURLPref(pref, { IDS: ids.join(",") });
|
||||
let results = [];
|
||||
let idCheck = ids.map(id => {
|
||||
if (id.startsWith("rta:")) {
|
||||
|
@ -451,9 +467,9 @@ var AddonRepository = {
|
|||
return id;
|
||||
});
|
||||
|
||||
const fetchNextPage = (url) => {
|
||||
const fetchNextPage = url => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let request = new ServiceRequest({mozAnon: true});
|
||||
let request = new ServiceRequest({ mozAnon: true });
|
||||
request.mozBackgroundRequest = true;
|
||||
request.open("GET", url, true);
|
||||
request.responseType = "json";
|
||||
|
@ -472,7 +488,9 @@ var AddonRepository = {
|
|||
}
|
||||
|
||||
try {
|
||||
let newResults = handler(response.results).filter(e => idCheck.includes(e.id));
|
||||
let newResults = handler(response.results).filter(e =>
|
||||
idCheck.includes(e.id)
|
||||
);
|
||||
results.push(...newResults);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
|
@ -500,9 +518,9 @@ var AddonRepository = {
|
|||
* @returns {array<AddonSearchResult>}
|
||||
*/
|
||||
async getAddonsByIDs(aIDs) {
|
||||
return this._fetchPaged(aIDs, PREF_GETADDONS_BYIDS,
|
||||
results => results.map(
|
||||
entry => this._parseAddon(entry)));
|
||||
return this._fetchPaged(aIDs, PREF_GETADDONS_BYIDS, results =>
|
||||
results.map(entry => this._parseAddon(entry))
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -521,17 +539,23 @@ var AddonRepository = {
|
|||
async _getFullData(aIDs) {
|
||||
let metadataPromise = this.getAddonsByIDs(aIDs, false);
|
||||
|
||||
let overridesPromise = this._fetchPaged(aIDs, PREF_COMPAT_OVERRIDES,
|
||||
results => results.map(
|
||||
entry => this._parseCompatEntry(entry)));
|
||||
let addons = [], overrides = [];
|
||||
let overridesPromise = this._fetchPaged(
|
||||
aIDs,
|
||||
PREF_COMPAT_OVERRIDES,
|
||||
results => results.map(entry => this._parseCompatEntry(entry))
|
||||
);
|
||||
let addons = [],
|
||||
overrides = [];
|
||||
try {
|
||||
[addons, overrides] = await Promise.all([metadataPromise, overridesPromise]);
|
||||
[addons, overrides] = await Promise.all([
|
||||
metadataPromise,
|
||||
overridesPromise,
|
||||
]);
|
||||
} catch (err) {
|
||||
logger.error(`Error in addon metadata check: ${err.message}`);
|
||||
}
|
||||
|
||||
return {addons, overrides};
|
||||
return { addons, overrides };
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -542,7 +566,9 @@ var AddonRepository = {
|
|||
* The array of add-on ids to add to the cache
|
||||
*/
|
||||
async cacheAddons(aIds) {
|
||||
logger.debug("cacheAddons: enabled " + this.cacheEnabled + " IDs " + aIds.toSource());
|
||||
logger.debug(
|
||||
"cacheAddons: enabled " + this.cacheEnabled + " IDs " + aIds.toSource()
|
||||
);
|
||||
if (!this.cacheEnabled) {
|
||||
return [];
|
||||
}
|
||||
|
@ -554,7 +580,7 @@ var AddonRepository = {
|
|||
return [];
|
||||
}
|
||||
|
||||
let {addons, overrides} = await this._getFullData(ids);
|
||||
let { addons, overrides } = await this._getFullData(ids);
|
||||
await AddonDatabase.update(addons, overrides);
|
||||
|
||||
return Array.from(addons.values());
|
||||
|
@ -587,7 +613,7 @@ var AddonRepository = {
|
|||
return;
|
||||
}
|
||||
|
||||
let {addons, overrides} = await this._getFullData(addonsToCache);
|
||||
let { addons, overrides } = await this._getFullData(addonsToCache);
|
||||
|
||||
AddonDatabase.repopulate(addons, overrides);
|
||||
|
||||
|
@ -643,7 +669,9 @@ var AddonRepository = {
|
|||
}
|
||||
|
||||
if (Array.isArray(aEntry.authors)) {
|
||||
let authors = aEntry.authors.map(author => new AddonManagerPrivate.AddonAuthor(author.name, author.url));
|
||||
let authors = aEntry.authors.map(
|
||||
author => new AddonManagerPrivate.AddonAuthor(author.name, author.url)
|
||||
);
|
||||
if (authors.length > 0) {
|
||||
addon.creator = authors[0];
|
||||
addon.developers = authors.slice(1);
|
||||
|
@ -652,16 +680,19 @@ var AddonRepository = {
|
|||
|
||||
if (typeof aEntry.previews == "object") {
|
||||
addon.screenshots = aEntry.previews.map(shot => {
|
||||
let safeSize = orig => Array.isArray(orig) && orig.length >= 2 ? orig : [null, null];
|
||||
let safeSize = orig =>
|
||||
Array.isArray(orig) && orig.length >= 2 ? orig : [null, null];
|
||||
let imageSize = safeSize(shot.image_size);
|
||||
let thumbSize = safeSize(shot.thumbnail_size);
|
||||
return new AddonManagerPrivate.AddonScreenshot(shot.image_url,
|
||||
imageSize[0],
|
||||
imageSize[1],
|
||||
shot.thumbnail_url,
|
||||
thumbSize[0],
|
||||
thumbSize[1],
|
||||
shot.caption);
|
||||
return new AddonManagerPrivate.AddonScreenshot(
|
||||
shot.image_url,
|
||||
imageSize[0],
|
||||
imageSize[1],
|
||||
shot.thumbnail_url,
|
||||
thumbSize[0],
|
||||
thumbSize[1],
|
||||
shot.caption
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -705,7 +736,9 @@ var AddonRepository = {
|
|||
return null;
|
||||
}
|
||||
|
||||
let override = new AddonManagerPrivate.AddonCompatibilityOverride("incompatible");
|
||||
let override = new AddonManagerPrivate.AddonCompatibilityOverride(
|
||||
"incompatible"
|
||||
);
|
||||
override.minVersion = range.addon_min_version;
|
||||
override.maxVersion = range.addon_max_version;
|
||||
|
||||
|
@ -726,7 +759,9 @@ var AddonRepository = {
|
|||
}
|
||||
|
||||
if (!override.appID) {
|
||||
logger.debug("Compatibility override is missing a valid application range.");
|
||||
logger.debug(
|
||||
"Compatibility override is missing a valid application range."
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -748,8 +783,9 @@ var AddonRepository = {
|
|||
}
|
||||
|
||||
url = url.replace(/%([A-Z_]+)%/g, function(aMatch, aKey) {
|
||||
return (aKey in aSubstitutions) ? encodeURIComponent(aSubstitutions[aKey])
|
||||
: aMatch;
|
||||
return aKey in aSubstitutions
|
||||
? encodeURIComponent(aSubstitutions[aKey])
|
||||
: aMatch;
|
||||
});
|
||||
|
||||
return Services.urlFormatter.formatURL(url);
|
||||
|
@ -757,21 +793,26 @@ var AddonRepository = {
|
|||
|
||||
// Find a AddonCompatibilityOverride that matches a given aAddonVersion and
|
||||
// application/platform version.
|
||||
findMatchingCompatOverride(aAddonVersion,
|
||||
aCompatOverrides,
|
||||
aAppVersion,
|
||||
aPlatformVersion) {
|
||||
findMatchingCompatOverride(
|
||||
aAddonVersion,
|
||||
aCompatOverrides,
|
||||
aAppVersion,
|
||||
aPlatformVersion
|
||||
) {
|
||||
for (let override of aCompatOverrides) {
|
||||
let appVersion = null;
|
||||
if (override.appID == TOOLKIT_ID)
|
||||
if (override.appID == TOOLKIT_ID) {
|
||||
appVersion = aPlatformVersion || Services.appinfo.platformVersion;
|
||||
else
|
||||
} else {
|
||||
appVersion = aAppVersion || Services.appinfo.version;
|
||||
}
|
||||
|
||||
if (Services.vc.compare(override.minVersion, aAddonVersion) <= 0 &&
|
||||
Services.vc.compare(aAddonVersion, override.maxVersion) <= 0 &&
|
||||
Services.vc.compare(override.appMinVersion, appVersion) <= 0 &&
|
||||
Services.vc.compare(appVersion, override.appMaxVersion) <= 0) {
|
||||
if (
|
||||
Services.vc.compare(override.minVersion, aAddonVersion) <= 0 &&
|
||||
Services.vc.compare(aAddonVersion, override.maxVersion) <= 0 &&
|
||||
Services.vc.compare(override.appMinVersion, appVersion) <= 0 &&
|
||||
Services.vc.compare(appVersion, override.appMaxVersion) <= 0
|
||||
) {
|
||||
return override;
|
||||
}
|
||||
}
|
||||
|
@ -787,7 +828,7 @@ var AddonRepository = {
|
|||
// http://addons-server.readthedocs.io/en/latest/topics/api/addons.html#language-tools
|
||||
let url = this._formatURLPref(PREF_GET_LANGPACKS);
|
||||
|
||||
let response = await fetch(url, {credentials: "omit"});
|
||||
let response = await fetch(url, { credentials: "omit" });
|
||||
if (!response.ok) {
|
||||
throw new Error("fetching available language packs failed");
|
||||
}
|
||||
|
@ -796,13 +837,18 @@ var AddonRepository = {
|
|||
|
||||
let result = [];
|
||||
for (let entry of data.results) {
|
||||
if (!entry.current_compatible_version ||
|
||||
!entry.current_compatible_version.files) {
|
||||
continue;
|
||||
if (
|
||||
!entry.current_compatible_version ||
|
||||
!entry.current_compatible_version.files
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let file of entry.current_compatible_version.files) {
|
||||
if (file.platform == "all" || file.platform == Services.appinfo.OS.toLowerCase()) {
|
||||
if (
|
||||
file.platform == "all" ||
|
||||
file.platform == Services.appinfo.OS.toLowerCase()
|
||||
) {
|
||||
result.push({
|
||||
target_locale: entry.target_locale,
|
||||
url: file.url,
|
||||
|
@ -840,66 +886,69 @@ var AddonDatabase = {
|
|||
openConnection() {
|
||||
if (!this.connectionPromise) {
|
||||
this.connectionPromise = (async () => {
|
||||
let inputDB, schema;
|
||||
let inputDB, schema;
|
||||
|
||||
try {
|
||||
let data = await OS.File.read(this.jsonFile, { encoding: "utf-8"});
|
||||
inputDB = JSON.parse(data);
|
||||
try {
|
||||
let data = await OS.File.read(this.jsonFile, { encoding: "utf-8" });
|
||||
inputDB = JSON.parse(data);
|
||||
|
||||
if (!inputDB.hasOwnProperty("addons") ||
|
||||
!Array.isArray(inputDB.addons)) {
|
||||
throw new Error("No addons array.");
|
||||
}
|
||||
if (
|
||||
!inputDB.hasOwnProperty("addons") ||
|
||||
!Array.isArray(inputDB.addons)
|
||||
) {
|
||||
throw new Error("No addons array.");
|
||||
}
|
||||
|
||||
if (!inputDB.hasOwnProperty("schema")) {
|
||||
throw new Error("No schema specified.");
|
||||
}
|
||||
if (!inputDB.hasOwnProperty("schema")) {
|
||||
throw new Error("No schema specified.");
|
||||
}
|
||||
|
||||
schema = parseInt(inputDB.schema, 10);
|
||||
schema = parseInt(inputDB.schema, 10);
|
||||
|
||||
if (!Number.isInteger(schema) ||
|
||||
schema < DB_MIN_JSON_SCHEMA) {
|
||||
throw new Error("Invalid schema value.");
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof OS.File.Error && e.becauseNoSuchFile) {
|
||||
logger.debug("No " + FILE_DATABASE + " found.");
|
||||
} else {
|
||||
logger.error(`Malformed ${FILE_DATABASE}: ${e} - resetting to empty`);
|
||||
}
|
||||
if (!Number.isInteger(schema) || schema < DB_MIN_JSON_SCHEMA) {
|
||||
throw new Error("Invalid schema value.");
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof OS.File.Error && e.becauseNoSuchFile) {
|
||||
logger.debug("No " + FILE_DATABASE + " found.");
|
||||
} else {
|
||||
logger.error(
|
||||
`Malformed ${FILE_DATABASE}: ${e} - resetting to empty`
|
||||
);
|
||||
}
|
||||
|
||||
// Create a blank addons.json file
|
||||
this.save();
|
||||
// Create a blank addons.json file
|
||||
this.save();
|
||||
|
||||
Services.prefs.setIntPref(PREF_GETADDONS_DB_SCHEMA, DB_SCHEMA);
|
||||
this._loaded = true;
|
||||
return this.DB;
|
||||
}
|
||||
Services.prefs.setIntPref(PREF_GETADDONS_DB_SCHEMA, DB_SCHEMA);
|
||||
this._loaded = true;
|
||||
return this.DB;
|
||||
}
|
||||
|
||||
Services.prefs.setIntPref(PREF_GETADDONS_DB_SCHEMA, DB_SCHEMA);
|
||||
Services.prefs.setIntPref(PREF_GETADDONS_DB_SCHEMA, DB_SCHEMA);
|
||||
|
||||
// Convert the addon and compat override objects as necessary
|
||||
// and store them in our in-memory copy of the database.
|
||||
for (let addon of inputDB.addons) {
|
||||
let id = addon.id;
|
||||
// Convert the addon and compat override objects as necessary
|
||||
// and store them in our in-memory copy of the database.
|
||||
for (let addon of inputDB.addons) {
|
||||
let id = addon.id;
|
||||
|
||||
let entry = this._parseAddon(addon);
|
||||
this.DB.addons.set(id, entry);
|
||||
let entry = this._parseAddon(addon);
|
||||
this.DB.addons.set(id, entry);
|
||||
|
||||
if (entry.compatibilityOverrides) {
|
||||
this.DB.compatOverrides.set(id, entry.compatibilityOverrides);
|
||||
}
|
||||
}
|
||||
if (entry.compatibilityOverrides) {
|
||||
this.DB.compatOverrides.set(id, entry.compatibilityOverrides);
|
||||
}
|
||||
}
|
||||
|
||||
if (inputDB.compatOverrides) {
|
||||
for (let entry of inputDB.compatOverrides) {
|
||||
this.DB.compatOverrides.set(entry.id, entry.compatRanges);
|
||||
}
|
||||
}
|
||||
if (inputDB.compatOverrides) {
|
||||
for (let entry of inputDB.compatOverrides) {
|
||||
this.DB.compatOverrides.set(entry.id, entry.compatRanges);
|
||||
}
|
||||
}
|
||||
|
||||
this._loaded = true;
|
||||
return this.DB;
|
||||
})();
|
||||
return this.DB;
|
||||
})();
|
||||
}
|
||||
|
||||
return this.connectionPromise;
|
||||
|
@ -949,9 +998,13 @@ var AddonDatabase = {
|
|||
// shutdown(true) never rejects
|
||||
this._deleting = this.shutdown(true)
|
||||
.then(() => OS.File.remove(this.jsonFile, {}))
|
||||
.catch(error => logger.error("Unable to delete Addon Repository file " +
|
||||
this.jsonFile, error))
|
||||
.then(() => this._deleting = null)
|
||||
.catch(error =>
|
||||
logger.error(
|
||||
"Unable to delete Addon Repository file " + this.jsonFile,
|
||||
error
|
||||
)
|
||||
)
|
||||
.then(() => (this._deleting = null))
|
||||
.then(aCallback);
|
||||
|
||||
return this._deleting;
|
||||
|
@ -965,20 +1018,26 @@ var AddonDatabase = {
|
|||
};
|
||||
|
||||
for (let [id, overrides] of this.DB.compatOverrides.entries()) {
|
||||
json.compatOverrides.push({id, compatRanges: overrides});
|
||||
json.compatOverrides.push({ id, compatRanges: overrides });
|
||||
}
|
||||
|
||||
await OS.File.writeAtomic(this.jsonFile, JSON.stringify(json),
|
||||
{tmpPath: `${this.jsonFile}.tmp`});
|
||||
await OS.File.writeAtomic(this.jsonFile, JSON.stringify(json), {
|
||||
tmpPath: `${this.jsonFile}.tmp`,
|
||||
});
|
||||
},
|
||||
|
||||
save() {
|
||||
if (!this._saveTask) {
|
||||
this._saveTask = new DeferredTask(() => this._saveNow(), DB_BATCH_TIMEOUT_MS);
|
||||
this._saveTask = new DeferredTask(
|
||||
() => this._saveNow(),
|
||||
DB_BATCH_TIMEOUT_MS
|
||||
);
|
||||
|
||||
if (!this._blockerAdded) {
|
||||
AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
"Flush AddonRepository", () => this.flush());
|
||||
"Flush AddonRepository",
|
||||
() => this.flush()
|
||||
);
|
||||
this._blockerAdded = true;
|
||||
}
|
||||
}
|
||||
|
@ -1041,7 +1100,9 @@ var AddonDatabase = {
|
|||
this._update(aAddons, aCompatOverrides);
|
||||
|
||||
let now = Math.round(Date.now() / 1000);
|
||||
logger.debug("Cache repopulated, setting " + PREF_METADATA_LASTUPDATE + " to " + now);
|
||||
logger.debug(
|
||||
"Cache repopulated, setting " + PREF_METADATA_LASTUPDATE + " to " + now
|
||||
);
|
||||
Services.prefs.setIntPref(PREF_METADATA_LASTUPDATE, now);
|
||||
},
|
||||
|
||||
|
@ -1090,19 +1151,24 @@ var AddonDatabase = {
|
|||
* @return Returns an AddonSearchResult object.
|
||||
*/
|
||||
_parseAddon(aObj) {
|
||||
if (aObj instanceof AddonSearchResult)
|
||||
if (aObj instanceof AddonSearchResult) {
|
||||
return aObj;
|
||||
}
|
||||
|
||||
let id = aObj.id;
|
||||
if (!aObj.id)
|
||||
if (!aObj.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let addon = new AddonSearchResult(id);
|
||||
|
||||
for (let expectedProperty of Object.keys(AddonSearchResult.prototype)) {
|
||||
if (!(expectedProperty in aObj) ||
|
||||
typeof(aObj[expectedProperty]) === "function")
|
||||
if (
|
||||
!(expectedProperty in aObj) ||
|
||||
typeof aObj[expectedProperty] === "function"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = aObj[expectedProperty];
|
||||
|
||||
|
@ -1113,9 +1179,7 @@ var AddonDatabase = {
|
|||
break;
|
||||
|
||||
case "creator":
|
||||
addon.creator = value
|
||||
? this._makeDeveloper(value)
|
||||
: null;
|
||||
addon.creator = value ? this._makeDeveloper(value) : null;
|
||||
break;
|
||||
|
||||
case "updateDate":
|
||||
|
@ -1123,21 +1187,27 @@ var AddonDatabase = {
|
|||
break;
|
||||
|
||||
case "developers":
|
||||
if (!addon.developers) addon.developers = [];
|
||||
if (!addon.developers) {
|
||||
addon.developers = [];
|
||||
}
|
||||
for (let developer of value) {
|
||||
addon.developers.push(this._makeDeveloper(developer));
|
||||
}
|
||||
break;
|
||||
|
||||
case "screenshots":
|
||||
if (!addon.screenshots) addon.screenshots = [];
|
||||
if (!addon.screenshots) {
|
||||
addon.screenshots = [];
|
||||
}
|
||||
for (let screenshot of value) {
|
||||
addon.screenshots.push(this._makeScreenshot(screenshot));
|
||||
}
|
||||
break;
|
||||
|
||||
case "icons":
|
||||
if (!addon.icons) addon.icons = {};
|
||||
if (!addon.icons) {
|
||||
addon.icons = {};
|
||||
}
|
||||
for (let size of Object.keys(aObj.icons)) {
|
||||
addon.icons[size] = aObj.icons[size];
|
||||
}
|
||||
|
@ -1150,7 +1220,9 @@ var AddonDatabase = {
|
|||
addon[expectedProperty] = value;
|
||||
}
|
||||
} catch (ex) {
|
||||
logger.warn("Error in parsing property value for " + expectedProperty + " | " + ex);
|
||||
logger.warn(
|
||||
"Error in parsing property value for " + expectedProperty + " | " + ex
|
||||
);
|
||||
}
|
||||
|
||||
// delete property from obj to indicate we've already
|
||||
|
@ -1165,7 +1237,7 @@ var AddonDatabase = {
|
|||
// The properties will be merged in the same object
|
||||
// prior to being written back through toJSON.
|
||||
for (let remainingProperty of Object.keys(aObj)) {
|
||||
switch (typeof(aObj[remainingProperty])) {
|
||||
switch (typeof aObj[remainingProperty]) {
|
||||
case "boolean":
|
||||
case "number":
|
||||
case "string":
|
||||
|
@ -1176,9 +1248,10 @@ var AddonDatabase = {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!remainingProperty.startsWith("_"))
|
||||
if (!remainingProperty.startsWith("_")) {
|
||||
addon._unsupportedProperties[remainingProperty] =
|
||||
aObj[remainingProperty];
|
||||
}
|
||||
}
|
||||
|
||||
return addon;
|
||||
|
@ -1214,7 +1287,14 @@ var AddonDatabase = {
|
|||
let thumbnailWidth = aObj.thumbnailWidth;
|
||||
let thumbnailHeight = aObj.thumbnailHeight;
|
||||
let caption = aObj.caption;
|
||||
return new AddonManagerPrivate.AddonScreenshot(url, width, height, thumbnailURL,
|
||||
thumbnailWidth, thumbnailHeight, caption);
|
||||
return new AddonManagerPrivate.AddonScreenshot(
|
||||
url,
|
||||
width,
|
||||
height,
|
||||
thumbnailURL,
|
||||
thumbnailWidth,
|
||||
thumbnailHeight,
|
||||
caption
|
||||
);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -4,10 +4,14 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "AddonSettings" ];
|
||||
var EXPORTED_SYMBOLS = ["AddonSettings"];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
|
||||
const PREF_SIGNATURES_REQUIRED = "xpinstall.signatures.required";
|
||||
const PREF_LANGPACK_SIGNATURES = "extensions.langpacks.signatures.required";
|
||||
|
@ -30,15 +34,27 @@ if (AppConstants.MOZ_REQUIRE_SIGNING && !Cu.isInAutomation) {
|
|||
makeConstant("REQUIRE_SIGNING", true);
|
||||
makeConstant("LANGPACKS_REQUIRE_SIGNING", true);
|
||||
} else {
|
||||
XPCOMUtils.defineLazyPreferenceGetter(AddonSettings, "REQUIRE_SIGNING",
|
||||
PREF_SIGNATURES_REQUIRED, false);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(AddonSettings, "LANGPACKS_REQUIRE_SIGNING",
|
||||
PREF_LANGPACK_SIGNATURES, false);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
AddonSettings,
|
||||
"REQUIRE_SIGNING",
|
||||
PREF_SIGNATURES_REQUIRED,
|
||||
false
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
AddonSettings,
|
||||
"LANGPACKS_REQUIRE_SIGNING",
|
||||
PREF_LANGPACK_SIGNATURES,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS || Cu.isInAutomation) {
|
||||
XPCOMUtils.defineLazyPreferenceGetter(AddonSettings, "ALLOW_LEGACY_EXTENSIONS",
|
||||
PREF_ALLOW_LEGACY, true);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
AddonSettings,
|
||||
"ALLOW_LEGACY_EXTENSIONS",
|
||||
PREF_ALLOW_LEGACY,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
makeConstant("ALLOW_LEGACY_EXTENSIONS", false);
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -9,36 +9,56 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "AddonUpdateChecker" ];
|
||||
var EXPORTED_SYMBOLS = ["AddonUpdateChecker"];
|
||||
|
||||
const TIMEOUT = 60 * 1000;
|
||||
const TOOLKIT_ID = "toolkit@mozilla.org";
|
||||
const TIMEOUT = 60 * 1000;
|
||||
const TOOLKIT_ID = "toolkit@mozilla.org";
|
||||
|
||||
const PREF_UPDATE_REQUIREBUILTINCERTS = "extensions.update.requireBuiltInCerts";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "AddonManagerPrivate",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "AddonRepository",
|
||||
"resource://gre/modules/addons/AddonRepository.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Blocklist",
|
||||
"resource://gre/modules/Blocklist.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "CertUtils",
|
||||
"resource://gre/modules/CertUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ServiceRequest",
|
||||
"resource://gre/modules/ServiceRequest.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"AddonManagerPrivate",
|
||||
"resource://gre/modules/AddonManager.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"AddonRepository",
|
||||
"resource://gre/modules/addons/AddonRepository.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Blocklist",
|
||||
"resource://gre/modules/Blocklist.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"CertUtils",
|
||||
"resource://gre/modules/CertUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ServiceRequest",
|
||||
"resource://gre/modules/ServiceRequest.jsm"
|
||||
);
|
||||
|
||||
const {Log} = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const LOGGER_ID = "addons.update-checker";
|
||||
|
||||
// Create a new logger for use by the Addons Update Checker
|
||||
// (Requires AddonManager.jsm)
|
||||
var logger = Log.repository.getLogger(LOGGER_ID);
|
||||
|
||||
const updateTypeHistogram = Services.telemetry.getHistogramById("EXTENSION_UPDATE_TYPE");
|
||||
const updateTypeHistogram = Services.telemetry.getHistogramById(
|
||||
"EXTENSION_UPDATE_TYPE"
|
||||
);
|
||||
|
||||
/**
|
||||
* Sanitizes the update URL in an update item, as returned by
|
||||
|
@ -64,18 +84,25 @@ function sanitizeUpdateURL(aUpdate, aRequest, aHashPattern, aHashString) {
|
|||
let principal = scriptSecurity.getChannelURIPrincipal(aRequest.channel);
|
||||
try {
|
||||
// This logs an error on failure, so no need to log it a second time
|
||||
scriptSecurity.checkLoadURIStrWithPrincipal(principal, aUpdate.updateURL,
|
||||
scriptSecurity.DISALLOW_SCRIPT);
|
||||
scriptSecurity.checkLoadURIStrWithPrincipal(
|
||||
principal,
|
||||
aUpdate.updateURL,
|
||||
scriptSecurity.DISALLOW_SCRIPT
|
||||
);
|
||||
} catch (e) {
|
||||
delete aUpdate.updateURL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (AddonManager.checkUpdateSecurity &&
|
||||
!aUpdate.updateURL.startsWith("https:") &&
|
||||
!aHashPattern.test(aUpdate.updateHash)) {
|
||||
logger.warn(`Update link ${aUpdate.updateURL} is not secure and is not verified ` +
|
||||
`by a strong enough hash (needs to be ${aHashString}).`);
|
||||
if (
|
||||
AddonManager.checkUpdateSecurity &&
|
||||
!aUpdate.updateURL.startsWith("https:") &&
|
||||
!aHashPattern.test(aUpdate.updateHash)
|
||||
) {
|
||||
logger.warn(
|
||||
`Update link ${aUpdate.updateURL} is not secure and is not verified ` +
|
||||
`by a strong enough hash (needs to be ${aHashString}).`
|
||||
);
|
||||
delete aUpdate.updateURL;
|
||||
delete aUpdate.updateHash;
|
||||
}
|
||||
|
@ -96,34 +123,45 @@ function sanitizeUpdateURL(aUpdate, aRequest, aHashPattern, aHashString) {
|
|||
*/
|
||||
function parseJSONManifest(aId, aRequest, aManifestData) {
|
||||
let TYPE_CHECK = {
|
||||
"array": val => Array.isArray(val),
|
||||
"object": val => val && typeof val == "object" && !Array.isArray(val),
|
||||
array: val => Array.isArray(val),
|
||||
object: val => val && typeof val == "object" && !Array.isArray(val),
|
||||
};
|
||||
|
||||
function getProperty(aObj, aProperty, aType, aDefault = undefined) {
|
||||
if (!(aProperty in aObj))
|
||||
if (!(aProperty in aObj)) {
|
||||
return aDefault;
|
||||
}
|
||||
|
||||
let value = aObj[aProperty];
|
||||
|
||||
let matchesType = aType in TYPE_CHECK ? TYPE_CHECK[aType](value) : typeof value == aType;
|
||||
if (!matchesType)
|
||||
throw Components.Exception(`Update manifest property '${aProperty}' has incorrect type (expected ${aType})`);
|
||||
let matchesType =
|
||||
aType in TYPE_CHECK ? TYPE_CHECK[aType](value) : typeof value == aType;
|
||||
if (!matchesType) {
|
||||
throw Components.Exception(
|
||||
`Update manifest property '${aProperty}' has incorrect type (expected ${aType})`
|
||||
);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function getRequiredProperty(aObj, aProperty, aType) {
|
||||
let value = getProperty(aObj, aProperty, aType);
|
||||
if (value === undefined)
|
||||
throw Components.Exception(`Update manifest is missing a required ${aProperty} property.`);
|
||||
if (value === undefined) {
|
||||
throw Components.Exception(
|
||||
`Update manifest is missing a required ${aProperty} property.`
|
||||
);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
let manifest = aManifestData;
|
||||
|
||||
if (!TYPE_CHECK.object(manifest))
|
||||
throw Components.Exception("Root element of update manifest must be a JSON object literal");
|
||||
if (!TYPE_CHECK.object(manifest)) {
|
||||
throw Components.Exception(
|
||||
"Root element of update manifest must be a JSON object literal"
|
||||
);
|
||||
}
|
||||
|
||||
// The set of add-ons this manifest has updates for
|
||||
let addons = getRequiredProperty(manifest, "addons", "object");
|
||||
|
@ -148,13 +186,16 @@ function parseJSONManifest(aId, aRequest, aManifestData) {
|
|||
|
||||
logger.debug(`Found an update entry for ${aId} version ${version}`);
|
||||
|
||||
let applications = getProperty(update, "applications", "object",
|
||||
{ gecko: {} });
|
||||
let applications = getProperty(update, "applications", "object", {
|
||||
gecko: {},
|
||||
});
|
||||
|
||||
// "gecko" is currently the only supported application entry. If
|
||||
// it's missing, skip this update.
|
||||
if (!("gecko" in applications)) {
|
||||
logger.debug("gecko not in application entry, skipping update of ${addon}");
|
||||
logger.debug(
|
||||
"gecko not in application entry, skipping update of ${addon}"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -162,8 +203,12 @@ function parseJSONManifest(aId, aRequest, aManifestData) {
|
|||
|
||||
let appEntry = {
|
||||
id: TOOLKIT_ID,
|
||||
minVersion: getProperty(app, "strict_min_version", "string",
|
||||
AddonManagerPrivate.webExtensionsMinPlatformVersion),
|
||||
minVersion: getProperty(
|
||||
app,
|
||||
"strict_min_version",
|
||||
"string",
|
||||
AddonManagerPrivate.webExtensionsMinPlatformVersion
|
||||
),
|
||||
maxVersion: "*",
|
||||
};
|
||||
|
||||
|
@ -179,8 +224,11 @@ function parseJSONManifest(aId, aRequest, aManifestData) {
|
|||
|
||||
if ("strict_max_version" in app) {
|
||||
if ("advisory_max_version" in app) {
|
||||
logger.warn("Ignoring 'advisory_max_version' update manifest property for " +
|
||||
aId + " property since 'strict_max_version' also present");
|
||||
logger.warn(
|
||||
"Ignoring 'advisory_max_version' update manifest property for " +
|
||||
aId +
|
||||
" property since 'strict_max_version' also present"
|
||||
);
|
||||
}
|
||||
|
||||
appEntry.maxVersion = getProperty(app, "strict_max_version", "string");
|
||||
|
@ -196,8 +244,9 @@ function parseJSONManifest(aId, aRequest, aManifestData) {
|
|||
// Note: This currently only has any effect on legacy extensions (mainly
|
||||
// those used in tests), since WebExtensions cannot yet specify app-specific
|
||||
// compatibility ranges.
|
||||
result.targetApplications.push(Object.assign({}, appEntry,
|
||||
{id: Services.appinfo.ID}));
|
||||
result.targetApplications.push(
|
||||
Object.assign({}, appEntry, { id: Services.appinfo.ID })
|
||||
);
|
||||
|
||||
// The JSON update protocol requires an SHA-2 hash. RDF still
|
||||
// supports SHA-1, for compatibility reasons.
|
||||
|
@ -224,13 +273,18 @@ function UpdateParser(aId, aUrl, aObserver) {
|
|||
this.observer = aObserver;
|
||||
this.url = aUrl;
|
||||
|
||||
let requireBuiltIn = Services.prefs.getBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS, true);
|
||||
let requireBuiltIn = Services.prefs.getBoolPref(
|
||||
PREF_UPDATE_REQUIREBUILTINCERTS,
|
||||
true
|
||||
);
|
||||
|
||||
logger.debug("Requesting " + aUrl);
|
||||
try {
|
||||
this.request = new ServiceRequest({mozAnon: true});
|
||||
this.request = new ServiceRequest({ mozAnon: true });
|
||||
this.request.open("GET", this.url, true);
|
||||
this.request.channel.notificationCallbacks = new CertUtils.BadCertHandler(!requireBuiltIn);
|
||||
this.request.channel.notificationCallbacks = new CertUtils.BadCertHandler(
|
||||
!requireBuiltIn
|
||||
);
|
||||
this.request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
// Prevent the request from writing to cache.
|
||||
this.request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
|
||||
|
@ -259,7 +313,10 @@ UpdateParser.prototype = {
|
|||
this.request = null;
|
||||
this._doneAt = new Error("place holder");
|
||||
|
||||
let requireBuiltIn = Services.prefs.getBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS, true);
|
||||
let requireBuiltIn = Services.prefs.getBoolPref(
|
||||
PREF_UPDATE_REQUIREBUILTINCERTS,
|
||||
true
|
||||
);
|
||||
|
||||
try {
|
||||
CertUtils.checkCert(request.channel, !requireBuiltIn);
|
||||
|
@ -277,8 +334,14 @@ UpdateParser.prototype = {
|
|||
|
||||
let channel = request.channel;
|
||||
if (channel instanceof Ci.nsIHttpChannel && !channel.requestSucceeded) {
|
||||
logger.warn("Request failed: " + this.url + " - " + channel.responseStatus +
|
||||
": " + channel.responseStatusText);
|
||||
logger.warn(
|
||||
"Request failed: " +
|
||||
this.url +
|
||||
" - " +
|
||||
channel.responseStatus +
|
||||
": " +
|
||||
channel.responseStatusText
|
||||
);
|
||||
this.notifyError(AddonManager.ERROR_DOWNLOAD_ERROR);
|
||||
return;
|
||||
}
|
||||
|
@ -301,7 +364,10 @@ UpdateParser.prototype = {
|
|||
logger.warn("onUpdateCheckComplete notification failed", e);
|
||||
}
|
||||
} else {
|
||||
logger.warn("onUpdateCheckComplete may not properly cancel", new Error("stack marker"));
|
||||
logger.warn(
|
||||
"onUpdateCheckComplete may not properly cancel",
|
||||
new Error("stack marker")
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -324,9 +390,14 @@ UpdateParser.prototype = {
|
|||
} else if (this.request.channel instanceof Ci.nsIHttpChannel) {
|
||||
try {
|
||||
if (this.request.channel.requestSucceeded) {
|
||||
logger.warn("Request failed: " + this.url + " - " +
|
||||
this.request.channel.responseStatus + ": " +
|
||||
this.request.channel.responseStatusText);
|
||||
logger.warn(
|
||||
"Request failed: " +
|
||||
this.url +
|
||||
" - " +
|
||||
this.request.channel.responseStatus +
|
||||
": " +
|
||||
this.request.channel.responseStatusText
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn("HTTP Request failed for an unknown reason");
|
||||
|
@ -386,30 +457,44 @@ UpdateParser.prototype = {
|
|||
* AddonCompatibilityOverride objects to match against. Optional.
|
||||
* @return true if the update is compatible with the application/platform
|
||||
*/
|
||||
function matchesVersions(aUpdate, aAppVersion, aPlatformVersion,
|
||||
aIgnoreMaxVersion, aIgnoreStrictCompat,
|
||||
aCompatOverrides) {
|
||||
function matchesVersions(
|
||||
aUpdate,
|
||||
aAppVersion,
|
||||
aPlatformVersion,
|
||||
aIgnoreMaxVersion,
|
||||
aIgnoreStrictCompat,
|
||||
aCompatOverrides
|
||||
) {
|
||||
if (aCompatOverrides) {
|
||||
let override = AddonRepository.findMatchingCompatOverride(aUpdate.version,
|
||||
aCompatOverrides,
|
||||
aAppVersion,
|
||||
aPlatformVersion);
|
||||
if (override && override.type == "incompatible")
|
||||
let override = AddonRepository.findMatchingCompatOverride(
|
||||
aUpdate.version,
|
||||
aCompatOverrides,
|
||||
aAppVersion,
|
||||
aPlatformVersion
|
||||
);
|
||||
if (override && override.type == "incompatible") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aUpdate.strictCompatibility && !aIgnoreStrictCompat)
|
||||
if (aUpdate.strictCompatibility && !aIgnoreStrictCompat) {
|
||||
aIgnoreMaxVersion = false;
|
||||
}
|
||||
|
||||
let result = false;
|
||||
for (let app of aUpdate.targetApplications) {
|
||||
if (app.id == Services.appinfo.ID) {
|
||||
return (Services.vc.compare(aAppVersion, app.minVersion) >= 0) &&
|
||||
(aIgnoreMaxVersion || (Services.vc.compare(aAppVersion, app.maxVersion) <= 0));
|
||||
return (
|
||||
Services.vc.compare(aAppVersion, app.minVersion) >= 0 &&
|
||||
(aIgnoreMaxVersion ||
|
||||
Services.vc.compare(aAppVersion, app.maxVersion) <= 0)
|
||||
);
|
||||
}
|
||||
if (app.id == TOOLKIT_ID) {
|
||||
result = (Services.vc.compare(aPlatformVersion, app.minVersion) >= 0) &&
|
||||
(aIgnoreMaxVersion || (Services.vc.compare(aPlatformVersion, app.maxVersion) <= 0));
|
||||
result =
|
||||
Services.vc.compare(aPlatformVersion, app.minVersion) >= 0 &&
|
||||
(aIgnoreMaxVersion ||
|
||||
Services.vc.compare(aPlatformVersion, app.maxVersion) <= 0);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -437,24 +522,40 @@ var AddonUpdateChecker = {
|
|||
* Ignore strictCompatibility when testing if an update matches. Optional.
|
||||
* @return an update object if one matches or null if not
|
||||
*/
|
||||
getCompatibilityUpdate(aUpdates, aVersion, aIgnoreCompatibility,
|
||||
aAppVersion, aPlatformVersion,
|
||||
aIgnoreMaxVersion, aIgnoreStrictCompat) {
|
||||
if (!aAppVersion)
|
||||
getCompatibilityUpdate(
|
||||
aUpdates,
|
||||
aVersion,
|
||||
aIgnoreCompatibility,
|
||||
aAppVersion,
|
||||
aPlatformVersion,
|
||||
aIgnoreMaxVersion,
|
||||
aIgnoreStrictCompat
|
||||
) {
|
||||
if (!aAppVersion) {
|
||||
aAppVersion = Services.appinfo.version;
|
||||
if (!aPlatformVersion)
|
||||
}
|
||||
if (!aPlatformVersion) {
|
||||
aPlatformVersion = Services.appinfo.platformVersion;
|
||||
}
|
||||
|
||||
for (let update of aUpdates) {
|
||||
if (Services.vc.compare(update.version, aVersion) == 0) {
|
||||
if (aIgnoreCompatibility) {
|
||||
for (let targetApp of update.targetApplications) {
|
||||
let id = targetApp.id;
|
||||
if (id == Services.appinfo.ID || id == TOOLKIT_ID)
|
||||
if (id == Services.appinfo.ID || id == TOOLKIT_ID) {
|
||||
return update;
|
||||
}
|
||||
}
|
||||
} else if (matchesVersions(update, aAppVersion, aPlatformVersion,
|
||||
aIgnoreMaxVersion, aIgnoreStrictCompat)) {
|
||||
} else if (
|
||||
matchesVersions(
|
||||
update,
|
||||
aAppVersion,
|
||||
aPlatformVersion,
|
||||
aIgnoreMaxVersion,
|
||||
aIgnoreStrictCompat
|
||||
)
|
||||
) {
|
||||
return update;
|
||||
}
|
||||
}
|
||||
|
@ -479,25 +580,46 @@ var AddonUpdateChecker = {
|
|||
* Array of AddonCompatibilityOverride to take into account. Optional.
|
||||
* @return an update object if one matches or null if not
|
||||
*/
|
||||
async getNewestCompatibleUpdate(aUpdates, aAppVersion, aPlatformVersion,
|
||||
aIgnoreMaxVersion, aIgnoreStrictCompat,
|
||||
aCompatOverrides) {
|
||||
if (!aAppVersion)
|
||||
async getNewestCompatibleUpdate(
|
||||
aUpdates,
|
||||
aAppVersion,
|
||||
aPlatformVersion,
|
||||
aIgnoreMaxVersion,
|
||||
aIgnoreStrictCompat,
|
||||
aCompatOverrides
|
||||
) {
|
||||
if (!aAppVersion) {
|
||||
aAppVersion = Services.appinfo.version;
|
||||
if (!aPlatformVersion)
|
||||
}
|
||||
if (!aPlatformVersion) {
|
||||
aPlatformVersion = Services.appinfo.platformVersion;
|
||||
}
|
||||
|
||||
let newest = null;
|
||||
for (let update of aUpdates) {
|
||||
if (!update.updateURL)
|
||||
if (!update.updateURL) {
|
||||
continue;
|
||||
let state = await Blocklist.getAddonBlocklistState(update, aAppVersion, aPlatformVersion);
|
||||
if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED)
|
||||
}
|
||||
let state = await Blocklist.getAddonBlocklistState(
|
||||
update,
|
||||
aAppVersion,
|
||||
aPlatformVersion
|
||||
);
|
||||
if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
|
||||
continue;
|
||||
if ((newest == null || (Services.vc.compare(newest.version, update.version) < 0)) &&
|
||||
matchesVersions(update, aAppVersion, aPlatformVersion,
|
||||
aIgnoreMaxVersion, aIgnoreStrictCompat,
|
||||
aCompatOverrides)) {
|
||||
}
|
||||
if (
|
||||
(newest == null ||
|
||||
Services.vc.compare(newest.version, update.version) < 0) &&
|
||||
matchesVersions(
|
||||
update,
|
||||
aAppVersion,
|
||||
aPlatformVersion,
|
||||
aIgnoreMaxVersion,
|
||||
aIgnoreStrictCompat,
|
||||
aCompatOverrides
|
||||
)
|
||||
) {
|
||||
newest = update;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,24 +7,25 @@
|
|||
"use strict";
|
||||
|
||||
(function() {
|
||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const MSG_JAR_FLUSH = "AddonJarFlush";
|
||||
const MSG_MESSAGE_MANAGER_CACHES_FLUSH = "AddonMessageManagerCachesFlush";
|
||||
const MSG_JAR_FLUSH = "AddonJarFlush";
|
||||
const MSG_MESSAGE_MANAGER_CACHES_FLUSH = "AddonMessageManagerCachesFlush";
|
||||
|
||||
|
||||
try {
|
||||
if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) {
|
||||
// Propagate JAR cache flush notifications across process boundaries.
|
||||
addMessageListener(MSG_JAR_FLUSH, function(message) {
|
||||
Services.obs.notifyObservers(null, "flush-cache-entry", message.data);
|
||||
});
|
||||
// Propagate message manager caches flush notifications across processes.
|
||||
addMessageListener(MSG_MESSAGE_MANAGER_CACHES_FLUSH, function() {
|
||||
Services.obs.notifyObservers(null, "message-manager-flush-caches");
|
||||
});
|
||||
try {
|
||||
if (
|
||||
Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT
|
||||
) {
|
||||
// Propagate JAR cache flush notifications across process boundaries.
|
||||
addMessageListener(MSG_JAR_FLUSH, function(message) {
|
||||
Services.obs.notifyObservers(null, "flush-cache-entry", message.data);
|
||||
});
|
||||
// Propagate message manager caches flush notifications across processes.
|
||||
addMessageListener(MSG_MESSAGE_MANAGER_CACHES_FLUSH, function() {
|
||||
Services.obs.notifyObservers(null, "message-manager-flush-caches");
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -6,65 +6,85 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = [];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {AddonManager, AddonManagerPrivate} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { AddonManager, AddonManagerPrivate } = ChromeUtils.import(
|
||||
"resource://gre/modules/AddonManager.jsm"
|
||||
);
|
||||
/* globals AddonManagerPrivate*/
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
/* globals OS*/
|
||||
const {Log} = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
// These symbols are, unfortunately, accessed via the module global from
|
||||
// tests, and therefore cannot be lexical definitions.
|
||||
var {GMPPrefs, GMPUtils, OPEN_H264_ID, WIDEVINE_ID} = ChromeUtils.import("resource://gre/modules/GMPUtils.jsm");
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
var { GMPPrefs, GMPUtils, OPEN_H264_ID, WIDEVINE_ID } = ChromeUtils.import(
|
||||
"resource://gre/modules/GMPUtils.jsm"
|
||||
);
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this, "GMPInstallManager", "resource://gre/modules/GMPInstallManager.jsm");
|
||||
this,
|
||||
"GMPInstallManager",
|
||||
"resource://gre/modules/GMPInstallManager.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this, "setTimeout", "resource://gre/modules/Timer.jsm");
|
||||
this,
|
||||
"setTimeout",
|
||||
"resource://gre/modules/Timer.jsm"
|
||||
);
|
||||
|
||||
const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties";
|
||||
const URI_EXTENSION_STRINGS =
|
||||
"chrome://mozapps/locale/extensions/extensions.properties";
|
||||
|
||||
const SEC_IN_A_DAY = 24 * 60 * 60;
|
||||
const SEC_IN_A_DAY = 24 * 60 * 60;
|
||||
// How long to wait after a user enabled EME before attempting to download CDMs.
|
||||
const GMP_CHECK_DELAY = 10 * 1000; // milliseconds
|
||||
const GMP_CHECK_DELAY = 10 * 1000; // milliseconds
|
||||
|
||||
const XHTML = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
const NS_GRE_DIR = "GreD";
|
||||
const CLEARKEY_PLUGIN_ID = "gmp-clearkey";
|
||||
const CLEARKEY_VERSION = "0.1";
|
||||
const NS_GRE_DIR = "GreD";
|
||||
const CLEARKEY_PLUGIN_ID = "gmp-clearkey";
|
||||
const CLEARKEY_VERSION = "0.1";
|
||||
|
||||
const GMP_LICENSE_INFO = "gmp_license_info";
|
||||
const GMP_PRIVACY_INFO = "gmp_privacy_info";
|
||||
const GMP_LEARN_MORE = "learn_more_label";
|
||||
const GMP_LICENSE_INFO = "gmp_license_info";
|
||||
const GMP_PRIVACY_INFO = "gmp_privacy_info";
|
||||
const GMP_LEARN_MORE = "learn_more_label";
|
||||
|
||||
const GMP_PLUGINS = [
|
||||
{
|
||||
id: OPEN_H264_ID,
|
||||
name: "openH264_name",
|
||||
description: "openH264_description2",
|
||||
id: OPEN_H264_ID,
|
||||
name: "openH264_name",
|
||||
description: "openH264_description2",
|
||||
// The following licenseURL is part of an awful hack to include the OpenH264
|
||||
// license without having bug 624602 fixed yet, and intentionally ignores
|
||||
// localisation.
|
||||
licenseURL: "chrome://mozapps/content/extensions/OpenH264-license.txt",
|
||||
homepageURL: "https://www.openh264.org/",
|
||||
licenseURL: "chrome://mozapps/content/extensions/OpenH264-license.txt",
|
||||
homepageURL: "https://www.openh264.org/",
|
||||
},
|
||||
{
|
||||
id: WIDEVINE_ID,
|
||||
name: "widevine_description",
|
||||
id: WIDEVINE_ID,
|
||||
name: "widevine_description",
|
||||
// Describe the purpose of both CDMs in the same way.
|
||||
description: "cdm_description2",
|
||||
licenseURL: "https://www.google.com/policies/privacy/",
|
||||
homepageURL: "https://www.widevine.com/",
|
||||
isEME: true,
|
||||
}];
|
||||
description: "cdm_description2",
|
||||
licenseURL: "https://www.google.com/policies/privacy/",
|
||||
homepageURL: "https://www.widevine.com/",
|
||||
isEME: true,
|
||||
},
|
||||
];
|
||||
XPCOMUtils.defineConstant(this, "GMP_PLUGINS", GMP_PLUGINS);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "pluginsBundle",
|
||||
() => Services.strings.createBundle("chrome://global/locale/plugins.properties"));
|
||||
XPCOMUtils.defineLazyGetter(this, "gmpService",
|
||||
() => Cc["@mozilla.org/gecko-media-plugin-service;1"].getService(Ci.mozIGeckoMediaPluginChromeService));
|
||||
XPCOMUtils.defineLazyGetter(this, "pluginsBundle", () =>
|
||||
Services.strings.createBundle("chrome://global/locale/plugins.properties")
|
||||
);
|
||||
XPCOMUtils.defineLazyGetter(this, "gmpService", () =>
|
||||
Cc["@mozilla.org/gecko-media-plugin-service;1"].getService(
|
||||
Ci.mozIGeckoMediaPluginChromeService
|
||||
)
|
||||
);
|
||||
|
||||
var gLogger;
|
||||
var gLogAppenderDump = null;
|
||||
|
@ -88,8 +108,6 @@ function configureLogging() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The GMPWrapper provides the info for the various GMP plugins to public
|
||||
* callers through the API.
|
||||
|
@ -97,16 +115,20 @@ function configureLogging() {
|
|||
function GMPWrapper(aPluginInfo, aRawPluginInfo) {
|
||||
this._plugin = aPluginInfo;
|
||||
this._rawPlugin = aRawPluginInfo;
|
||||
this._log =
|
||||
Log.repository.getLoggerWithMessagePrefix("Toolkit.GMP",
|
||||
"GMPWrapper(" +
|
||||
this._plugin.id + ") ");
|
||||
Services.prefs.addObserver(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED,
|
||||
this._plugin.id),
|
||||
this, true);
|
||||
Services.prefs.addObserver(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION,
|
||||
this._plugin.id),
|
||||
this, true);
|
||||
this._log = Log.repository.getLoggerWithMessagePrefix(
|
||||
"Toolkit.GMP",
|
||||
"GMPWrapper(" + this._plugin.id + ") "
|
||||
);
|
||||
Services.prefs.addObserver(
|
||||
GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED, this._plugin.id),
|
||||
this,
|
||||
true
|
||||
);
|
||||
Services.prefs.addObserver(
|
||||
GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION, this._plugin.id),
|
||||
this,
|
||||
true
|
||||
);
|
||||
if (this._plugin.isEME) {
|
||||
Services.prefs.addObserver(GMPPrefs.KEY_EME_ENABLED, this, true);
|
||||
Services.mm.addMessageListener("EMEVideo:ContentMediaKeysRequest", this);
|
||||
|
@ -114,41 +136,67 @@ function GMPWrapper(aPluginInfo, aRawPluginInfo) {
|
|||
}
|
||||
|
||||
GMPWrapper.prototype = {
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference,
|
||||
]),
|
||||
|
||||
// An active task that checks for plugin updates and installs them.
|
||||
_updateTask: null,
|
||||
_gmpPath: null,
|
||||
_isUpdateCheckPending: false,
|
||||
|
||||
set gmpPath(aPath) { this._gmpPath = aPath; },
|
||||
set gmpPath(aPath) {
|
||||
this._gmpPath = aPath;
|
||||
},
|
||||
get gmpPath() {
|
||||
if (!this._gmpPath && this.isInstalled) {
|
||||
this._gmpPath = OS.Path.join(OS.Constants.Path.profileDir,
|
||||
this._plugin.id,
|
||||
GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_VERSION,
|
||||
null, this._plugin.id));
|
||||
this._gmpPath = OS.Path.join(
|
||||
OS.Constants.Path.profileDir,
|
||||
this._plugin.id,
|
||||
GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_VERSION, null, this._plugin.id)
|
||||
);
|
||||
}
|
||||
return this._gmpPath;
|
||||
},
|
||||
|
||||
get id() { return this._plugin.id; },
|
||||
get type() { return "plugin"; },
|
||||
get isGMPlugin() { return true; },
|
||||
get name() { return this._plugin.name; },
|
||||
get creator() { return null; },
|
||||
get homepageURL() { return this._plugin.homepageURL; },
|
||||
get id() {
|
||||
return this._plugin.id;
|
||||
},
|
||||
get type() {
|
||||
return "plugin";
|
||||
},
|
||||
get isGMPlugin() {
|
||||
return true;
|
||||
},
|
||||
get name() {
|
||||
return this._plugin.name;
|
||||
},
|
||||
get creator() {
|
||||
return null;
|
||||
},
|
||||
get homepageURL() {
|
||||
return this._plugin.homepageURL;
|
||||
},
|
||||
|
||||
get description() { return this._plugin.description; },
|
||||
get fullDescription() { return null; },
|
||||
get description() {
|
||||
return this._plugin.description;
|
||||
},
|
||||
get fullDescription() {
|
||||
return null;
|
||||
},
|
||||
|
||||
getFullDescription(doc) {
|
||||
let plugin = this._rawPlugin;
|
||||
|
||||
let frag = doc.createDocumentFragment();
|
||||
for (let [urlProp, labelId] of [["learnMoreURL", GMP_LEARN_MORE],
|
||||
["licenseURL", this.id == WIDEVINE_ID ?
|
||||
GMP_PRIVACY_INFO : GMP_LICENSE_INFO]]) {
|
||||
for (let [urlProp, labelId] of [
|
||||
["learnMoreURL", GMP_LEARN_MORE],
|
||||
[
|
||||
"licenseURL",
|
||||
this.id == WIDEVINE_ID ? GMP_PRIVACY_INFO : GMP_LICENSE_INFO,
|
||||
],
|
||||
]) {
|
||||
if (plugin[urlProp]) {
|
||||
let a = doc.createElementNS(XHTML, "a");
|
||||
a.href = plugin[urlProp];
|
||||
|
@ -156,8 +204,10 @@ GMPWrapper.prototype = {
|
|||
a.textContent = pluginsBundle.GetStringFromName(labelId);
|
||||
|
||||
if (frag.childElementCount) {
|
||||
frag.append(doc.createElementNS(XHTML, "br"),
|
||||
doc.createElementNS(XHTML, "br"));
|
||||
frag.append(
|
||||
doc.createElementNS(XHTML, "br"),
|
||||
doc.createElementNS(XHTML, "br")
|
||||
);
|
||||
}
|
||||
frag.append(a);
|
||||
}
|
||||
|
@ -167,16 +217,25 @@ GMPWrapper.prototype = {
|
|||
},
|
||||
|
||||
get version() {
|
||||
return GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_VERSION, null, this._plugin.id);
|
||||
return GMPPrefs.getString(
|
||||
GMPPrefs.KEY_PLUGIN_VERSION,
|
||||
null,
|
||||
this._plugin.id
|
||||
);
|
||||
},
|
||||
|
||||
get isActive() {
|
||||
return !this.appDisabled &&
|
||||
!this.userDisabled &&
|
||||
!GMPUtils.isPluginHidden(this._plugin);
|
||||
return (
|
||||
!this.appDisabled &&
|
||||
!this.userDisabled &&
|
||||
!GMPUtils.isPluginHidden(this._plugin)
|
||||
);
|
||||
},
|
||||
get appDisabled() {
|
||||
if (this._plugin.isEME && !GMPPrefs.getBool(GMPPrefs.KEY_EME_ENABLED, true)) {
|
||||
if (
|
||||
this._plugin.isEME &&
|
||||
!GMPPrefs.getBool(GMPPrefs.KEY_EME_ENABLED, true)
|
||||
) {
|
||||
// If "media.eme.enabled" is false, all EME plugins are disabled.
|
||||
return true;
|
||||
}
|
||||
|
@ -184,10 +243,18 @@ GMPWrapper.prototype = {
|
|||
},
|
||||
|
||||
get userDisabled() {
|
||||
return !GMPPrefs.getBool(GMPPrefs.KEY_PLUGIN_ENABLED, true, this._plugin.id);
|
||||
return !GMPPrefs.getBool(
|
||||
GMPPrefs.KEY_PLUGIN_ENABLED,
|
||||
true,
|
||||
this._plugin.id
|
||||
);
|
||||
},
|
||||
set userDisabled(aVal) {
|
||||
GMPPrefs.setBool(GMPPrefs.KEY_PLUGIN_ENABLED, aVal === false, this._plugin.id);
|
||||
GMPPrefs.setBool(
|
||||
GMPPrefs.KEY_PLUGIN_ENABLED,
|
||||
aVal === false,
|
||||
this._plugin.id
|
||||
);
|
||||
},
|
||||
|
||||
async enable() {
|
||||
|
@ -197,26 +264,38 @@ GMPWrapper.prototype = {
|
|||
this.userDisabled = true;
|
||||
},
|
||||
|
||||
get blocklistState() { return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; },
|
||||
get size() { return 0; },
|
||||
get scope() { return AddonManager.SCOPE_APPLICATION; },
|
||||
get pendingOperations() { return AddonManager.PENDING_NONE; },
|
||||
get blocklistState() {
|
||||
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
},
|
||||
get size() {
|
||||
return 0;
|
||||
},
|
||||
get scope() {
|
||||
return AddonManager.SCOPE_APPLICATION;
|
||||
},
|
||||
get pendingOperations() {
|
||||
return AddonManager.PENDING_NONE;
|
||||
},
|
||||
|
||||
get operationsRequiringRestart() { return AddonManager.OP_NEEDS_RESTART_NONE; },
|
||||
get operationsRequiringRestart() {
|
||||
return AddonManager.OP_NEEDS_RESTART_NONE;
|
||||
},
|
||||
|
||||
get permissions() {
|
||||
let permissions = 0;
|
||||
if (!this.appDisabled) {
|
||||
permissions |= AddonManager.PERM_CAN_UPGRADE;
|
||||
permissions |= this.userDisabled ? AddonManager.PERM_CAN_ENABLE :
|
||||
AddonManager.PERM_CAN_DISABLE;
|
||||
permissions |= this.userDisabled
|
||||
? AddonManager.PERM_CAN_ENABLE
|
||||
: AddonManager.PERM_CAN_DISABLE;
|
||||
}
|
||||
return permissions;
|
||||
},
|
||||
|
||||
get updateDate() {
|
||||
let time = Number(GMPPrefs.getInt(GMPPrefs.KEY_PLUGIN_LAST_UPDATE, 0,
|
||||
this._plugin.id));
|
||||
let time = Number(
|
||||
GMPPrefs.getInt(GMPPrefs.KEY_PLUGIN_LAST_UPDATE, 0, this._plugin.id)
|
||||
);
|
||||
if (this.isInstalled) {
|
||||
return new Date(time * 1000);
|
||||
}
|
||||
|
@ -240,7 +319,7 @@ GMPWrapper.prototype = {
|
|||
},
|
||||
|
||||
get installTelemetryInfo() {
|
||||
return {source: "gmp-plugin"};
|
||||
return { source: "gmp-plugin" };
|
||||
},
|
||||
|
||||
isCompatibleWith(aAppVersion, aPlatformVersion) {
|
||||
|
@ -252,8 +331,13 @@ GMPWrapper.prototype = {
|
|||
return AddonManager.AUTOUPDATE_DEFAULT;
|
||||
}
|
||||
|
||||
return GMPPrefs.getBool(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, true, this._plugin.id) ?
|
||||
AddonManager.AUTOUPDATE_ENABLE : AddonManager.AUTOUPDATE_DISABLE;
|
||||
return GMPPrefs.getBool(
|
||||
GMPPrefs.KEY_PLUGIN_AUTOUPDATE,
|
||||
true,
|
||||
this._plugin.id
|
||||
)
|
||||
? AddonManager.AUTOUPDATE_ENABLE
|
||||
: AddonManager.AUTOUPDATE_DISABLE;
|
||||
},
|
||||
|
||||
set applyBackgroundUpdates(aVal) {
|
||||
|
@ -267,34 +351,44 @@ GMPWrapper.prototype = {
|
|||
},
|
||||
|
||||
findUpdates(aListener, aReason, aAppVersion, aPlatformVersion) {
|
||||
this._log.trace("findUpdates() - " + this._plugin.id + " - reason=" +
|
||||
aReason);
|
||||
this._log.trace(
|
||||
"findUpdates() - " + this._plugin.id + " - reason=" + aReason
|
||||
);
|
||||
|
||||
AddonManagerPrivate.callNoUpdateListeners(this, aListener);
|
||||
|
||||
if (aReason === AddonManager.UPDATE_WHEN_PERIODIC_UPDATE) {
|
||||
if (!AddonManager.shouldAutoUpdate(this)) {
|
||||
this._log.trace("findUpdates() - " + this._plugin.id +
|
||||
" - no autoupdate");
|
||||
this._log.trace(
|
||||
"findUpdates() - " + this._plugin.id + " - no autoupdate"
|
||||
);
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
let secSinceLastCheck =
|
||||
Date.now() / 1000 - Services.prefs.getIntPref(GMPPrefs.KEY_UPDATE_LAST_CHECK, 0);
|
||||
Date.now() / 1000 -
|
||||
Services.prefs.getIntPref(GMPPrefs.KEY_UPDATE_LAST_CHECK, 0);
|
||||
if (secSinceLastCheck <= SEC_IN_A_DAY) {
|
||||
this._log.trace("findUpdates() - " + this._plugin.id +
|
||||
" - last check was less then a day ago");
|
||||
this._log.trace(
|
||||
"findUpdates() - " +
|
||||
this._plugin.id +
|
||||
" - last check was less then a day ago"
|
||||
);
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
} else if (aReason !== AddonManager.UPDATE_WHEN_USER_REQUESTED) {
|
||||
this._log.trace("findUpdates() - " + this._plugin.id +
|
||||
" - the given reason to update is not supported");
|
||||
this._log.trace(
|
||||
"findUpdates() - " +
|
||||
this._plugin.id +
|
||||
" - the given reason to update is not supported"
|
||||
);
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
if (this._updateTask !== null) {
|
||||
this._log.trace("findUpdates() - " + this._plugin.id +
|
||||
" - update task already running");
|
||||
this._log.trace(
|
||||
"findUpdates() - " + this._plugin.id + " - update task already running"
|
||||
);
|
||||
return this._updateTask;
|
||||
}
|
||||
|
||||
|
@ -305,17 +399,23 @@ GMPWrapper.prototype = {
|
|||
let res = await installManager.checkForAddons();
|
||||
let update = res.gmpAddons.find(addon => addon.id === this._plugin.id);
|
||||
if (update && update.isValid && !update.isInstalled) {
|
||||
this._log.trace("findUpdates() - found update for " +
|
||||
this._plugin.id + ", installing");
|
||||
this._log.trace(
|
||||
"findUpdates() - found update for " +
|
||||
this._plugin.id +
|
||||
", installing"
|
||||
);
|
||||
await installManager.installAddon(update);
|
||||
} else {
|
||||
this._log.trace("findUpdates() - no updates for " + this._plugin.id);
|
||||
}
|
||||
this._log.info("findUpdates() - updateTask succeeded for " +
|
||||
this._plugin.id);
|
||||
this._log.info(
|
||||
"findUpdates() - updateTask succeeded for " + this._plugin.id
|
||||
);
|
||||
} catch (e) {
|
||||
this._log.error("findUpdates() - updateTask for " + this._plugin.id +
|
||||
" threw", e);
|
||||
this._log.error(
|
||||
"findUpdates() - updateTask for " + this._plugin.id + " threw",
|
||||
e
|
||||
);
|
||||
throw e;
|
||||
} finally {
|
||||
this._updateTask = null;
|
||||
|
@ -326,7 +426,9 @@ GMPWrapper.prototype = {
|
|||
return this._updateTask;
|
||||
},
|
||||
|
||||
get pluginMimeTypes() { return []; },
|
||||
get pluginMimeTypes() {
|
||||
return [];
|
||||
},
|
||||
get pluginLibraries() {
|
||||
if (this.isInstalled) {
|
||||
let path = this.version;
|
||||
|
@ -336,9 +438,11 @@ GMPWrapper.prototype = {
|
|||
},
|
||||
get pluginFullpath() {
|
||||
if (this.isInstalled) {
|
||||
let path = OS.Path.join(OS.Constants.Path.profileDir,
|
||||
this._plugin.id,
|
||||
this.version);
|
||||
let path = OS.Path.join(
|
||||
OS.Constants.Path.profileDir,
|
||||
this._plugin.id,
|
||||
this.version
|
||||
);
|
||||
return [path];
|
||||
}
|
||||
return [];
|
||||
|
@ -349,42 +453,64 @@ GMPWrapper.prototype = {
|
|||
},
|
||||
|
||||
_handleEnabledChanged() {
|
||||
this._log.info("_handleEnabledChanged() id=" +
|
||||
this._plugin.id + " isActive=" + this.isActive);
|
||||
this._log.info(
|
||||
"_handleEnabledChanged() id=" +
|
||||
this._plugin.id +
|
||||
" isActive=" +
|
||||
this.isActive
|
||||
);
|
||||
|
||||
AddonManagerPrivate.callAddonListeners(this.isActive ?
|
||||
"onEnabling" : "onDisabling",
|
||||
this, false);
|
||||
AddonManagerPrivate.callAddonListeners(
|
||||
this.isActive ? "onEnabling" : "onDisabling",
|
||||
this,
|
||||
false
|
||||
);
|
||||
if (this._gmpPath) {
|
||||
if (this.isActive) {
|
||||
this._log.info("onPrefEnabledChanged() - adding gmp directory " +
|
||||
this._gmpPath);
|
||||
this._log.info(
|
||||
"onPrefEnabledChanged() - adding gmp directory " + this._gmpPath
|
||||
);
|
||||
gmpService.addPluginDirectory(this._gmpPath);
|
||||
} else {
|
||||
this._log.info("onPrefEnabledChanged() - removing gmp directory " +
|
||||
this._gmpPath);
|
||||
this._log.info(
|
||||
"onPrefEnabledChanged() - removing gmp directory " + this._gmpPath
|
||||
);
|
||||
gmpService.removePluginDirectory(this._gmpPath);
|
||||
}
|
||||
}
|
||||
AddonManagerPrivate.callAddonListeners(this.isActive ?
|
||||
"onEnabled" : "onDisabled",
|
||||
this);
|
||||
AddonManagerPrivate.callAddonListeners(
|
||||
this.isActive ? "onEnabled" : "onDisabled",
|
||||
this
|
||||
);
|
||||
},
|
||||
|
||||
onPrefEMEGlobalEnabledChanged() {
|
||||
this._log.info("onPrefEMEGlobalEnabledChanged() id=" + this._plugin.id +
|
||||
" appDisabled=" + this.appDisabled + " isActive=" + this.isActive +
|
||||
" hidden=" + GMPUtils.isPluginHidden(this._plugin));
|
||||
this._log.info(
|
||||
"onPrefEMEGlobalEnabledChanged() id=" +
|
||||
this._plugin.id +
|
||||
" appDisabled=" +
|
||||
this.appDisabled +
|
||||
" isActive=" +
|
||||
this.isActive +
|
||||
" hidden=" +
|
||||
GMPUtils.isPluginHidden(this._plugin)
|
||||
);
|
||||
|
||||
AddonManagerPrivate.callAddonListeners("onPropertyChanged", this,
|
||||
["appDisabled"]);
|
||||
AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, [
|
||||
"appDisabled",
|
||||
]);
|
||||
// If EME or the GMP itself are disabled, uninstall the GMP.
|
||||
// Otherwise, check for updates, so we download and install the GMP.
|
||||
if (this.appDisabled) {
|
||||
this.uninstallPlugin();
|
||||
} else if (!GMPUtils.isPluginHidden(this._plugin)) {
|
||||
AddonManagerPrivate.callInstallListeners("onExternalInstall", null, this,
|
||||
null, false);
|
||||
AddonManagerPrivate.callInstallListeners(
|
||||
"onExternalInstall",
|
||||
null,
|
||||
this,
|
||||
null,
|
||||
false
|
||||
);
|
||||
AddonManagerPrivate.callAddonListeners("onInstalling", this, false);
|
||||
AddonManagerPrivate.callAddonListeners("onInstalled", this);
|
||||
this.checkForUpdates(GMP_CHECK_DELAY);
|
||||
|
@ -413,7 +539,7 @@ GMPWrapper.prototype = {
|
|||
}, delay);
|
||||
},
|
||||
|
||||
receiveMessage({target: browser, data: data}) {
|
||||
receiveMessage({ target: browser, data: data }) {
|
||||
this._log.trace("receiveMessage() data=" + data);
|
||||
let parsedData;
|
||||
try {
|
||||
|
@ -422,7 +548,7 @@ GMPWrapper.prototype = {
|
|||
this._log.error("Malformed EME video message with data: " + data);
|
||||
return;
|
||||
}
|
||||
let {status} = parsedData;
|
||||
let { status } = parsedData;
|
||||
if (status == "cdm-not-installed") {
|
||||
this.checkForUpdates(0);
|
||||
}
|
||||
|
@ -437,25 +563,36 @@ GMPWrapper.prototype = {
|
|||
onPrefVersionChanged() {
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalling", this, false);
|
||||
if (this._gmpPath) {
|
||||
this._log.info("onPrefVersionChanged() - unregistering gmp directory " +
|
||||
this._gmpPath);
|
||||
gmpService.removeAndDeletePluginDirectory(this._gmpPath, true /* can defer */);
|
||||
this._log.info(
|
||||
"onPrefVersionChanged() - unregistering gmp directory " + this._gmpPath
|
||||
);
|
||||
gmpService.removeAndDeletePluginDirectory(
|
||||
this._gmpPath,
|
||||
true /* can defer */
|
||||
);
|
||||
}
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalled", this);
|
||||
|
||||
AddonManagerPrivate.callInstallListeners("onExternalInstall", null, this,
|
||||
null, false);
|
||||
AddonManagerPrivate.callInstallListeners(
|
||||
"onExternalInstall",
|
||||
null,
|
||||
this,
|
||||
null,
|
||||
false
|
||||
);
|
||||
AddonManagerPrivate.callAddonListeners("onInstalling", this, false);
|
||||
this._gmpPath = null;
|
||||
if (this.isInstalled) {
|
||||
this._gmpPath = OS.Path.join(OS.Constants.Path.profileDir,
|
||||
this._plugin.id,
|
||||
GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_VERSION,
|
||||
null, this._plugin.id));
|
||||
this._gmpPath = OS.Path.join(
|
||||
OS.Constants.Path.profileDir,
|
||||
this._plugin.id,
|
||||
GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_VERSION, null, this._plugin.id)
|
||||
);
|
||||
}
|
||||
if (this._gmpPath && this.isActive) {
|
||||
this._log.info("onPrefVersionChanged() - registering gmp directory " +
|
||||
this._gmpPath);
|
||||
this._log.info(
|
||||
"onPrefVersionChanged() - registering gmp directory " + this._gmpPath
|
||||
);
|
||||
gmpService.addPluginDirectory(this._gmpPath);
|
||||
}
|
||||
AddonManagerPrivate.callAddonListeners("onInstalled", this);
|
||||
|
@ -463,9 +600,15 @@ GMPWrapper.prototype = {
|
|||
|
||||
observe(subject, topic, pref) {
|
||||
if (topic == "nsPref:changed") {
|
||||
if (pref == GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED, this._plugin.id)) {
|
||||
if (
|
||||
pref ==
|
||||
GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED, this._plugin.id)
|
||||
) {
|
||||
this.onPrefEnabledChanged();
|
||||
} else if (pref == GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION, this._plugin.id)) {
|
||||
} else if (
|
||||
pref ==
|
||||
GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION, this._plugin.id)
|
||||
) {
|
||||
this.onPrefVersionChanged();
|
||||
} else if (pref == GMPPrefs.KEY_EME_ENABLED) {
|
||||
this.onPrefEMEGlobalEnabledChanged();
|
||||
|
@ -476,8 +619,9 @@ GMPWrapper.prototype = {
|
|||
uninstallPlugin() {
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalling", this, false);
|
||||
if (this.gmpPath) {
|
||||
this._log.info("uninstallPlugin() - unregistering gmp directory " +
|
||||
this.gmpPath);
|
||||
this._log.info(
|
||||
"uninstallPlugin() - unregistering gmp directory " + this.gmpPath
|
||||
);
|
||||
gmpService.removeAndDeletePluginDirectory(this.gmpPath);
|
||||
}
|
||||
GMPPrefs.reset(GMPPrefs.KEY_PLUGIN_VERSION, this.id);
|
||||
|
@ -487,13 +631,20 @@ GMPWrapper.prototype = {
|
|||
},
|
||||
|
||||
shutdown() {
|
||||
Services.prefs.removeObserver(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED,
|
||||
this._plugin.id), this);
|
||||
Services.prefs.removeObserver(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION,
|
||||
this._plugin.id), this);
|
||||
Services.prefs.removeObserver(
|
||||
GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED, this._plugin.id),
|
||||
this
|
||||
);
|
||||
Services.prefs.removeObserver(
|
||||
GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION, this._plugin.id),
|
||||
this
|
||||
);
|
||||
if (this._plugin.isEME) {
|
||||
Services.prefs.removeObserver(GMPPrefs.KEY_EME_ENABLED, this);
|
||||
Services.mm.removeMessageListener("EMEVideo:ContentMediaKeysRequest", this);
|
||||
Services.mm.removeMessageListener(
|
||||
"EMEVideo:ContentMediaKeysRequest",
|
||||
this
|
||||
);
|
||||
}
|
||||
return this._updateTask;
|
||||
},
|
||||
|
@ -515,8 +666,9 @@ GMPWrapper.prototype = {
|
|||
infoName = id + ".info";
|
||||
}
|
||||
|
||||
return fileExists(this.gmpPath, libName) &&
|
||||
fileExists(this.gmpPath, infoName);
|
||||
return (
|
||||
fileExists(this.gmpPath, libName) && fileExists(this.gmpPath, infoName)
|
||||
);
|
||||
},
|
||||
|
||||
validate() {
|
||||
|
@ -529,8 +681,11 @@ GMPWrapper.prototype = {
|
|||
}
|
||||
|
||||
let expectedABI = GMPUtils._expectedABI(this._plugin);
|
||||
let abi = GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_ABI, expectedABI,
|
||||
this._plugin.id);
|
||||
let abi = GMPPrefs.getString(
|
||||
GMPPrefs.KEY_PLUGIN_ABI,
|
||||
expectedABI,
|
||||
this._plugin.id
|
||||
);
|
||||
if (abi != expectedABI) {
|
||||
// ABI doesn't match. Possibly this is a profile migrated across platforms
|
||||
// or from 32 -> 64 bit.
|
||||
|
@ -551,14 +706,18 @@ GMPWrapper.prototype = {
|
|||
};
|
||||
|
||||
var GMPProvider = {
|
||||
get name() { return "GMPProvider"; },
|
||||
get name() {
|
||||
return "GMPProvider";
|
||||
},
|
||||
|
||||
_plugins: null,
|
||||
|
||||
startup() {
|
||||
configureLogging();
|
||||
this._log = Log.repository.getLoggerWithMessagePrefix("Toolkit.GMP",
|
||||
"GMPProvider.");
|
||||
this._log = Log.repository.getLoggerWithMessagePrefix(
|
||||
"Toolkit.GMP",
|
||||
"GMPProvider."
|
||||
);
|
||||
this.buildPluginList();
|
||||
this.ensureProperCDMInstallState();
|
||||
|
||||
|
@ -568,20 +727,23 @@ var GMPProvider = {
|
|||
let wrapper = plugin.wrapper;
|
||||
let gmpPath = wrapper.gmpPath;
|
||||
let isEnabled = wrapper.isActive;
|
||||
this._log.trace("startup - enabled=" + isEnabled + ", gmpPath=" +
|
||||
gmpPath);
|
||||
this._log.trace(
|
||||
"startup - enabled=" + isEnabled + ", gmpPath=" + gmpPath
|
||||
);
|
||||
|
||||
if (gmpPath && isEnabled) {
|
||||
let validation = wrapper.validate();
|
||||
if (validation.mismatchedABI) {
|
||||
this._log.info("startup - gmp " + plugin.id +
|
||||
" mismatched ABI, uninstalling");
|
||||
this._log.info(
|
||||
"startup - gmp " + plugin.id + " mismatched ABI, uninstalling"
|
||||
);
|
||||
wrapper.uninstallPlugin();
|
||||
continue;
|
||||
}
|
||||
if (!validation.valid) {
|
||||
this._log.info("startup - gmp " + plugin.id +
|
||||
" invalid, uninstalling");
|
||||
this._log.info(
|
||||
"startup - gmp " + plugin.id + " invalid, uninstalling"
|
||||
);
|
||||
wrapper.uninstallPlugin();
|
||||
continue;
|
||||
}
|
||||
|
@ -589,26 +751,31 @@ var GMPProvider = {
|
|||
try {
|
||||
gmpService.addPluginDirectory(gmpPath);
|
||||
} catch (e) {
|
||||
if (e.name != "NS_ERROR_NOT_AVAILABLE")
|
||||
if (e.name != "NS_ERROR_NOT_AVAILABLE") {
|
||||
throw e;
|
||||
this._log.warn("startup - adding gmp directory failed with " +
|
||||
e.name + " - sandboxing not available?", e);
|
||||
}
|
||||
this._log.warn(
|
||||
"startup - adding gmp directory failed with " +
|
||||
e.name +
|
||||
" - sandboxing not available?",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
let greDir = Services.dirsvc.get(NS_GRE_DIR,
|
||||
Ci.nsIFile);
|
||||
let greDir = Services.dirsvc.get(NS_GRE_DIR, Ci.nsIFile);
|
||||
let path = greDir.path;
|
||||
if (GMPUtils._isWindowsOnARM64()) {
|
||||
path = OS.Path.join(path, "i686");
|
||||
}
|
||||
let clearkeyPath = OS.Path.join(path,
|
||||
CLEARKEY_PLUGIN_ID,
|
||||
CLEARKEY_VERSION);
|
||||
this._log.info("startup - adding clearkey CDM directory " +
|
||||
clearkeyPath);
|
||||
let clearkeyPath = OS.Path.join(
|
||||
path,
|
||||
CLEARKEY_PLUGIN_ID,
|
||||
CLEARKEY_VERSION
|
||||
);
|
||||
this._log.info("startup - adding clearkey CDM directory " + clearkeyPath);
|
||||
gmpService.addPluginDirectory(clearkeyPath);
|
||||
} catch (e) {
|
||||
this._log.warn("startup - adding clearkey CDM failed", e);
|
||||
|
@ -654,8 +821,7 @@ var GMPProvider = {
|
|||
},
|
||||
|
||||
async getAddonsByTypes(aTypes) {
|
||||
if (!this.isEnabled ||
|
||||
(aTypes && !aTypes.includes("plugin"))) {
|
||||
if (!this.isEnabled || (aTypes && !aTypes.includes("plugin"))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
@ -700,8 +866,12 @@ var GMPProvider = {
|
|||
};
|
||||
|
||||
AddonManagerPrivate.registerProvider(GMPProvider, [
|
||||
new AddonManagerPrivate.AddonType("plugin", URI_EXTENSION_STRINGS,
|
||||
"type.plugin.name",
|
||||
AddonManager.VIEW_TYPE_LIST, 6000,
|
||||
AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE),
|
||||
new AddonManagerPrivate.AddonType(
|
||||
"plugin",
|
||||
URI_EXTENSION_STRINGS,
|
||||
"type.plugin.name",
|
||||
AddonManager.VIEW_TYPE_LIST,
|
||||
6000,
|
||||
AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE
|
||||
),
|
||||
]);
|
||||
|
|
|
@ -8,17 +8,23 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = [];
|
||||
|
||||
const {AddonManager, AddonManagerPrivate} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
|
||||
const { AddonManager, AddonManagerPrivate } = ChromeUtils.import(
|
||||
"resource://gre/modules/AddonManager.jsm"
|
||||
);
|
||||
/* globals AddonManagerPrivate*/
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Blocklist",
|
||||
"resource://gre/modules/Blocklist.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Blocklist",
|
||||
"resource://gre/modules/Blocklist.jsm"
|
||||
);
|
||||
|
||||
const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties";
|
||||
const LIST_UPDATED_TOPIC = "plugins-list-updated";
|
||||
const URI_EXTENSION_STRINGS =
|
||||
"chrome://mozapps/locale/extensions/extensions.properties";
|
||||
const LIST_UPDATED_TOPIC = "plugins-list-updated";
|
||||
|
||||
const {Log} = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const LOGGER_ID = "addons.plugins";
|
||||
|
||||
// Create a new logger for use by the Addons Plugin Provider
|
||||
|
@ -48,10 +54,11 @@ var PluginProvider = {
|
|||
|
||||
async observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case LIST_UPDATED_TOPIC:
|
||||
if (this.plugins)
|
||||
this.updatePluginList();
|
||||
break;
|
||||
case LIST_UPDATED_TOPIC:
|
||||
if (this.plugins) {
|
||||
this.updatePluginList();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -59,10 +66,12 @@ var PluginProvider = {
|
|||
* Creates a PluginWrapper for a plugin object.
|
||||
*/
|
||||
buildWrapper(aPlugin) {
|
||||
return new PluginWrapper(aPlugin.id,
|
||||
aPlugin.name,
|
||||
aPlugin.description,
|
||||
aPlugin.tags);
|
||||
return new PluginWrapper(
|
||||
aPlugin.id,
|
||||
aPlugin.name,
|
||||
aPlugin.description,
|
||||
aPlugin.tags
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -72,11 +81,13 @@ var PluginProvider = {
|
|||
* The ID of the add-on to retrieve
|
||||
*/
|
||||
async getAddonByID(aId) {
|
||||
if (!this.plugins)
|
||||
if (!this.plugins) {
|
||||
this.buildPluginList();
|
||||
}
|
||||
|
||||
if (aId in this.plugins)
|
||||
if (aId in this.plugins) {
|
||||
return this.buildWrapper(this.plugins[aId]);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
|
@ -91,11 +102,13 @@ var PluginProvider = {
|
|||
return [];
|
||||
}
|
||||
|
||||
if (!this.plugins)
|
||||
if (!this.plugins) {
|
||||
this.buildPluginList();
|
||||
}
|
||||
|
||||
return Promise.all(Object.keys(this.plugins).map(
|
||||
id => this.getAddonByID(id)));
|
||||
return Promise.all(
|
||||
Object.keys(this.plugins).map(id => this.getAddonByID(id))
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -114,15 +127,16 @@ var PluginProvider = {
|
|||
* @return a dictionary of plugins indexed by our generated ID
|
||||
*/
|
||||
getPluginList() {
|
||||
let tags = Cc["@mozilla.org/plugin/host;1"].
|
||||
getService(Ci.nsIPluginHost).
|
||||
getPluginTags();
|
||||
let tags = Cc["@mozilla.org/plugin/host;1"]
|
||||
.getService(Ci.nsIPluginHost)
|
||||
.getPluginTags();
|
||||
|
||||
let list = {};
|
||||
let seenPlugins = {};
|
||||
for (let tag of tags) {
|
||||
if (!(tag.name in seenPlugins))
|
||||
if (!(tag.name in seenPlugins)) {
|
||||
seenPlugins[tag.name] = {};
|
||||
}
|
||||
if (!(tag.description in seenPlugins[tag.name])) {
|
||||
let plugin = {
|
||||
id: tag.name + tag.description,
|
||||
|
@ -156,10 +170,12 @@ var PluginProvider = {
|
|||
updatePluginList() {
|
||||
let newList = this.getPluginList();
|
||||
|
||||
let lostPlugins = Object.keys(this.plugins).filter(id => !(id in newList)).
|
||||
map(id => this.buildWrapper(this.plugins[id]));
|
||||
let newPlugins = Object.keys(newList).filter(id => !(id in this.plugins)).
|
||||
map(id => this.buildWrapper(newList[id]));
|
||||
let lostPlugins = Object.keys(this.plugins)
|
||||
.filter(id => !(id in newList))
|
||||
.map(id => this.buildWrapper(this.plugins[id]));
|
||||
let newPlugins = Object.keys(newList)
|
||||
.filter(id => !(id in this.plugins))
|
||||
.map(id => this.buildWrapper(newList[id]));
|
||||
let matchedIDs = Object.keys(newList).filter(id => id in this.plugins);
|
||||
|
||||
// The plugin host generates new tags for every plugin after a scan and
|
||||
|
@ -172,40 +188,51 @@ var PluginProvider = {
|
|||
let newWrapper = this.buildWrapper(newList[id]);
|
||||
|
||||
if (newWrapper.isActive != oldWrapper.isActive) {
|
||||
AddonManagerPrivate.callAddonListeners(newWrapper.isActive ?
|
||||
"onEnabling" : "onDisabling",
|
||||
newWrapper, false);
|
||||
AddonManagerPrivate.callAddonListeners(
|
||||
newWrapper.isActive ? "onEnabling" : "onDisabling",
|
||||
newWrapper,
|
||||
false
|
||||
);
|
||||
changedWrappers.push(newWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
// Notify about new installs
|
||||
for (let plugin of newPlugins) {
|
||||
AddonManagerPrivate.callInstallListeners("onExternalInstall", null,
|
||||
plugin, null, false);
|
||||
AddonManagerPrivate.callInstallListeners(
|
||||
"onExternalInstall",
|
||||
null,
|
||||
plugin,
|
||||
null,
|
||||
false
|
||||
);
|
||||
AddonManagerPrivate.callAddonListeners("onInstalling", plugin, false);
|
||||
}
|
||||
|
||||
// Notify for any plugins that have vanished.
|
||||
for (let plugin of lostPlugins)
|
||||
for (let plugin of lostPlugins) {
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalling", plugin, false);
|
||||
}
|
||||
|
||||
this.plugins = newList;
|
||||
|
||||
// Signal that new installs are complete
|
||||
for (let plugin of newPlugins)
|
||||
for (let plugin of newPlugins) {
|
||||
AddonManagerPrivate.callAddonListeners("onInstalled", plugin);
|
||||
}
|
||||
|
||||
// Signal that enables/disables are complete
|
||||
for (let wrapper of changedWrappers) {
|
||||
AddonManagerPrivate.callAddonListeners(wrapper.isActive ?
|
||||
"onEnabled" : "onDisabled",
|
||||
wrapper);
|
||||
AddonManagerPrivate.callAddonListeners(
|
||||
wrapper.isActive ? "onEnabled" : "onDisabled",
|
||||
wrapper
|
||||
);
|
||||
}
|
||||
|
||||
// Signal that uninstalls are complete
|
||||
for (let plugin of lostPlugins)
|
||||
for (let plugin of lostPlugins) {
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalled", plugin);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -242,35 +269,48 @@ PluginWrapper.prototype = {
|
|||
},
|
||||
|
||||
get version() {
|
||||
let { tags: [tag] } = pluginFor(this);
|
||||
let {
|
||||
tags: [tag],
|
||||
} = pluginFor(this);
|
||||
return tag.version;
|
||||
},
|
||||
|
||||
get homepageURL() {
|
||||
let { description } = pluginFor(this);
|
||||
if (/<A\s+HREF=[^>]*>/i.test(description))
|
||||
if (/<A\s+HREF=[^>]*>/i.test(description)) {
|
||||
return /<A\s+HREF=["']?([^>"'\s]*)/i.exec(description)[1];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
get isActive() {
|
||||
let { tags: [tag] } = pluginFor(this);
|
||||
let {
|
||||
tags: [tag],
|
||||
} = pluginFor(this);
|
||||
return !tag.blocklisted && !tag.disabled;
|
||||
},
|
||||
|
||||
get appDisabled() {
|
||||
let { tags: [tag] } = pluginFor(this);
|
||||
let {
|
||||
tags: [tag],
|
||||
} = pluginFor(this);
|
||||
return tag.blocklisted;
|
||||
},
|
||||
|
||||
get userDisabled() {
|
||||
let { tags: [tag] } = pluginFor(this);
|
||||
if (tag.disabled)
|
||||
let {
|
||||
tags: [tag],
|
||||
} = pluginFor(this);
|
||||
if (tag.disabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tag.clicktoplay ||
|
||||
this.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE ||
|
||||
this.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE) {
|
||||
if (
|
||||
tag.clicktoplay ||
|
||||
this.blocklistState ==
|
||||
Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE ||
|
||||
this.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE
|
||||
) {
|
||||
return AddonManager.STATE_ASK_TO_ACTIVATE;
|
||||
}
|
||||
|
||||
|
@ -283,18 +323,20 @@ PluginWrapper.prototype = {
|
|||
val = AddonManager.STATE_ASK_TO_ACTIVATE;
|
||||
}
|
||||
|
||||
if (val === previousVal)
|
||||
if (val === previousVal) {
|
||||
return val;
|
||||
}
|
||||
|
||||
let { tags } = pluginFor(this);
|
||||
|
||||
for (let tag of tags) {
|
||||
if (val === true)
|
||||
if (val === true) {
|
||||
tag.enabledState = Ci.nsIPluginTag.STATE_DISABLED;
|
||||
else if (val === false)
|
||||
} else if (val === false) {
|
||||
tag.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
|
||||
else if (val == AddonManager.STATE_ASK_TO_ACTIVATE)
|
||||
} else if (val == AddonManager.STATE_ASK_TO_ACTIVATE) {
|
||||
tag.enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
|
||||
}
|
||||
}
|
||||
|
||||
// If 'userDisabled' was 'true' and we're going to a state that's not
|
||||
|
@ -313,9 +355,13 @@ PluginWrapper.prototype = {
|
|||
|
||||
// If the 'userDisabled' value involved AddonManager.STATE_ASK_TO_ACTIVATE,
|
||||
// call the onPropertyChanged listeners.
|
||||
if (previousVal == AddonManager.STATE_ASK_TO_ACTIVATE ||
|
||||
val == AddonManager.STATE_ASK_TO_ACTIVATE) {
|
||||
AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["userDisabled"]);
|
||||
if (
|
||||
previousVal == AddonManager.STATE_ASK_TO_ACTIVATE ||
|
||||
val == AddonManager.STATE_ASK_TO_ACTIVATE
|
||||
) {
|
||||
AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, [
|
||||
"userDisabled",
|
||||
]);
|
||||
}
|
||||
|
||||
return val;
|
||||
|
@ -329,26 +375,32 @@ PluginWrapper.prototype = {
|
|||
},
|
||||
|
||||
get blocklistState() {
|
||||
let { tags: [tag] } = pluginFor(this);
|
||||
let {
|
||||
tags: [tag],
|
||||
} = pluginFor(this);
|
||||
return tag.blocklistState;
|
||||
},
|
||||
|
||||
async getBlocklistURL() {
|
||||
let { tags: [tag] } = pluginFor(this);
|
||||
let {
|
||||
tags: [tag],
|
||||
} = pluginFor(this);
|
||||
return Blocklist.getPluginBlockURL(tag);
|
||||
},
|
||||
|
||||
get pluginLibraries() {
|
||||
let libs = [];
|
||||
for (let tag of pluginFor(this).tags)
|
||||
for (let tag of pluginFor(this).tags) {
|
||||
libs.push(tag.filename);
|
||||
}
|
||||
return libs;
|
||||
},
|
||||
|
||||
get pluginFullpath() {
|
||||
let paths = [];
|
||||
for (let tag of pluginFor(this).tags)
|
||||
for (let tag of pluginFor(this).tags) {
|
||||
paths.push(tag.fullpath);
|
||||
}
|
||||
return paths;
|
||||
},
|
||||
|
||||
|
@ -379,27 +431,33 @@ PluginWrapper.prototype = {
|
|||
},
|
||||
|
||||
get scope() {
|
||||
let { tags: [tag] } = pluginFor(this);
|
||||
let {
|
||||
tags: [tag],
|
||||
} = pluginFor(this);
|
||||
let path = tag.fullpath;
|
||||
// Plugins inside the application directory are in the application scope
|
||||
let dir = Services.dirsvc.get("APlugns", Ci.nsIFile);
|
||||
if (path.startsWith(dir.path))
|
||||
if (path.startsWith(dir.path)) {
|
||||
return AddonManager.SCOPE_APPLICATION;
|
||||
}
|
||||
|
||||
// Plugins inside the profile directory are in the profile scope
|
||||
dir = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
if (path.startsWith(dir.path))
|
||||
if (path.startsWith(dir.path)) {
|
||||
return AddonManager.SCOPE_PROFILE;
|
||||
}
|
||||
|
||||
// Plugins anywhere else in the user's home are in the user scope,
|
||||
// but not all platforms have a home directory.
|
||||
try {
|
||||
dir = Services.dirsvc.get("Home", Ci.nsIFile);
|
||||
if (path.startsWith(dir.path))
|
||||
if (path.startsWith(dir.path)) {
|
||||
return AddonManager.SCOPE_USER;
|
||||
}
|
||||
} catch (e) {
|
||||
if (!e.result || e.result != Cr.NS_ERROR_FAILURE)
|
||||
if (!e.result || e.result != Cr.NS_ERROR_FAILURE) {
|
||||
throw e;
|
||||
}
|
||||
// Do nothing: missing "Home".
|
||||
}
|
||||
|
||||
|
@ -416,14 +474,17 @@ PluginWrapper.prototype = {
|
|||
},
|
||||
|
||||
get permissions() {
|
||||
let { tags: [tag] } = pluginFor(this);
|
||||
let {
|
||||
tags: [tag],
|
||||
} = pluginFor(this);
|
||||
let permissions = 0;
|
||||
if (tag.isEnabledStateLocked) {
|
||||
return permissions;
|
||||
}
|
||||
if (!this.appDisabled) {
|
||||
if (this.userDisabled !== true)
|
||||
if (this.userDisabled !== true) {
|
||||
permissions |= AddonManager.PERM_CAN_DISABLE;
|
||||
}
|
||||
|
||||
if (this.userDisabled !== AddonManager.STATE_ASK_TO_ACTIVATE) {
|
||||
permissions |= AddonManager.PERM_CAN_ASK_TO_ACTIVATE;
|
||||
|
@ -431,9 +492,14 @@ PluginWrapper.prototype = {
|
|||
|
||||
let blocklistState = this.blocklistState;
|
||||
let isCTPBlocklisted =
|
||||
(blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE ||
|
||||
blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE);
|
||||
if (this.userDisabled !== false && !isCTPBlocklisted && !this.isFlashPlugin) {
|
||||
blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE ||
|
||||
blocklistState ==
|
||||
Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE;
|
||||
if (
|
||||
this.userDisabled !== false &&
|
||||
!isCTPBlocklisted &&
|
||||
!this.isFlashPlugin
|
||||
) {
|
||||
permissions |= AddonManager.PERM_CAN_ENABLE;
|
||||
}
|
||||
}
|
||||
|
@ -445,7 +511,10 @@ PluginWrapper.prototype = {
|
|||
},
|
||||
|
||||
get optionsURL() {
|
||||
return "chrome://mozapps/content/extensions/pluginPrefs.xul#id=" + encodeURIComponent(this.id);
|
||||
return (
|
||||
"chrome://mozapps/content/extensions/pluginPrefs.xul#id=" +
|
||||
encodeURIComponent(this.id)
|
||||
);
|
||||
},
|
||||
|
||||
get updateDate() {
|
||||
|
@ -469,7 +538,7 @@ PluginWrapper.prototype = {
|
|||
},
|
||||
|
||||
get installTelemetryInfo() {
|
||||
return {source: "plugin"};
|
||||
return { source: "plugin" };
|
||||
},
|
||||
|
||||
isCompatibleWith(aAppVersion, aPlatformVersion) {
|
||||
|
@ -477,12 +546,15 @@ PluginWrapper.prototype = {
|
|||
},
|
||||
|
||||
findUpdates(aListener, aReason, aAppVersion, aPlatformVersion) {
|
||||
if ("onNoCompatibilityUpdateAvailable" in aListener)
|
||||
if ("onNoCompatibilityUpdateAvailable" in aListener) {
|
||||
aListener.onNoCompatibilityUpdateAvailable(this);
|
||||
if ("onNoUpdateAvailable" in aListener)
|
||||
}
|
||||
if ("onNoUpdateAvailable" in aListener) {
|
||||
aListener.onNoUpdateAvailable(this);
|
||||
if ("onUpdateFinished" in aListener)
|
||||
}
|
||||
if ("onUpdateFinished" in aListener) {
|
||||
aListener.onUpdateFinished(this);
|
||||
}
|
||||
},
|
||||
|
||||
get isFlashPlugin() {
|
||||
|
@ -491,8 +563,12 @@ PluginWrapper.prototype = {
|
|||
};
|
||||
|
||||
AddonManagerPrivate.registerProvider(PluginProvider, [
|
||||
new AddonManagerPrivate.AddonType("plugin", URI_EXTENSION_STRINGS,
|
||||
"type.plugin.name",
|
||||
AddonManager.VIEW_TYPE_LIST, 6000,
|
||||
AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE),
|
||||
new AddonManagerPrivate.AddonType(
|
||||
"plugin",
|
||||
URI_EXTENSION_STRINGS,
|
||||
"type.plugin.name",
|
||||
AddonManager.VIEW_TYPE_LIST,
|
||||
6000,
|
||||
AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE
|
||||
),
|
||||
]);
|
||||
|
|
|
@ -6,35 +6,51 @@
|
|||
|
||||
/* exported ProductAddonChecker */
|
||||
|
||||
const LOCAL_GMP_SOURCES = [{
|
||||
"id": "gmp-gmpopenh264",
|
||||
"src": "chrome://global/content/gmp-sources/openh264.json",
|
||||
}, {
|
||||
"id": "gmp-widevinecdm",
|
||||
"src": "chrome://global/content/gmp-sources/widevinecdm.json",
|
||||
}];
|
||||
const LOCAL_GMP_SOURCES = [
|
||||
{
|
||||
id: "gmp-gmpopenh264",
|
||||
src: "chrome://global/content/gmp-sources/openh264.json",
|
||||
},
|
||||
{
|
||||
id: "gmp-widevinecdm",
|
||||
src: "chrome://global/content/gmp-sources/widevinecdm.json",
|
||||
},
|
||||
];
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "ProductAddonChecker" ];
|
||||
var EXPORTED_SYMBOLS = ["ProductAddonChecker"];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {Log} = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const {CertUtils} = ChromeUtils.import("resource://gre/modules/CertUtils.jsm");
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const { CertUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/CertUtils.jsm"
|
||||
);
|
||||
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
/* globals GMPPrefs */
|
||||
ChromeUtils.defineModuleGetter(this, "GMPPrefs",
|
||||
"resource://gre/modules/GMPUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"GMPPrefs",
|
||||
"resource://gre/modules/GMPUtils.jsm"
|
||||
);
|
||||
|
||||
/* globals OS */
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "UpdateUtils",
|
||||
"resource://gre/modules/UpdateUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"UpdateUtils",
|
||||
"resource://gre/modules/UpdateUtils.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "ServiceRequest",
|
||||
"resource://gre/modules/ServiceRequest.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ServiceRequest",
|
||||
"resource://gre/modules/ServiceRequest.jsm"
|
||||
);
|
||||
|
||||
// This exists so that tests can override the XHR behaviour for downloading
|
||||
// the addon update XML file.
|
||||
|
@ -68,8 +84,7 @@ function getRequestStatus(request) {
|
|||
let status = null;
|
||||
try {
|
||||
status = request.status;
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (status != null) {
|
||||
return status;
|
||||
|
@ -100,7 +115,9 @@ function downloadXML(url, allowNonBuiltIn = false, allowedCerts = null) {
|
|||
request = request.wrappedJSObject;
|
||||
}
|
||||
request.open("GET", url, true);
|
||||
request.channel.notificationCallbacks = new CertUtils.BadCertHandler(allowNonBuiltIn);
|
||||
request.channel.notificationCallbacks = new CertUtils.BadCertHandler(
|
||||
allowNonBuiltIn
|
||||
);
|
||||
// Prevent the request from reading from the cache.
|
||||
request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
// Prevent the request from writing to the cache.
|
||||
|
@ -110,7 +127,9 @@ function downloadXML(url, allowNonBuiltIn = false, allowedCerts = null) {
|
|||
// Use conservative TLS settings. See bug 1325501.
|
||||
// TODO move to ServiceRequest.
|
||||
if (request.channel instanceof Ci.nsIHttpChannelInternal) {
|
||||
request.channel.QueryInterface(Ci.nsIHttpChannelInternal).beConservative = true;
|
||||
request.channel.QueryInterface(
|
||||
Ci.nsIHttpChannelInternal
|
||||
).beConservative = true;
|
||||
}
|
||||
request.timeout = TIMEOUT_DELAY_MS;
|
||||
|
||||
|
@ -123,17 +142,18 @@ function downloadXML(url, allowNonBuiltIn = false, allowedCerts = null) {
|
|||
// might only implement Pragma: no-cache
|
||||
request.setRequestHeader("Pragma", "no-cache");
|
||||
|
||||
let fail = (event) => {
|
||||
let fail = event => {
|
||||
let request = event.target;
|
||||
let status = getRequestStatus(request);
|
||||
let message = "Failed downloading XML, status: " + status + ", reason: " + event.type;
|
||||
let message =
|
||||
"Failed downloading XML, status: " + status + ", reason: " + event.type;
|
||||
logger.warn(message);
|
||||
let ex = new Error(message);
|
||||
ex.status = status;
|
||||
reject(ex);
|
||||
};
|
||||
|
||||
let success = (event) => {
|
||||
let success = event => {
|
||||
logger.info("Completed downloading document");
|
||||
let request = event.target;
|
||||
|
||||
|
@ -162,7 +182,7 @@ function downloadXML(url, allowNonBuiltIn = false, allowedCerts = null) {
|
|||
function downloadJSON(uri) {
|
||||
logger.info("fetching config from: " + uri);
|
||||
return new Promise((resolve, reject) => {
|
||||
let xmlHttp = new ServiceRequest({mozAnon: true});
|
||||
let xmlHttp = new ServiceRequest({ mozAnon: true });
|
||||
|
||||
xmlHttp.onload = function(aResponse) {
|
||||
resolve(JSON.parse(this.responseText));
|
||||
|
@ -178,7 +198,6 @@ function downloadJSON(uri) {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses a list of add-ons from a DOM document.
|
||||
*
|
||||
|
@ -191,8 +210,11 @@ function downloadJSON(uri) {
|
|||
function parseXML(document) {
|
||||
// Check that the root element is correct
|
||||
if (document.documentElement.localName != "updates") {
|
||||
throw new Error("got node name: " + document.documentElement.localName +
|
||||
", expected: updates");
|
||||
throw new Error(
|
||||
"got node name: " +
|
||||
document.documentElement.localName +
|
||||
", expected: updates"
|
||||
);
|
||||
}
|
||||
|
||||
// Check if there are any addons elements in the updates element
|
||||
|
@ -206,7 +228,14 @@ function parseXML(document) {
|
|||
for (let addonElement of addonList) {
|
||||
let addon = {};
|
||||
|
||||
for (let name of ["id", "URL", "hashFunction", "hashValue", "version", "size"]) {
|
||||
for (let name of [
|
||||
"id",
|
||||
"URL",
|
||||
"hashFunction",
|
||||
"hashValue",
|
||||
"version",
|
||||
"size",
|
||||
]) {
|
||||
if (addonElement.hasAttribute(name)) {
|
||||
addon[name] = addonElement.getAttribute(name);
|
||||
}
|
||||
|
@ -229,42 +258,44 @@ function parseXML(document) {
|
|||
function downloadLocalConfig() {
|
||||
if (!GMPPrefs.getBool(GMPPrefs.KEY_UPDATE_ENABLED, true)) {
|
||||
logger.info("Updates are disabled via media.gmp-manager.updateEnabled");
|
||||
return Promise.resolve({usedFallback: true, gmpAddons: []});
|
||||
return Promise.resolve({ usedFallback: true, gmpAddons: [] });
|
||||
}
|
||||
|
||||
return Promise.all(LOCAL_GMP_SOURCES.map(conf => {
|
||||
return downloadJSON(conf.src).then(addons => {
|
||||
let platforms = addons.vendors[conf.id].platforms;
|
||||
let target = Services.appinfo.OS + "_" + UpdateUtils.ABI;
|
||||
let details = null;
|
||||
return Promise.all(
|
||||
LOCAL_GMP_SOURCES.map(conf => {
|
||||
return downloadJSON(conf.src).then(addons => {
|
||||
let platforms = addons.vendors[conf.id].platforms;
|
||||
let target = Services.appinfo.OS + "_" + UpdateUtils.ABI;
|
||||
let details = null;
|
||||
|
||||
while (!details) {
|
||||
if (!(target in platforms)) {
|
||||
// There was no matching platform so return false, this addon
|
||||
// will be filtered from the results below
|
||||
logger.info("no details found for: " + target);
|
||||
return false;
|
||||
while (!details) {
|
||||
if (!(target in platforms)) {
|
||||
// There was no matching platform so return false, this addon
|
||||
// will be filtered from the results below
|
||||
logger.info("no details found for: " + target);
|
||||
return false;
|
||||
}
|
||||
// Field either has the details of the binary or is an alias
|
||||
// to another build target key that does
|
||||
if (platforms[target].alias) {
|
||||
target = platforms[target].alias;
|
||||
} else {
|
||||
details = platforms[target];
|
||||
}
|
||||
}
|
||||
// Field either has the details of the binary or is an alias
|
||||
// to another build target key that does
|
||||
if (platforms[target].alias) {
|
||||
target = platforms[target].alias;
|
||||
} else {
|
||||
details = platforms[target];
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("found plugin: " + conf.id);
|
||||
return {
|
||||
"id": conf.id,
|
||||
"URL": details.fileUrl,
|
||||
"hashFunction": addons.hashFunction,
|
||||
"hashValue": details.hashValue,
|
||||
"version": addons.vendors[conf.id].version,
|
||||
"size": details.filesize,
|
||||
};
|
||||
});
|
||||
})).then(addons => {
|
||||
logger.info("found plugin: " + conf.id);
|
||||
return {
|
||||
id: conf.id,
|
||||
URL: details.fileUrl,
|
||||
hashFunction: addons.hashFunction,
|
||||
hashValue: details.hashValue,
|
||||
version: addons.vendors[conf.id].version,
|
||||
size: details.filesize,
|
||||
};
|
||||
});
|
||||
})
|
||||
).then(addons => {
|
||||
// Some filters may not match this platform so
|
||||
// filter those out
|
||||
addons = addons.filter(x => x !== false);
|
||||
|
@ -294,7 +325,9 @@ function downloadFile(url) {
|
|||
return;
|
||||
}
|
||||
(async function() {
|
||||
let f = await OS.File.openUnique(OS.Path.join(OS.Constants.Path.tmpDir, "tmpaddon"));
|
||||
let f = await OS.File.openUnique(
|
||||
OS.Path.join(OS.Constants.Path.tmpDir, "tmpaddon")
|
||||
);
|
||||
let path = f.path;
|
||||
logger.info(`Downloaded file will be saved to ${path}`);
|
||||
await f.file.close();
|
||||
|
@ -303,10 +336,14 @@ function downloadFile(url) {
|
|||
})().then(resolve, reject);
|
||||
};
|
||||
|
||||
let fail = (event) => {
|
||||
let fail = event => {
|
||||
let request = event.target;
|
||||
let status = getRequestStatus(request);
|
||||
let message = "Failed downloading via XHR, status: " + status + ", reason: " + event.type;
|
||||
let message =
|
||||
"Failed downloading via XHR, status: " +
|
||||
status +
|
||||
", reason: " +
|
||||
event.type;
|
||||
logger.warn(message);
|
||||
let ex = new Error(message);
|
||||
ex.status = status;
|
||||
|
@ -321,7 +358,9 @@ function downloadFile(url) {
|
|||
// Use conservative TLS settings. See bug 1325501.
|
||||
// TODO move to ServiceRequest.
|
||||
if (xhr.channel instanceof Ci.nsIHttpChannelInternal) {
|
||||
xhr.channel.QueryInterface(Ci.nsIHttpChannelInternal).beConservative = true;
|
||||
xhr.channel.QueryInterface(
|
||||
Ci.nsIHttpChannelInternal
|
||||
).beConservative = true;
|
||||
}
|
||||
xhr.send(null);
|
||||
} catch (ex) {
|
||||
|
@ -358,8 +397,9 @@ function binaryToHex(input) {
|
|||
var computeHash = async function(hashFunction, path) {
|
||||
let file = await OS.File.open(path, { existing: true, read: true });
|
||||
try {
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"].
|
||||
createInstance(Ci.nsICryptoHash);
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
|
||||
Ci.nsICryptoHash
|
||||
);
|
||||
hasher.initWithString(hashFunction);
|
||||
|
||||
let bytes;
|
||||
|
@ -389,7 +429,13 @@ var verifyFile = async function(properties, path) {
|
|||
if (properties.size !== undefined) {
|
||||
let stat = await OS.File.stat(path);
|
||||
if (stat.size != properties.size) {
|
||||
throw new Error("Downloaded file was " + stat.size + " bytes but expected " + properties.size + " bytes.");
|
||||
throw new Error(
|
||||
"Downloaded file was " +
|
||||
stat.size +
|
||||
" bytes but expected " +
|
||||
properties.size +
|
||||
" bytes."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,7 +443,9 @@ var verifyFile = async function(properties, path) {
|
|||
let expectedDigest = properties.hashValue.toLowerCase();
|
||||
let digest = await computeHash(properties.hashFunction, path);
|
||||
if (digest != expectedDigest) {
|
||||
throw new Error("Hash was `" + digest + "` but expected `" + expectedDigest + "`.");
|
||||
throw new Error(
|
||||
"Hash was `" + digest + "` but expected `" + expectedDigest + "`."
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -421,7 +469,7 @@ const ProductAddonChecker = {
|
|||
getProductAddonList(url, allowNonBuiltIn = false, allowedCerts = null) {
|
||||
if (!GMPPrefs.getBool(GMPPrefs.KEY_UPDATE_ENABLED, true)) {
|
||||
logger.info("Updates are disabled via media.gmp-manager.updateEnabled");
|
||||
return Promise.resolve({usedFallback: true, gmpAddons: []});
|
||||
return Promise.resolve({ usedFallback: true, gmpAddons: [] });
|
||||
}
|
||||
|
||||
return downloadXML(url, allowNonBuiltIn, allowedCerts)
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -5,7 +5,9 @@
|
|||
// Test plugin blocking.
|
||||
|
||||
const gHttpTestRoot = "http://127.0.0.1:8888/" + RELATIVE_DIR + "/";
|
||||
const {AddonTestUtils} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
|
||||
function updateBlocklist(aURL, aCallback) {
|
||||
var observer = function() {
|
||||
|
@ -16,19 +18,24 @@ function updateBlocklist(aURL, aCallback) {
|
|||
if (Services.prefs.getBoolPref("extensions.blocklist.useXML", true)) {
|
||||
info("Loading plugin data " + aURL + " using xml implementation.");
|
||||
Services.prefs.setCharPref("extensions.blocklist.url", aURL);
|
||||
var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
|
||||
.getService(Ci.nsITimerCallback);
|
||||
var blocklistNotifier = Cc[
|
||||
"@mozilla.org/extensions/blocklist;1"
|
||||
].getService(Ci.nsITimerCallback);
|
||||
blocklistNotifier.notify(null);
|
||||
} else {
|
||||
info("Loading plugin data " + aURL + " using remote settings.");
|
||||
if (aURL.endsWith("blockNoPlugins.xml")) {
|
||||
AddonTestUtils.loadBlocklistRawData({plugins: []});
|
||||
AddonTestUtils.loadBlocklistRawData({ plugins: [] });
|
||||
} else if (aURL.endsWith("blockPluginHard.xml")) {
|
||||
AddonTestUtils.loadBlocklistRawData({plugins: [{
|
||||
matchFilename: "libnptest\\.so|nptest\\.dll|Test\\.plugin",
|
||||
versionRange: [{"severity": "2"}],
|
||||
blockID: "p9999",
|
||||
}]});
|
||||
AddonTestUtils.loadBlocklistRawData({
|
||||
plugins: [
|
||||
{
|
||||
matchFilename: "libnptest\\.so|nptest\\.dll|Test\\.plugin",
|
||||
versionRange: [{ severity: "2" }],
|
||||
blockID: "p9999",
|
||||
},
|
||||
],
|
||||
});
|
||||
} else {
|
||||
ok(false, "Should never be asked to update to unknown blocklist data.");
|
||||
}
|
||||
|
@ -38,7 +45,9 @@ function updateBlocklist(aURL, aCallback) {
|
|||
var _originalBlocklistURL = null;
|
||||
function setAndUpdateBlocklist(aURL, aCallback) {
|
||||
if (!_originalBlocklistURL) {
|
||||
_originalBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
|
||||
_originalBlocklistURL = Services.prefs.getCharPref(
|
||||
"extensions.blocklist.url"
|
||||
);
|
||||
}
|
||||
updateBlocklist(aURL, aCallback);
|
||||
}
|
||||
|
@ -48,23 +57,37 @@ function resetBlocklist() {
|
|||
}
|
||||
|
||||
function getXULPluginUI(plugin, anonid) {
|
||||
if (plugin.openOrClosedShadowRoot &&
|
||||
plugin.openOrClosedShadowRoot.isUAWidget()) {
|
||||
if (
|
||||
plugin.openOrClosedShadowRoot &&
|
||||
plugin.openOrClosedShadowRoot.isUAWidget()
|
||||
) {
|
||||
return plugin.openOrClosedShadowRoot.getElementById(anonid);
|
||||
}
|
||||
return plugin.ownerDocument.
|
||||
getAnonymousElementByAttribute(plugin, "anonid", anonid);
|
||||
return plugin.ownerDocument.getAnonymousElementByAttribute(
|
||||
plugin,
|
||||
"anonid",
|
||||
anonid
|
||||
);
|
||||
}
|
||||
|
||||
function assertPluginActiveState({managerWindow, pluginId, expectedActivateState}) {
|
||||
function assertPluginActiveState({
|
||||
managerWindow,
|
||||
pluginId,
|
||||
expectedActivateState,
|
||||
}) {
|
||||
let pluginEl = get_addon_element(managerWindow, pluginId);
|
||||
ok(pluginEl, `Got the about:addon entry for "${pluginId}"`);
|
||||
|
||||
if (managerWindow.useHtmlViews) {
|
||||
const pluginOptions = pluginEl.querySelector("plugin-options");
|
||||
const pluginCheckedItem = pluginOptions.querySelector("panel-item[checked]");
|
||||
is(pluginCheckedItem.getAttribute("action"), expectedActivateState,
|
||||
`plugin should have ${expectedActivateState} state selected`);
|
||||
const pluginCheckedItem = pluginOptions.querySelector(
|
||||
"panel-item[checked]"
|
||||
);
|
||||
is(
|
||||
pluginCheckedItem.getAttribute("action"),
|
||||
expectedActivateState,
|
||||
`plugin should have ${expectedActivateState} state selected`
|
||||
);
|
||||
} else {
|
||||
// Assertions for the XUL about:addons views.
|
||||
pluginEl.parentNode.ensureElementIsVisible(pluginEl);
|
||||
|
@ -74,13 +97,23 @@ function assertPluginActiveState({managerWindow, pluginId, expectedActivateState
|
|||
is_element_hidden(disableButton, "disable button should be hidden");
|
||||
let menu = getXULPluginUI(pluginEl, "state-menulist");
|
||||
is_element_visible(menu, "state menu should be visible");
|
||||
let activateItem = getXULPluginUI(pluginEl, `${expectedActivateState}-menuitem`);
|
||||
ok(activateItem, `Got a menu item for the ${expectedActivateState} plugin activate state`);
|
||||
is(menu.selectedItem, activateItem, `state menu should have '${expectedActivateState}' selected`);
|
||||
let activateItem = getXULPluginUI(
|
||||
pluginEl,
|
||||
`${expectedActivateState}-menuitem`
|
||||
);
|
||||
ok(
|
||||
activateItem,
|
||||
`Got a menu item for the ${expectedActivateState} plugin activate state`
|
||||
);
|
||||
is(
|
||||
menu.selectedItem,
|
||||
activateItem,
|
||||
`state menu should have '${expectedActivateState}' selected`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function setPluginActivateState({managerWindow, pluginId, activateState}) {
|
||||
function setPluginActivateState({ managerWindow, pluginId, activateState }) {
|
||||
let pluginEl = get_addon_element(managerWindow, pluginId);
|
||||
ok(pluginEl, `Got the about:addon entry for "${pluginId}"`);
|
||||
|
||||
|
@ -92,14 +125,17 @@ function setPluginActivateState({managerWindow, pluginId, activateState}) {
|
|||
} else {
|
||||
// Activate plugin on the XUL about:addons views.
|
||||
let activateItem = getXULPluginUI(pluginEl, `${activateState}-menuitem`);
|
||||
ok(activateItem, `Got a menu item for the ${activateState} plugin activate state`);
|
||||
ok(
|
||||
activateItem,
|
||||
`Got a menu item for the ${activateState} plugin activate state`
|
||||
);
|
||||
let menu = getXULPluginUI(pluginEl, "state-menulist");
|
||||
menu.selectedItem = activateItem;
|
||||
activateItem.doCommand();
|
||||
}
|
||||
}
|
||||
|
||||
async function assertPluginAppDisabled({managerWindow, pluginId}) {
|
||||
async function assertPluginAppDisabled({ managerWindow, pluginId }) {
|
||||
const pluginEl = get_addon_element(managerWindow, pluginId);
|
||||
ok(pluginEl, `Got the about:addon entry for "${pluginId}"`);
|
||||
|
||||
|
@ -109,12 +145,19 @@ async function assertPluginAppDisabled({managerWindow, pluginId}) {
|
|||
pluginOptions.querySelector("panel-list").open = true;
|
||||
// tests all buttons disabled (besides the checked one and the expand action)
|
||||
// are expected to be disabled if locked is true.
|
||||
for (const item of pluginOptions.querySelectorAll("panel-item:not([hidden])")) {
|
||||
for (const item of pluginOptions.querySelectorAll(
|
||||
"panel-item:not([hidden])"
|
||||
)) {
|
||||
const actionName = item.getAttribute("action");
|
||||
if (!item.hasAttribute("checked") && actionName !== "expand" &&
|
||||
actionName !== "preferences") {
|
||||
ok(item.shadowRoot.querySelector("button").disabled,
|
||||
`Plugin action "${actionName}" should be disabled`);
|
||||
if (
|
||||
!item.hasAttribute("checked") &&
|
||||
actionName !== "expand" &&
|
||||
actionName !== "preferences"
|
||||
) {
|
||||
ok(
|
||||
item.shadowRoot.querySelector("button").disabled,
|
||||
`Plugin action "${actionName}" should be disabled`
|
||||
);
|
||||
}
|
||||
}
|
||||
pluginOptions.querySelector("panel-list").open = false;
|
||||
|
@ -165,11 +208,18 @@ async function test_CTP_plugins(aboutAddonsType) {
|
|||
expectedActivateState: "ask-to-activate",
|
||||
});
|
||||
|
||||
let pluginTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, gHttpTestRoot + "plugin_test.html");
|
||||
let pluginTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
gHttpTestRoot + "plugin_test.html"
|
||||
);
|
||||
let pluginBrowser = pluginTab.linkedBrowser;
|
||||
|
||||
let condition = () => PopupNotifications.getNotification("click-to-play-plugins", pluginBrowser);
|
||||
await BrowserTestUtils.waitForCondition(condition, "part4: should have a click-to-play notification");
|
||||
let condition = () =>
|
||||
PopupNotifications.getNotification("click-to-play-plugins", pluginBrowser);
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
condition,
|
||||
"part4: should have a click-to-play notification"
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(pluginTab);
|
||||
|
||||
|
@ -179,14 +229,22 @@ async function test_CTP_plugins(aboutAddonsType) {
|
|||
activateState: "always-activate",
|
||||
});
|
||||
|
||||
pluginTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, gHttpTestRoot + "plugin_test.html");
|
||||
pluginTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
gHttpTestRoot + "plugin_test.html"
|
||||
);
|
||||
|
||||
await ContentTask.spawn(pluginTab.linkedBrowser, null, async function() {
|
||||
let testPlugin = content.document.getElementById("test");
|
||||
ok(testPlugin, "part5: should have a plugin element in the page");
|
||||
let objLoadingContent = testPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
let objLoadingContent = testPlugin.QueryInterface(
|
||||
Ci.nsIObjectLoadingContent
|
||||
);
|
||||
let condition = () => objLoadingContent.activated;
|
||||
await ContentTaskUtils.waitForCondition(condition, "part5: waited too long for plugin to activate");
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
condition,
|
||||
"part5: waited too long for plugin to activate"
|
||||
);
|
||||
ok(objLoadingContent.activated, "part6: plugin should be activated");
|
||||
});
|
||||
|
||||
|
@ -198,13 +256,18 @@ async function test_CTP_plugins(aboutAddonsType) {
|
|||
activateState: "never-activate",
|
||||
});
|
||||
|
||||
pluginTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, gHttpTestRoot + "plugin_test.html");
|
||||
pluginTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
gHttpTestRoot + "plugin_test.html"
|
||||
);
|
||||
pluginBrowser = pluginTab.linkedBrowser;
|
||||
|
||||
await ContentTask.spawn(pluginTab.linkedBrowser, null, async function() {
|
||||
let testPlugin = content.document.getElementById("test");
|
||||
ok(testPlugin, "part7: should have a plugin element in the page");
|
||||
let objLoadingContent = testPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
let objLoadingContent = testPlugin.QueryInterface(
|
||||
Ci.nsIObjectLoadingContent
|
||||
);
|
||||
ok(!objLoadingContent.activated, "part7: plugin should not be activated");
|
||||
});
|
||||
|
||||
|
@ -224,15 +287,23 @@ async function test_CTP_plugins(aboutAddonsType) {
|
|||
activateState: "always-activate",
|
||||
});
|
||||
|
||||
pluginTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, gHttpTestRoot + "plugin_test.html");
|
||||
pluginTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
gHttpTestRoot + "plugin_test.html"
|
||||
);
|
||||
pluginBrowser = pluginTab.linkedBrowser;
|
||||
|
||||
await ContentTask.spawn(pluginTab.linkedBrowser, null, async function() {
|
||||
let testPlugin = content.document.getElementById("test");
|
||||
ok(testPlugin, "part9: should have a plugin element in the page");
|
||||
let objLoadingContent = testPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
let objLoadingContent = testPlugin.QueryInterface(
|
||||
Ci.nsIObjectLoadingContent
|
||||
);
|
||||
let condition = () => objLoadingContent.activated;
|
||||
await ContentTaskUtils.waitForCondition(condition, "part9: waited too long for plugin to activate");
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
condition,
|
||||
"part9: waited too long for plugin to activate"
|
||||
);
|
||||
ok(objLoadingContent.activated, "part10: plugin should be activated");
|
||||
});
|
||||
|
||||
|
@ -244,11 +315,18 @@ async function test_CTP_plugins(aboutAddonsType) {
|
|||
activateState: "ask-to-activate",
|
||||
});
|
||||
|
||||
pluginTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, gHttpTestRoot + "plugin_test.html");
|
||||
pluginTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
gHttpTestRoot + "plugin_test.html"
|
||||
);
|
||||
pluginBrowser = pluginTab.linkedBrowser;
|
||||
|
||||
condition = () => PopupNotifications.getNotification("click-to-play-plugins", pluginBrowser);
|
||||
await BrowserTestUtils.waitForCondition(condition, "part11: should have a click-to-play notification");
|
||||
condition = () =>
|
||||
PopupNotifications.getNotification("click-to-play-plugins", pluginBrowser);
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
condition,
|
||||
"part11: should have a click-to-play notification"
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(pluginTab);
|
||||
await close_manager(managerWindow);
|
||||
|
@ -321,7 +399,7 @@ async function checkPlugins() {
|
|||
set: [["extensions.htmlaboutaddons.enabled", false]],
|
||||
});
|
||||
managerWindow = await open_manager("addons://list/plugin");
|
||||
await assertPluginAppDisabled({managerWindow, pluginId: testPluginId});
|
||||
await assertPluginAppDisabled({ managerWindow, pluginId: testPluginId });
|
||||
await close_manager(managerWindow);
|
||||
|
||||
info("Test blocklisted plugin actions disabled in HTML about:addons");
|
||||
|
@ -329,6 +407,6 @@ async function checkPlugins() {
|
|||
set: [["extensions.htmlaboutaddons.enabled", true]],
|
||||
});
|
||||
managerWindow = await open_manager("addons://list/plugin");
|
||||
await assertPluginAppDisabled({managerWindow, pluginId: testPluginId});
|
||||
await assertPluginAppDisabled({ managerWindow, pluginId: testPluginId });
|
||||
await close_manager(managerWindow);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {PromiseTestUtils} = ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm");
|
||||
const { PromiseTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/PromiseTestUtils.jsm"
|
||||
);
|
||||
// Whitelist rejections related to closing an about:debugging too soon after it has been
|
||||
// just opened in a new tab and loaded.
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Connection closed/);
|
||||
|
@ -50,7 +52,7 @@ add_task(async function testAboutDebugging() {
|
|||
let aboutDebuggingTab = gBrowser.selectedTab;
|
||||
|
||||
if (newAboutAddons) {
|
||||
const {AboutDebugging} = aboutDebuggingTab.linkedBrowser.contentWindow;
|
||||
const { AboutDebugging } = aboutDebuggingTab.linkedBrowser.contentWindow;
|
||||
// Avoid test failures due to closing the about:debugging tab
|
||||
// while it is still initializing.
|
||||
info("Wait until about:debugging actions are finished");
|
||||
|
@ -63,7 +65,8 @@ add_task(async function testAboutDebugging() {
|
|||
|
||||
info("Re-open about:debugging");
|
||||
let switched = TestUtils.waitForCondition(
|
||||
() => gBrowser.selectedTab == aboutDebuggingTab);
|
||||
() => gBrowser.selectedTab == aboutDebuggingTab
|
||||
);
|
||||
debugAddonsBtn.doCommand();
|
||||
await switched;
|
||||
|
||||
|
|
|
@ -1,62 +1,83 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const URI_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
|
||||
const URI_BLOCKLIST_DIALOG =
|
||||
"chrome://mozapps/content/extensions/blocklist.xul";
|
||||
|
||||
// This tests that the blocklist dialog still affects soft-blocked add-ons
|
||||
// if the user clicks the "Restart Later" button. It also ensures that the
|
||||
// "Cancel" button is correctly renamed (to "Restart Later").
|
||||
var args = {
|
||||
restart: false,
|
||||
list: [{
|
||||
name: "Bug 523784 softblocked addon",
|
||||
version: "1",
|
||||
icon: "chrome://global/skin/plugins/pluginGeneric.svg",
|
||||
disable: false,
|
||||
blocked: false,
|
||||
url: "http://example.com/bug523784_1",
|
||||
}],
|
||||
list: [
|
||||
{
|
||||
name: "Bug 523784 softblocked addon",
|
||||
version: "1",
|
||||
icon: "chrome://global/skin/plugins/pluginGeneric.svg",
|
||||
disable: false,
|
||||
blocked: false,
|
||||
url: "http://example.com/bug523784_1",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let windowObserver = function(aSubject, aTopic, aData) {
|
||||
if (aTopic != "domwindowopened")
|
||||
if (aTopic != "domwindowopened") {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.ww.unregisterNotification(windowObserver);
|
||||
|
||||
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
|
||||
win.addEventListener("load", function() {
|
||||
executeSoon(() => bug523784_test1(win));
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
executeSoon(() => bug523784_test1(win));
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
};
|
||||
Services.ww.registerNotification(windowObserver);
|
||||
|
||||
args.wrappedJSObject = args;
|
||||
Services.ww.openWindow(null, URI_BLOCKLIST_DIALOG, "",
|
||||
"chrome,centerscreen,dialog,titlebar", args);
|
||||
Services.ww.openWindow(
|
||||
null,
|
||||
URI_BLOCKLIST_DIALOG,
|
||||
"",
|
||||
"chrome,centerscreen,dialog,titlebar",
|
||||
args
|
||||
);
|
||||
}
|
||||
|
||||
function bug523784_test1(win) {
|
||||
let bundle = Services.strings.
|
||||
createBundle("chrome://mozapps/locale/update/updates.properties");
|
||||
let bundle = Services.strings.createBundle(
|
||||
"chrome://mozapps/locale/update/updates.properties"
|
||||
);
|
||||
let cancelButton = win.document.documentElement.getButton("cancel");
|
||||
let moreInfoLink = win.document.getElementById("moreInfo");
|
||||
|
||||
is(cancelButton.getAttribute("label"),
|
||||
bundle.GetStringFromName("restartLaterButton"),
|
||||
"Text should be changed on Cancel button");
|
||||
is(cancelButton.getAttribute("accesskey"),
|
||||
bundle.GetStringFromName("restartLaterButton.accesskey"),
|
||||
"Accesskey should also be changed on Cancel button");
|
||||
is(moreInfoLink.getAttribute("href"),
|
||||
"http://example.com/bug523784_1",
|
||||
"More Info link should link to a detailed blocklist page.");
|
||||
is(
|
||||
cancelButton.getAttribute("label"),
|
||||
bundle.GetStringFromName("restartLaterButton"),
|
||||
"Text should be changed on Cancel button"
|
||||
);
|
||||
is(
|
||||
cancelButton.getAttribute("accesskey"),
|
||||
bundle.GetStringFromName("restartLaterButton.accesskey"),
|
||||
"Accesskey should also be changed on Cancel button"
|
||||
);
|
||||
is(
|
||||
moreInfoLink.getAttribute("href"),
|
||||
"http://example.com/bug523784_1",
|
||||
"More Info link should link to a detailed blocklist page."
|
||||
);
|
||||
let windowObserver = function(aSubject, aTopic, aData) {
|
||||
if (aTopic != "domwindowclosed")
|
||||
if (aTopic != "domwindowclosed") {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.ww.unregisterNotification(windowObserver);
|
||||
|
||||
|
@ -72,22 +93,31 @@ function bug523784_test1(win) {
|
|||
|
||||
function bug523784_test2(win) {
|
||||
let windowObserver = function(aSubject, aTopic, aData) {
|
||||
if (aTopic != "domwindowopened")
|
||||
if (aTopic != "domwindowopened") {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.ww.unregisterNotification(windowObserver);
|
||||
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
|
||||
win.addEventListener("load", function() {
|
||||
executeSoon(function() {
|
||||
let moreInfoLink = win.document.getElementById("moreInfo");
|
||||
let cancelButton = win.document.documentElement.getButton("cancel");
|
||||
is(moreInfoLink.getAttribute("href"),
|
||||
Services.urlFormatter.formatURLPref("extensions.blocklist.detailsURL"),
|
||||
"More Info link should link to the general blocklist page.");
|
||||
cancelButton.doCommand();
|
||||
executeSoon(finish);
|
||||
});
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
executeSoon(function() {
|
||||
let moreInfoLink = win.document.getElementById("moreInfo");
|
||||
let cancelButton = win.document.documentElement.getButton("cancel");
|
||||
is(
|
||||
moreInfoLink.getAttribute("href"),
|
||||
Services.urlFormatter.formatURLPref(
|
||||
"extensions.blocklist.detailsURL"
|
||||
),
|
||||
"More Info link should link to the general blocklist page."
|
||||
);
|
||||
cancelButton.doCommand();
|
||||
executeSoon(finish);
|
||||
});
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
};
|
||||
Services.ww.registerNotification(windowObserver);
|
||||
|
||||
|
@ -111,6 +141,11 @@ function bug523784_test2(win) {
|
|||
});
|
||||
|
||||
args.wrappedJSObject = args;
|
||||
Services.ww.openWindow(null, URI_BLOCKLIST_DIALOG, "",
|
||||
"chrome,centerscreen,dialog,titlebar", args);
|
||||
Services.ww.openWindow(
|
||||
null,
|
||||
URI_BLOCKLIST_DIALOG,
|
||||
"",
|
||||
"chrome,centerscreen,dialog,titlebar",
|
||||
args
|
||||
);
|
||||
}
|
||||
|
|
|
@ -20,39 +20,59 @@ async function test() {
|
|||
var addonPrefsURI = CHROMEROOT + "addon_prefs.xul";
|
||||
|
||||
var gProvider = new MockProvider();
|
||||
gProvider.createAddons([{
|
||||
id: "test1@tests.mozilla.org",
|
||||
name: "Test add-on 1",
|
||||
description: "foo",
|
||||
},
|
||||
{
|
||||
id: "test2@tests.mozilla.org",
|
||||
name: "Test add-on 2",
|
||||
description: "bar",
|
||||
optionsURL: addonPrefsURI,
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "test1@tests.mozilla.org",
|
||||
name: "Test add-on 1",
|
||||
description: "foo",
|
||||
},
|
||||
{
|
||||
id: "test2@tests.mozilla.org",
|
||||
name: "Test add-on 2",
|
||||
description: "bar",
|
||||
optionsURL: addonPrefsURI,
|
||||
},
|
||||
]);
|
||||
|
||||
let aManager = await open_manager("addons://list/extension");
|
||||
var addonList = aManager.document.getElementById("addon-list");
|
||||
for (var addonItem of addonList.childNodes) {
|
||||
if (addonItem.hasAttribute("name") &&
|
||||
addonItem.getAttribute("name") == "Test add-on 1")
|
||||
if (
|
||||
addonItem.hasAttribute("name") &&
|
||||
addonItem.getAttribute("name") == "Test add-on 1"
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var prefsBtn = aManager.document.getAnonymousElementByAttribute(addonItem,
|
||||
"anonid",
|
||||
"preferences-btn");
|
||||
is(prefsBtn.hidden, true, "Prefs button should be hidden for addon with no optionsURL set");
|
||||
var prefsBtn = aManager.document.getAnonymousElementByAttribute(
|
||||
addonItem,
|
||||
"anonid",
|
||||
"preferences-btn"
|
||||
);
|
||||
is(
|
||||
prefsBtn.hidden,
|
||||
true,
|
||||
"Prefs button should be hidden for addon with no optionsURL set"
|
||||
);
|
||||
|
||||
for (addonItem of addonList.childNodes) {
|
||||
if (addonItem.hasAttribute("name") &&
|
||||
addonItem.getAttribute("name") == "Test add-on 2")
|
||||
if (
|
||||
addonItem.hasAttribute("name") &&
|
||||
addonItem.getAttribute("name") == "Test add-on 2"
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
prefsBtn = aManager.document.getAnonymousElementByAttribute(addonItem,
|
||||
"anonid",
|
||||
"preferences-btn");
|
||||
is(prefsBtn.hidden, true, "Prefs button should not be shown for addon with just an optionsURL set");
|
||||
prefsBtn = aManager.document.getAnonymousElementByAttribute(
|
||||
addonItem,
|
||||
"anonid",
|
||||
"preferences-btn"
|
||||
);
|
||||
is(
|
||||
prefsBtn.hidden,
|
||||
true,
|
||||
"Prefs button should not be shown for addon with just an optionsURL set"
|
||||
);
|
||||
|
||||
close_manager(aManager, finish);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
// Simulates quickly switching between different list views to verify that only
|
||||
// the last selected is displayed
|
||||
|
||||
const {PromiseTestUtils} = ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm");
|
||||
const { PromiseTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/PromiseTestUtils.jsm"
|
||||
);
|
||||
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/this\._errorLink/);
|
||||
|
||||
|
|
|
@ -14,11 +14,19 @@ async function checkInstallConfirmation(...names) {
|
|||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
var installInfo = aSubject.wrappedJSObject;
|
||||
isnot(installInfo.browser, null, "Notification should have non-null browser");
|
||||
Assert.deepEqual(installInfo.installs[0].installTelemetryInfo, {
|
||||
source: "about:addons",
|
||||
method: "install-from-file",
|
||||
}, "Got the expected installTelemetryInfo");
|
||||
isnot(
|
||||
installInfo.browser,
|
||||
null,
|
||||
"Notification should have non-null browser"
|
||||
);
|
||||
Assert.deepEqual(
|
||||
installInfo.installs[0].installTelemetryInfo,
|
||||
{
|
||||
source: "about:addons",
|
||||
method: "install-from-file",
|
||||
},
|
||||
"Got the expected installTelemetryInfo"
|
||||
);
|
||||
notificationCount++;
|
||||
},
|
||||
};
|
||||
|
@ -34,7 +42,9 @@ async function checkInstallConfirmation(...names) {
|
|||
|
||||
info(`Saw install for ${name}`);
|
||||
if (results.length < names.length) {
|
||||
info(`Waiting for installs for ${names.filter(n => !results.includes(n))}`);
|
||||
info(
|
||||
`Waiting for installs for ${names.filter(n => !results.includes(n))}`
|
||||
);
|
||||
|
||||
promise = promisePopupNotificationShown("addon-webext-permissions");
|
||||
}
|
||||
|
@ -43,7 +53,11 @@ async function checkInstallConfirmation(...names) {
|
|||
|
||||
Assert.deepEqual(results.sort(), names.sort(), "Got expected installs");
|
||||
|
||||
is(notificationCount, names.length, `Saw ${names.length} addon-install-started notification`);
|
||||
is(
|
||||
notificationCount,
|
||||
names.length,
|
||||
`Saw ${names.length} addon-install-started notification`
|
||||
);
|
||||
Services.obs.removeObserver(observer, "addon-install-started");
|
||||
}
|
||||
|
||||
|
@ -51,9 +65,9 @@ add_task(async function test_install_from_file() {
|
|||
gManagerWindow = await open_manager("addons://list/extension");
|
||||
|
||||
var filePaths = [
|
||||
get_addon_file_url("browser_dragdrop1.xpi"),
|
||||
get_addon_file_url("browser_dragdrop2.xpi"),
|
||||
];
|
||||
get_addon_file_url("browser_dragdrop1.xpi"),
|
||||
get_addon_file_url("browser_dragdrop2.xpi"),
|
||||
];
|
||||
for (let uri of filePaths) {
|
||||
ok(uri.file != null, `Should have file for ${uri.spec}`);
|
||||
ok(uri.file instanceof Ci.nsIFile, `Should have nsIFile for ${uri.spec}`);
|
||||
|
@ -62,7 +76,10 @@ add_task(async function test_install_from_file() {
|
|||
|
||||
// Set handler that executes the core test after the window opens,
|
||||
// and resolves the promise when the window closes
|
||||
let pInstallURIClosed = checkInstallConfirmation("Drag Drop test 1", "Drag Drop test 2");
|
||||
let pInstallURIClosed = checkInstallConfirmation(
|
||||
"Drag Drop test 1",
|
||||
"Drag Drop test 2"
|
||||
);
|
||||
|
||||
gManagerWindow.gViewController.doCommand("cmd_installFromFile");
|
||||
|
||||
|
|
|
@ -17,7 +17,11 @@ async function test() {
|
|||
aWindow = await open_manager(null);
|
||||
utils = new CategoryUtilities(aWindow);
|
||||
|
||||
is(utils.selectedCategory, "plugin", "Should have shown the plugins category");
|
||||
is(
|
||||
utils.selectedCategory,
|
||||
"plugin",
|
||||
"Should have shown the plugins category"
|
||||
);
|
||||
|
||||
// Open the extensions category
|
||||
utils.openType("extension", async function() {
|
||||
|
@ -26,7 +30,11 @@ async function test() {
|
|||
aWindow = await open_manager(null);
|
||||
utils = new CategoryUtilities(aWindow);
|
||||
|
||||
is(utils.selectedCategory, "extension", "Should have shown the extensions category");
|
||||
is(
|
||||
utils.selectedCategory,
|
||||
"extension",
|
||||
"Should have shown the extensions category"
|
||||
);
|
||||
close_manager(aWindow, finish);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -37,6 +37,6 @@ function f_key_test() {
|
|||
}
|
||||
|
||||
function slash_key_test() {
|
||||
EventUtils.synthesizeKey("/", { }, gManagerWindow);
|
||||
EventUtils.synthesizeKey("/", {}, gManagerWindow);
|
||||
is(focusCount, 2, "Search box should have been focused due to the / key");
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
var gManagerWindow;
|
||||
var gCategoryUtilities;
|
||||
var gProvider;
|
||||
var gInstallProperties = [{
|
||||
name: "Locale Category Test",
|
||||
type: "locale",
|
||||
}];
|
||||
var gInstallProperties = [
|
||||
{
|
||||
name: "Locale Category Test",
|
||||
type: "locale",
|
||||
},
|
||||
];
|
||||
var gInstall;
|
||||
var gExpectedCancel = false;
|
||||
var gTestInstallListener = {
|
||||
|
@ -92,4 +94,3 @@ add_test(async function() {
|
|||
gExpectedCancel = true;
|
||||
gInstall.cancel();
|
||||
});
|
||||
|
||||
|
|
|
@ -9,10 +9,12 @@ var gManagerWindow;
|
|||
var gCategoryUtilities;
|
||||
var gProvider;
|
||||
var gInstall;
|
||||
var gInstallProperties = [{
|
||||
name: "Locale Category Test",
|
||||
type: "locale",
|
||||
}];
|
||||
var gInstallProperties = [
|
||||
{
|
||||
name: "Locale Category Test",
|
||||
type: "locale",
|
||||
},
|
||||
];
|
||||
|
||||
async function test() {
|
||||
try {
|
||||
|
@ -50,7 +52,12 @@ function check_hidden(aExpectedHidden) {
|
|||
is(hidden, !!aExpectedHidden, "Should have correct hidden state");
|
||||
}
|
||||
|
||||
async function run_open_test(aTestSetup, aLoadHidden, aInitializedHidden, aSelected) {
|
||||
async function run_open_test(
|
||||
aTestSetup,
|
||||
aLoadHidden,
|
||||
aInitializedHidden,
|
||||
aSelected
|
||||
) {
|
||||
function loadCallback(aManagerWindow) {
|
||||
gManagerWindow = aManagerWindow;
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
|
@ -60,7 +67,7 @@ async function run_open_test(aTestSetup, aLoadHidden, aInitializedHidden, aSelec
|
|||
async function run() {
|
||||
await open_manager(null, null, loadCallback);
|
||||
check_hidden(aInitializedHidden);
|
||||
var selected = (gCategoryUtilities.selectedCategory == "locale");
|
||||
var selected = gCategoryUtilities.selectedCategory == "locale";
|
||||
is(selected, !!aSelected, "Should have correct selected state");
|
||||
|
||||
run_next_test();
|
||||
|
@ -70,7 +77,6 @@ async function run_open_test(aTestSetup, aLoadHidden, aInitializedHidden, aSelec
|
|||
aTestSetup ? aTestSetup(run) : run();
|
||||
}
|
||||
|
||||
|
||||
// Tests that the locale category is hidden when there are no locales installed
|
||||
add_test(function() {
|
||||
run_open_test(null, true, true);
|
||||
|
@ -124,4 +130,3 @@ add_test(function() {
|
|||
gInstall.cancel();
|
||||
run_open_test(null, false, true);
|
||||
});
|
||||
|
||||
|
|
|
@ -18,22 +18,26 @@ SpecialPowers.pushPrefEnv({
|
|||
add_task(async function test() {
|
||||
gProvider = new MockProvider();
|
||||
|
||||
gProvider.createAddons([{
|
||||
id: "extension@tests.mozilla.org",
|
||||
name: "Extension 1",
|
||||
type: "extension",
|
||||
version: "123",
|
||||
}, {
|
||||
id: "theme@tests.mozilla.org",
|
||||
name: "Theme 2",
|
||||
type: "theme",
|
||||
version: "456",
|
||||
}, {
|
||||
id: "lwtheme@personas.mozilla.org",
|
||||
name: "Persona 3",
|
||||
type: "theme",
|
||||
version: "789",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "extension@tests.mozilla.org",
|
||||
name: "Extension 1",
|
||||
type: "extension",
|
||||
version: "123",
|
||||
},
|
||||
{
|
||||
id: "theme@tests.mozilla.org",
|
||||
name: "Theme 2",
|
||||
type: "theme",
|
||||
version: "456",
|
||||
},
|
||||
{
|
||||
id: "lwtheme@personas.mozilla.org",
|
||||
name: "Persona 3",
|
||||
type: "theme",
|
||||
version: "789",
|
||||
},
|
||||
]);
|
||||
|
||||
gManagerWindow = await open_manager();
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
|
@ -44,7 +48,11 @@ function get(aId) {
|
|||
}
|
||||
|
||||
function get_node(parent, anonid) {
|
||||
return parent.ownerDocument.getAnonymousElementByAttribute(parent, "anonid", anonid);
|
||||
return parent.ownerDocument.getAnonymousElementByAttribute(
|
||||
parent,
|
||||
"anonid",
|
||||
anonid
|
||||
);
|
||||
}
|
||||
|
||||
function open_details(aList, aItem, aCallback) {
|
||||
|
|
|
@ -32,12 +32,14 @@ async function test() {
|
|||
|
||||
gProvider = new MockProvider();
|
||||
|
||||
gProvider.createAddons([{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "addon 1",
|
||||
version: "1.0",
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "addon 1",
|
||||
version: "1.0",
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
|
||||
},
|
||||
]);
|
||||
|
||||
let aWindow = await open_manager("addons://list/extension");
|
||||
gManagerWindow = aWindow;
|
||||
|
@ -48,22 +50,24 @@ async function test() {
|
|||
run_next_test();
|
||||
}
|
||||
|
||||
|
||||
function end_test() {
|
||||
close_manager(gManagerWindow, finish);
|
||||
}
|
||||
|
||||
|
||||
function wait_for_popup(aCallback) {
|
||||
if (gUtilsMenu.state == "open") {
|
||||
aCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
gUtilsMenu.addEventListener("popupshown", function() {
|
||||
info("Utilities menu shown");
|
||||
aCallback();
|
||||
}, {once: true});
|
||||
gUtilsMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
info("Utilities menu shown");
|
||||
aCallback();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
|
||||
function wait_for_hide(aCallback) {
|
||||
|
@ -72,38 +76,63 @@ function wait_for_hide(aCallback) {
|
|||
return;
|
||||
}
|
||||
|
||||
gUtilsMenu.addEventListener("popuphidden", function() {
|
||||
info("Utilities menu hidden");
|
||||
aCallback();
|
||||
}, {once: true});
|
||||
gUtilsMenu.addEventListener(
|
||||
"popuphidden",
|
||||
function() {
|
||||
info("Utilities menu hidden");
|
||||
aCallback();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
|
||||
add_test(function() {
|
||||
gSetDefault = gManagerWindow.document.getElementById("utils-autoUpdateDefault");
|
||||
gResetToAutomatic = gManagerWindow.document.getElementById("utils-resetAddonUpdatesToAutomatic");
|
||||
gResetToManual = gManagerWindow.document.getElementById("utils-resetAddonUpdatesToManual");
|
||||
gSetDefault = gManagerWindow.document.getElementById(
|
||||
"utils-autoUpdateDefault"
|
||||
);
|
||||
gResetToAutomatic = gManagerWindow.document.getElementById(
|
||||
"utils-resetAddonUpdatesToAutomatic"
|
||||
);
|
||||
gResetToManual = gManagerWindow.document.getElementById(
|
||||
"utils-resetAddonUpdatesToManual"
|
||||
);
|
||||
|
||||
info("Ensuring default prefs are set to true");
|
||||
Services.prefs.setBoolPref(PREF_UPDATE_ENABLED, true);
|
||||
Services.prefs.setBoolPref(PREF_AUTOUPDATE_DEFAULT, true);
|
||||
|
||||
wait_for_popup(function() {
|
||||
is(gSetDefault.getAttribute("checked"), "true",
|
||||
"#1 Set Default menuitem should be checked");
|
||||
is_element_visible(gResetToAutomatic,
|
||||
"#1 Reset to Automatic menuitem should be visible");
|
||||
is_element_hidden(gResetToManual,
|
||||
"#1 Reset to Manual menuitem should be hidden");
|
||||
is(
|
||||
gSetDefault.getAttribute("checked"),
|
||||
"true",
|
||||
"#1 Set Default menuitem should be checked"
|
||||
);
|
||||
is_element_visible(
|
||||
gResetToAutomatic,
|
||||
"#1 Reset to Automatic menuitem should be visible"
|
||||
);
|
||||
is_element_hidden(
|
||||
gResetToManual,
|
||||
"#1 Reset to Manual menuitem should be hidden"
|
||||
);
|
||||
|
||||
var listener = {
|
||||
onPropertyChanged(aAddon, aProperties) {
|
||||
AddonManager.removeAddonListener(listener);
|
||||
is(aAddon.id, gProvider.addons[0].id,
|
||||
"Should get onPropertyChanged event for correct addon");
|
||||
ok(!("applyBackgroundUpdates" in aProperties),
|
||||
"Should have gotten applyBackgroundUpdates in properties array");
|
||||
is(aAddon.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DEFAULT,
|
||||
"Addon.applyBackgroundUpdates should have been reset to default");
|
||||
is(
|
||||
aAddon.id,
|
||||
gProvider.addons[0].id,
|
||||
"Should get onPropertyChanged event for correct addon"
|
||||
);
|
||||
ok(
|
||||
!("applyBackgroundUpdates" in aProperties),
|
||||
"Should have gotten applyBackgroundUpdates in properties array"
|
||||
);
|
||||
is(
|
||||
aAddon.applyBackgroundUpdates,
|
||||
AddonManager.AUTOUPDATE_DEFAULT,
|
||||
"Addon.applyBackgroundUpdates should have been reset to default"
|
||||
);
|
||||
|
||||
info("Setting Addon.applyBackgroundUpdates back to disabled");
|
||||
aAddon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
|
||||
|
@ -114,115 +143,162 @@ add_test(function() {
|
|||
AddonManager.addAddonListener(listener);
|
||||
|
||||
info("Clicking Reset to Automatic menuitem");
|
||||
EventUtils.synthesizeMouseAtCenter(gResetToAutomatic, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gResetToAutomatic, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
info("Opening utilities menu");
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
info("Disabling extensions.update.enabled");
|
||||
Services.prefs.setBoolPref(PREF_UPDATE_ENABLED, false);
|
||||
|
||||
wait_for_popup(function() {
|
||||
isnot(gSetDefault.getAttribute("checked"), "true",
|
||||
"#2 Set Default menuitem should not be checked");
|
||||
is_element_visible(gResetToAutomatic,
|
||||
"#2 Reset to Automatic menuitem should be visible");
|
||||
is_element_hidden(gResetToManual,
|
||||
"#2 Reset to Manual menuitem should be hidden");
|
||||
isnot(
|
||||
gSetDefault.getAttribute("checked"),
|
||||
"true",
|
||||
"#2 Set Default menuitem should not be checked"
|
||||
);
|
||||
is_element_visible(
|
||||
gResetToAutomatic,
|
||||
"#2 Reset to Automatic menuitem should be visible"
|
||||
);
|
||||
is_element_hidden(
|
||||
gResetToManual,
|
||||
"#2 Reset to Manual menuitem should be hidden"
|
||||
);
|
||||
|
||||
wait_for_hide(run_next_test);
|
||||
|
||||
info("Clicking Set Default menuitem to reenable");
|
||||
EventUtils.synthesizeMouseAtCenter(gSetDefault, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gSetDefault, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
info("Opening utilities menu");
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
ok(Services.prefs.getBoolPref(PREF_UPDATE_ENABLED),
|
||||
"extensions.update.enabled should be true after the previous test");
|
||||
ok(Services.prefs.getBoolPref(PREF_AUTOUPDATE_DEFAULT),
|
||||
"extensions.update.autoUpdateDefault should be true after the previous test");
|
||||
ok(
|
||||
Services.prefs.getBoolPref(PREF_UPDATE_ENABLED),
|
||||
"extensions.update.enabled should be true after the previous test"
|
||||
);
|
||||
ok(
|
||||
Services.prefs.getBoolPref(PREF_AUTOUPDATE_DEFAULT),
|
||||
"extensions.update.autoUpdateDefault should be true after the previous test"
|
||||
);
|
||||
|
||||
info("Disabling both extensions.update.enabled and extensions.update.autoUpdateDefault");
|
||||
info(
|
||||
"Disabling both extensions.update.enabled and extensions.update.autoUpdateDefault"
|
||||
);
|
||||
Services.prefs.setBoolPref(PREF_UPDATE_ENABLED, false);
|
||||
Services.prefs.setBoolPref(PREF_AUTOUPDATE_DEFAULT, false);
|
||||
|
||||
wait_for_popup(function() {
|
||||
isnot(gSetDefault.getAttribute("checked"), "true",
|
||||
"#3 Set Default menuitem should not be checked");
|
||||
is_element_hidden(gResetToAutomatic,
|
||||
"#3 Reset to automatic menuitem should be hidden");
|
||||
is_element_visible(gResetToManual,
|
||||
"#3 Reset to manual menuitem should be visible");
|
||||
isnot(
|
||||
gSetDefault.getAttribute("checked"),
|
||||
"true",
|
||||
"#3 Set Default menuitem should not be checked"
|
||||
);
|
||||
is_element_hidden(
|
||||
gResetToAutomatic,
|
||||
"#3 Reset to automatic menuitem should be hidden"
|
||||
);
|
||||
is_element_visible(
|
||||
gResetToManual,
|
||||
"#3 Reset to manual menuitem should be visible"
|
||||
);
|
||||
|
||||
wait_for_hide(run_next_test);
|
||||
|
||||
info("Clicking Set Default menuitem to reenable");
|
||||
EventUtils.synthesizeMouseAtCenter(gSetDefault, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gSetDefault, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
info("Opening utilities menu");
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
ok(Services.prefs.getBoolPref(PREF_UPDATE_ENABLED),
|
||||
"extensions.update.enabled should be true after the previous test");
|
||||
ok(Services.prefs.getBoolPref(PREF_AUTOUPDATE_DEFAULT),
|
||||
"extensions.update.autoUpdateDefault should be true after the previous test");
|
||||
ok(
|
||||
Services.prefs.getBoolPref(PREF_UPDATE_ENABLED),
|
||||
"extensions.update.enabled should be true after the previous test"
|
||||
);
|
||||
ok(
|
||||
Services.prefs.getBoolPref(PREF_AUTOUPDATE_DEFAULT),
|
||||
"extensions.update.autoUpdateDefault should be true after the previous test"
|
||||
);
|
||||
|
||||
info("clicking the button to disable extensions.update.autoUpdateDefault");
|
||||
wait_for_popup(function() {
|
||||
is(gSetDefault.getAttribute("checked"), "true",
|
||||
"#4 Set Default menuitem should be checked");
|
||||
is_element_visible(gResetToAutomatic,
|
||||
"#4 Reset to Automatic menuitem should be visible");
|
||||
is_element_hidden(gResetToManual,
|
||||
"#4 Reset to Manual menuitem should be hidden");
|
||||
is(
|
||||
gSetDefault.getAttribute("checked"),
|
||||
"true",
|
||||
"#4 Set Default menuitem should be checked"
|
||||
);
|
||||
is_element_visible(
|
||||
gResetToAutomatic,
|
||||
"#4 Reset to Automatic menuitem should be visible"
|
||||
);
|
||||
is_element_hidden(
|
||||
gResetToManual,
|
||||
"#4 Reset to Manual menuitem should be hidden"
|
||||
);
|
||||
|
||||
wait_for_hide(run_next_test);
|
||||
|
||||
info("Clicking Set Default menuitem to disable");
|
||||
EventUtils.synthesizeMouseAtCenter(gSetDefault, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gSetDefault, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
info("Opening utilities menu");
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
ok(Services.prefs.getBoolPref(PREF_UPDATE_ENABLED),
|
||||
"extensions.update.enabled should be true after the previous test");
|
||||
is(Services.prefs.getBoolPref(PREF_AUTOUPDATE_DEFAULT), false,
|
||||
"extensions.update.autoUpdateDefault should be false after the previous test");
|
||||
ok(
|
||||
Services.prefs.getBoolPref(PREF_UPDATE_ENABLED),
|
||||
"extensions.update.enabled should be true after the previous test"
|
||||
);
|
||||
is(
|
||||
Services.prefs.getBoolPref(PREF_AUTOUPDATE_DEFAULT),
|
||||
false,
|
||||
"extensions.update.autoUpdateDefault should be false after the previous test"
|
||||
);
|
||||
|
||||
wait_for_popup(function() {
|
||||
isnot(gSetDefault.getAttribute("checked"), "true",
|
||||
"#5 Set Default menuitem should not be checked");
|
||||
is_element_hidden(gResetToAutomatic,
|
||||
"#5 Reset to automatic menuitem should be hidden");
|
||||
is_element_visible(gResetToManual,
|
||||
"#5 Reset to manual menuitem should be visible");
|
||||
isnot(
|
||||
gSetDefault.getAttribute("checked"),
|
||||
"true",
|
||||
"#5 Set Default menuitem should not be checked"
|
||||
);
|
||||
is_element_hidden(
|
||||
gResetToAutomatic,
|
||||
"#5 Reset to automatic menuitem should be hidden"
|
||||
);
|
||||
is_element_visible(
|
||||
gResetToManual,
|
||||
"#5 Reset to manual menuitem should be visible"
|
||||
);
|
||||
|
||||
var listener = {
|
||||
onPropertyChanged(aAddon, aProperties) {
|
||||
AddonManager.removeAddonListener(listener);
|
||||
is(aAddon.id, gProvider.addons[0].id,
|
||||
"Should get onPropertyChanged event for correct addon");
|
||||
ok(!("applyBackgroundUpdates" in aProperties),
|
||||
"Should have gotten applyBackgroundUpdates in properties array");
|
||||
is(aAddon.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DEFAULT,
|
||||
"Addon.applyBackgroundUpdates should have been reset to default");
|
||||
is(
|
||||
aAddon.id,
|
||||
gProvider.addons[0].id,
|
||||
"Should get onPropertyChanged event for correct addon"
|
||||
);
|
||||
ok(
|
||||
!("applyBackgroundUpdates" in aProperties),
|
||||
"Should have gotten applyBackgroundUpdates in properties array"
|
||||
);
|
||||
is(
|
||||
aAddon.applyBackgroundUpdates,
|
||||
AddonManager.AUTOUPDATE_DEFAULT,
|
||||
"Addon.applyBackgroundUpdates should have been reset to default"
|
||||
);
|
||||
|
||||
info("Setting Addon.applyBackgroundUpdates back to disabled");
|
||||
aAddon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
|
||||
|
@ -233,42 +309,54 @@ add_test(function() {
|
|||
AddonManager.addAddonListener(listener);
|
||||
|
||||
info("Clicking Reset to Manual menuitem");
|
||||
EventUtils.synthesizeMouseAtCenter(gResetToManual, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gResetToManual, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
info("Opening utilities menu");
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
wait_for_popup(function() {
|
||||
isnot(gSetDefault.getAttribute("checked"), "true",
|
||||
"#6 Set Default menuitem should not be checked");
|
||||
is_element_hidden(gResetToAutomatic,
|
||||
"#6 Reset to automatic menuitem should be hidden");
|
||||
is_element_visible(gResetToManual,
|
||||
"#6 Reset to manual menuitem should be visible");
|
||||
isnot(
|
||||
gSetDefault.getAttribute("checked"),
|
||||
"true",
|
||||
"#6 Set Default menuitem should not be checked"
|
||||
);
|
||||
is_element_hidden(
|
||||
gResetToAutomatic,
|
||||
"#6 Reset to automatic menuitem should be hidden"
|
||||
);
|
||||
is_element_visible(
|
||||
gResetToManual,
|
||||
"#6 Reset to manual menuitem should be visible"
|
||||
);
|
||||
|
||||
wait_for_hide(run_next_test);
|
||||
|
||||
info("Clicking Set Default menuitem");
|
||||
EventUtils.synthesizeMouseAtCenter(gSetDefault, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gSetDefault, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
info("Opening utilities menu");
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
wait_for_popup(function() {
|
||||
is(gSetDefault.getAttribute("checked"), "true",
|
||||
"#7 Set Default menuitem should be checked");
|
||||
is_element_visible(gResetToAutomatic,
|
||||
"#7 Reset to Automatic menuitem should be visible");
|
||||
is_element_hidden(gResetToManual,
|
||||
"#7 Reset to Manual menuitem should be hidden");
|
||||
is(
|
||||
gSetDefault.getAttribute("checked"),
|
||||
"true",
|
||||
"#7 Set Default menuitem should be checked"
|
||||
);
|
||||
is_element_visible(
|
||||
gResetToAutomatic,
|
||||
"#7 Reset to Automatic menuitem should be visible"
|
||||
);
|
||||
is_element_hidden(
|
||||
gResetToManual,
|
||||
"#7 Reset to Manual menuitem should be hidden"
|
||||
);
|
||||
|
||||
wait_for_hide(run_next_test);
|
||||
|
||||
|
@ -276,6 +364,5 @@ add_test(function() {
|
|||
});
|
||||
|
||||
info("Opening utilities menu");
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gUtilsBtn, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
|
|
|
@ -20,65 +20,76 @@ async function test() {
|
|||
|
||||
gProvider = new MockProvider();
|
||||
|
||||
gProvider.createAddons([{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "addon 1",
|
||||
version: "1.0",
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
|
||||
}, {
|
||||
id: "addon2@tests.mozilla.org",
|
||||
name: "addon 2",
|
||||
version: "2.0",
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
|
||||
}, {
|
||||
id: "addon3@tests.mozilla.org",
|
||||
name: "addon 3",
|
||||
version: "3.0",
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
|
||||
}]);
|
||||
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "addon 1",
|
||||
version: "1.0",
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
|
||||
},
|
||||
{
|
||||
id: "addon2@tests.mozilla.org",
|
||||
name: "addon 2",
|
||||
version: "2.0",
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
|
||||
},
|
||||
{
|
||||
id: "addon3@tests.mozilla.org",
|
||||
name: "addon 3",
|
||||
version: "3.0",
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
|
||||
},
|
||||
]);
|
||||
|
||||
let aWindow = await open_manager("addons://updates/available");
|
||||
gManagerWindow = aWindow;
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
|
||||
function end_test() {
|
||||
close_manager(gManagerWindow, finish);
|
||||
}
|
||||
|
||||
|
||||
add_test(function() {
|
||||
var list = gManagerWindow.document.getElementById("updates-list");
|
||||
is(list.childNodes.length, 0, "Available updates list should be empty");
|
||||
|
||||
var emptyNotice = gManagerWindow.document.getElementById("empty-availableUpdates-msg");
|
||||
var emptyNotice = gManagerWindow.document.getElementById(
|
||||
"empty-availableUpdates-msg"
|
||||
);
|
||||
is_element_visible(emptyNotice, "Empty notice should be visible");
|
||||
|
||||
var updateSelected = gManagerWindow.document.getElementById("update-selected-btn");
|
||||
var updateSelected = gManagerWindow.document.getElementById(
|
||||
"update-selected-btn"
|
||||
);
|
||||
is_element_hidden(updateSelected, "Update Selected button should be hidden");
|
||||
|
||||
info("Adding updates");
|
||||
gProvider.createInstalls([{
|
||||
name: "addon 1",
|
||||
version: "1.1",
|
||||
existingAddon: gProvider.addons[0],
|
||||
}, {
|
||||
name: "addon 2",
|
||||
version: "2.1",
|
||||
existingAddon: gProvider.addons[1],
|
||||
}, {
|
||||
name: "addon 3",
|
||||
version: "3.1",
|
||||
existingAddon: gProvider.addons[2],
|
||||
}]);
|
||||
gProvider.createInstalls([
|
||||
{
|
||||
name: "addon 1",
|
||||
version: "1.1",
|
||||
existingAddon: gProvider.addons[0],
|
||||
},
|
||||
{
|
||||
name: "addon 2",
|
||||
version: "2.1",
|
||||
existingAddon: gProvider.addons[1],
|
||||
},
|
||||
{
|
||||
name: "addon 3",
|
||||
version: "3.1",
|
||||
existingAddon: gProvider.addons[2],
|
||||
},
|
||||
]);
|
||||
|
||||
function wait_for_refresh() {
|
||||
if (list.childNodes.length == 3 &&
|
||||
list.childNodes[0].mManualUpdate &&
|
||||
list.childNodes[1].mManualUpdate &&
|
||||
list.childNodes[2].mManualUpdate) {
|
||||
if (
|
||||
list.childNodes.length == 3 &&
|
||||
list.childNodes[0].mManualUpdate &&
|
||||
list.childNodes[1].mManualUpdate &&
|
||||
list.childNodes[2].mManualUpdate
|
||||
) {
|
||||
run_next_test();
|
||||
} else {
|
||||
info("Waiting for pane to refresh");
|
||||
|
@ -89,7 +100,6 @@ add_test(function() {
|
|||
setTimeout(wait_for_refresh, 10);
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
var list = gManagerWindow.document.getElementById("updates-list");
|
||||
is(list.childNodes.length, 3, "Available updates list should have 2 items");
|
||||
|
@ -101,51 +111,119 @@ add_test(function() {
|
|||
var item3 = get_addon_element(gManagerWindow, "addon3@tests.mozilla.org");
|
||||
isnot(item3, null, "Item for addon3@tests.mozilla.org should be in list");
|
||||
|
||||
var emptyNotice = gManagerWindow.document.getElementById("empty-availableUpdates-msg");
|
||||
var emptyNotice = gManagerWindow.document.getElementById(
|
||||
"empty-availableUpdates-msg"
|
||||
);
|
||||
is_element_hidden(emptyNotice, "Empty notice should be hidden");
|
||||
|
||||
var updateSelected = gManagerWindow.document.getElementById("update-selected-btn");
|
||||
is_element_visible(updateSelected, "Update Selected button should be visible");
|
||||
is(updateSelected.disabled, false, "Update Selected button should be enabled by default");
|
||||
var updateSelected = gManagerWindow.document.getElementById(
|
||||
"update-selected-btn"
|
||||
);
|
||||
is_element_visible(
|
||||
updateSelected,
|
||||
"Update Selected button should be visible"
|
||||
);
|
||||
is(
|
||||
updateSelected.disabled,
|
||||
false,
|
||||
"Update Selected button should be enabled by default"
|
||||
);
|
||||
|
||||
is(item1._includeUpdate.checked, true, "Include Update checkbox should be checked by default for addon1");
|
||||
is(item2._includeUpdate.checked, true, "Include Update checkbox should be checked by default for addon2");
|
||||
is(item3._includeUpdate.checked, true, "Include Update checkbox should be checked by default for addon3");
|
||||
is(
|
||||
item1._includeUpdate.checked,
|
||||
true,
|
||||
"Include Update checkbox should be checked by default for addon1"
|
||||
);
|
||||
is(
|
||||
item2._includeUpdate.checked,
|
||||
true,
|
||||
"Include Update checkbox should be checked by default for addon2"
|
||||
);
|
||||
is(
|
||||
item3._includeUpdate.checked,
|
||||
true,
|
||||
"Include Update checkbox should be checked by default for addon3"
|
||||
);
|
||||
|
||||
info("Unchecking Include Update checkbox for addon1");
|
||||
EventUtils.synthesizeMouse(item1._includeUpdate, 2, 2, { }, gManagerWindow);
|
||||
is(item1._includeUpdate.checked, false, "Include Update checkbox should now be be unchecked for addon1");
|
||||
is(updateSelected.disabled, false, "Update Selected button should still be enabled");
|
||||
EventUtils.synthesizeMouse(item1._includeUpdate, 2, 2, {}, gManagerWindow);
|
||||
is(
|
||||
item1._includeUpdate.checked,
|
||||
false,
|
||||
"Include Update checkbox should now be be unchecked for addon1"
|
||||
);
|
||||
is(
|
||||
updateSelected.disabled,
|
||||
false,
|
||||
"Update Selected button should still be enabled"
|
||||
);
|
||||
|
||||
info("Unchecking Include Update checkbox for addon2");
|
||||
EventUtils.synthesizeMouse(item2._includeUpdate, 2, 2, { }, gManagerWindow);
|
||||
is(item2._includeUpdate.checked, false, "Include Update checkbox should now be be unchecked for addon2");
|
||||
is(updateSelected.disabled, false, "Update Selected button should still be enabled");
|
||||
EventUtils.synthesizeMouse(item2._includeUpdate, 2, 2, {}, gManagerWindow);
|
||||
is(
|
||||
item2._includeUpdate.checked,
|
||||
false,
|
||||
"Include Update checkbox should now be be unchecked for addon2"
|
||||
);
|
||||
is(
|
||||
updateSelected.disabled,
|
||||
false,
|
||||
"Update Selected button should still be enabled"
|
||||
);
|
||||
|
||||
info("Unchecking Include Update checkbox for addon3");
|
||||
EventUtils.synthesizeMouse(item3._includeUpdate, 2, 2, { }, gManagerWindow);
|
||||
is(item3._includeUpdate.checked, false, "Include Update checkbox should now be be unchecked for addon3");
|
||||
is(updateSelected.disabled, true, "Update Selected button should now be disabled");
|
||||
EventUtils.synthesizeMouse(item3._includeUpdate, 2, 2, {}, gManagerWindow);
|
||||
is(
|
||||
item3._includeUpdate.checked,
|
||||
false,
|
||||
"Include Update checkbox should now be be unchecked for addon3"
|
||||
);
|
||||
is(
|
||||
updateSelected.disabled,
|
||||
true,
|
||||
"Update Selected button should now be disabled"
|
||||
);
|
||||
|
||||
info("Checking Include Update checkbox for addon2");
|
||||
EventUtils.synthesizeMouse(item2._includeUpdate, 2, 2, { }, gManagerWindow);
|
||||
is(item2._includeUpdate.checked, true, "Include Update checkbox should now be be checked for addon2");
|
||||
is(updateSelected.disabled, false, "Update Selected button should now be enabled");
|
||||
EventUtils.synthesizeMouse(item2._includeUpdate, 2, 2, {}, gManagerWindow);
|
||||
is(
|
||||
item2._includeUpdate.checked,
|
||||
true,
|
||||
"Include Update checkbox should now be be checked for addon2"
|
||||
);
|
||||
is(
|
||||
updateSelected.disabled,
|
||||
false,
|
||||
"Update Selected button should now be enabled"
|
||||
);
|
||||
|
||||
info("Checking Include Update checkbox for addon3");
|
||||
EventUtils.synthesizeMouse(item3._includeUpdate, 2, 2, { }, gManagerWindow);
|
||||
is(item3._includeUpdate.checked, true, "Include Update checkbox should now be be checked for addon3");
|
||||
is(updateSelected.disabled, false, "Update Selected button should now be enabled");
|
||||
EventUtils.synthesizeMouse(item3._includeUpdate, 2, 2, {}, gManagerWindow);
|
||||
is(
|
||||
item3._includeUpdate.checked,
|
||||
true,
|
||||
"Include Update checkbox should now be be checked for addon3"
|
||||
);
|
||||
is(
|
||||
updateSelected.disabled,
|
||||
false,
|
||||
"Update Selected button should now be enabled"
|
||||
);
|
||||
|
||||
var installCount = 0;
|
||||
var listener = {
|
||||
onDownloadStarted(aInstall) {
|
||||
isnot(aInstall.existingAddon.id, "addon1@tests.mozilla.org", "Should not have seen a download start for addon1");
|
||||
isnot(
|
||||
aInstall.existingAddon.id,
|
||||
"addon1@tests.mozilla.org",
|
||||
"Should not have seen a download start for addon1"
|
||||
);
|
||||
},
|
||||
|
||||
onInstallEnded(aInstall) {
|
||||
if (++installCount < 2)
|
||||
if (++installCount < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
gProvider.installs[0].removeTestListener(listener);
|
||||
gProvider.installs[1].removeTestListener(listener);
|
||||
|
@ -154,9 +232,21 @@ add_test(function() {
|
|||
// Installs are started synchronously so by the time an executeSoon is
|
||||
// executed all installs that are going to start will have started
|
||||
executeSoon(function() {
|
||||
is(gProvider.installs[0].state, AddonManager.STATE_AVAILABLE, "addon1 should not have been upgraded");
|
||||
is(gProvider.installs[1].state, AddonManager.STATE_INSTALLED, "addon2 should have been upgraded");
|
||||
is(gProvider.installs[2].state, AddonManager.STATE_INSTALLED, "addon3 should have been upgraded");
|
||||
is(
|
||||
gProvider.installs[0].state,
|
||||
AddonManager.STATE_AVAILABLE,
|
||||
"addon1 should not have been upgraded"
|
||||
);
|
||||
is(
|
||||
gProvider.installs[1].state,
|
||||
AddonManager.STATE_INSTALLED,
|
||||
"addon2 should have been upgraded"
|
||||
);
|
||||
is(
|
||||
gProvider.installs[2].state,
|
||||
AddonManager.STATE_INSTALLED,
|
||||
"addon3 should have been upgraded"
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -166,22 +256,39 @@ add_test(function() {
|
|||
gProvider.installs[1].addTestListener(listener);
|
||||
gProvider.installs[2].addTestListener(listener);
|
||||
info("Clicking Update Selected button");
|
||||
EventUtils.synthesizeMouseAtCenter(updateSelected, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(updateSelected, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
var updateSelected = gManagerWindow.document.getElementById("update-selected-btn");
|
||||
is(updateSelected.disabled, true, "Update Selected button should be disabled");
|
||||
var updateSelected = gManagerWindow.document.getElementById(
|
||||
"update-selected-btn"
|
||||
);
|
||||
is(
|
||||
updateSelected.disabled,
|
||||
true,
|
||||
"Update Selected button should be disabled"
|
||||
);
|
||||
|
||||
var item1 = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
|
||||
isnot(item1, null, "Item for addon1@tests.mozilla.org should be in list");
|
||||
is(item1._includeUpdate.checked, false, "Include Update checkbox should not have changed");
|
||||
is(
|
||||
item1._includeUpdate.checked,
|
||||
false,
|
||||
"Include Update checkbox should not have changed"
|
||||
);
|
||||
|
||||
info("Checking Include Update checkbox for addon1");
|
||||
EventUtils.synthesizeMouse(item1._includeUpdate, 2, 2, { }, gManagerWindow);
|
||||
is(item1._includeUpdate.checked, true, "Include Update checkbox should now be be checked for addon1");
|
||||
is(updateSelected.disabled, false, "Update Selected button should now not be disabled");
|
||||
EventUtils.synthesizeMouse(item1._includeUpdate, 2, 2, {}, gManagerWindow);
|
||||
is(
|
||||
item1._includeUpdate.checked,
|
||||
true,
|
||||
"Include Update checkbox should now be be checked for addon1"
|
||||
);
|
||||
is(
|
||||
updateSelected.disabled,
|
||||
false,
|
||||
"Update Selected button should now not be disabled"
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -28,8 +28,16 @@ async function open_details(aId, aType, aCallback) {
|
|||
while (item) {
|
||||
if ("mAddon" in item && item.mAddon.id == aId) {
|
||||
list.ensureElementIsVisible(item);
|
||||
EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
item,
|
||||
{ clickCount: 1 },
|
||||
gManagerWindow
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
item,
|
||||
{ clickCount: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
wait_for_view_load(gManagerWindow, aCallback);
|
||||
return;
|
||||
}
|
||||
|
@ -49,12 +57,17 @@ function get_list_view_warning_node() {
|
|||
item = item.nextSibling;
|
||||
}
|
||||
ok(found, "Test add-on node should have been found.");
|
||||
return item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning");
|
||||
return item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
|
||||
function get_detail_view_warning_node(aManagerWindow) {
|
||||
if (aManagerWindow)
|
||||
if (aManagerWindow) {
|
||||
return aManagerWindow.document.getElementById("detail-warning");
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
@ -63,13 +76,15 @@ async function test() {
|
|||
|
||||
gProvider = new MockProvider();
|
||||
|
||||
gProvider.createAddons([{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "Test add-on",
|
||||
description: "A test add-on",
|
||||
isCompatible: false,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_SOFTBLOCKED,
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "Test add-on",
|
||||
description: "A test add-on",
|
||||
isCompatible: false,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_SOFTBLOCKED,
|
||||
},
|
||||
]);
|
||||
|
||||
let aWindow = await open_manager(null);
|
||||
gManagerWindow = aWindow;
|
||||
|
@ -88,7 +103,11 @@ add_test(async function() {
|
|||
Services.prefs.setBoolPref(PREF_CHECK_COMPATIBILITY, true);
|
||||
let warning_node = get_list_view_warning_node();
|
||||
is_element_visible(warning_node, "Warning message should be visible");
|
||||
is(warning_node.textContent, "Test add-on is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
|
||||
is(
|
||||
warning_node.textContent,
|
||||
"Test add-on is incompatible with " + gApp + " " + gVersion + ".",
|
||||
"Warning message should be correct"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
@ -96,7 +115,11 @@ add_test(function() {
|
|||
open_details("addon1@tests.mozilla.org", "extension", function() {
|
||||
let warning_node = get_detail_view_warning_node(gManagerWindow);
|
||||
is_element_visible(warning_node, "Warning message should be visible");
|
||||
is(warning_node.textContent, "Test add-on is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
|
||||
is(
|
||||
warning_node.textContent,
|
||||
"Test add-on is incompatible with " + gApp + " " + gVersion + ".",
|
||||
"Warning message should be correct"
|
||||
);
|
||||
Services.prefs.setBoolPref(PREF_CHECK_COMPATIBILITY, false);
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -107,7 +130,11 @@ add_test(async function() {
|
|||
await gCategoryUtilities.openType("extension");
|
||||
let warning_node = get_list_view_warning_node();
|
||||
is_element_visible(warning_node, "Warning message should be visible");
|
||||
is(warning_node.textContent, "Test add-on is known to cause security or stability issues.", "Warning message should be correct");
|
||||
is(
|
||||
warning_node.textContent,
|
||||
"Test add-on is known to cause security or stability issues.",
|
||||
"Warning message should be correct"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
@ -115,7 +142,11 @@ add_test(function() {
|
|||
open_details("addon1@tests.mozilla.org", "extension", function() {
|
||||
let warning_node = get_detail_view_warning_node(gManagerWindow);
|
||||
is_element_visible(warning_node, "Warning message should be visible");
|
||||
is(warning_node.textContent, "Test add-on is known to cause security or stability issues.", "Warning message should be correct");
|
||||
is(
|
||||
warning_node.textContent,
|
||||
"Test add-on is known to cause security or stability issues.",
|
||||
"Warning message should be correct"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,117 +4,169 @@
|
|||
|
||||
// Bug 591465 - Context menu of add-ons miss context related state change entries
|
||||
|
||||
|
||||
var gManagerWindow;
|
||||
var gProvider;
|
||||
var gContextMenu;
|
||||
|
||||
|
||||
add_task(async function setup() {
|
||||
gProvider = new MockProvider();
|
||||
|
||||
gProvider.createAddons([{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "addon 1",
|
||||
version: "1.0",
|
||||
}, {
|
||||
id: "addon2@tests.mozilla.org",
|
||||
name: "addon 2",
|
||||
version: "1.0",
|
||||
_userDisabled: true,
|
||||
}, {
|
||||
id: "theme1@tests.mozilla.org",
|
||||
name: "theme 1",
|
||||
version: "1.0",
|
||||
type: "theme",
|
||||
}, {
|
||||
id: "theme2@tests.mozilla.org",
|
||||
name: "theme 2",
|
||||
version: "1.0",
|
||||
type: "theme",
|
||||
_userDisabled: true,
|
||||
}, {
|
||||
id: "theme3@tests.mozilla.org",
|
||||
name: "theme 3",
|
||||
version: "1.0",
|
||||
type: "theme",
|
||||
permissions: 0,
|
||||
}]);
|
||||
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "addon 1",
|
||||
version: "1.0",
|
||||
},
|
||||
{
|
||||
id: "addon2@tests.mozilla.org",
|
||||
name: "addon 2",
|
||||
version: "1.0",
|
||||
_userDisabled: true,
|
||||
},
|
||||
{
|
||||
id: "theme1@tests.mozilla.org",
|
||||
name: "theme 1",
|
||||
version: "1.0",
|
||||
type: "theme",
|
||||
},
|
||||
{
|
||||
id: "theme2@tests.mozilla.org",
|
||||
name: "theme 2",
|
||||
version: "1.0",
|
||||
type: "theme",
|
||||
_userDisabled: true,
|
||||
},
|
||||
{
|
||||
id: "theme3@tests.mozilla.org",
|
||||
name: "theme 3",
|
||||
version: "1.0",
|
||||
type: "theme",
|
||||
permissions: 0,
|
||||
},
|
||||
]);
|
||||
|
||||
let aWindow = await open_manager("addons://list/extension");
|
||||
gManagerWindow = aWindow;
|
||||
gContextMenu = aWindow.document.getElementById("addonitem-popup");
|
||||
});
|
||||
|
||||
function check_contextmenu(
|
||||
aIsTheme,
|
||||
aIsEnabled,
|
||||
aIsRemote,
|
||||
aIsDetails,
|
||||
aIsSingleItemCase
|
||||
) {
|
||||
if (aIsTheme || aIsEnabled || aIsRemote) {
|
||||
is_element_hidden(
|
||||
gManagerWindow.document.getElementById("menuitem_enableItem"),
|
||||
"'Enable' should be hidden"
|
||||
);
|
||||
} else {
|
||||
is_element_visible(
|
||||
gManagerWindow.document.getElementById("menuitem_enableItem"),
|
||||
"'Enable' should be visible"
|
||||
);
|
||||
}
|
||||
|
||||
function check_contextmenu(aIsTheme, aIsEnabled, aIsRemote, aIsDetails, aIsSingleItemCase) {
|
||||
if (aIsTheme || aIsEnabled || aIsRemote)
|
||||
is_element_hidden(gManagerWindow.document.getElementById("menuitem_enableItem"),
|
||||
"'Enable' should be hidden");
|
||||
else
|
||||
is_element_visible(gManagerWindow.document.getElementById("menuitem_enableItem"),
|
||||
"'Enable' should be visible");
|
||||
if (aIsTheme || !aIsEnabled || aIsRemote) {
|
||||
is_element_hidden(
|
||||
gManagerWindow.document.getElementById("menuitem_disableItem"),
|
||||
"'Disable' should be hidden"
|
||||
);
|
||||
} else {
|
||||
is_element_visible(
|
||||
gManagerWindow.document.getElementById("menuitem_disableItem"),
|
||||
"'Disable' should be visible"
|
||||
);
|
||||
}
|
||||
|
||||
if (aIsTheme || !aIsEnabled || aIsRemote)
|
||||
is_element_hidden(gManagerWindow.document.getElementById("menuitem_disableItem"),
|
||||
"'Disable' should be hidden");
|
||||
else
|
||||
is_element_visible(gManagerWindow.document.getElementById("menuitem_disableItem"),
|
||||
"'Disable' should be visible");
|
||||
if (!aIsTheme || aIsEnabled || aIsRemote || aIsSingleItemCase) {
|
||||
is_element_hidden(
|
||||
gManagerWindow.document.getElementById("menuitem_enableTheme"),
|
||||
"'Wear Theme' should be hidden"
|
||||
);
|
||||
} else {
|
||||
is_element_visible(
|
||||
gManagerWindow.document.getElementById("menuitem_enableTheme"),
|
||||
"'Wear Theme' should be visible"
|
||||
);
|
||||
}
|
||||
|
||||
if (!aIsTheme || aIsEnabled || aIsRemote || aIsSingleItemCase)
|
||||
is_element_hidden(gManagerWindow.document.getElementById("menuitem_enableTheme"),
|
||||
"'Wear Theme' should be hidden");
|
||||
else
|
||||
is_element_visible(gManagerWindow.document.getElementById("menuitem_enableTheme"),
|
||||
"'Wear Theme' should be visible");
|
||||
if (!aIsTheme || !aIsEnabled || aIsRemote || aIsSingleItemCase) {
|
||||
is_element_hidden(
|
||||
gManagerWindow.document.getElementById("menuitem_disableTheme"),
|
||||
"'Stop Wearing Theme' should be hidden"
|
||||
);
|
||||
} else {
|
||||
is_element_visible(
|
||||
gManagerWindow.document.getElementById("menuitem_disableTheme"),
|
||||
"'Stop Wearing Theme' should be visible"
|
||||
);
|
||||
}
|
||||
|
||||
if (!aIsTheme || !aIsEnabled || aIsRemote || aIsSingleItemCase)
|
||||
is_element_hidden(gManagerWindow.document.getElementById("menuitem_disableTheme"),
|
||||
"'Stop Wearing Theme' should be hidden");
|
||||
else
|
||||
is_element_visible(gManagerWindow.document.getElementById("menuitem_disableTheme"),
|
||||
"'Stop Wearing Theme' should be visible");
|
||||
if (aIsRemote) {
|
||||
is_element_visible(
|
||||
gManagerWindow.document.getElementById("menuitem_installItem"),
|
||||
"'Install' should be visible"
|
||||
);
|
||||
} else {
|
||||
is_element_hidden(
|
||||
gManagerWindow.document.getElementById("menuitem_installItem"),
|
||||
"'Install' should be hidden"
|
||||
);
|
||||
}
|
||||
|
||||
if (aIsRemote)
|
||||
is_element_visible(gManagerWindow.document.getElementById("menuitem_installItem"),
|
||||
"'Install' should be visible");
|
||||
else
|
||||
is_element_hidden(gManagerWindow.document.getElementById("menuitem_installItem"),
|
||||
"'Install' should be hidden");
|
||||
if (aIsDetails) {
|
||||
is_element_hidden(
|
||||
gManagerWindow.document.getElementById("menuitem_showDetails"),
|
||||
"'Show More Information' should be hidden in details view"
|
||||
);
|
||||
} else {
|
||||
is_element_visible(
|
||||
gManagerWindow.document.getElementById("menuitem_showDetails"),
|
||||
"'Show More Information' should be visible in list view"
|
||||
);
|
||||
}
|
||||
|
||||
if (aIsDetails)
|
||||
is_element_hidden(gManagerWindow.document.getElementById("menuitem_showDetails"),
|
||||
"'Show More Information' should be hidden in details view");
|
||||
else
|
||||
is_element_visible(gManagerWindow.document.getElementById("menuitem_showDetails"),
|
||||
"'Show More Information' should be visible in list view");
|
||||
|
||||
if (aIsSingleItemCase)
|
||||
is_element_hidden(gManagerWindow.document.getElementById("addonitem-menuseparator"),
|
||||
"Menu separator should be hidden with only one menu item");
|
||||
else
|
||||
is_element_visible(gManagerWindow.document.getElementById("addonitem-menuseparator"),
|
||||
"Menu separator should be visible with multiple menu items");
|
||||
if (aIsSingleItemCase) {
|
||||
is_element_hidden(
|
||||
gManagerWindow.document.getElementById("addonitem-menuseparator"),
|
||||
"Menu separator should be hidden with only one menu item"
|
||||
);
|
||||
} else {
|
||||
is_element_visible(
|
||||
gManagerWindow.document.getElementById("addonitem-menuseparator"),
|
||||
"Menu separator should be visible with multiple menu items"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
add_test(function() {
|
||||
var el = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
|
||||
isnot(el, null, "Should have found addon element");
|
||||
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(false, true, false, false, false);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(false, true, false, false, false);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu on enabled extension item");
|
||||
el.parentNode.ensureElementIsVisible(el);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
add_test(async function() {
|
||||
|
@ -122,17 +174,27 @@ add_test(async function() {
|
|||
isnot(el, null, "Should have found addon element");
|
||||
await el.mAddon.disable();
|
||||
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(false, false, false, false, false);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(false, false, false, false, false);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu on newly disabled extension item");
|
||||
el.parentNode.ensureElementIsVisible(el);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
add_test(async function() {
|
||||
|
@ -140,156 +202,251 @@ add_test(async function() {
|
|||
isnot(el, null, "Should have found addon element");
|
||||
await el.mAddon.enable();
|
||||
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(false, true, false, false, false);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(false, true, false, false, false);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu on newly enabled extension item");
|
||||
el.parentNode.ensureElementIsVisible(el);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
add_test(function() {
|
||||
var el = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
|
||||
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(false, false, false, false, false);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(false, false, false, false, false);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu on disabled extension item");
|
||||
el.parentNode.ensureElementIsVisible(el);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
add_test(async function() {
|
||||
gManagerWindow.loadView("addons://list/theme");
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
var el = get_addon_element(gManagerWindow, "theme1@tests.mozilla.org");
|
||||
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(true, true, false, false, false);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(true, true, false, false, false);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu on enabled theme item");
|
||||
el.parentNode.ensureElementIsVisible(el);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
var el = get_addon_element(gManagerWindow, "theme2@tests.mozilla.org");
|
||||
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(true, false, false, false, false);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(true, false, false, false, false);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu on disabled theme item");
|
||||
el.parentNode.ensureElementIsVisible(el);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
add_test(async function() {
|
||||
gManagerWindow.loadView("addons://detail/addon1@tests.mozilla.org");
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(false, true, false, true, false);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(false, true, false, true, false);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu on enabled extension, in detail view");
|
||||
var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
var el = gManagerWindow.document.querySelector(
|
||||
"#detail-view .detail-view-container"
|
||||
);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
add_test(async function() {
|
||||
gManagerWindow.loadView("addons://detail/addon2@tests.mozilla.org");
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(false, false, false, true, false);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(false, false, false, true, false);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu on disabled extension, in detail view");
|
||||
var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
var el = gManagerWindow.document.querySelector(
|
||||
"#detail-view .detail-view-container"
|
||||
);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
add_test(async function() {
|
||||
gManagerWindow.loadView("addons://detail/theme1@tests.mozilla.org");
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(true, true, false, true, false);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(true, true, false, true, false);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu on enabled theme, in detail view");
|
||||
var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
var el = gManagerWindow.document.querySelector(
|
||||
"#detail-view .detail-view-container"
|
||||
);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
add_test(async function() {
|
||||
gManagerWindow.loadView("addons://detail/theme2@tests.mozilla.org");
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(true, false, false, true, false);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(true, false, false, true, false);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu on disabled theme, in detail view");
|
||||
var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
var el = gManagerWindow.document.querySelector(
|
||||
"#detail-view .detail-view-container"
|
||||
);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
add_test(async function() {
|
||||
gManagerWindow.loadView("addons://detail/theme3@tests.mozilla.org");
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
gContextMenu.addEventListener("popupshown", function() {
|
||||
check_contextmenu(true, true, false, true, true);
|
||||
gContextMenu.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
check_contextmenu(true, true, false, true, true);
|
||||
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
gContextMenu.hidePopup();
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
info("Opening context menu with single menu item on enabled theme, in detail view");
|
||||
var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
info(
|
||||
"Opening context menu with single menu item on enabled theme, in detail view"
|
||||
);
|
||||
var el = gManagerWindow.document.querySelector(
|
||||
"#detail-view .detail-view-container"
|
||||
);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
add_task(function end_test() {
|
||||
return close_manager(gManagerWindow, finish);
|
||||
});
|
||||
|
|
|
@ -38,12 +38,14 @@ SpecialPowers.pushPrefEnv({
|
|||
async function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gProvider = new MockProvider(true, [{
|
||||
id: "mock-addon",
|
||||
name: "Mock Add-ons",
|
||||
uiPriority: 4500,
|
||||
flags: AddonManager.TYPE_UI_VIEW_LIST,
|
||||
}]);
|
||||
gProvider = new MockProvider(true, [
|
||||
{
|
||||
id: "mock-addon",
|
||||
name: "Mock Add-ons",
|
||||
uiPriority: 4500,
|
||||
flags: AddonManager.TYPE_UI_VIEW_LIST,
|
||||
},
|
||||
]);
|
||||
|
||||
let aWindow = await open_manager(VIEW_ID);
|
||||
gManagerWindow = aWindow;
|
||||
|
@ -64,18 +66,25 @@ function check_list(aItem) {
|
|||
// Check state of the empty notice
|
||||
let emptyNotice = gManagerWindow.document.getElementById(EMPTY_ID);
|
||||
ok(emptyNotice != null, "Should have found the empty notice");
|
||||
is(!emptyNotice.hidden, (aItem == null), "Empty notice should be showing if list empty");
|
||||
is(
|
||||
!emptyNotice.hidden,
|
||||
aItem == null,
|
||||
"Empty notice should be showing if list empty"
|
||||
);
|
||||
|
||||
// Check the children of the list
|
||||
let list = gManagerWindow.document.getElementById(LIST_ID);
|
||||
is(list.childNodes.length, aItem ? 1 : 0, "Should get expected number of items in list");
|
||||
is(
|
||||
list.childNodes.length,
|
||||
aItem ? 1 : 0,
|
||||
"Should get expected number of items in list"
|
||||
);
|
||||
if (aItem != null) {
|
||||
let itemName = list.firstChild.getAttribute("name");
|
||||
is(itemName, aItem.name, "List item should have correct name");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test that the empty notice is showing and no items are showing in list
|
||||
add_test(function() {
|
||||
check_list(null);
|
||||
|
@ -160,4 +169,3 @@ add_test(async function() {
|
|||
check_list(gItem);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
|
|
@ -26,7 +26,11 @@ function end_test() {
|
|||
add_test(async function() {
|
||||
let aManager = await open_manager("addons://detail/foo");
|
||||
gCategoryUtilities = new CategoryUtilities(aManager);
|
||||
is(gCategoryUtilities.selectedCategory, "discover", "Should fall back to the discovery pane");
|
||||
is(
|
||||
gCategoryUtilities.selectedCategory,
|
||||
"discover",
|
||||
"Should fall back to the discovery pane"
|
||||
);
|
||||
|
||||
close_manager(aManager, run_next_test);
|
||||
});
|
||||
|
@ -34,15 +38,21 @@ add_test(async function() {
|
|||
// Also test that opening directly to an add-on that does exist doesn't break
|
||||
// and selects the right category
|
||||
add_test(async function() {
|
||||
new MockProvider().createAddons([{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "addon 1",
|
||||
version: "1.0",
|
||||
}]);
|
||||
new MockProvider().createAddons([
|
||||
{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "addon 1",
|
||||
version: "1.0",
|
||||
},
|
||||
]);
|
||||
|
||||
let aManager = await open_manager("addons://detail/addon1@tests.mozilla.org");
|
||||
gCategoryUtilities = new CategoryUtilities(aManager);
|
||||
is(gCategoryUtilities.selectedCategory, "extension", "Should have selected the right category");
|
||||
is(
|
||||
gCategoryUtilities.selectedCategory,
|
||||
"extension",
|
||||
"Should have selected the right category"
|
||||
);
|
||||
|
||||
close_manager(aManager, run_next_test);
|
||||
});
|
||||
|
|
|
@ -17,8 +17,11 @@ async function test() {
|
|||
Services.prefs.clearUserPref(PREF_UI_LASTCATEGORY);
|
||||
|
||||
aWindow = await open_manager(null);
|
||||
is(new CategoryUtilities(aWindow).selectedCategory, "discover",
|
||||
"Should have loaded the right view");
|
||||
is(
|
||||
new CategoryUtilities(aWindow).selectedCategory,
|
||||
"discover",
|
||||
"Should have loaded the right view"
|
||||
);
|
||||
|
||||
close_manager(aWindow, finish);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,10 @@ async function test() {
|
|||
waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
|
||||
ok(AddonManager.strictCompatibility, "Strict compatibility should be enabled");
|
||||
ok(
|
||||
AddonManager.strictCompatibility,
|
||||
"Strict compatibility should be enabled"
|
||||
);
|
||||
|
||||
let aAddons = await AddonManager.getAllAddons();
|
||||
aAddons.sort(function compareTypeName(a, b) {
|
||||
|
@ -18,10 +21,14 @@ async function test() {
|
|||
let allCompatible = true;
|
||||
for (let a of aAddons) {
|
||||
// Ignore plugins.
|
||||
if (a.type == "plugin" || a.id == "workerbootstrap-test@mozilla.org")
|
||||
if (a.type == "plugin" || a.id == "workerbootstrap-test@mozilla.org") {
|
||||
continue;
|
||||
}
|
||||
|
||||
ok(a.isCompatible, a.type + " " + a.name + " " + a.version + " should be compatible");
|
||||
ok(
|
||||
a.isCompatible,
|
||||
a.type + " " + a.name + " " + a.version + " should be compatible"
|
||||
);
|
||||
allCompatible = allCompatible && a.isCompatible;
|
||||
}
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -23,23 +23,29 @@ SpecialPowers.pushPrefEnv({
|
|||
var gProgressListener = {
|
||||
onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
// Only care about the network stop status events
|
||||
if (!(aStateFlags & (Ci.nsIWebProgressListener.STATE_IS_NETWORK)) ||
|
||||
!(aStateFlags & (Ci.nsIWebProgressListener.STATE_STOP)))
|
||||
if (
|
||||
!(aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) ||
|
||||
!(aStateFlags & Ci.nsIWebProgressListener.STATE_STOP)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gLoadCompleteCallback)
|
||||
if (gLoadCompleteCallback) {
|
||||
executeSoon(gLoadCompleteCallback);
|
||||
}
|
||||
gLoadCompleteCallback = null;
|
||||
},
|
||||
|
||||
onLocationChange() { },
|
||||
onSecurityChange() { },
|
||||
onProgressChange() { },
|
||||
onStatusChange() { },
|
||||
onContentBlockingEvent() { },
|
||||
onLocationChange() {},
|
||||
onSecurityChange() {},
|
||||
onProgressChange() {},
|
||||
onStatusChange() {},
|
||||
onContentBlockingEvent() {},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference,
|
||||
]),
|
||||
};
|
||||
|
||||
function test() {
|
||||
|
@ -52,23 +58,26 @@ function test() {
|
|||
|
||||
gProvider = new MockProvider();
|
||||
|
||||
gProvider.createAddons([{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "Test add-on 1",
|
||||
type: "extension",
|
||||
version: "2.2",
|
||||
isCompatible: false,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_SOFTBLOCKED,
|
||||
userDisabled: false,
|
||||
}, {
|
||||
id: "addon3@tests.mozilla.org",
|
||||
name: "Test add-on 3",
|
||||
type: "theme",
|
||||
version: "1.2b1",
|
||||
isCompatible: false,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
|
||||
userDisabled: true,
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "Test add-on 1",
|
||||
type: "extension",
|
||||
version: "2.2",
|
||||
isCompatible: false,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_SOFTBLOCKED,
|
||||
userDisabled: false,
|
||||
},
|
||||
{
|
||||
id: "addon3@tests.mozilla.org",
|
||||
name: "Test add-on 3",
|
||||
type: "theme",
|
||||
version: "1.2b1",
|
||||
isCompatible: false,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
|
||||
userDisabled: true,
|
||||
},
|
||||
]);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
@ -78,26 +87,34 @@ function end_test() {
|
|||
}
|
||||
|
||||
function getURL(aBrowser) {
|
||||
if (gManagerWindow.document.getElementById("discover-view").selectedPanel !=
|
||||
aBrowser)
|
||||
if (
|
||||
gManagerWindow.document.getElementById("discover-view").selectedPanel !=
|
||||
aBrowser
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var url = aBrowser.currentURI.spec;
|
||||
var pos = url.indexOf("#");
|
||||
if (pos != -1)
|
||||
if (pos != -1) {
|
||||
return url.substring(0, pos);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
function getHash(aBrowser) {
|
||||
if (gManagerWindow.document.getElementById("discover-view").selectedPanel !=
|
||||
aBrowser)
|
||||
if (
|
||||
gManagerWindow.document.getElementById("discover-view").selectedPanel !=
|
||||
aBrowser
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var url = aBrowser.currentURI.spec;
|
||||
var pos = url.indexOf("#");
|
||||
if (pos != -1)
|
||||
if (pos != -1) {
|
||||
return decodeURIComponent(url.substring(pos + 1));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -113,14 +130,22 @@ async function testHash(aBrowser, aTestAddonVisible) {
|
|||
is(typeof data, "object", "Hash should be a JS object");
|
||||
|
||||
// Ensure that at least the test add-ons are present
|
||||
if (aTestAddonVisible[0])
|
||||
if (aTestAddonVisible[0]) {
|
||||
ok("addon1@tests.mozilla.org" in data, "Test add-on 1 should be listed");
|
||||
else
|
||||
ok(!("addon1@tests.mozilla.org" in data), "Test add-on 1 should not be listed");
|
||||
if (aTestAddonVisible[1])
|
||||
} else {
|
||||
ok(
|
||||
!("addon1@tests.mozilla.org" in data),
|
||||
"Test add-on 1 should not be listed"
|
||||
);
|
||||
}
|
||||
if (aTestAddonVisible[1]) {
|
||||
ok("addon3@tests.mozilla.org" in data, "Test add-on 3 should be listed");
|
||||
else
|
||||
ok(!("addon3@tests.mozilla.org" in data), "Test add-on 3 should not be listed");
|
||||
} else {
|
||||
ok(
|
||||
!("addon3@tests.mozilla.org" in data),
|
||||
"Test add-on 3 should not be listed"
|
||||
);
|
||||
}
|
||||
|
||||
// Test against all the add-ons the manager knows about since plugins and
|
||||
// app extensions may exist
|
||||
|
@ -128,8 +153,9 @@ async function testHash(aBrowser, aTestAddonVisible) {
|
|||
for (let addon of aAddons) {
|
||||
if (!(addon.id in data)) {
|
||||
// Test add-ons will have shown an error if necessary above
|
||||
if (addon.id.substring(6) != "@tests.mozilla.org")
|
||||
if (addon.id.substring(6) != "@tests.mozilla.org") {
|
||||
ok(false, "Add-on " + addon.id + " was not included in the data");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -138,25 +164,42 @@ async function testHash(aBrowser, aTestAddonVisible) {
|
|||
is(addonData.name, addon.name, "Name should be correct");
|
||||
is(addonData.version, addon.version, "Version should be correct");
|
||||
is(addonData.type, addon.type, "Type should be correct");
|
||||
is(addonData.userDisabled, addon.userDisabled, "userDisabled should be correct");
|
||||
is(addonData.isBlocklisted, addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED, "blocklisted should be correct");
|
||||
is(addonData.isCompatible, addon.isCompatible, "isCompatible should be correct");
|
||||
is(
|
||||
addonData.userDisabled,
|
||||
addon.userDisabled,
|
||||
"userDisabled should be correct"
|
||||
);
|
||||
is(
|
||||
addonData.isBlocklisted,
|
||||
addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED,
|
||||
"blocklisted should be correct"
|
||||
);
|
||||
is(
|
||||
addonData.isCompatible,
|
||||
addon.isCompatible,
|
||||
"isCompatible should be correct"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function isLoading() {
|
||||
var loading = gManagerWindow.document.getElementById("discover-view").selectedPanel ==
|
||||
gManagerWindow.document.getElementById("discover-loading");
|
||||
var loading =
|
||||
gManagerWindow.document.getElementById("discover-view").selectedPanel ==
|
||||
gManagerWindow.document.getElementById("discover-loading");
|
||||
if (loading) {
|
||||
is_element_visible(gManagerWindow.document.querySelector("#discover-loading .loading"),
|
||||
"Loading message should be visible when its panel is the selected panel");
|
||||
is_element_visible(
|
||||
gManagerWindow.document.querySelector("#discover-loading .loading"),
|
||||
"Loading message should be visible when its panel is the selected panel"
|
||||
);
|
||||
}
|
||||
return loading;
|
||||
}
|
||||
|
||||
function isError() {
|
||||
return gManagerWindow.document.getElementById("discover-view").selectedPanel ==
|
||||
gManagerWindow.document.getElementById("discover-error");
|
||||
return (
|
||||
gManagerWindow.document.getElementById("discover-view").selectedPanel ==
|
||||
gManagerWindow.document.getElementById("discover-error")
|
||||
);
|
||||
}
|
||||
|
||||
function clickLink(aId, aCallback) {
|
||||
|
@ -170,7 +213,7 @@ function clickLink(aId, aCallback) {
|
|||
};
|
||||
|
||||
var link = browser.contentDocument.getElementById(aId);
|
||||
EventUtils.sendMouseEvent({type: "click"}, link);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, link);
|
||||
|
||||
executeSoon(function() {
|
||||
ok(isLoading(), "Clicking a link should show the loading pane");
|
||||
|
@ -200,13 +243,20 @@ add_test(async function() {
|
|||
// selected view displays the right url
|
||||
add_test(async function() {
|
||||
// Hide one of the test add-ons
|
||||
Services.prefs.setBoolPref("extensions.addon3@tests.mozilla.org.getAddons.cache.enabled", false);
|
||||
Services.prefs.setBoolPref(
|
||||
"extensions.addon3@tests.mozilla.org.getAddons.cache.enabled",
|
||||
false
|
||||
);
|
||||
await open_manager(null, null, function(aWindow) {
|
||||
gManagerWindow = aWindow;
|
||||
ok(isLoading(), "Should be loading at first");
|
||||
});
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
is(gCategoryUtilities.selectedCategory, "discover", "Should have loaded the right view");
|
||||
is(
|
||||
gCategoryUtilities.selectedCategory,
|
||||
"discover",
|
||||
"Should have loaded the right view"
|
||||
);
|
||||
|
||||
var browser = gManagerWindow.document.getElementById("discover-browser");
|
||||
is(getURL(browser), MAIN_URL, "Should have loaded the right url");
|
||||
|
@ -218,7 +268,9 @@ add_test(async function() {
|
|||
// Tests that loading the add-ons manager with the discovery view as the initial
|
||||
// view displays the right url
|
||||
add_test(async function() {
|
||||
Services.prefs.clearUserPref("extensions.addon3@tests.mozilla.org.getAddons.cache.enabled");
|
||||
Services.prefs.clearUserPref(
|
||||
"extensions.addon3@tests.mozilla.org.getAddons.cache.enabled"
|
||||
);
|
||||
let aWindow = await open_manager(null);
|
||||
gManagerWindow = aWindow;
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
|
@ -229,7 +281,11 @@ add_test(async function() {
|
|||
ok(isLoading(), "Should be loading at first");
|
||||
});
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
is(gCategoryUtilities.selectedCategory, "discover", "Should have loaded the right view");
|
||||
is(
|
||||
gCategoryUtilities.selectedCategory,
|
||||
"discover",
|
||||
"Should have loaded the right view"
|
||||
);
|
||||
|
||||
var browser = gManagerWindow.document.getElementById("discover-browser");
|
||||
is(getURL(browser), MAIN_URL, "Should have loaded the right url");
|
||||
|
@ -261,7 +317,11 @@ add_test(async function() {
|
|||
let aWindow = await open_manager(null);
|
||||
gManagerWindow = aWindow;
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
is(gCategoryUtilities.selectedCategory, "discover", "Should have loaded the right view");
|
||||
is(
|
||||
gCategoryUtilities.selectedCategory,
|
||||
"discover",
|
||||
"Should have loaded the right view"
|
||||
);
|
||||
|
||||
var browser = gManagerWindow.document.getElementById("discover-browser");
|
||||
is(getURL(browser), MAIN_URL, "Should have loaded the right url");
|
||||
|
@ -281,7 +341,11 @@ add_test(async function() {
|
|||
aWindow = await open_manager("addons://discover/");
|
||||
gManagerWindow = aWindow;
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
is(gCategoryUtilities.selectedCategory, "discover", "Should have loaded the right view");
|
||||
is(
|
||||
gCategoryUtilities.selectedCategory,
|
||||
"discover",
|
||||
"Should have loaded the right view"
|
||||
);
|
||||
|
||||
var browser = gManagerWindow.document.getElementById("discover-browser");
|
||||
is(getURL(browser), MAIN_URL, "Should have loaded the right url");
|
||||
|
@ -357,7 +421,11 @@ add_test(async function() {
|
|||
is(getURL(browser), MAIN_URL, "Should have loaded the right url");
|
||||
|
||||
await clickLink("link-good");
|
||||
is(getURL(browser), "https://example.com/" + RELATIVE_DIR + "releaseNotes.xhtml", "Should have loaded the right url");
|
||||
is(
|
||||
getURL(browser),
|
||||
"https://example.com/" + RELATIVE_DIR + "releaseNotes.xhtml",
|
||||
"Should have loaded the right url"
|
||||
);
|
||||
|
||||
await gCategoryUtilities.openType("extension");
|
||||
await gCategoryUtilities.openType("discover");
|
||||
|
@ -378,10 +446,11 @@ add_test(async function() {
|
|||
|
||||
var count = 10;
|
||||
function clickAgain(aCallback) {
|
||||
if (count-- == 0)
|
||||
if (count-- == 0) {
|
||||
aCallback();
|
||||
else
|
||||
} else {
|
||||
clickLink("link-normal", clickAgain.bind(null, aCallback));
|
||||
}
|
||||
}
|
||||
|
||||
clickAgain(async function() {
|
||||
|
@ -408,13 +477,21 @@ add_test(async function() {
|
|||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
|
||||
var browser = gManagerWindow.document.getElementById("discover-browser");
|
||||
is(getURL(browser), TESTROOT + "discovery.html", "Should have loaded the right url");
|
||||
is(
|
||||
getURL(browser),
|
||||
TESTROOT + "discovery.html",
|
||||
"Should have loaded the right url"
|
||||
);
|
||||
|
||||
await clickLink("link-normal");
|
||||
is(getURL(browser), MAIN_URL, "Should have loaded the right url");
|
||||
|
||||
await clickLink("link-http");
|
||||
is(getURL(browser), TESTROOT + "discovery.html", "Should have loaded the right url");
|
||||
is(
|
||||
getURL(browser),
|
||||
TESTROOT + "discovery.html",
|
||||
"Should have loaded the right url"
|
||||
);
|
||||
|
||||
close_manager(gManagerWindow, run_next_test);
|
||||
});
|
||||
|
@ -430,28 +507,40 @@ add_test(async function() {
|
|||
|
||||
var browser = gManagerWindow.document.getElementById("discover-browser");
|
||||
|
||||
EventUtils.synthesizeMouse(gCategoryUtilities.get("discover"), 2, 2, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
gCategoryUtilities.get("discover"),
|
||||
2,
|
||||
2,
|
||||
{},
|
||||
gManagerWindow
|
||||
);
|
||||
|
||||
// Do this after wait_for_view_load has had a chance to setup its
|
||||
// listeners.
|
||||
executeSoon(() => {
|
||||
ok(isLoading(), "Should be loading");
|
||||
// This will actually stop the about:blank load
|
||||
browser.stop();
|
||||
ok(isLoading(), "Should be loading");
|
||||
// This will actually stop the about:blank load
|
||||
browser.stop();
|
||||
});
|
||||
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
ok(isError(), "Should have shown the error page");
|
||||
|
||||
await gCategoryUtilities.openType("extension");
|
||||
EventUtils.synthesizeMouse(gCategoryUtilities.get("discover"), 2, 2, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
gCategoryUtilities.get("discover"),
|
||||
2,
|
||||
2,
|
||||
{},
|
||||
gManagerWindow
|
||||
);
|
||||
|
||||
// Do this after wait_for_view_load has had a chance to setup its
|
||||
// listeners.
|
||||
executeSoon(() => {
|
||||
ok(isLoading(), "Should be loading");
|
||||
// This will actually stop the about:blank load
|
||||
browser.stop();
|
||||
ok(isLoading(), "Should be loading");
|
||||
// This will actually stop the about:blank load
|
||||
browser.stop();
|
||||
});
|
||||
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
|
@ -482,43 +571,68 @@ add_test(async function() {
|
|||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
|
||||
browser = gManagerWindow.document.getElementById("discover-browser");
|
||||
is(getURL(browser), url, "Should be able to load the chrome XUL file a second time");
|
||||
is(
|
||||
getURL(browser),
|
||||
url,
|
||||
"Should be able to load the chrome XUL file a second time"
|
||||
);
|
||||
|
||||
close_manager(gManagerWindow, run_next_test);
|
||||
});
|
||||
|
||||
// Bug 711693 - Send the compatibility mode when loading the Discovery pane
|
||||
add_test(async function() {
|
||||
info("Test '%COMPATIBILITY_MODE%' in the URL is correctly replaced by 'normal'");
|
||||
Services.prefs.setCharPref(PREF_DISCOVERURL, MAIN_URL + "?mode=%COMPATIBILITY_MODE%");
|
||||
info(
|
||||
"Test '%COMPATIBILITY_MODE%' in the URL is correctly replaced by 'normal'"
|
||||
);
|
||||
Services.prefs.setCharPref(
|
||||
PREF_DISCOVERURL,
|
||||
MAIN_URL + "?mode=%COMPATIBILITY_MODE%"
|
||||
);
|
||||
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, false);
|
||||
|
||||
let aWindow = await open_manager("addons://discover/");
|
||||
gManagerWindow = aWindow;
|
||||
var browser = gManagerWindow.document.getElementById("discover-browser");
|
||||
is(getURL(browser), MAIN_URL + "?mode=normal", "Should have loaded the right url");
|
||||
is(
|
||||
getURL(browser),
|
||||
MAIN_URL + "?mode=normal",
|
||||
"Should have loaded the right url"
|
||||
);
|
||||
close_manager(gManagerWindow, run_next_test);
|
||||
});
|
||||
|
||||
add_test(async function() {
|
||||
info("Test '%COMPATIBILITY_MODE%' in the URL is correctly replaced by 'strict'");
|
||||
info(
|
||||
"Test '%COMPATIBILITY_MODE%' in the URL is correctly replaced by 'strict'"
|
||||
);
|
||||
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
|
||||
|
||||
let aWindow = await open_manager("addons://discover/");
|
||||
gManagerWindow = aWindow;
|
||||
var browser = gManagerWindow.document.getElementById("discover-browser");
|
||||
is(getURL(browser), MAIN_URL + "?mode=strict", "Should have loaded the right url");
|
||||
is(
|
||||
getURL(browser),
|
||||
MAIN_URL + "?mode=strict",
|
||||
"Should have loaded the right url"
|
||||
);
|
||||
close_manager(gManagerWindow, run_next_test);
|
||||
});
|
||||
|
||||
add_test(async function() {
|
||||
info("Test '%COMPATIBILITY_MODE%' in the URL is correctly replaced by 'ignore'");
|
||||
info(
|
||||
"Test '%COMPATIBILITY_MODE%' in the URL is correctly replaced by 'ignore'"
|
||||
);
|
||||
Services.prefs.setBoolPref(PREF_CHECK_COMPATIBILITY, false);
|
||||
|
||||
let aWindow = await open_manager("addons://discover/");
|
||||
gManagerWindow = aWindow;
|
||||
var browser = gManagerWindow.document.getElementById("discover-browser");
|
||||
is(getURL(browser), MAIN_URL + "?mode=ignore", "Should have loaded the right url");
|
||||
is(
|
||||
getURL(browser),
|
||||
MAIN_URL + "?mode=ignore",
|
||||
"Should have loaded the right url"
|
||||
);
|
||||
close_manager(gManagerWindow, run_next_test);
|
||||
});
|
||||
|
||||
|
@ -528,18 +642,32 @@ async function bug_601442_test_elements(visible) {
|
|||
let aWindow = await open_manager("addons://list/extension");
|
||||
gManagerWindow = aWindow;
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
if (visible)
|
||||
ok(gCategoryUtilities.isTypeVisible("discover"), "Discover category should be visible");
|
||||
else
|
||||
ok(!gCategoryUtilities.isTypeVisible("discover"), "Discover category should not be visible");
|
||||
if (visible) {
|
||||
ok(
|
||||
gCategoryUtilities.isTypeVisible("discover"),
|
||||
"Discover category should be visible"
|
||||
);
|
||||
} else {
|
||||
ok(
|
||||
!gCategoryUtilities.isTypeVisible("discover"),
|
||||
"Discover category should not be visible"
|
||||
);
|
||||
}
|
||||
|
||||
gManagerWindow.loadView("addons://list/dictionary");
|
||||
let aManager = await wait_for_view_load(gManagerWindow);
|
||||
var button = aManager.document.getElementById("discover-button-install");
|
||||
if (visible)
|
||||
ok(!BrowserTestUtils.is_hidden(button), "Discover button should be visible!");
|
||||
else
|
||||
ok(BrowserTestUtils.is_hidden(button), "Discover button should not be visible!");
|
||||
if (visible) {
|
||||
ok(
|
||||
!BrowserTestUtils.is_hidden(button),
|
||||
"Discover button should be visible!"
|
||||
);
|
||||
} else {
|
||||
ok(
|
||||
BrowserTestUtils.is_hidden(button),
|
||||
"Discover button should not be visible!"
|
||||
);
|
||||
}
|
||||
|
||||
close_manager(gManagerWindow, run_next_test);
|
||||
}
|
||||
|
@ -574,7 +702,11 @@ add_test(async function() {
|
|||
let aWindow = await open_manager(null);
|
||||
gManagerWindow = aWindow;
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
is(gCategoryUtilities.selectedCategory, "extension", "Should be showing the extension view");
|
||||
is(
|
||||
gCategoryUtilities.selectedCategory,
|
||||
"extension",
|
||||
"Should be showing the extension view"
|
||||
);
|
||||
close_manager(gManagerWindow, run_next_test);
|
||||
Services.prefs.clearUserPref(PREF_DISCOVER_ENABLED);
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
const {ClientID} = ChromeUtils.import("resource://gre/modules/ClientID.jsm");
|
||||
const { ClientID } = ChromeUtils.import("resource://gre/modules/ClientID.jsm");
|
||||
|
||||
const MAIN_URL = "https://example.com/" + RELATIVE_DIR + "discovery.html";
|
||||
|
||||
|
@ -36,18 +36,28 @@ function waitForHeader() {
|
|||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
[PREF_DISCOVERURL, MAIN_URL],
|
||||
["datareporting.healthreport.uploadEnabled", true],
|
||||
["browser.discovery.enabled", true],
|
||||
]});
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[PREF_DISCOVERURL, MAIN_URL],
|
||||
["datareporting.healthreport.uploadEnabled", true],
|
||||
["browser.discovery.enabled", true],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_no_private_clientid() {
|
||||
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({private: true});
|
||||
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({
|
||||
private: true,
|
||||
});
|
||||
let [header, manager] = await Promise.all([
|
||||
waitForHeader(),
|
||||
open_manager("addons://discover/", undefined, undefined, undefined, privateWindow),
|
||||
open_manager(
|
||||
"addons://discover/",
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
privateWindow
|
||||
),
|
||||
]);
|
||||
ok(PrivateBrowsingUtils.isContentWindowPrivate(manager), "window is private");
|
||||
is(header, null, "header was not set");
|
||||
|
|
|
@ -12,20 +12,33 @@
|
|||
// we only need EventUtils.js for a few files which is why we are using loadSubScript.
|
||||
var gManagerWindow;
|
||||
var EventUtils = {};
|
||||
Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
|
||||
EventUtils
|
||||
);
|
||||
|
||||
async function checkInstallConfirmation(...names) {
|
||||
let notificationCount = 0;
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
let installInfo = aSubject.wrappedJSObject;
|
||||
isnot(installInfo.browser, null, "Notification should have non-null browser");
|
||||
isnot(
|
||||
installInfo.browser,
|
||||
null,
|
||||
"Notification should have non-null browser"
|
||||
);
|
||||
|
||||
is(installInfo.installs.length, 1, "Got one AddonInstall instance as expected");
|
||||
is(
|
||||
installInfo.installs.length,
|
||||
1,
|
||||
"Got one AddonInstall instance as expected"
|
||||
);
|
||||
|
||||
Assert.deepEqual(installInfo.installs[0].installTelemetryInfo,
|
||||
{source: "about:addons", method: "drag-and-drop"},
|
||||
"Got the expected installTelemetryInfo");
|
||||
Assert.deepEqual(
|
||||
installInfo.installs[0].installTelemetryInfo,
|
||||
{ source: "about:addons", method: "drag-and-drop" },
|
||||
"Got the expected installTelemetryInfo"
|
||||
);
|
||||
|
||||
notificationCount++;
|
||||
},
|
||||
|
@ -42,7 +55,9 @@ async function checkInstallConfirmation(...names) {
|
|||
|
||||
info(`Saw install for ${name}`);
|
||||
if (results.length < names.length) {
|
||||
info(`Waiting for installs for ${names.filter(n => !results.includes(n))}`);
|
||||
info(
|
||||
`Waiting for installs for ${names.filter(n => !results.includes(n))}`
|
||||
);
|
||||
|
||||
promise = promisePopupNotificationShown("addon-webext-permissions");
|
||||
}
|
||||
|
@ -51,7 +66,11 @@ async function checkInstallConfirmation(...names) {
|
|||
|
||||
Assert.deepEqual(results.sort(), names.sort(), "Got expected installs");
|
||||
|
||||
is(notificationCount, names.length, `Saw ${names.length} addon-install-started notification`);
|
||||
is(
|
||||
notificationCount,
|
||||
names.length,
|
||||
`Saw ${names.length} addon-install-started notification`
|
||||
);
|
||||
Services.obs.removeObserver(observer, "addon-install-started");
|
||||
}
|
||||
|
||||
|
@ -68,9 +87,13 @@ add_task(async function test_drop_url() {
|
|||
gManagerWindow = await open_manager("addons://list/extension");
|
||||
let promise = checkInstallConfirmation("Drag Drop test 1");
|
||||
let viewContainer = getViewContainer(gManagerWindow);
|
||||
let effect = EventUtils.synthesizeDrop(viewContainer, viewContainer,
|
||||
[[{type: "text/x-moz-url", data: url}]],
|
||||
"copy", gManagerWindow);
|
||||
let effect = EventUtils.synthesizeDrop(
|
||||
viewContainer,
|
||||
viewContainer,
|
||||
[[{ type: "text/x-moz-url", data: url }]],
|
||||
"copy",
|
||||
gManagerWindow
|
||||
);
|
||||
is(effect, "copy", "Drag should be accepted");
|
||||
await promise;
|
||||
await close_manager(gManagerWindow);
|
||||
|
@ -83,9 +106,13 @@ add_task(async function test_drop_file() {
|
|||
await wait_for_view_load(gManagerWindow);
|
||||
let promise = checkInstallConfirmation("Drag Drop test 1");
|
||||
let viewContainer = getViewContainer(gManagerWindow);
|
||||
let effect = EventUtils.synthesizeDrop(viewContainer, viewContainer,
|
||||
[[{type: "application/x-moz-file", data: fileurl.file}]],
|
||||
"copy", gManagerWindow);
|
||||
let effect = EventUtils.synthesizeDrop(
|
||||
viewContainer,
|
||||
viewContainer,
|
||||
[[{ type: "application/x-moz-file", data: fileurl.file }]],
|
||||
"copy",
|
||||
gManagerWindow
|
||||
);
|
||||
is(effect, "copy", "Drag should be accepted");
|
||||
await promise;
|
||||
await close_manager(gManagerWindow);
|
||||
|
@ -97,12 +124,21 @@ add_task(async function test_drop_multiple_urls() {
|
|||
let url2 = TESTROOT2 + "addons/browser_dragdrop2.xpi";
|
||||
gManagerWindow = await open_manager("addons://list/extension");
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
let promise = checkInstallConfirmation("Drag Drop test 1", "Drag Drop test 2");
|
||||
let promise = checkInstallConfirmation(
|
||||
"Drag Drop test 1",
|
||||
"Drag Drop test 2"
|
||||
);
|
||||
let viewContainer = getViewContainer(gManagerWindow);
|
||||
let effect = EventUtils.synthesizeDrop(viewContainer, viewContainer,
|
||||
[[{type: "text/x-moz-url", data: url1}],
|
||||
[{type: "text/x-moz-url", data: url2}]],
|
||||
"copy", gManagerWindow);
|
||||
let effect = EventUtils.synthesizeDrop(
|
||||
viewContainer,
|
||||
viewContainer,
|
||||
[
|
||||
[{ type: "text/x-moz-url", data: url1 }],
|
||||
[{ type: "text/x-moz-url", data: url2 }],
|
||||
],
|
||||
"copy",
|
||||
gManagerWindow
|
||||
);
|
||||
is(effect, "copy", "Drag should be accepted");
|
||||
await promise;
|
||||
await close_manager(gManagerWindow);
|
||||
|
@ -114,12 +150,21 @@ add_task(async function test_drop_multiple_files() {
|
|||
let fileurl2 = get_addon_file_url("browser_dragdrop2.xpi");
|
||||
gManagerWindow = await open_manager("addons://list/extension");
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
let promise = checkInstallConfirmation("Drag Drop test 1", "Drag Drop test 2");
|
||||
let promise = checkInstallConfirmation(
|
||||
"Drag Drop test 1",
|
||||
"Drag Drop test 2"
|
||||
);
|
||||
let viewContainer = getViewContainer(gManagerWindow);
|
||||
let effect = EventUtils.synthesizeDrop(viewContainer, viewContainer,
|
||||
[[{type: "application/x-moz-file", data: fileurl1.file}],
|
||||
[{type: "application/x-moz-file", data: fileurl2.file}]],
|
||||
"copy", gManagerWindow);
|
||||
let effect = EventUtils.synthesizeDrop(
|
||||
viewContainer,
|
||||
viewContainer,
|
||||
[
|
||||
[{ type: "application/x-moz-file", data: fileurl1.file }],
|
||||
[{ type: "application/x-moz-file", data: fileurl2.file }],
|
||||
],
|
||||
"copy",
|
||||
gManagerWindow
|
||||
);
|
||||
is(effect, "copy", "Drag should be accepted");
|
||||
await promise;
|
||||
await close_manager(gManagerWindow);
|
||||
|
@ -131,12 +176,21 @@ add_task(async function test_drop_file_and_url() {
|
|||
let fileurl = get_addon_file_url("browser_dragdrop2.xpi");
|
||||
gManagerWindow = await open_manager("addons://list/extension");
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
let promise = checkInstallConfirmation("Drag Drop test 1", "Drag Drop test 2");
|
||||
let promise = checkInstallConfirmation(
|
||||
"Drag Drop test 1",
|
||||
"Drag Drop test 2"
|
||||
);
|
||||
let viewContainer = getViewContainer(gManagerWindow);
|
||||
let effect = EventUtils.synthesizeDrop(viewContainer, viewContainer,
|
||||
[[{type: "text/x-moz-url", data: url}],
|
||||
[{type: "application/x-moz-file", data: fileurl.file}]],
|
||||
"copy", gManagerWindow);
|
||||
let effect = EventUtils.synthesizeDrop(
|
||||
viewContainer,
|
||||
viewContainer,
|
||||
[
|
||||
[{ type: "text/x-moz-url", data: url }],
|
||||
[{ type: "application/x-moz-file", data: fileurl.file }],
|
||||
],
|
||||
"copy",
|
||||
gManagerWindow
|
||||
);
|
||||
is(effect, "copy", "Drag should be accepted");
|
||||
await promise;
|
||||
await close_manager(gManagerWindow);
|
||||
|
@ -152,9 +206,13 @@ add_task(async function test_drop_incompat_file() {
|
|||
|
||||
let url = `${TESTROOT}/addons/browser_dragdrop_incompat.xpi`;
|
||||
let viewContainer = getViewContainer(gManagerWindow);
|
||||
EventUtils.synthesizeDrop(viewContainer, viewContainer,
|
||||
[[{type: "text/x-moz-url", data: url}]],
|
||||
"copy", gManagerWindow);
|
||||
EventUtils.synthesizeDrop(
|
||||
viewContainer,
|
||||
viewContainer,
|
||||
[[{ type: "text/x-moz-url", data: url }]],
|
||||
"copy",
|
||||
gManagerWindow
|
||||
);
|
||||
|
||||
await errorPromise;
|
||||
ok(true, "Got addon-install-failed event");
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Test Permission Popup for Sideloaded Extensions.
|
||||
*/
|
||||
const {AddonTestUtils} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
* Test Permission Popup for Sideloaded Extensions.
|
||||
*/
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
const ADDON_ID = "addon1@test.mozilla.org";
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
|
@ -13,13 +15,26 @@ AddonTestUtils.initMochitest(this);
|
|||
function assertDisabledSideloadedExtensionElement(managerWindow, addonElement) {
|
||||
const doc = addonElement.ownerDocument;
|
||||
if (managerWindow.useHtmlViews) {
|
||||
const toggleDisabled = addonElement.querySelector('[action="toggle-disabled"]');
|
||||
is(doc.l10n.getAttributes(toggleDisabled).id, "enable-addon-button",
|
||||
"Addon toggle-disabled action has the enable label");
|
||||
const toggleDisabled = addonElement.querySelector(
|
||||
'[action="toggle-disabled"]'
|
||||
);
|
||||
is(
|
||||
doc.l10n.getAttributes(toggleDisabled).id,
|
||||
"enable-addon-button",
|
||||
"Addon toggle-disabled action has the enable label"
|
||||
);
|
||||
} else {
|
||||
let el = doc.getAnonymousElementByAttribute(addonElement, "anonid", "disable-btn");
|
||||
let el = doc.getAnonymousElementByAttribute(
|
||||
addonElement,
|
||||
"anonid",
|
||||
"disable-btn"
|
||||
);
|
||||
is_element_hidden(el, "Disable button not visible.");
|
||||
el = doc.getAnonymousElementByAttribute(addonElement, "anonid", "enable-btn");
|
||||
el = doc.getAnonymousElementByAttribute(
|
||||
addonElement,
|
||||
"anonid",
|
||||
"enable-btn"
|
||||
);
|
||||
is_element_visible(el, "Enable button visible");
|
||||
}
|
||||
}
|
||||
|
@ -27,13 +42,26 @@ function assertDisabledSideloadedExtensionElement(managerWindow, addonElement) {
|
|||
function assertEnabledSideloadedExtensionElement(managerWindow, addonElement) {
|
||||
const doc = addonElement.ownerDocument;
|
||||
if (managerWindow.useHtmlViews) {
|
||||
const toggleDisabled = addonElement.querySelector('[action="toggle-disabled"]');
|
||||
is(doc.l10n.getAttributes(toggleDisabled).id, "enable-addon-button",
|
||||
"Addon toggle-disabled action has the enable label");
|
||||
const toggleDisabled = addonElement.querySelector(
|
||||
'[action="toggle-disabled"]'
|
||||
);
|
||||
is(
|
||||
doc.l10n.getAttributes(toggleDisabled).id,
|
||||
"enable-addon-button",
|
||||
"Addon toggle-disabled action has the enable label"
|
||||
);
|
||||
} else {
|
||||
let el = doc.getAnonymousElementByAttribute(addonElement, "anonid", "disable-btn");
|
||||
let el = doc.getAnonymousElementByAttribute(
|
||||
addonElement,
|
||||
"anonid",
|
||||
"disable-btn"
|
||||
);
|
||||
is_element_hidden(el, "Disable button not visible.");
|
||||
el = doc.getAnonymousElementByAttribute(addonElement, "anonid", "enable-btn");
|
||||
el = doc.getAnonymousElementByAttribute(
|
||||
addonElement,
|
||||
"anonid",
|
||||
"enable-btn"
|
||||
);
|
||||
is_element_visible(el, "Enable button visible");
|
||||
}
|
||||
}
|
||||
|
@ -43,8 +71,12 @@ function clickEnableExtension(managerWindow, addonElement) {
|
|||
addonElement.querySelector('[action="toggle-disabled"]').click();
|
||||
} else {
|
||||
const doc = addonElement.ownerDocument;
|
||||
const el = doc.getAnonymousElementByAttribute(addonElement, "anonid", "enable-btn");
|
||||
EventUtils.synthesizeMouseAtCenter(el, {clickCount: 1}, managerWindow);
|
||||
const el = doc.getAnonymousElementByAttribute(
|
||||
addonElement,
|
||||
"anonid",
|
||||
"enable-btn"
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(el, { clickCount: 1 }, managerWindow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,17 +92,19 @@ async function test_sideloaded_extension_permissions_prompt() {
|
|||
|
||||
let options = {
|
||||
manifest: {
|
||||
applications: {gecko: {id: ADDON_ID}},
|
||||
applications: { gecko: { id: ADDON_ID } },
|
||||
name: "Test 1",
|
||||
permissions: ["history", "https://*/*"],
|
||||
icons: {"64": "foo-icon.png"},
|
||||
icons: { "64": "foo-icon.png" },
|
||||
},
|
||||
};
|
||||
|
||||
let xpi = AddonTestUtils.createTempWebExtensionFile(options);
|
||||
await AddonTestUtils.manuallyInstall(xpi);
|
||||
|
||||
let changePromise = new Promise(resolve => ExtensionsUI.once("change", resolve));
|
||||
let changePromise = new Promise(resolve =>
|
||||
ExtensionsUI.once("change", resolve)
|
||||
);
|
||||
ExtensionsUI._checkForSideloaded();
|
||||
await changePromise;
|
||||
|
||||
|
@ -88,10 +122,16 @@ async function test_sideloaded_extension_permissions_prompt() {
|
|||
|
||||
ok(PopupNotifications.isPanelOpen, "Permission popup should be visible");
|
||||
panel.secondaryButton.click();
|
||||
ok(!PopupNotifications.isPanelOpen, "Permission popup should be closed / closing");
|
||||
ok(
|
||||
!PopupNotifications.isPanelOpen,
|
||||
"Permission popup should be closed / closing"
|
||||
);
|
||||
|
||||
addon = await AddonManager.getAddonByID(ADDON_ID);
|
||||
ok(!addon.seen, "Seen flag should remain false after permissions are refused");
|
||||
ok(
|
||||
!addon.seen,
|
||||
"Seen flag should remain false after permissions are refused"
|
||||
);
|
||||
|
||||
// Test click event on permission accept option.
|
||||
addon = get_addon_element(manager, ADDON_ID);
|
||||
|
@ -105,10 +145,16 @@ async function test_sideloaded_extension_permissions_prompt() {
|
|||
|
||||
ok(PopupNotifications.isPanelOpen, "Permission popup should be visible");
|
||||
|
||||
let notificationPromise = acceptAppMenuNotificationWhenShown("addon-installed", ADDON_ID);
|
||||
let notificationPromise = acceptAppMenuNotificationWhenShown(
|
||||
"addon-installed",
|
||||
ADDON_ID
|
||||
);
|
||||
|
||||
panel.button.click();
|
||||
ok(!PopupNotifications.isPanelOpen, "Permission popup should be closed / closing");
|
||||
ok(
|
||||
!PopupNotifications.isPanelOpen,
|
||||
"Permission popup should be closed / closing"
|
||||
);
|
||||
await notificationPromise;
|
||||
|
||||
addon = await AddonManager.getAddonByID(ADDON_ID);
|
||||
|
|
|
@ -13,8 +13,10 @@ function promiseInstallNotification(aBrowser) {
|
|||
return;
|
||||
}
|
||||
|
||||
let notification =
|
||||
PopupNotifications.getNotification(ADDON_INSTALL_ID, aBrowser);
|
||||
let notification = PopupNotifications.getNotification(
|
||||
ADDON_INSTALL_ID,
|
||||
aBrowser
|
||||
);
|
||||
if (!notification) {
|
||||
return;
|
||||
}
|
||||
|
@ -30,16 +32,20 @@ function promiseInstallNotification(aBrowser) {
|
|||
}
|
||||
|
||||
function waitForAnyNewTabAndInstallNotification() {
|
||||
return new Promise((resolve) => {
|
||||
gBrowser.tabContainer.addEventListener("TabOpen", function(openEvent) {
|
||||
let newTab = openEvent.target;
|
||||
resolve([newTab, promiseInstallNotification(newTab.linkedBrowser)]);
|
||||
}, {once: true});
|
||||
return new Promise(resolve => {
|
||||
gBrowser.tabContainer.addEventListener(
|
||||
"TabOpen",
|
||||
function(openEvent) {
|
||||
let newTab = openEvent.target;
|
||||
resolve([newTab, promiseInstallNotification(newTab.linkedBrowser)]);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function CheckBrowserInPid(browser, expectedPid, message) {
|
||||
return ContentTask.spawn(browser, { expectedPid, message }, (arg) => {
|
||||
return ContentTask.spawn(browser, { expectedPid, message }, arg => {
|
||||
is(Services.appinfo.processID, arg.expectedPid, arg.message);
|
||||
});
|
||||
}
|
||||
|
@ -57,27 +63,41 @@ async function testOpenedAndDraggedXPI(aBrowser) {
|
|||
urlbar.focus();
|
||||
EventUtils.synthesizeKey("KEY_Enter");
|
||||
await promiseNotification;
|
||||
await CheckBrowserInPid(aBrowser, browserPid,
|
||||
"Check that browser has not switched process.");
|
||||
await CheckBrowserInPid(
|
||||
aBrowser,
|
||||
browserPid,
|
||||
"Check that browser has not switched process."
|
||||
);
|
||||
|
||||
// No process switch for XPI file:// URI dragged to tab.
|
||||
let tab = gBrowser.getTabForBrowser(aBrowser);
|
||||
promiseNotification = promiseInstallNotification(aBrowser);
|
||||
let effect = EventUtils.synthesizeDrop(tab, tab,
|
||||
[[{type: "text/uri-list", data: fileurl1.spec}]],
|
||||
"move");
|
||||
let effect = EventUtils.synthesizeDrop(
|
||||
tab,
|
||||
tab,
|
||||
[[{ type: "text/uri-list", data: fileurl1.spec }]],
|
||||
"move"
|
||||
);
|
||||
is(effect, "move", "Drag should be accepted");
|
||||
await promiseNotification;
|
||||
await CheckBrowserInPid(aBrowser, browserPid,
|
||||
"Check that browser has not switched process.");
|
||||
await CheckBrowserInPid(
|
||||
aBrowser,
|
||||
browserPid,
|
||||
"Check that browser has not switched process."
|
||||
);
|
||||
|
||||
// No process switch for two XPI file:// URIs dragged to tab.
|
||||
promiseNotification = promiseInstallNotification(aBrowser);
|
||||
let promiseTabAndNotification = waitForAnyNewTabAndInstallNotification();
|
||||
effect = EventUtils.synthesizeDrop(tab, tab,
|
||||
[[{type: "text/uri-list", data: fileurl1.spec}],
|
||||
[{type: "text/uri-list", data: fileurl2.spec}]],
|
||||
"move");
|
||||
effect = EventUtils.synthesizeDrop(
|
||||
tab,
|
||||
tab,
|
||||
[
|
||||
[{ type: "text/uri-list", data: fileurl1.spec }],
|
||||
[{ type: "text/uri-list", data: fileurl2.spec }],
|
||||
],
|
||||
"move"
|
||||
);
|
||||
is(effect, "move", "Drag should be accepted");
|
||||
let [newTab, newTabInstallNotification] = await promiseTabAndNotification;
|
||||
await promiseNotification;
|
||||
|
@ -86,12 +106,18 @@ async function testOpenedAndDraggedXPI(aBrowser) {
|
|||
}
|
||||
await newTabInstallNotification;
|
||||
BrowserTestUtils.removeTab(newTab);
|
||||
await CheckBrowserInPid(aBrowser, browserPid,
|
||||
"Check that browser has not switched process.");
|
||||
await CheckBrowserInPid(
|
||||
aBrowser,
|
||||
browserPid,
|
||||
"Check that browser has not switched process."
|
||||
);
|
||||
}
|
||||
|
||||
// Test for bug 1175267.
|
||||
add_task(async function() {
|
||||
await BrowserTestUtils.withNewTab("http://example.com", testOpenedAndDraggedXPI);
|
||||
await BrowserTestUtils.withNewTab(
|
||||
"http://example.com",
|
||||
testOpenedAndDraggedXPI
|
||||
);
|
||||
await BrowserTestUtils.withNewTab("about:robots", testOpenedAndDraggedXPI);
|
||||
});
|
||||
|
|
|
@ -10,7 +10,8 @@ async function loadDetail(aWindow, id) {
|
|||
if (aWindow.useHtmlViews) {
|
||||
let browser = await aWindow.getHtmlBrowser();
|
||||
let card = browser.contentDocument.querySelector(
|
||||
`addon-card[addon-id="${id}"]`);
|
||||
`addon-card[addon-id="${id}"]`
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(card, {}, browser.contentWindow);
|
||||
} else {
|
||||
let card = aWindow.document.querySelector(`.addon.card[value="${id}"]`);
|
||||
|
@ -27,7 +28,7 @@ async function checkCompatibility(hboxSelector, buttonSelector) {
|
|||
|
||||
let id = "test@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {applications: {gecko: {id}}},
|
||||
manifest: { applications: { gecko: { id } } },
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
await extension.startup();
|
||||
|
@ -38,11 +39,23 @@ async function checkCompatibility(hboxSelector, buttonSelector) {
|
|||
|
||||
function checkMessage(visible) {
|
||||
if (visible) {
|
||||
is_element_visible(hbox, "Check Compatibility warning hbox should be visible");
|
||||
is_element_visible(button, "Check Compatibility warning button should be visible");
|
||||
is_element_visible(
|
||||
hbox,
|
||||
"Check Compatibility warning hbox should be visible"
|
||||
);
|
||||
is_element_visible(
|
||||
button,
|
||||
"Check Compatibility warning button should be visible"
|
||||
);
|
||||
} else {
|
||||
is_element_hidden(hbox, "Check Compatibility warning hbox should be hidden");
|
||||
is_element_hidden(button, "Check Compatibility warning button should be hidden");
|
||||
is_element_hidden(
|
||||
hbox,
|
||||
"Check Compatibility warning hbox should be hidden"
|
||||
);
|
||||
is_element_hidden(
|
||||
button,
|
||||
"Check Compatibility warning button should be hidden"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,8 +76,12 @@ async function checkCompatibility(hboxSelector, buttonSelector) {
|
|||
|
||||
// Check the button works.
|
||||
info("Clicking 'Enable' button");
|
||||
EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
|
||||
is(AddonManager.checkCompatibility, true, "Check Compatibility pref should be cleared");
|
||||
EventUtils.synthesizeMouse(button, 2, 2, {}, aWindow);
|
||||
is(
|
||||
AddonManager.checkCompatibility,
|
||||
true,
|
||||
"Check Compatibility pref should be cleared"
|
||||
);
|
||||
checkMessage(false);
|
||||
|
||||
await close_manager(aWindow);
|
||||
|
@ -80,7 +97,7 @@ async function checkSecurity(hboxSelector, buttonSelector) {
|
|||
|
||||
let id = "test-security@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {applications: {gecko: {id}}},
|
||||
manifest: { applications: { gecko: { id } } },
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
await extension.startup();
|
||||
|
@ -91,11 +108,23 @@ async function checkSecurity(hboxSelector, buttonSelector) {
|
|||
|
||||
function checkMessage(visible) {
|
||||
if (visible) {
|
||||
is_element_visible(hbox, "Check Update Security warning hbox should be visible");
|
||||
is_element_visible(button, "Check Update Security warning button should be visible");
|
||||
is_element_visible(
|
||||
hbox,
|
||||
"Check Update Security warning hbox should be visible"
|
||||
);
|
||||
is_element_visible(
|
||||
button,
|
||||
"Check Update Security warning button should be visible"
|
||||
);
|
||||
} else {
|
||||
is_element_hidden(hbox, "Check Update Security warning hbox should be hidden");
|
||||
is_element_hidden(button, "Check Update Security warning button should be hidden");
|
||||
is_element_hidden(
|
||||
hbox,
|
||||
"Check Update Security warning hbox should be hidden"
|
||||
);
|
||||
is_element_hidden(
|
||||
button,
|
||||
"Check Update Security warning button should be hidden"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,8 +145,12 @@ async function checkSecurity(hboxSelector, buttonSelector) {
|
|||
|
||||
// Check the button works.
|
||||
info("Clicking 'Enable' button");
|
||||
EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
|
||||
is(Services.prefs.prefHasUserValue(pref), false, "Check Update Security pref should be cleared");
|
||||
EventUtils.synthesizeMouse(button, 2, 2, {}, aWindow);
|
||||
is(
|
||||
Services.prefs.prefHasUserValue(pref),
|
||||
false,
|
||||
"Check Update Security pref should be cleared"
|
||||
);
|
||||
checkMessage(false);
|
||||
|
||||
await close_manager(aWindow);
|
||||
|
@ -129,7 +162,7 @@ async function checkSafeMode(hboxSelector) {
|
|||
|
||||
let id = "test-safemode@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {applications: {gecko: {id}}},
|
||||
manifest: { applications: { gecko: { id } } },
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
await extension.startup();
|
||||
|
@ -139,7 +172,10 @@ async function checkSafeMode(hboxSelector) {
|
|||
|
||||
function checkMessage(visible) {
|
||||
if (visible) {
|
||||
is_element_visible(hbox, "Check safe mode warning hbox should be visible");
|
||||
is_element_visible(
|
||||
hbox,
|
||||
"Check safe mode warning hbox should be visible"
|
||||
);
|
||||
} else {
|
||||
is_element_hidden(hbox, "Check safe mode warning hbox should be hidden");
|
||||
}
|
||||
|
@ -149,7 +185,9 @@ async function checkSafeMode(hboxSelector) {
|
|||
checkMessage(false);
|
||||
|
||||
// Mock safe mode by setting the page attribute.
|
||||
aWindow.document.getElementById("addons-page").setAttribute("warning", "safemode");
|
||||
aWindow.document
|
||||
.getElementById("addons-page")
|
||||
.setAttribute("warning", "safemode");
|
||||
|
||||
// Check detail view.
|
||||
await loadDetail(aWindow, id);
|
||||
|
@ -172,7 +210,8 @@ add_task(async function testCompatCheckXUL() {
|
|||
});
|
||||
await checkCompatibility(
|
||||
"#list-view hbox.global-warning-checkcompatibility",
|
||||
"#list-view button.global-warning-checkcompatibility");
|
||||
"#list-view button.global-warning-checkcompatibility"
|
||||
);
|
||||
// No popPrefEnv because of bug 1557397.
|
||||
});
|
||||
|
||||
|
@ -182,7 +221,8 @@ add_task(async function testCompatCheckHTML() {
|
|||
});
|
||||
await checkCompatibility(
|
||||
"#html-view .global-warning-checkcompatibility",
|
||||
"#html-view .global-warning-checkcompatibility button");
|
||||
"#html-view .global-warning-checkcompatibility button"
|
||||
);
|
||||
// No popPrefEnv because of bug 1557397.
|
||||
});
|
||||
|
||||
|
@ -192,7 +232,8 @@ add_task(async function testSecurityCheckXUL() {
|
|||
});
|
||||
await checkSecurity(
|
||||
"#list-view hbox.global-warning-updatesecurity",
|
||||
"#list-view button.global-warning-updatesecurity");
|
||||
"#list-view button.global-warning-updatesecurity"
|
||||
);
|
||||
// No popPrefEnv because of bug 1557397.
|
||||
});
|
||||
|
||||
|
@ -202,7 +243,8 @@ add_task(async function testSecurityCheckHTML() {
|
|||
});
|
||||
await checkSecurity(
|
||||
"#html-view .global-warning-updatesecurity",
|
||||
"#html-view .global-warning-updatesecurity button");
|
||||
"#html-view .global-warning-updatesecurity button"
|
||||
);
|
||||
// No popPrefEnv because of bug 1557397.
|
||||
});
|
||||
|
||||
|
|
|
@ -5,8 +5,13 @@
|
|||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Promise.jsm", this);
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
var GMPScope = ChromeUtils.import("resource://gre/modules/addons/GMPProvider.jsm", null);
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
var GMPScope = ChromeUtils.import(
|
||||
"resource://gre/modules/addons/GMPProvider.jsm",
|
||||
null
|
||||
);
|
||||
|
||||
const TEST_DATE = new Date(2013, 0, 1, 12);
|
||||
|
||||
|
@ -17,10 +22,12 @@ var gMockAddons = [];
|
|||
|
||||
for (let plugin of GMPScope.GMP_PLUGINS) {
|
||||
let mockAddon = Object.freeze({
|
||||
id: plugin.id,
|
||||
isValid: true,
|
||||
isInstalled: false,
|
||||
isEME: !!(plugin.id == "gmp-widevinecdm" || plugin.id.indexOf("gmp-eme-") == 0),
|
||||
id: plugin.id,
|
||||
isValid: true,
|
||||
isInstalled: false,
|
||||
isEME: !!(
|
||||
plugin.id == "gmp-widevinecdm" || plugin.id.indexOf("gmp-eme-") == 0
|
||||
),
|
||||
});
|
||||
gMockAddons.push(mockAddon);
|
||||
}
|
||||
|
@ -30,14 +37,14 @@ var gInstallDeferred = null;
|
|||
var gPrefs = Services.prefs;
|
||||
var getKey = GMPScope.GMPPrefs.getPrefKey;
|
||||
|
||||
function MockGMPInstallManager() {
|
||||
}
|
||||
function MockGMPInstallManager() {}
|
||||
|
||||
MockGMPInstallManager.prototype = {
|
||||
checkForAddons: () => Promise.resolve({
|
||||
usedFallback: true,
|
||||
gmpAddons: gMockAddons,
|
||||
}),
|
||||
checkForAddons: () =>
|
||||
Promise.resolve({
|
||||
usedFallback: true,
|
||||
gmpAddons: gMockAddons,
|
||||
}),
|
||||
|
||||
installAddon: addon => {
|
||||
gInstalledAddonId = addon.id;
|
||||
|
@ -49,9 +56,17 @@ MockGMPInstallManager.prototype = {
|
|||
function openDetailsView(aId) {
|
||||
let view = get_current_view(gManagerWindow);
|
||||
if (gManagerWindow.useHtmlViews) {
|
||||
Assert.equal(view.id, "html-view", "Should be in the list view to use this function");
|
||||
Assert.equal(
|
||||
view.id,
|
||||
"html-view",
|
||||
"Should be in the list view to use this function"
|
||||
);
|
||||
} else {
|
||||
Assert.equal(view.id, "list-view", "Should be in the list view to use this function");
|
||||
Assert.equal(
|
||||
view.id,
|
||||
"list-view",
|
||||
"Should be in the list view to use this function"
|
||||
);
|
||||
}
|
||||
|
||||
let item = get_addon_element(gManagerWindow, aId);
|
||||
|
@ -67,7 +82,7 @@ function openDetailsView(aId) {
|
|||
});
|
||||
}
|
||||
|
||||
async function initializeState({useHtmlViews}) {
|
||||
async function initializeState({ useHtmlViews }) {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.htmlaboutaddons.enabled", useHtmlViews]],
|
||||
});
|
||||
|
@ -81,12 +96,24 @@ async function initializeState({useHtmlViews}) {
|
|||
|
||||
registerCleanupFunction(async function() {
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id));
|
||||
gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, addon.id));
|
||||
gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, addon.id));
|
||||
gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id));
|
||||
gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VISIBLE, addon.id));
|
||||
gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id));
|
||||
gPrefs.clearUserPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id)
|
||||
);
|
||||
gPrefs.clearUserPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, addon.id)
|
||||
);
|
||||
gPrefs.clearUserPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, addon.id)
|
||||
);
|
||||
gPrefs.clearUserPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id)
|
||||
);
|
||||
gPrefs.clearUserPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VISIBLE, addon.id)
|
||||
);
|
||||
gPrefs.clearUserPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id)
|
||||
);
|
||||
}
|
||||
gPrefs.clearUserPref(GMPScope.GMPPrefs.KEY_LOGGING_DUMP);
|
||||
gPrefs.clearUserPref(GMPScope.GMPPrefs.KEY_LOGGING_LEVEL);
|
||||
|
@ -100,12 +127,30 @@ async function initializeState({useHtmlViews}) {
|
|||
// disabled.
|
||||
gPrefs.setBoolPref(GMPScope.GMPPrefs.KEY_EME_ENABLED, true);
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id), false);
|
||||
gPrefs.setIntPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, addon.id), 0);
|
||||
gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, addon.id), false);
|
||||
gPrefs.setCharPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id), "");
|
||||
gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VISIBLE, addon.id), true);
|
||||
gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id), true);
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id),
|
||||
false
|
||||
);
|
||||
gPrefs.setIntPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, addon.id),
|
||||
0
|
||||
);
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, addon.id),
|
||||
false
|
||||
);
|
||||
gPrefs.setCharPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id),
|
||||
""
|
||||
);
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VISIBLE, addon.id),
|
||||
true
|
||||
);
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id),
|
||||
true
|
||||
);
|
||||
}
|
||||
await GMPScope.GMPProvider.shutdown();
|
||||
GMPScope.GMPProvider.startup();
|
||||
|
@ -123,27 +168,60 @@ async function testNotInstalledDisabled() {
|
|||
// Open the options menu (needed to check the disabled buttons).
|
||||
const pluginOptions = item.querySelector("plugin-options");
|
||||
pluginOptions.querySelector("panel-list").open = true;
|
||||
const neverActivate = pluginOptions.querySelector("panel-item[action=never-activate]");
|
||||
ok(neverActivate.hasAttribute("checked"), "Plugin state should be never-activate");
|
||||
const neverActivate = pluginOptions.querySelector(
|
||||
"panel-item[action=never-activate]"
|
||||
);
|
||||
ok(
|
||||
neverActivate.hasAttribute("checked"),
|
||||
"Plugin state should be never-activate"
|
||||
);
|
||||
pluginOptions.querySelector("panel-list").open = false;
|
||||
} else {
|
||||
item.parentNode.ensureElementIsVisible(item);
|
||||
is(item.getAttribute("active"), "false", "Should be disabled");
|
||||
|
||||
let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning");
|
||||
let el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"warning"
|
||||
);
|
||||
is_element_hidden(el, "Warning notification is hidden.");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"class",
|
||||
"disabled-postfix"
|
||||
);
|
||||
is_element_visible(el, "disabled-postfix is visible.");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"disable-btn"
|
||||
);
|
||||
is_element_hidden(el, "Disable button not visible.");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"enable-btn"
|
||||
);
|
||||
is_element_hidden(el, "Enable button not visible.");
|
||||
|
||||
let menu = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "state-menulist");
|
||||
let menu = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"state-menulist"
|
||||
);
|
||||
is_element_visible(menu, "State menu should be visible.");
|
||||
|
||||
let neverActivate = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "never-activate-menuitem");
|
||||
is(menu.selectedItem, neverActivate, "Plugin state should be never-activate.");
|
||||
let neverActivate = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"never-activate-menuitem"
|
||||
);
|
||||
is(
|
||||
menu.selectedItem,
|
||||
neverActivate,
|
||||
"Plugin state should be never-activate."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +245,10 @@ async function testNotInstalledDisabledDetails() {
|
|||
|
||||
async function testNotInstalled() {
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id), true);
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id),
|
||||
true
|
||||
);
|
||||
let item = get_addon_element(gManagerWindow, addon.id);
|
||||
Assert.ok(item, "Got add-on element:" + addon.id);
|
||||
if (gManagerWindow.useHtmlViews) {
|
||||
|
@ -175,27 +256,60 @@ async function testNotInstalled() {
|
|||
// Open the options menu (needed to check the disabled buttons).
|
||||
const pluginOptions = item.querySelector("plugin-options");
|
||||
pluginOptions.querySelector("panel-list").open = true;
|
||||
const alwaysActivate = pluginOptions.querySelector("panel-item[action=always-activate]");
|
||||
ok(alwaysActivate.hasAttribute("checked"), "Plugin state should be always-activate");
|
||||
const alwaysActivate = pluginOptions.querySelector(
|
||||
"panel-item[action=always-activate]"
|
||||
);
|
||||
ok(
|
||||
alwaysActivate.hasAttribute("checked"),
|
||||
"Plugin state should be always-activate"
|
||||
);
|
||||
pluginOptions.querySelector("panel-list").open = false;
|
||||
} else {
|
||||
item.parentNode.ensureElementIsVisible(item);
|
||||
is(item.getAttribute("active"), "true");
|
||||
|
||||
let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning");
|
||||
let el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"warning"
|
||||
);
|
||||
is_element_visible(el, "Warning notification is visible.");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"class",
|
||||
"disabled-postfix"
|
||||
);
|
||||
is_element_hidden(el, "disabled-postfix is hidden.");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"disable-btn"
|
||||
);
|
||||
is_element_hidden(el, "Disable button not visible.");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"enable-btn"
|
||||
);
|
||||
is_element_hidden(el, "Enable button not visible.");
|
||||
|
||||
let menu = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "state-menulist");
|
||||
let menu = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"state-menulist"
|
||||
);
|
||||
is_element_visible(menu, "State menu should be visible.");
|
||||
|
||||
let alwaysActivate = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "always-activate-menuitem");
|
||||
is(menu.selectedItem, alwaysActivate, "Plugin state should be always-activate.");
|
||||
let alwaysActivate = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"always-activate-menuitem"
|
||||
);
|
||||
is(
|
||||
menu.selectedItem,
|
||||
alwaysActivate,
|
||||
"Plugin state should be always-activate."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,10 +339,18 @@ async function testNotInstalledDetails() {
|
|||
|
||||
async function testInstalled() {
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.setIntPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, addon.id),
|
||||
TEST_DATE.getTime());
|
||||
gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, addon.id), false);
|
||||
gPrefs.setCharPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id), "1.2.3.4");
|
||||
gPrefs.setIntPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, addon.id),
|
||||
TEST_DATE.getTime()
|
||||
);
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, addon.id),
|
||||
false
|
||||
);
|
||||
gPrefs.setCharPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id),
|
||||
"1.2.3.4"
|
||||
);
|
||||
|
||||
let item = get_addon_element(gManagerWindow, addon.id);
|
||||
Assert.ok(item, "Got add-on element.");
|
||||
|
@ -237,27 +359,60 @@ async function testInstalled() {
|
|||
// Open the options menu (needed to check the disabled buttons).
|
||||
const pluginOptions = item.querySelector("plugin-options");
|
||||
pluginOptions.querySelector("panel-list").open = true;
|
||||
const alwaysActivate = pluginOptions.querySelector("panel-item[action=always-activate]");
|
||||
ok(alwaysActivate.hasAttribute("checked"), "Plugin state should be always-activate");
|
||||
const alwaysActivate = pluginOptions.querySelector(
|
||||
"panel-item[action=always-activate]"
|
||||
);
|
||||
ok(
|
||||
alwaysActivate.hasAttribute("checked"),
|
||||
"Plugin state should be always-activate"
|
||||
);
|
||||
pluginOptions.querySelector("panel-list").open = false;
|
||||
} else {
|
||||
item.parentNode.ensureElementIsVisible(item);
|
||||
is(item.getAttribute("active"), "true");
|
||||
|
||||
let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning");
|
||||
let el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"warning"
|
||||
);
|
||||
is_element_hidden(el, "Warning notification is hidden.");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"class",
|
||||
"disabled-postfix"
|
||||
);
|
||||
is_element_hidden(el, "disabled-postfix is hidden.");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"disable-btn"
|
||||
);
|
||||
is_element_hidden(el, "Disable button not visible.");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
|
||||
el = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"enable-btn"
|
||||
);
|
||||
is_element_hidden(el, "Enable button not visible.");
|
||||
|
||||
let menu = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "state-menulist");
|
||||
let menu = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"state-menulist"
|
||||
);
|
||||
is_element_visible(menu, "State menu should be visible.");
|
||||
|
||||
let alwaysActivate = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "always-activate-menuitem");
|
||||
is(menu.selectedItem, alwaysActivate, "Plugin state should be always-activate.");
|
||||
let alwaysActivate = item.ownerDocument.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"always-activate-menuitem"
|
||||
);
|
||||
is(
|
||||
menu.selectedItem,
|
||||
alwaysActivate,
|
||||
"Plugin state should be always-activate."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -268,8 +423,10 @@ async function testInstalledDetails() {
|
|||
|
||||
if (gManagerWindow.useHtmlViews) {
|
||||
let card = get_addon_element(gManagerWindow, addon.id);
|
||||
is_element_visible(card.querySelector("[action=update-check]"),
|
||||
"Find updates link is bisible");
|
||||
is_element_visible(
|
||||
card.querySelector("[action=update-check]"),
|
||||
"Find updates link is bisible"
|
||||
);
|
||||
} else {
|
||||
let doc = gManagerWindow.document;
|
||||
|
||||
|
@ -289,8 +446,14 @@ async function testInstalledDetails() {
|
|||
};
|
||||
contextMenu.addEventListener("popupshown", listener);
|
||||
el = doc.getElementsByClassName("detail-view-container")[0];
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(el, 4, 4, {}, gManagerWindow);
|
||||
EventUtils.synthesizeMouse(
|
||||
el,
|
||||
4,
|
||||
4,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gManagerWindow
|
||||
);
|
||||
});
|
||||
let menuSep = doc.getElementById("addonitem-menuseparator");
|
||||
is_element_hidden(menuSep, "Menu separator is hidden.");
|
||||
|
@ -311,8 +474,13 @@ async function testInstalledGlobalEmeDisabled() {
|
|||
// Open the options menu (needed to check the disabled buttons).
|
||||
const pluginOptions = item.querySelector("plugin-options");
|
||||
pluginOptions.querySelector("panel-list").open = true;
|
||||
const askActivate = pluginOptions.querySelector("panel-item[action=ask-to-activate]");
|
||||
ok(askActivate.shadowRoot.querySelector("button").disabled, "ask-to-activate should be disabled");
|
||||
const askActivate = pluginOptions.querySelector(
|
||||
"panel-item[action=ask-to-activate]"
|
||||
);
|
||||
ok(
|
||||
askActivate.shadowRoot.querySelector("button").disabled,
|
||||
"ask-to-activate should be disabled"
|
||||
);
|
||||
pluginOptions.querySelector("panel-list").open = false;
|
||||
} else {
|
||||
Assert.ok(!item, "Couldn't get add-on element.");
|
||||
|
@ -333,16 +501,23 @@ async function testPreferencesButton() {
|
|||
];
|
||||
|
||||
for (let preferences of prefValues) {
|
||||
dump("Testing preferences button with pref settings: " +
|
||||
JSON.stringify(preferences) + "\n");
|
||||
dump(
|
||||
"Testing preferences button with pref settings: " +
|
||||
JSON.stringify(preferences) +
|
||||
"\n"
|
||||
);
|
||||
for (let addon of gMockAddons) {
|
||||
await close_manager(gManagerWindow);
|
||||
gManagerWindow = await open_manager();
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
gPrefs.setCharPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id),
|
||||
preferences.version);
|
||||
gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id),
|
||||
preferences.enabled);
|
||||
gPrefs.setCharPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id),
|
||||
preferences.version
|
||||
);
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id),
|
||||
preferences.enabled
|
||||
);
|
||||
|
||||
await gCategoryUtilities.openType("plugin");
|
||||
let doc = gManagerWindow.document;
|
||||
|
@ -352,14 +527,26 @@ async function testPreferencesButton() {
|
|||
// Open the options menu (needed to check the more options action is enabled).
|
||||
const pluginOptions = item.querySelector("plugin-options");
|
||||
pluginOptions.querySelector("panel-list").open = true;
|
||||
const moreOptions = pluginOptions.querySelector("panel-item[action=expand]");
|
||||
ok(!moreOptions.shadowRoot.querySelector("button").disabled,
|
||||
"more options action should be enabled");
|
||||
const moreOptions = pluginOptions.querySelector(
|
||||
"panel-item[action=expand]"
|
||||
);
|
||||
ok(
|
||||
!moreOptions.shadowRoot.querySelector("button").disabled,
|
||||
"more options action should be enabled"
|
||||
);
|
||||
moreOptions.click();
|
||||
} else {
|
||||
let button = doc.getAnonymousElementByAttribute(item, "anonid", "preferences-btn");
|
||||
let button = doc.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"preferences-btn"
|
||||
);
|
||||
is_element_visible(button);
|
||||
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
button,
|
||||
{ clickCount: 1 },
|
||||
gManagerWindow
|
||||
);
|
||||
}
|
||||
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
|
@ -392,13 +579,25 @@ async function testUpdateButton() {
|
|||
let detail = get_addon_element(gManagerWindow, addon.id);
|
||||
detail.querySelector("[action=update-check]").click();
|
||||
} else {
|
||||
let button = doc.getAnonymousElementByAttribute(item, "anonid", "preferences-btn");
|
||||
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
|
||||
let button = doc.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"preferences-btn"
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
button,
|
||||
{ clickCount: 1 },
|
||||
gManagerWindow
|
||||
);
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
|
||||
button = doc.getElementById("detail-findUpdates-btn");
|
||||
Assert.ok(button != null, "Got detail-findUpdates-btn");
|
||||
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
button,
|
||||
{ clickCount: 1 },
|
||||
gManagerWindow
|
||||
);
|
||||
}
|
||||
|
||||
await gInstallDeferred.promise;
|
||||
|
@ -414,7 +613,9 @@ async function testUpdateButton() {
|
|||
|
||||
async function testEmeSupport() {
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id));
|
||||
gPrefs.clearUserPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id)
|
||||
);
|
||||
}
|
||||
await GMPScope.GMPProvider.shutdown();
|
||||
GMPScope.GMPProvider.startup();
|
||||
|
@ -426,17 +627,23 @@ async function testEmeSupport() {
|
|||
if (AppConstants.isPlatformAndVersionAtLeast("win", "6")) {
|
||||
Assert.ok(item, "Adobe EME supported, found add-on element.");
|
||||
} else {
|
||||
Assert.ok(!item,
|
||||
"Adobe EME not supported, couldn't find add-on element.");
|
||||
Assert.ok(
|
||||
!item,
|
||||
"Adobe EME not supported, couldn't find add-on element."
|
||||
);
|
||||
}
|
||||
} else if (addon.id == GMPScope.WIDEVINE_ID) {
|
||||
if (AppConstants.isPlatformAndVersionAtLeast("win", "6") ||
|
||||
AppConstants.platform == "macosx" ||
|
||||
AppConstants.platform == "linux") {
|
||||
if (
|
||||
AppConstants.isPlatformAndVersionAtLeast("win", "6") ||
|
||||
AppConstants.platform == "macosx" ||
|
||||
AppConstants.platform == "linux"
|
||||
) {
|
||||
Assert.ok(item, "Widevine supported, found add-on element.");
|
||||
} else {
|
||||
Assert.ok(!item,
|
||||
"Widevine not supported, couldn't find add-on element.");
|
||||
Assert.ok(
|
||||
!item,
|
||||
"Widevine not supported, couldn't find add-on element."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Assert.ok(item, "Found add-on element.");
|
||||
|
@ -444,8 +651,14 @@ async function testEmeSupport() {
|
|||
}
|
||||
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VISIBLE, addon.id), true);
|
||||
gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id), true);
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VISIBLE, addon.id),
|
||||
true
|
||||
);
|
||||
gPrefs.setBoolPref(
|
||||
getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id),
|
||||
true
|
||||
);
|
||||
}
|
||||
await GMPScope.GMPProvider.shutdown();
|
||||
GMPScope.GMPProvider.startup();
|
||||
|
@ -475,9 +688,9 @@ async function test_gmpProvider(initializeStateOptions) {
|
|||
}
|
||||
|
||||
add_task(function test_gmpProvider_on_XUL_aboutaddons() {
|
||||
return test_gmpProvider({useHtmlViews: false});
|
||||
return test_gmpProvider({ useHtmlViews: false });
|
||||
});
|
||||
|
||||
add_task(async function test_gmpProvider_on_HTML_aboutaddons() {
|
||||
return test_gmpProvider({useHtmlViews: true});
|
||||
return test_gmpProvider({ useHtmlViews: true });
|
||||
});
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,10 +1,14 @@
|
|||
/* eslint max-len: ["error", 80] */
|
||||
|
||||
const {AddonTestUtils} =
|
||||
ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm", {});
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm",
|
||||
{}
|
||||
);
|
||||
|
||||
const {ExtensionPermissions} =
|
||||
ChromeUtils.import("resource://gre/modules/ExtensionPermissions.jsm", {});
|
||||
const { ExtensionPermissions } = ChromeUtils.import(
|
||||
"resource://gre/modules/ExtensionPermissions.jsm",
|
||||
{}
|
||||
);
|
||||
|
||||
let gProvider;
|
||||
let promptService;
|
||||
|
@ -16,8 +20,9 @@ function getAddonCard(doc, addonId) {
|
|||
}
|
||||
|
||||
function getDetailRows(card) {
|
||||
return Array.from(card.querySelectorAll(
|
||||
'[name="details"] .addon-detail-row:not([hidden])'));
|
||||
return Array.from(
|
||||
card.querySelectorAll('[name="details"] .addon-detail-row:not([hidden])')
|
||||
);
|
||||
}
|
||||
|
||||
function checkLabel(row, name) {
|
||||
|
@ -28,8 +33,11 @@ function checkLabel(row, name) {
|
|||
} else {
|
||||
id = `addon-detail-${name}-label`;
|
||||
}
|
||||
is(row.ownerDocument.l10n.getAttributes(row.querySelector("label")).id,
|
||||
id, `The ${name} label is set`);
|
||||
is(
|
||||
row.ownerDocument.l10n.getAttributes(row.querySelector("label")).id,
|
||||
id,
|
||||
`The ${name} label is set`
|
||||
);
|
||||
}
|
||||
|
||||
function checkLink(link, url, text = url) {
|
||||
|
@ -39,7 +47,9 @@ function checkLink(link, url, text = url) {
|
|||
// Check the fluent data.
|
||||
Assert.deepEqual(
|
||||
link.ownerDocument.l10n.getAttributes(link),
|
||||
text, "The fluent data is set correctly");
|
||||
text,
|
||||
"The fluent data is set correctly"
|
||||
);
|
||||
} else {
|
||||
// Just check text.
|
||||
is(link.textContent, text, "The text is set");
|
||||
|
@ -61,8 +71,10 @@ function checkOptions(doc, options, expectedOptions) {
|
|||
is(input.value, expected.value, "The value is right");
|
||||
is(input.checked, expected.checked, "The checked property is correct");
|
||||
Assert.deepEqual(
|
||||
doc.l10n.getAttributes(text), {id: expected.label, args: null},
|
||||
"The label has the right text");
|
||||
doc.l10n.getAttributes(text),
|
||||
{ id: expected.label, args: null },
|
||||
"The label has the right text"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,8 +87,10 @@ function assertDeckHeadingHidden(group) {
|
|||
|
||||
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`);
|
||||
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`);
|
||||
|
@ -93,56 +107,65 @@ async function hasPrivateAllowed(id) {
|
|||
|
||||
add_task(async function enableHtmlViews() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.htmlaboutaddons.enabled", true],
|
||||
["extensions.allowPrivateBrowsingByDefault", false]],
|
||||
set: [
|
||||
["extensions.htmlaboutaddons.enabled", true],
|
||||
["extensions.allowPrivateBrowsingByDefault", false],
|
||||
],
|
||||
});
|
||||
|
||||
gProvider = new MockProvider();
|
||||
gProvider.createAddons([{
|
||||
id: "addon1@mochi.test",
|
||||
name: "Test add-on 1",
|
||||
creator: {name: "The creator", url: "http://example.com/me"},
|
||||
version: "3.1",
|
||||
description: "Short description",
|
||||
fullDescription: "Longer description\nWith brs!",
|
||||
type: "extension",
|
||||
contributionURL: "http://localhost/contribute",
|
||||
averageRating: 4.279,
|
||||
userPermissions: {
|
||||
origins: ["<all_urls>", "file://*/*"],
|
||||
permissions: ["alarms", "contextMenus", "tabs", "webNavigation"],
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "addon1@mochi.test",
|
||||
name: "Test add-on 1",
|
||||
creator: { name: "The creator", url: "http://example.com/me" },
|
||||
version: "3.1",
|
||||
description: "Short description",
|
||||
fullDescription: "Longer description\nWith brs!",
|
||||
type: "extension",
|
||||
contributionURL: "http://localhost/contribute",
|
||||
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",
|
||||
updateDate: new Date("2019-03-07T01:00:00"),
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_ENABLE,
|
||||
},
|
||||
reviewCount: 5,
|
||||
reviewURL: "http://example.com/reviews",
|
||||
homepageURL: "http://example.com/addon1",
|
||||
updateDate: new Date("2019-03-07T01:00:00"),
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_ENABLE,
|
||||
}, {
|
||||
id: "addon2@mochi.test",
|
||||
name: "Test add-on 2",
|
||||
creator: {name: "I made it"},
|
||||
description: "Short description",
|
||||
userPermissions: {
|
||||
origins: [],
|
||||
permissions: ["alarms", "contextMenus"],
|
||||
{
|
||||
id: "addon2@mochi.test",
|
||||
name: "Test add-on 2",
|
||||
creator: { name: "I made it" },
|
||||
description: "Short description",
|
||||
userPermissions: {
|
||||
origins: [],
|
||||
permissions: ["alarms", "contextMenus"],
|
||||
},
|
||||
type: "extension",
|
||||
},
|
||||
type: "extension",
|
||||
}, {
|
||||
id: "theme1@mochi.test",
|
||||
name: "Test theme",
|
||||
creator: {name: "Artist", url: "http://example.com/artist"},
|
||||
description: "A nice tree",
|
||||
type: "theme",
|
||||
screenshots: [{
|
||||
url: "http://example.com/preview-wide.png",
|
||||
width: 760,
|
||||
height: 92,
|
||||
}, {
|
||||
url: "http://example.com/preview.png",
|
||||
width: 680,
|
||||
height: 92,
|
||||
}],
|
||||
}]);
|
||||
{
|
||||
id: "theme1@mochi.test",
|
||||
name: "Test theme",
|
||||
creator: { name: "Artist", url: "http://example.com/artist" },
|
||||
description: "A nice tree",
|
||||
type: "theme",
|
||||
screenshots: [
|
||||
{
|
||||
url: "http://example.com/preview-wide.png",
|
||||
width: 760,
|
||||
height: 92,
|
||||
},
|
||||
{
|
||||
url: "http://example.com/preview.png",
|
||||
width: 680,
|
||||
height: 92,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
promptService = mockPromptService();
|
||||
});
|
||||
|
@ -153,7 +176,7 @@ add_task(async function testOpenDetailView() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test",
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
@ -161,7 +184,7 @@ add_task(async function testOpenDetailView() {
|
|||
let extension2 = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test",
|
||||
applications: {gecko: {id: id2}},
|
||||
applications: { gecko: { id: id2 } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
@ -182,7 +205,7 @@ add_task(async function testOpenDetailView() {
|
|||
let card = getAddonCard(doc, id);
|
||||
ok(!card.querySelector("addon-details"), "The card doesn't have details");
|
||||
let loaded = waitForViewLoad(win);
|
||||
EventUtils.synthesizeMouseAtCenter(card, {clickCount: 1}, win);
|
||||
EventUtils.synthesizeMouseAtCenter(card, { clickCount: 1 }, win);
|
||||
await loaded;
|
||||
|
||||
card = getAddonCard(doc, id);
|
||||
|
@ -211,15 +234,30 @@ add_task(async function testOpenDetailView() {
|
|||
await extension2.unload();
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "view", "aboutAddons", "detail",
|
||||
{type: "extension", addonId: id}],
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "view", "aboutAddons", "detail",
|
||||
{type: "extension", addonId: id}],
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "view", "aboutAddons", "detail",
|
||||
{type: "extension", addonId: id2}],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: id },
|
||||
],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: id },
|
||||
],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: id2 },
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -229,7 +267,7 @@ add_task(async function testDetailOperations() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test",
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
@ -242,7 +280,7 @@ add_task(async function testDetailOperations() {
|
|||
let card = getAddonCard(doc, id);
|
||||
ok(!card.querySelector("addon-details"), "The card doesn't have details");
|
||||
let loaded = waitForViewLoad(win);
|
||||
EventUtils.synthesizeMouseAtCenter(card, {clickCount: 1}, win);
|
||||
EventUtils.synthesizeMouseAtCenter(card, { clickCount: 1 }, win);
|
||||
await loaded;
|
||||
|
||||
card = getAddonCard(doc, id);
|
||||
|
@ -274,8 +312,9 @@ add_task(async function testDetailOperations() {
|
|||
// The (disabled) text should be shown now.
|
||||
Assert.deepEqual(
|
||||
doc.l10n.getAttributes(name),
|
||||
{id: "addon-name-disabled", args: {name: "Test"}},
|
||||
"The name is updated to the disabled text");
|
||||
{ id: "addon-name-disabled", args: { name: "Test" } },
|
||||
"The name is updated to the disabled text"
|
||||
);
|
||||
|
||||
// Enable the add-on.
|
||||
let extensionStarted = AddonTestUtils.promiseWebExtensionStartup(id);
|
||||
|
@ -302,11 +341,12 @@ add_task(async function testDetailOperations() {
|
|||
// We're on the list view now and there's no card for this extension.
|
||||
const addonList = doc.querySelector("addon-list");
|
||||
ok(addonList, "There's an addon-list now");
|
||||
ok(!getAddonCard(doc, id),
|
||||
"The extension no longer has a card");
|
||||
ok(!getAddonCard(doc, id), "The extension no longer has a card");
|
||||
let addon = await AddonManager.getAddonByID(id);
|
||||
ok(addon && !!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL),
|
||||
"The addon is pending uninstall");
|
||||
ok(
|
||||
addon && !!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL),
|
||||
"The addon is pending uninstall"
|
||||
);
|
||||
|
||||
// Ensure that a pending uninstall bar has been created for the
|
||||
// pending uninstall extension, and pressing the undo button will
|
||||
|
@ -326,20 +366,50 @@ add_task(async function testDetailOperations() {
|
|||
await extension.unload();
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "view", "aboutAddons", "detail",
|
||||
{type: "extension", addonId: id}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: id, action: "disable", view: "detail"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: id, action: "enable"}],
|
||||
["addonsManager", "action", "aboutAddons", "cancelled",
|
||||
{type: "extension", addonId: id, action: "uninstall", view: "detail"}],
|
||||
["addonsManager", "action", "aboutAddons", "accepted",
|
||||
{type: "extension", addonId: id, action: "uninstall", view: "detail"}],
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: id, action: "undo", view: "list"}],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: id },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "extension", addonId: id, action: "disable", view: "detail" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "extension", addonId: id, action: "enable" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"cancelled",
|
||||
{ type: "extension", addonId: id, action: "uninstall", view: "detail" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"accepted",
|
||||
{ type: "extension", addonId: id, action: "uninstall", view: "detail" },
|
||||
],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "extension", addonId: id, action: "undo", view: "list" },
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -377,14 +447,19 @@ add_task(async function testFullDetails() {
|
|||
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>");
|
||||
is(
|
||||
desc.innerHTML,
|
||||
"Longer description<br>With brs!",
|
||||
"The full description replaces newlines with <br>"
|
||||
);
|
||||
|
||||
let contrib = details.querySelector(".addon-detail-contribute");
|
||||
ok(contrib, "The contribution section is visible");
|
||||
|
||||
let waitForTab = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser, "http://localhost/contribute");
|
||||
gBrowser,
|
||||
"http://localhost/contribute"
|
||||
);
|
||||
contrib.querySelector("button").click();
|
||||
BrowserTestUtils.removeTab(await waitForTab);
|
||||
|
||||
|
@ -394,9 +469,9 @@ add_task(async function testFullDetails() {
|
|||
let row = rows.shift();
|
||||
checkLabel(row, "updates");
|
||||
let expectedOptions = [
|
||||
{value: "1", label: "addon-detail-updates-radio-default", checked: false},
|
||||
{value: "2", label: "addon-detail-updates-radio-on", checked: true},
|
||||
{value: "0", label: "addon-detail-updates-radio-off", checked: false},
|
||||
{ value: "1", label: "addon-detail-updates-radio-default", checked: false },
|
||||
{ value: "2", label: "addon-detail-updates-radio-on", checked: true },
|
||||
{ value: "0", label: "addon-detail-updates-radio-off", checked: false },
|
||||
];
|
||||
let options = row.lastElementChild.querySelectorAll("label");
|
||||
checkOptions(doc, options, expectedOptions);
|
||||
|
@ -409,8 +484,11 @@ add_task(async function testFullDetails() {
|
|||
row = rows.shift();
|
||||
ok(row.classList.contains("addon-detail-help-row"), "There's a help row");
|
||||
ok(!row.hidden, "The help row is shown");
|
||||
is(doc.l10n.getAttributes(row).id, "addon-detail-private-browsing-help",
|
||||
"The help row is for private browsing");
|
||||
is(
|
||||
doc.l10n.getAttributes(row).id,
|
||||
"addon-detail-private-browsing-help",
|
||||
"The help row is for private browsing"
|
||||
);
|
||||
|
||||
// Author.
|
||||
row = rows.shift();
|
||||
|
@ -449,30 +527,36 @@ add_task(async function testFullDetails() {
|
|||
link = rating.querySelector("a");
|
||||
checkLink(link, "http://example.com/reviews", {
|
||||
id: "addon-detail-reviews-link",
|
||||
args: {numberOfReviews: 5},
|
||||
args: { numberOfReviews: 5 },
|
||||
});
|
||||
|
||||
// While we are here, let's test edge cases of star ratings.
|
||||
async function testRating(rating, ratingRounded, expectation) {
|
||||
starsElem.rating = rating;
|
||||
await starsElem.ownerDocument.l10n.translateElements([starsElem]);
|
||||
is(starsElem.ratingBuckets.join(","), expectation,
|
||||
`Rendering of rating ${rating}`);
|
||||
is(
|
||||
starsElem.ratingBuckets.join(","),
|
||||
expectation,
|
||||
`Rendering of rating ${rating}`
|
||||
);
|
||||
|
||||
is(starsElem.title, `Rated ${ratingRounded} out of 5`,
|
||||
"Rendered title must contain at most one fractional digit");
|
||||
is(
|
||||
starsElem.title,
|
||||
`Rated ${ratingRounded} out of 5`,
|
||||
"Rendered title must contain at most one fractional digit"
|
||||
);
|
||||
}
|
||||
await testRating(0.000, "0", "empty,empty,empty,empty,empty");
|
||||
await testRating(0.0, "0", "empty,empty,empty,empty,empty");
|
||||
await testRating(0.123, "0.1", "empty,empty,empty,empty,empty");
|
||||
await testRating(0.249, "0.2", "empty,empty,empty,empty,empty");
|
||||
await testRating(0.250, "0.3", "half,empty,empty,empty,empty");
|
||||
await testRating(0.25, "0.3", "half,empty,empty,empty,empty");
|
||||
await testRating(0.749, "0.7", "half,empty,empty,empty,empty");
|
||||
await testRating(0.750, "0.8", "full,empty,empty,empty,empty");
|
||||
await testRating(1.000, "1", "full,empty,empty,empty,empty");
|
||||
await testRating(0.75, "0.8", "full,empty,empty,empty,empty");
|
||||
await testRating(1.0, "1", "full,empty,empty,empty,empty");
|
||||
await testRating(4.249, "4.2", "full,full,full,full,empty");
|
||||
await testRating(4.250, "4.3", "full,full,full,full,half");
|
||||
await testRating(4.25, "4.3", "full,full,full,full,half");
|
||||
await testRating(4.749, "4.7", "full,full,full,full,half");
|
||||
await testRating(5.000, "5", "full,full,full,full,full");
|
||||
await testRating(5.0, "5", "full,full,full,full,full");
|
||||
|
||||
// That should've been all the rows.
|
||||
is(rows.length, 0, "There are no more rows left");
|
||||
|
@ -480,11 +564,21 @@ add_task(async function testFullDetails() {
|
|||
await closeView(win);
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "view", "aboutAddons", "detail",
|
||||
{type: "extension", addonId: id}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: id, action: "contribute", view: "detail"}],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: id },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "extension", addonId: id, action: "contribute", view: "detail" },
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -524,8 +618,11 @@ add_task(async function testMinimalExtension() {
|
|||
row = rows.shift();
|
||||
ok(row.classList.contains("addon-detail-help-row"), "There's a help row");
|
||||
ok(!row.hidden, "The help row is shown");
|
||||
is(doc.l10n.getAttributes(row).id, "addon-detail-private-browsing-help",
|
||||
"The help row is for private browsing");
|
||||
is(
|
||||
doc.l10n.getAttributes(row).id,
|
||||
"addon-detail-private-browsing-help",
|
||||
"The help row is for private browsing"
|
||||
);
|
||||
|
||||
// Author.
|
||||
row = rows.shift();
|
||||
|
@ -645,7 +742,7 @@ add_task(async function testPrivateBrowsingExtension() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "My PB extension",
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
},
|
||||
useAddonManager: "permanent",
|
||||
});
|
||||
|
@ -659,7 +756,7 @@ add_task(async function testPrivateBrowsingExtension() {
|
|||
let card = getAddonCard(doc, id);
|
||||
let badge = card.querySelector(".addon-badge-private-browsing-allowed");
|
||||
ok(badge.hidden, "The PB badge is hidden initially");
|
||||
ok(!await hasPrivateAllowed(id), "PB is not allowed");
|
||||
ok(!(await hasPrivateAllowed(id)), "PB is not allowed");
|
||||
|
||||
// Load the detail view.
|
||||
let loaded = waitForViewLoad(win);
|
||||
|
@ -670,7 +767,7 @@ add_task(async function testPrivateBrowsingExtension() {
|
|||
card = getAddonCard(doc, id);
|
||||
badge = card.querySelector(".addon-badge-private-browsing-allowed");
|
||||
ok(badge.hidden, "The PB badge is hidden on the detail view");
|
||||
ok(!await hasPrivateAllowed(id), "PB is not allowed");
|
||||
ok(!(await hasPrivateAllowed(id)), "PB is not allowed");
|
||||
|
||||
let pbRow = card.querySelector(".addon-detail-row-private-browsing");
|
||||
|
||||
|
@ -697,7 +794,7 @@ add_task(async function testPrivateBrowsingExtension() {
|
|||
await updated;
|
||||
|
||||
ok(badge.hidden, "The PB badge is hidden");
|
||||
ok(!await hasPrivateAllowed(id), "PB is disallowed");
|
||||
ok(!(await hasPrivateAllowed(id)), "PB is disallowed");
|
||||
|
||||
// Allow PB.
|
||||
updated = BrowserTestUtils.waitForEvent(card, "update");
|
||||
|
@ -711,28 +808,68 @@ add_task(async function testPrivateBrowsingExtension() {
|
|||
await extension.unload();
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "view", "aboutAddons", "detail",
|
||||
{type: "extension", addonId: id}],
|
||||
["addonsManager", "action", "aboutAddons", "on",
|
||||
{type: "extension", addonId: id, action: "privateBrowsingAllowed",
|
||||
view: "detail"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: id, action: "disable"}],
|
||||
["addonsManager", "action", "aboutAddons", "off",
|
||||
{type: "extension", addonId: id, action: "privateBrowsingAllowed",
|
||||
view: "detail"}],
|
||||
["addonsManager", "action", "aboutAddons", "on",
|
||||
{type: "extension", addonId: id, action: "privateBrowsingAllowed",
|
||||
view: "detail"}],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: id },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"on",
|
||||
{
|
||||
type: "extension",
|
||||
addonId: id,
|
||||
action: "privateBrowsingAllowed",
|
||||
view: "detail",
|
||||
},
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "extension", addonId: id, action: "disable" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"off",
|
||||
{
|
||||
type: "extension",
|
||||
addonId: id,
|
||||
action: "privateBrowsingAllowed",
|
||||
view: "detail",
|
||||
},
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"on",
|
||||
{
|
||||
type: "extension",
|
||||
addonId: id,
|
||||
action: "privateBrowsingAllowed",
|
||||
view: "detail",
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
add_task(async function testInvalidExtension() {
|
||||
let win = await open_manager("addons://detail/foo");
|
||||
let categoryUtils = new CategoryUtilities(win);
|
||||
is(categoryUtils.selectedCategory, "discover",
|
||||
"Should fall back to the discovery pane");
|
||||
is(
|
||||
categoryUtils.selectedCategory,
|
||||
"discover",
|
||||
"Should fall back to the discovery pane"
|
||||
);
|
||||
|
||||
ok(!gBrowser.canGoBack, "The view has been replaced");
|
||||
|
||||
|
@ -746,8 +883,11 @@ add_task(async function testInvalidExtensionNoDiscover() {
|
|||
|
||||
let win = await open_manager("addons://detail/foo");
|
||||
let categoryUtils = new CategoryUtilities(win);
|
||||
is(categoryUtils.selectedCategory, "extension",
|
||||
"Should fall back to the extension list if discover is disabled");
|
||||
is(
|
||||
categoryUtils.selectedCategory,
|
||||
"extension",
|
||||
"Should fall back to the extension list if discover is disabled"
|
||||
);
|
||||
|
||||
ok(!gBrowser.canGoBack, "The view has been replaced");
|
||||
|
||||
|
@ -760,7 +900,7 @@ add_task(async function testExternalUninstall() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Remove me",
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
@ -795,7 +935,7 @@ add_task(async function testExternalThemeUninstall() {
|
|||
let id = "remove-theme@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
name: "Remove theme",
|
||||
theme: {},
|
||||
},
|
||||
|
@ -832,13 +972,13 @@ add_task(async function testPrivateBrowsingAllowedListView() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Allowed PB extension",
|
||||
applications: {gecko: {id: "allowed@mochi.test"}},
|
||||
applications: { gecko: { id: "allowed@mochi.test" } },
|
||||
},
|
||||
useAddonManager: "permanent",
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
let perms = {permissions: ["internal:privateBrowsingAllowed"], origins: []};
|
||||
let perms = { permissions: ["internal:privateBrowsingAllowed"], origins: [] };
|
||||
await ExtensionPermissions.add("allowed@mochi.test", perms);
|
||||
let addon = await AddonManager.getAddonByID("allowed@mochi.test");
|
||||
await addon.reload();
|
||||
|
@ -867,7 +1007,7 @@ add_task(async function testPermissions() {
|
|||
await loaded;
|
||||
|
||||
card = getAddonCard(doc, id);
|
||||
let {deck, tabGroup} = card.details;
|
||||
let { deck, tabGroup } = card.details;
|
||||
|
||||
// Check all the deck buttons are hidden.
|
||||
assertDeckHeadingButtons(tabGroup, ["details", "permissions"]);
|
||||
|
@ -885,13 +1025,18 @@ add_task(async function testPermissions() {
|
|||
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}`);
|
||||
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");
|
||||
is(
|
||||
doc.l10n.getAttributes(row).id,
|
||||
"addon-permissions-empty",
|
||||
"There's a message when no permissions are shown"
|
||||
);
|
||||
}
|
||||
|
||||
info("Check learn more link");
|
||||
|
@ -927,7 +1072,9 @@ add_task(async function testGoBackButton() {
|
|||
|
||||
let loadDetailView = () => {
|
||||
let loaded = waitForViewLoad(win);
|
||||
getAddonCard(doc, id).querySelector("[action=expand]").click();
|
||||
getAddonCard(doc, id)
|
||||
.querySelector("[action=expand]")
|
||||
.click();
|
||||
return loaded;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
/* eslint max-len: ["error", 80] */
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
AddonTestUtils,
|
||||
} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
|
||||
const {
|
||||
ExtensionUtils: {
|
||||
promiseEvent,
|
||||
promiseObserved,
|
||||
},
|
||||
} = ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
ExtensionUtils: { promiseEvent, promiseObserved },
|
||||
} = ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
|
||||
// The response to the discovery API, as documented at:
|
||||
// https://addons-server.readthedocs.io/en/latest/topics/api/discovery.html
|
||||
|
@ -23,17 +20,23 @@ const API_RESPONSE_FILE = RELATIVE_DIR + "discovery/api_response.json";
|
|||
|
||||
const AMO_TEST_HOST = "rewritten-for-testing.addons.allizom.org";
|
||||
|
||||
const ArrayBufferInputStream =
|
||||
Components.Constructor("@mozilla.org/io/arraybuffer-input-stream;1",
|
||||
"nsIArrayBufferInputStream", "setData");
|
||||
const ArrayBufferInputStream = Components.Constructor(
|
||||
"@mozilla.org/io/arraybuffer-input-stream;1",
|
||||
"nsIArrayBufferInputStream",
|
||||
"setData"
|
||||
);
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
|
||||
const amoServer = AddonTestUtils.createHttpServer({hosts: [AMO_TEST_HOST]});
|
||||
const amoServer = AddonTestUtils.createHttpServer({ hosts: [AMO_TEST_HOST] });
|
||||
|
||||
amoServer.registerFile("/png",
|
||||
FileUtils.getFile("CurWorkD",
|
||||
`${RELATIVE_DIR}discovery/small-1x1.png`.split("/")));
|
||||
amoServer.registerFile(
|
||||
"/png",
|
||||
FileUtils.getFile(
|
||||
"CurWorkD",
|
||||
`${RELATIVE_DIR}discovery/small-1x1.png`.split("/")
|
||||
)
|
||||
);
|
||||
amoServer.registerPathHandler("/dummy", (request, response) => {
|
||||
response.write("Dummy");
|
||||
});
|
||||
|
@ -55,8 +58,8 @@ function getTestExpectationFromApiResult(result) {
|
|||
// Read the content of API_RESPONSE_FILE, and replaces any embedded URLs with
|
||||
// URLs that point to the `amoServer` test server.
|
||||
async function readAPIResponseFixture() {
|
||||
let apiText = await OS.File.read(API_RESPONSE_FILE, {encoding: "utf-8"});
|
||||
apiText = apiText.replace(/\bhttps?:\/\/[^"]+(?=")/g, (url) => {
|
||||
let apiText = await OS.File.read(API_RESPONSE_FILE, { encoding: "utf-8" });
|
||||
apiText = apiText.replace(/\bhttps?:\/\/[^"]+(?=")/g, url => {
|
||||
try {
|
||||
url = new URL(url);
|
||||
} catch (e) {
|
||||
|
@ -114,8 +117,9 @@ class DiscoveryAPIHandler {
|
|||
|
||||
// Retrieve the list of visible action elements inside a document or container.
|
||||
function getVisibleActions(documentOrElement) {
|
||||
return Array.from(documentOrElement.querySelectorAll("[action]"))
|
||||
.filter(elem => elem.offsetWidth && elem.offsetHeight);
|
||||
return Array.from(documentOrElement.querySelectorAll("[action]")).filter(
|
||||
elem => elem.offsetWidth && elem.offsetHeight
|
||||
);
|
||||
}
|
||||
|
||||
function getActionName(actionElement) {
|
||||
|
@ -142,7 +146,7 @@ function getCardByAddonId(win, addonId) {
|
|||
// Wait until the current `<discovery-pane>` element has finished loading its
|
||||
// cards. This can be used after the cards have been loaded.
|
||||
function promiseDiscopaneUpdate(win) {
|
||||
let {cardsReady} = getCardContainer(win);
|
||||
let { cardsReady } = getCardContainer(win);
|
||||
ok(cardsReady, "Discovery cards should have started to initialize");
|
||||
return cardsReady;
|
||||
}
|
||||
|
@ -154,15 +158,20 @@ async function switchToNonDiscoView(win) {
|
|||
// share the same document.
|
||||
win.managerWindow.gViewController.loadView("addons://list/extensions");
|
||||
await wait_for_view_load(win.managerWindow);
|
||||
ok(win.document.querySelector("addon-list"),
|
||||
"Should be at the extension list view");
|
||||
ok(
|
||||
win.document.querySelector("addon-list"),
|
||||
"Should be at the extension list view"
|
||||
);
|
||||
}
|
||||
|
||||
// Switch to the discopane and wait until it has fully rendered, including any
|
||||
// cards from the discovery API.
|
||||
async function switchToDiscoView(win) {
|
||||
is(getDiscoveryElement(win), null,
|
||||
"Cannot switch to discopane when the discopane is already shown");
|
||||
is(
|
||||
getDiscoveryElement(win),
|
||||
null,
|
||||
"Cannot switch to discopane when the discopane is already shown"
|
||||
);
|
||||
win.managerWindow.gViewController.loadView("addons://discover/");
|
||||
await wait_for_view_load(win.managerWindow);
|
||||
await promiseDiscopaneUpdate(win);
|
||||
|
@ -192,8 +201,11 @@ async function promiseAddonInstall(amoServer, extensionData) {
|
|||
amoServer.registerFile("/xpi", xpiFile);
|
||||
|
||||
let addonId = extensionData.manifest.applications.gecko.id;
|
||||
let installedPromise =
|
||||
waitAppMenuNotificationShown("addon-installed", addonId, true);
|
||||
let installedPromise = waitAppMenuNotificationShown(
|
||||
"addon-installed",
|
||||
addonId,
|
||||
true
|
||||
);
|
||||
|
||||
if (!extensionData.manifest.theme) {
|
||||
info(`${description}: Waiting for permission prompt`);
|
||||
|
@ -202,8 +214,9 @@ async function promiseAddonInstall(amoServer, extensionData) {
|
|||
panel.button.click();
|
||||
} else {
|
||||
info(`${description}: Waiting for install prompt`);
|
||||
let panel =
|
||||
await promisePopupNotificationShown("addon-install-confirmation");
|
||||
let panel = await promisePopupNotificationShown(
|
||||
"addon-install-confirmation"
|
||||
);
|
||||
panel.button.click();
|
||||
}
|
||||
|
||||
|
@ -211,11 +224,15 @@ async function promiseAddonInstall(amoServer, extensionData) {
|
|||
await installedPromise;
|
||||
|
||||
let addon = await AddonManager.getAddonByID(addonId);
|
||||
Assert.deepEqual(addon.installTelemetryInfo, {
|
||||
// This is the expected source because before the HTML-based discopane,
|
||||
// "disco" was already used to mark installs from the AMO-hosted discopane.
|
||||
source: "disco",
|
||||
}, "The installed add-on should have the expected telemetry info");
|
||||
Assert.deepEqual(
|
||||
addon.installTelemetryInfo,
|
||||
{
|
||||
// This is the expected source because before the HTML-based discopane,
|
||||
// "disco" was already used to mark installs from the AMO-hosted discopane.
|
||||
source: "disco",
|
||||
},
|
||||
"The installed add-on should have the expected telemetry info"
|
||||
);
|
||||
}
|
||||
|
||||
// Install an add-on by clicking on the card.
|
||||
|
@ -224,7 +241,8 @@ async function testCardInstall(card) {
|
|||
Assert.deepEqual(
|
||||
getVisibleActions(card).map(getActionName),
|
||||
["install-addon"],
|
||||
"Should have an Install button before install");
|
||||
"Should have an Install button before install"
|
||||
);
|
||||
|
||||
let installButton =
|
||||
card.querySelector("[data-l10n-id='install-extension-button']") ||
|
||||
|
@ -237,7 +255,8 @@ async function testCardInstall(card) {
|
|||
Assert.deepEqual(
|
||||
getVisibleActions(card).map(getActionName),
|
||||
["manage-addon"],
|
||||
"Should have a Manage button after install");
|
||||
"Should have a Manage button after install"
|
||||
);
|
||||
}
|
||||
|
||||
// Uninstall the add-on (not via the card, since it has no uninstall button).
|
||||
|
@ -246,7 +265,8 @@ async function testAddonUninstall(card) {
|
|||
Assert.deepEqual(
|
||||
getVisibleActions(card).map(getActionName),
|
||||
["manage-addon"],
|
||||
"Should have a Manage button before uninstall");
|
||||
"Should have a Manage button before uninstall"
|
||||
);
|
||||
|
||||
let addon = await AddonManager.getAddonByID(card.addonId);
|
||||
|
||||
|
@ -257,14 +277,17 @@ async function testAddonUninstall(card) {
|
|||
Assert.deepEqual(
|
||||
getVisibleActions(card).map(getActionName),
|
||||
["install-addon"],
|
||||
"Should have an Install button after uninstall");
|
||||
"Should have an Install button after uninstall"
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.getAddons.discovery.api_url",
|
||||
`http://${AMO_TEST_HOST}/discoapi`],
|
||||
[
|
||||
"extensions.getAddons.discovery.api_url",
|
||||
`http://${AMO_TEST_HOST}/discoapi`,
|
||||
],
|
||||
// Enable HTML for all because some tests load non-discopane views.
|
||||
["extensions.htmlaboutaddons.enabled", true],
|
||||
["extensions.htmlaboutaddons.discover.enabled", true],
|
||||
|
@ -293,7 +316,8 @@ add_task(async function discopane_with_real_api_data() {
|
|||
Assert.deepEqual(
|
||||
getVisibleActions(win.document).map(getActionName),
|
||||
[],
|
||||
"The AMO button should be invisible when the AMO API hasn't responded");
|
||||
"The AMO button should be invisible when the AMO API hasn't responded"
|
||||
);
|
||||
|
||||
apiHandler.unblockResponses();
|
||||
await promiseDiscopaneUpdate(win);
|
||||
|
@ -306,14 +330,16 @@ add_task(async function discopane_with_real_api_data() {
|
|||
...new Array(apiResultArray.length).fill("install-addon"),
|
||||
"open-amo",
|
||||
],
|
||||
"All add-on cards should be rendered, with AMO button at the end.");
|
||||
"All add-on cards should be rendered, with AMO button at the end."
|
||||
);
|
||||
|
||||
let imgCount = await waitForAllImagesLoaded(win);
|
||||
is(imgCount, apiResultArray.length, "Expected an image for every result");
|
||||
|
||||
// Check that the cards have the expected content.
|
||||
let cards =
|
||||
Array.from(win.document.querySelectorAll("recommended-addon-card"));
|
||||
let cards = Array.from(
|
||||
win.document.querySelectorAll("recommended-addon-card")
|
||||
);
|
||||
is(cards.length, apiResultArray.length, "Every API result has a card");
|
||||
for (let [i, card] of cards.entries()) {
|
||||
let expectations = getTestExpectationFromApiResult(apiResultArray[i]);
|
||||
|
@ -325,26 +351,36 @@ add_task(async function discopane_with_real_api_data() {
|
|||
};
|
||||
checkContent(".disco-addon-name", expectations.addonName);
|
||||
await win.document.l10n.translateFragment(card);
|
||||
checkContent(".disco-addon-author [data-l10n-name='author']",
|
||||
expectations.authorName);
|
||||
checkContent(
|
||||
".disco-addon-author [data-l10n-name='author']",
|
||||
expectations.authorName
|
||||
);
|
||||
|
||||
let amoListingLink = card.querySelector(".disco-addon-author a");
|
||||
ok(amoListingLink.search.includes("utm_source=firefox-browser"),
|
||||
`Listing link should have attribution parameter, url=${amoListingLink}`);
|
||||
ok(
|
||||
amoListingLink.search.includes("utm_source=firefox-browser"),
|
||||
`Listing link should have attribution parameter, url=${amoListingLink}`
|
||||
);
|
||||
|
||||
let actions = getVisibleActions(card);
|
||||
is(actions.length, 1, "Card should only have one install button");
|
||||
let installButton = actions[0];
|
||||
if (expectations.typeIsTheme) {
|
||||
// Theme button + screenshot
|
||||
ok(installButton.matches("[data-l10n-id='install-theme-button'"),
|
||||
"Has theme install button");
|
||||
ok(card.querySelector(".card-heading-image").offsetWidth,
|
||||
"Preview image must be visible");
|
||||
ok(
|
||||
installButton.matches("[data-l10n-id='install-theme-button'"),
|
||||
"Has theme install button"
|
||||
);
|
||||
ok(
|
||||
card.querySelector(".card-heading-image").offsetWidth,
|
||||
"Preview image must be visible"
|
||||
);
|
||||
} else {
|
||||
// Extension button + extended description.
|
||||
ok(installButton.matches("[data-l10n-id='install-extension-button'"),
|
||||
"Has extension install button");
|
||||
ok(
|
||||
installButton.matches("[data-l10n-id='install-extension-button'"),
|
||||
"Has extension install button"
|
||||
);
|
||||
checkContent(".disco-description-intro", expectations.editorialHead);
|
||||
checkContent(".disco-description-main", expectations.editorialBody);
|
||||
|
||||
|
@ -360,8 +396,9 @@ add_task(async function discopane_with_real_api_data() {
|
|||
if (expectations.dailyUsers) {
|
||||
Assert.deepEqual(
|
||||
win.document.l10n.getAttributes(userCountElem),
|
||||
{id: "user-count", args: {dailyUsers: expectations.dailyUsers}},
|
||||
"Card count should be rendered");
|
||||
{ id: "user-count", args: { dailyUsers: expectations.dailyUsers } },
|
||||
"Card count should be rendered"
|
||||
);
|
||||
} else {
|
||||
is(userCountElem.offsetWidth, 0, "User count element is not visible");
|
||||
}
|
||||
|
@ -380,8 +417,8 @@ add_task(async function discopane_with_real_api_data() {
|
|||
add_task(async function install_from_discopane() {
|
||||
const apiText = await readAPIResponseFixture();
|
||||
const apiResultArray = JSON.parse(apiText).results;
|
||||
let getAddonIdByAMOAddonType =
|
||||
type => apiResultArray.find(r => r.addon.type === type).addon.guid;
|
||||
let getAddonIdByAMOAddonType = type =>
|
||||
apiResultArray.find(r => r.addon.type === type).addon.guid;
|
||||
const FIRST_EXTENSION_ID = getAddonIdByAMOAddonType("extension");
|
||||
const FIRST_THEME_ID = getAddonIdByAMOAddonType("statictheme");
|
||||
|
||||
|
@ -398,7 +435,7 @@ add_task(async function install_from_discopane() {
|
|||
manifest: {
|
||||
name: "My Awesome Add-on",
|
||||
description: "Test extension install button",
|
||||
applications: {gecko: {id: FIRST_EXTENSION_ID}},
|
||||
applications: { gecko: { id: FIRST_EXTENSION_ID } },
|
||||
permissions: ["<all_urls>"],
|
||||
},
|
||||
});
|
||||
|
@ -410,7 +447,7 @@ add_task(async function install_from_discopane() {
|
|||
manifest: {
|
||||
name: "My Fancy Theme",
|
||||
description: "Test theme install button",
|
||||
applications: {gecko: {id: FIRST_THEME_ID}},
|
||||
applications: { gecko: { id: FIRST_THEME_ID } },
|
||||
theme: {
|
||||
colors: {
|
||||
tab_selected: "red",
|
||||
|
@ -434,15 +471,34 @@ add_task(async function install_from_discopane() {
|
|||
...new Array(apiResultArray.length - 2).fill("install-addon"),
|
||||
"open-amo",
|
||||
],
|
||||
"The Install buttons should be replaced with Manage buttons");
|
||||
"The Install buttons should be replaced with Manage buttons"
|
||||
);
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{action: "installFromRecommendation", view: "discover",
|
||||
addonId: FIRST_EXTENSION_ID, type: "extension"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{action: "installFromRecommendation", view: "discover",
|
||||
addonId: FIRST_THEME_ID, type: "theme"}],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{
|
||||
action: "installFromRecommendation",
|
||||
view: "discover",
|
||||
addonId: FIRST_EXTENSION_ID,
|
||||
type: "extension",
|
||||
},
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{
|
||||
action: "installFromRecommendation",
|
||||
view: "discover",
|
||||
addonId: FIRST_THEME_ID,
|
||||
type: "theme",
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
// End of the testing installation from a card.
|
||||
|
@ -451,22 +507,35 @@ add_task(async function install_from_discopane() {
|
|||
// and in order to be able to force the discovery pane to be rendered again.
|
||||
let loaded = waitForViewLoad(win);
|
||||
getCardByAddonId(win, FIRST_EXTENSION_ID)
|
||||
.querySelector("[action='manage-addon']").click();
|
||||
.querySelector("[action='manage-addon']")
|
||||
.click();
|
||||
await loaded;
|
||||
{
|
||||
let addonCard =
|
||||
win.document.querySelector(
|
||||
`addon-card[addon-id="${FIRST_EXTENSION_ID}"]`);
|
||||
let addonCard = win.document.querySelector(
|
||||
`addon-card[addon-id="${FIRST_EXTENSION_ID}"]`
|
||||
);
|
||||
ok(addonCard, "Add-on details should be shown");
|
||||
ok(addonCard.expanded, "The card should have been expanded");
|
||||
// TODO bug 1540253: Check that the "recommended" badge is visible.
|
||||
}
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{action: "manage", view: "discover", addonId: FIRST_EXTENSION_ID,
|
||||
type: "extension"}],
|
||||
], {methods: ["action"]});
|
||||
assertAboutAddonsTelemetryEvents(
|
||||
[
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{
|
||||
action: "manage",
|
||||
view: "discover",
|
||||
addonId: FIRST_EXTENSION_ID,
|
||||
type: "extension",
|
||||
},
|
||||
],
|
||||
],
|
||||
{ methods: ["action"] }
|
||||
);
|
||||
|
||||
// Now we are going to force an updated rendering and check that the cards are
|
||||
// in the expected order, and then test uninstallation of the above add-ons.
|
||||
|
@ -481,7 +550,8 @@ add_task(async function install_from_discopane() {
|
|||
"manage-addon",
|
||||
"open-amo",
|
||||
],
|
||||
"Already-installed add-ons should be rendered at the end of the list");
|
||||
"Already-installed add-ons should be rendered at the end of the list"
|
||||
);
|
||||
|
||||
promiseThemeChange = promiseObserved("lightweight-theme-styling-update");
|
||||
await testAddonUninstall(getCardByAddonId(win, FIRST_THEME_ID));
|
||||
|
@ -503,15 +573,23 @@ add_task(async function discopane_navigate_while_loading() {
|
|||
|
||||
let updatePromise = promiseDiscopaneUpdate(win);
|
||||
let didUpdateDiscopane = false;
|
||||
updatePromise.then(() => { didUpdateDiscopane = true; });
|
||||
updatePromise.then(() => {
|
||||
didUpdateDiscopane = true;
|
||||
});
|
||||
|
||||
// Switch views while the request is pending.
|
||||
await switchToNonDiscoView(win);
|
||||
|
||||
is(didUpdateDiscopane, false,
|
||||
"discopane should still not be updated because the request is blocked");
|
||||
is(getDiscoveryElement(win), null,
|
||||
"Discopane should be removed after switching to the extension list");
|
||||
is(
|
||||
didUpdateDiscopane,
|
||||
false,
|
||||
"discopane should still not be updated because the request is blocked"
|
||||
);
|
||||
is(
|
||||
getDiscoveryElement(win),
|
||||
null,
|
||||
"Discopane should be removed after switching to the extension list"
|
||||
);
|
||||
|
||||
// Release pending requests, to verify that completing the request will not
|
||||
// cause changes to the visible view. The updatePromise will still resolve
|
||||
|
@ -519,10 +597,15 @@ add_task(async function discopane_navigate_while_loading() {
|
|||
apiHandler.unblockResponses();
|
||||
|
||||
await updatePromise;
|
||||
ok(win.document.querySelector("addon-list"),
|
||||
"Should still be at the extension list view");
|
||||
is(getDiscoveryElement(win), null,
|
||||
"Discopane should not be in the document when it is not the active view");
|
||||
ok(
|
||||
win.document.querySelector("addon-list"),
|
||||
"Should still be at the extension list view"
|
||||
);
|
||||
is(
|
||||
getDiscoveryElement(win),
|
||||
null,
|
||||
"Discopane should not be in the document when it is not the active view"
|
||||
);
|
||||
|
||||
is(apiHandler.requestCount, 1, "Discovery API should be fetched once");
|
||||
|
||||
|
@ -563,7 +646,8 @@ add_task(async function discopane_cache_api_responses() {
|
|||
Assert.deepEqual(
|
||||
getVisibleActions(win.document).map(getActionName),
|
||||
["open-amo"],
|
||||
"The AMO button should be visible even when the response was invalid");
|
||||
"The AMO button should be visible even when the response was invalid"
|
||||
);
|
||||
|
||||
// Change to a valid response, so that the next response will be cached.
|
||||
apiHandler.setResponseText(`{"results": []}`);
|
||||
|
@ -571,15 +655,21 @@ add_task(async function discopane_cache_api_responses() {
|
|||
await switchToNonDiscoView(win);
|
||||
await switchToDiscoView(win); // Request #2
|
||||
|
||||
is(apiHandler.requestCount, 2,
|
||||
"Should fetch new data because an invalid response should not be cached");
|
||||
is(
|
||||
apiHandler.requestCount,
|
||||
2,
|
||||
"Should fetch new data because an invalid response should not be cached"
|
||||
);
|
||||
|
||||
await switchToNonDiscoView(win);
|
||||
await switchToDiscoView(win);
|
||||
await closeView(win);
|
||||
|
||||
is(apiHandler.requestCount, 2,
|
||||
"The previous response was valid and should have been reused");
|
||||
is(
|
||||
apiHandler.requestCount,
|
||||
2,
|
||||
"The previous response was valid and should have been reused"
|
||||
);
|
||||
|
||||
// Now open a new about:addons page and verify that a new API request is sent.
|
||||
let anotherWin = await loadInitialView("discover");
|
||||
|
@ -593,8 +683,18 @@ add_task(async function discopane_no_cookies() {
|
|||
let requestPromise = new Promise(resolve => {
|
||||
amoServer.registerPathHandler("/discoapi", resolve);
|
||||
});
|
||||
Services.cookies.add(AMO_TEST_HOST, "/", "name", "value", false, false,
|
||||
false, Date.now() / 1000 + 600, {}, Ci.nsICookie.SAMESITE_NONE);
|
||||
Services.cookies.add(
|
||||
AMO_TEST_HOST,
|
||||
"/",
|
||||
"name",
|
||||
"value",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Date.now() / 1000 + 600,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_NONE
|
||||
);
|
||||
let win = await loadInitialView("discover");
|
||||
let request = await requestPromise;
|
||||
ok(!request.hasHeader("Cookie"), "discovery API should not receive cookies");
|
||||
|
@ -614,21 +714,25 @@ add_task(async function discopane_interaction_telemetry() {
|
|||
// Minimal API response to get the link in recommended-addon-card to render.
|
||||
const DUMMY_EXTENSION_ID = "dummy@extensionid";
|
||||
const apiResponse = {
|
||||
results: [{
|
||||
addon: {
|
||||
guid: DUMMY_EXTENSION_ID,
|
||||
type: "extension",
|
||||
authors: [{
|
||||
name: "Some author",
|
||||
}],
|
||||
url: `http://${AMO_TEST_HOST}/dummy`,
|
||||
icon_url: `http://${AMO_TEST_HOST}/png`,
|
||||
results: [
|
||||
{
|
||||
addon: {
|
||||
guid: DUMMY_EXTENSION_ID,
|
||||
type: "extension",
|
||||
authors: [
|
||||
{
|
||||
name: "Some author",
|
||||
},
|
||||
],
|
||||
url: `http://${AMO_TEST_HOST}/dummy`,
|
||||
icon_url: `http://${AMO_TEST_HOST}/png`,
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
};
|
||||
let apiHandler = new DiscoveryAPIHandler(JSON.stringify(apiResponse));
|
||||
|
||||
let expectedAmoUrlFor = (where) => {
|
||||
let expectedAmoUrlFor = where => {
|
||||
// eslint-disable-next-line max-len
|
||||
return `http://${AMO_TEST_HOST}/dummy?utm_source=firefox-browser&utm_medium=firefox-browser&utm_content=${where}`;
|
||||
};
|
||||
|
@ -636,11 +740,15 @@ add_task(async function discopane_interaction_telemetry() {
|
|||
let testClickInDiscoCard = async (selector, utmContentParam) => {
|
||||
let tabbrowser = win.windowRoot.ownerGlobal.gBrowser;
|
||||
let tabPromise = BrowserTestUtils.waitForNewTab(tabbrowser);
|
||||
getDiscoveryElement(win).querySelector(selector).click();
|
||||
getDiscoveryElement(win)
|
||||
.querySelector(selector)
|
||||
.click();
|
||||
let tab = await tabPromise;
|
||||
is(tab.linkedBrowser.currentURI.spec,
|
||||
expectedAmoUrlFor(utmContentParam),
|
||||
"Expected URL of new tab");
|
||||
is(
|
||||
tab.linkedBrowser.currentURI.spec,
|
||||
expectedAmoUrlFor(utmContentParam),
|
||||
"Expected URL of new tab"
|
||||
);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
};
|
||||
|
||||
|
@ -657,8 +765,8 @@ add_task(async function discopane_interaction_telemetry() {
|
|||
await testClickInDiscoCard(".disco-addon-author a", "discopane-entry-link");
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "link", "aboutAddons", "discomore", {view: "discover"}],
|
||||
["addonsManager", "link", "aboutAddons", "discohome", {view: "discover"}],
|
||||
["addonsManager", "link", "aboutAddons", "discomore", { view: "discover" }],
|
||||
["addonsManager", "link", "aboutAddons", "discohome", { view: "discover" }],
|
||||
]);
|
||||
|
||||
is(apiHandler.requestCount, 1, "Discovery API should be fetched once");
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
/* eslint max-len: ["error", 80] */
|
||||
"use strict";
|
||||
|
||||
const {ClientID} = ChromeUtils.import("resource://gre/modules/ClientID.jsm");
|
||||
const { ClientID } = ChromeUtils.import("resource://gre/modules/ClientID.jsm");
|
||||
|
||||
const {
|
||||
AddonTestUtils,
|
||||
} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
const server = AddonTestUtils.createHttpServer();
|
||||
const serverBaseUrl = `http://localhost:${server.identity.primaryPort}/`;
|
||||
server.registerPathHandler("/sumo/personalized-addons",
|
||||
(request, response) => {
|
||||
response.write("This is a SUMO page that explains personalized add-ons.");
|
||||
});
|
||||
server.registerPathHandler("/sumo/personalized-addons", (request, response) => {
|
||||
response.write("This is a SUMO page that explains personalized add-ons.");
|
||||
});
|
||||
|
||||
// Before a discovery API request is triggered, this method should be called.
|
||||
// Resolves with the value of the "telemetry-client-id" query parameter.
|
||||
|
@ -80,8 +79,10 @@ add_task(async function clientid_enabled() {
|
|||
// TODO: Fix this together with bug 1537933
|
||||
//
|
||||
// is(await requestPromise, EXPECTED_CLIENT_ID,
|
||||
ok(await requestPromise,
|
||||
"Moz-Client-Id should be set when telemetry & discovery are enabled");
|
||||
ok(
|
||||
await requestPromise,
|
||||
"Moz-Client-Id should be set when telemetry & discovery are enabled"
|
||||
);
|
||||
|
||||
Services.telemetry.clearEvents();
|
||||
|
||||
|
@ -97,9 +98,18 @@ add_task(async function clientid_enabled() {
|
|||
|
||||
await closeView(win);
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "link", "aboutAddons", "disconotice", {view: "discover"}],
|
||||
], {methods: ["link"]});
|
||||
assertAboutAddonsTelemetryEvents(
|
||||
[
|
||||
[
|
||||
"addonsManager",
|
||||
"link",
|
||||
"aboutAddons",
|
||||
"disconotice",
|
||||
{ view: "discover" },
|
||||
],
|
||||
],
|
||||
{ methods: ["link"] }
|
||||
);
|
||||
});
|
||||
|
||||
// Test that the clientid is not sent when disabled via prefs.
|
||||
|
@ -111,25 +121,39 @@ add_task(async function clientid_disabled() {
|
|||
let requestPromise = promiseOneDiscoveryApiRequest();
|
||||
let win = await loadInitialView("discover");
|
||||
ok(!isNoticeVisible(win), "Notice about personalization should be hidden");
|
||||
is(await requestPromise, null,
|
||||
"Moz-Client-Id should not be sent when discovery is disabled");
|
||||
is(
|
||||
await requestPromise,
|
||||
null,
|
||||
"Moz-Client-Id should not be sent when discovery is disabled"
|
||||
);
|
||||
await closeView(win);
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
||||
// Test that the clientid is not sent from private windows.
|
||||
add_task(async function clientid_from_private_window() {
|
||||
let privateWindow =
|
||||
await BrowserTestUtils.openNewBrowserWindow({private: true});
|
||||
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({
|
||||
private: true,
|
||||
});
|
||||
|
||||
let requestPromise = promiseOneDiscoveryApiRequest();
|
||||
let managerWindow =
|
||||
await open_manager("addons://discover/", null, null, null, privateWindow);
|
||||
ok(PrivateBrowsingUtils.isContentWindowPrivate(managerWindow),
|
||||
"Addon-manager is in a private window");
|
||||
let managerWindow = await open_manager(
|
||||
"addons://discover/",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
privateWindow
|
||||
);
|
||||
ok(
|
||||
PrivateBrowsingUtils.isContentWindowPrivate(managerWindow),
|
||||
"Addon-manager is in a private window"
|
||||
);
|
||||
|
||||
is(await requestPromise, null,
|
||||
"Moz-Client-Id should not be sent in private windows");
|
||||
is(
|
||||
await requestPromise,
|
||||
null,
|
||||
"Moz-Client-Id should not be sent in private windows"
|
||||
);
|
||||
|
||||
await close_manager(managerWindow);
|
||||
await BrowserTestUtils.closeWindow(privateWindow);
|
||||
|
@ -153,8 +177,10 @@ add_task(async function clientid_enabled_from_extension_list() {
|
|||
|
||||
ok(isNoticeVisible(win), "Notice about personalization should be visible");
|
||||
|
||||
ok(await requestPromise,
|
||||
"Moz-Client-Id should be set when telemetry & discovery are enabled");
|
||||
ok(
|
||||
await requestPromise,
|
||||
"Moz-Client-Id should be set when telemetry & discovery are enabled"
|
||||
);
|
||||
|
||||
// Make sure switching to the theme view doesn't trigger another request.
|
||||
await switchView(win, "theme");
|
||||
|
@ -186,16 +212,18 @@ add_task(async function clientid_enabled_from_theme_list() {
|
|||
|
||||
ok(!isNoticeVisible(win), "Notice about personalization should be hidden");
|
||||
|
||||
is(await requestPromise, null,
|
||||
"Moz-Client-Id should not be sent when loading themes initially");
|
||||
is(
|
||||
await requestPromise,
|
||||
null,
|
||||
"Moz-Client-Id should not be sent when loading themes initially"
|
||||
);
|
||||
|
||||
info("Load the extension list and verify the client ID is now sent");
|
||||
|
||||
requestPromise = promiseOneDiscoveryApiRequest();
|
||||
await switchView(win, "extension");
|
||||
|
||||
ok(await requestPromise,
|
||||
"Moz-Client-Id is now sent for extensions");
|
||||
ok(await requestPromise, "Moz-Client-Id is now sent for extensions");
|
||||
|
||||
await closeView(win);
|
||||
await SpecialPowers.popPrefEnv();
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* eslint max-len: ["error", 80] */
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
AddonTestUtils,
|
||||
} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
const server = AddonTestUtils.createHttpServer();
|
||||
|
@ -24,19 +24,28 @@ async function checkIfDiscoverVisible(expectVisible) {
|
|||
let managerWindow = await open_manager(null);
|
||||
let categoryUtilities = new CategoryUtilities(managerWindow);
|
||||
|
||||
is(categoryUtilities.isTypeVisible("discover"), expectVisible,
|
||||
"Visibility of discopane");
|
||||
is(
|
||||
categoryUtilities.isTypeVisible("discover"),
|
||||
expectVisible,
|
||||
"Visibility of discopane"
|
||||
);
|
||||
|
||||
await wait_for_view_load(managerWindow);
|
||||
if (expectVisible) {
|
||||
is(categoryUtilities.selectedCategory, "discover",
|
||||
"Expected discopane as the default view");
|
||||
is(
|
||||
categoryUtilities.selectedCategory,
|
||||
"discover",
|
||||
"Expected discopane as the default view"
|
||||
);
|
||||
await requestPromise;
|
||||
is(requestCount, 1, "Expected discovery API request");
|
||||
} else {
|
||||
// The next view (after discopane) is the extension list.
|
||||
is(categoryUtilities.selectedCategory, "extension",
|
||||
"Should fall back to another view when the discopane is disabled");
|
||||
is(
|
||||
categoryUtilities.selectedCategory,
|
||||
"extension",
|
||||
"Should fall back to another view when the discopane is disabled"
|
||||
);
|
||||
is(requestCount, 0, "Discovery API should not be requested");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* eslint max-len: ["error", 80] */
|
||||
|
||||
const {
|
||||
AddonTestUtils,
|
||||
} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
|
||||
|
@ -45,17 +45,21 @@ add_task(async function enableHtmlViews() {
|
|||
let extensionsCreated = 0;
|
||||
|
||||
function createExtensions(manifestExtras) {
|
||||
return manifestExtras.map(extra => ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test extension",
|
||||
applications: {gecko: {id: `test-${extensionsCreated++}@mochi.test`}},
|
||||
icons: {
|
||||
32: "test-icon.png",
|
||||
return manifestExtras.map(extra =>
|
||||
ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test extension",
|
||||
applications: {
|
||||
gecko: { id: `test-${extensionsCreated++}@mochi.test` },
|
||||
},
|
||||
icons: {
|
||||
32: "test-icon.png",
|
||||
},
|
||||
...extra,
|
||||
},
|
||||
...extra,
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
}));
|
||||
useAddonManager: "temporary",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function testExtensionList() {
|
||||
|
@ -63,7 +67,7 @@ add_task(async function testExtensionList() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test extension",
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
icons: {
|
||||
32: "test-icon.png",
|
||||
},
|
||||
|
@ -92,30 +96,45 @@ add_task(async function testExtensionList() {
|
|||
ok(card, "The card is in the enabled section");
|
||||
|
||||
// Check the properties of the card.
|
||||
is(card.querySelector(".addon-name").textContent, "Test extension",
|
||||
"The name is set");
|
||||
is(
|
||||
card.querySelector(".addon-name").textContent,
|
||||
"Test extension",
|
||||
"The name is set"
|
||||
);
|
||||
let icon = card.querySelector(".addon-icon");
|
||||
ok(icon.src.endsWith("/test-icon.png"), "The icon is set");
|
||||
|
||||
// Disable the extension.
|
||||
let disableButton = card.querySelector('[action="toggle-disabled"]');
|
||||
is(doc.l10n.getAttributes(disableButton).id, "disable-addon-button",
|
||||
"The button has the disable label");
|
||||
is(
|
||||
doc.l10n.getAttributes(disableButton).id,
|
||||
"disable-addon-button",
|
||||
"The button has the disable label"
|
||||
);
|
||||
|
||||
let disabled = BrowserTestUtils.waitForEvent(list, "move");
|
||||
disableButton.click();
|
||||
await disabled;
|
||||
is(card.parentNode, disabledSection,
|
||||
"The card is now in the disabled section");
|
||||
is(
|
||||
card.parentNode,
|
||||
disabledSection,
|
||||
"The card is now in the disabled section"
|
||||
);
|
||||
|
||||
// The disable button is now enable.
|
||||
is(doc.l10n.getAttributes(disableButton).id, "enable-addon-button",
|
||||
"The button has the enable label");
|
||||
is(
|
||||
doc.l10n.getAttributes(disableButton).id,
|
||||
"enable-addon-button",
|
||||
"The button has the enable label"
|
||||
);
|
||||
|
||||
// Remove the add-on.
|
||||
let removeButton = card.querySelector('[action="remove"]');
|
||||
is(doc.l10n.getAttributes(removeButton).id, "remove-addon-button",
|
||||
"The button has the remove label");
|
||||
is(
|
||||
doc.l10n.getAttributes(removeButton).id,
|
||||
"remove-addon-button",
|
||||
"The button has the remove label"
|
||||
);
|
||||
|
||||
// Remove but cancel.
|
||||
let cancelled = BrowserTestUtils.waitForEvent(card, "remove-cancelled");
|
||||
|
@ -129,8 +148,10 @@ add_task(async function testExtensionList() {
|
|||
await removed;
|
||||
|
||||
addon = await AddonManager.getAddonByID(id);
|
||||
ok(addon && !!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL),
|
||||
"The addon is pending uninstall");
|
||||
ok(
|
||||
addon && !!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL),
|
||||
"The addon is pending uninstall"
|
||||
);
|
||||
|
||||
// Ensure that a pending uninstall bar has been created for the
|
||||
// pending uninstall extension, and pressing the undo button will
|
||||
|
@ -144,7 +165,7 @@ add_task(async function testExtensionList() {
|
|||
const extension2 = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test extension 2",
|
||||
applications: {gecko: {id: "test-2@mochi.test"}},
|
||||
applications: { gecko: { id: "test-2@mochi.test" } },
|
||||
icons: {
|
||||
32: "test-icon.png",
|
||||
},
|
||||
|
@ -154,8 +175,10 @@ add_task(async function testExtensionList() {
|
|||
await extension2.startup();
|
||||
|
||||
await added;
|
||||
ok(getCardByAddonId(list, extension2.id),
|
||||
"Got a card added for the second extension");
|
||||
ok(
|
||||
getCardByAddonId(list, extension2.id),
|
||||
"Got a card added for the second extension"
|
||||
);
|
||||
|
||||
info("Uninstall the second test extension and wait for addon card removed");
|
||||
removed = BrowserTestUtils.waitForEvent(list, "remove");
|
||||
|
@ -163,8 +186,10 @@ add_task(async function testExtensionList() {
|
|||
addon2.uninstall(true);
|
||||
await removed;
|
||||
|
||||
ok(!getCardByAddonId(list, extension2.id),
|
||||
"Addon card for the second extension removed");
|
||||
ok(
|
||||
!getCardByAddonId(list, extension2.id),
|
||||
"Addon card for the second extension removed"
|
||||
);
|
||||
|
||||
assertHasPendingUninstalls(list, 2);
|
||||
assertHasPendingUninstallAddon(list, addon2);
|
||||
|
@ -177,10 +202,14 @@ add_task(async function testExtensionList() {
|
|||
info("Wait for the second pending uninstal add-ons startup");
|
||||
await addon2Started;
|
||||
|
||||
ok(getCardByAddonId(disabledSection, addon.id),
|
||||
"The card for the first extension is in the disabled section");
|
||||
ok(getCardByAddonId(enabledSection, addon2.id),
|
||||
"The card for the second extension is in the enabled section");
|
||||
ok(
|
||||
getCardByAddonId(disabledSection, addon.id),
|
||||
"The card for the first extension is in the disabled section"
|
||||
);
|
||||
ok(
|
||||
getCardByAddonId(enabledSection, addon2.id),
|
||||
"The card for the second extension is in the enabled section"
|
||||
);
|
||||
|
||||
await extension2.unload();
|
||||
await extension.unload();
|
||||
|
@ -190,7 +219,7 @@ add_task(async function testExtensionList() {
|
|||
const themeXpi = AddonTestUtils.createTempWebExtensionFile({
|
||||
manifest: {
|
||||
name: "My theme",
|
||||
applications: {gecko: {id: "theme@mochi.test"}},
|
||||
applications: { gecko: { id: "theme@mochi.test" } },
|
||||
theme: {},
|
||||
},
|
||||
});
|
||||
|
@ -204,7 +233,7 @@ add_task(async function testExtensionList() {
|
|||
const xpi = AddonTestUtils.createTempWebExtensionFile({
|
||||
manifest: {
|
||||
name: "Test extension 3",
|
||||
applications: {gecko: {id: "test-3@mochi.test"}},
|
||||
applications: { gecko: { id: "test-3@mochi.test" } },
|
||||
icons: {
|
||||
32: "test-icon.png",
|
||||
},
|
||||
|
@ -214,45 +243,86 @@ add_task(async function testExtensionList() {
|
|||
added = BrowserTestUtils.waitForEvent(list, "add");
|
||||
const addon3 = await AddonManager.installTemporaryAddon(xpi);
|
||||
await added;
|
||||
ok(getCardByAddonId(list, addon3.id),
|
||||
"Addon card for the third extension added");
|
||||
ok(
|
||||
getCardByAddonId(list, addon3.id),
|
||||
"Addon card for the third extension added"
|
||||
);
|
||||
|
||||
removed = BrowserTestUtils.waitForEvent(list, "remove");
|
||||
addon3.uninstall(true);
|
||||
await removed;
|
||||
ok(!getCardByAddonId(list, addon3.id),
|
||||
"Addon card for the third extension removed");
|
||||
ok(
|
||||
!getCardByAddonId(list, addon3.id),
|
||||
"Addon card for the third extension removed"
|
||||
);
|
||||
|
||||
assertHasPendingUninstalls(list, 1);
|
||||
ok(addon3 && !!(addon3.pendingOperations & AddonManager.PENDING_UNINSTALL),
|
||||
"The third addon is pending uninstall");
|
||||
ok(
|
||||
addon3 && !!(addon3.pendingOperations & AddonManager.PENDING_UNINSTALL),
|
||||
"The third addon is pending uninstall"
|
||||
);
|
||||
|
||||
await closeView(win);
|
||||
|
||||
ok(!await AddonManager.getAddonByID(addon3.id),
|
||||
"The third addon has been fully uninstalled");
|
||||
ok(
|
||||
!(await AddonManager.getAddonByID(addon3.id)),
|
||||
"The third addon has been fully uninstalled"
|
||||
);
|
||||
|
||||
ok(themeAddon.pendingOperations & AddonManager.PENDING_UNINSTALL,
|
||||
"The theme addon is pending after the list extension view is closed");
|
||||
ok(
|
||||
themeAddon.pendingOperations & AddonManager.PENDING_UNINSTALL,
|
||||
"The theme addon is pending after the list extension view is closed"
|
||||
);
|
||||
|
||||
await themeAddon.uninstall();
|
||||
|
||||
ok(!await AddonManager.getAddonByID(themeAddon.id),
|
||||
"The theme addon is fully uninstalled");
|
||||
ok(
|
||||
!(await AddonManager.getAddonByID(themeAddon.id)),
|
||||
"The theme addon is fully uninstalled"
|
||||
);
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: id, view: "list", action: "disable"}],
|
||||
["addonsManager", "action", "aboutAddons", "cancelled",
|
||||
{type: "extension", addonId: id, view: "list", action: "uninstall"}],
|
||||
["addonsManager", "action", "aboutAddons", "accepted",
|
||||
{type: "extension", addonId: id, view: "list", action: "uninstall"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: id, view: "list", action: "undo"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: "test-2@mochi.test", view: "list",
|
||||
action: "undo"}],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "extension", addonId: id, view: "list", action: "disable" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"cancelled",
|
||||
{ type: "extension", addonId: id, view: "list", action: "uninstall" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"accepted",
|
||||
{ type: "extension", addonId: id, view: "list", action: "uninstall" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "extension", addonId: id, view: "list", action: "undo" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{
|
||||
type: "extension",
|
||||
addonId: "test-2@mochi.test",
|
||||
view: "list",
|
||||
action: "undo",
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -260,7 +330,7 @@ add_task(async function testMouseSupport() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test extension",
|
||||
applications: {gecko: {id: "test@mochi.test"}},
|
||||
applications: { gecko: { id: "test@mochi.test" } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
@ -277,7 +347,10 @@ add_task(async function testMouseSupport() {
|
|||
|
||||
ok(!panel.open, "The panel is initially closed");
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
menuButton, {type: "mousedown"}, gBrowser.selectedBrowser);
|
||||
menuButton,
|
||||
{ type: "mousedown" },
|
||||
gBrowser.selectedBrowser
|
||||
);
|
||||
ok(panel.open, "The panel is now open");
|
||||
|
||||
await closeView(win);
|
||||
|
@ -288,7 +361,7 @@ add_task(async function testKeyboardSupport() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test extension",
|
||||
applications: {gecko: {id: "test@mochi.test"}},
|
||||
applications: { gecko: { id: "test@mochi.test" } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
@ -328,7 +401,7 @@ add_task(async function testKeyboardSupport() {
|
|||
// Test tabbing out of the menu.
|
||||
space();
|
||||
is(moreOptionsMenu.open, true, "The menu is open");
|
||||
tab({shiftKey: true});
|
||||
tab({ shiftKey: true });
|
||||
is(moreOptionsMenu.open, false, "Tabbing away from the menu closes it");
|
||||
tab();
|
||||
isFocused(moreOptionsButton, "The button is focused again");
|
||||
|
@ -364,8 +437,11 @@ add_task(async function testKeyboardSupport() {
|
|||
space();
|
||||
await disabled;
|
||||
is(moreOptionsMenu.open, false, "The menu is closed");
|
||||
is(card.parentNode, disabledSection,
|
||||
"The card is now in the disabled section");
|
||||
is(
|
||||
card.parentNode,
|
||||
disabledSection,
|
||||
"The card is now in the disabled section"
|
||||
);
|
||||
|
||||
// Open the menu again.
|
||||
shown = BrowserTestUtils.waitForEvent(moreOptionsMenu, "shown");
|
||||
|
@ -389,9 +465,9 @@ add_task(async function testKeyboardSupport() {
|
|||
|
||||
add_task(async function testExtensionReordering() {
|
||||
let extensions = createExtensions([
|
||||
{name: "Extension One"},
|
||||
{name: "This is last"},
|
||||
{name: "An extension, is first"},
|
||||
{ name: "Extension One" },
|
||||
{ name: "This is last" },
|
||||
{ name: "An extension, is first" },
|
||||
]);
|
||||
|
||||
await Promise.all(extensions.map(extension => extension.startup()));
|
||||
|
@ -409,11 +485,11 @@ add_task(async function testExtensionReordering() {
|
|||
is(cards.length, 3, "Each extension has an addon-card");
|
||||
|
||||
let order = Array.from(cards).map(card => card.addon.name);
|
||||
Assert.deepEqual(order, [
|
||||
"An extension, is first",
|
||||
"Extension One",
|
||||
"This is last",
|
||||
], "The add-ons are sorted by name");
|
||||
Assert.deepEqual(
|
||||
order,
|
||||
["An extension, is first", "Extension One", "This is last"],
|
||||
"The add-ons are sorted by name"
|
||||
);
|
||||
|
||||
// Disable the second extension.
|
||||
let disabledSection = getSection(doc, "disabled");
|
||||
|
@ -421,45 +497,52 @@ add_task(async function testExtensionReordering() {
|
|||
|
||||
// Disable the add-ons in a different order.
|
||||
let reorderedCards = [cards[1], cards[0], cards[2]];
|
||||
for (let {addon} of reorderedCards) {
|
||||
for (let { addon } of reorderedCards) {
|
||||
let moved = BrowserTestUtils.waitForEvent(list, "move");
|
||||
await addon.disable();
|
||||
await moved;
|
||||
}
|
||||
|
||||
order = Array.from(getTestCards(disabledSection))
|
||||
.map(card => card.addon.name);
|
||||
Assert.deepEqual(order, [
|
||||
"An extension, is first",
|
||||
"Extension One",
|
||||
"This is last",
|
||||
], "The add-ons are sorted by name");
|
||||
order = Array.from(getTestCards(disabledSection)).map(
|
||||
card => card.addon.name
|
||||
);
|
||||
Assert.deepEqual(
|
||||
order,
|
||||
["An extension, is first", "Extension One", "This is last"],
|
||||
"The add-ons are sorted by name"
|
||||
);
|
||||
|
||||
// All of our installed add-ons are disabled, install a new one.
|
||||
let [newExtension] = createExtensions([{name: "Extension New"}]);
|
||||
let [newExtension] = createExtensions([{ name: "Extension New" }]);
|
||||
let added = BrowserTestUtils.waitForEvent(list, "add");
|
||||
await newExtension.startup();
|
||||
await added;
|
||||
|
||||
let [newCard] = getTestCards(enabledSection);
|
||||
is(newCard.addon.name, "Extension New",
|
||||
"The new add-on is in the enabled list");
|
||||
is(
|
||||
newCard.addon.name,
|
||||
"Extension New",
|
||||
"The new add-on is in the enabled list"
|
||||
);
|
||||
|
||||
// Enable everything again.
|
||||
for (let {addon} of cards) {
|
||||
for (let { addon } of cards) {
|
||||
let moved = BrowserTestUtils.waitForEvent(list, "move");
|
||||
await addon.enable();
|
||||
await moved;
|
||||
}
|
||||
|
||||
order = Array.from(getTestCards(enabledSection))
|
||||
.map(card => card.addon.name);
|
||||
Assert.deepEqual(order, [
|
||||
"An extension, is first",
|
||||
"Extension New",
|
||||
"Extension One",
|
||||
"This is last",
|
||||
], "The add-ons are sorted by name");
|
||||
order = Array.from(getTestCards(enabledSection)).map(card => card.addon.name);
|
||||
Assert.deepEqual(
|
||||
order,
|
||||
[
|
||||
"An extension, is first",
|
||||
"Extension New",
|
||||
"Extension One",
|
||||
"This is last",
|
||||
],
|
||||
"The add-ons are sorted by name"
|
||||
);
|
||||
|
||||
// Remove the new extension.
|
||||
let removed = BrowserTestUtils.waitForEvent(list, "remove");
|
||||
|
@ -474,7 +557,7 @@ add_task(async function testExtensionReordering() {
|
|||
add_task(async function testThemeList() {
|
||||
let theme = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id: "theme@mochi.test"}},
|
||||
applications: { gecko: { id: "theme@mochi.test" } },
|
||||
name: "My theme",
|
||||
theme: {},
|
||||
},
|
||||
|
@ -502,25 +585,39 @@ add_task(async function testThemeList() {
|
|||
let enabledSection = getSection(doc, "enabled");
|
||||
let disabledSection = getSection(doc, "disabled");
|
||||
|
||||
await TestUtils.waitForCondition(() =>
|
||||
enabledSection.querySelectorAll("addon-card").length == 1);
|
||||
await TestUtils.waitForCondition(
|
||||
() => enabledSection.querySelectorAll("addon-card").length == 1
|
||||
);
|
||||
|
||||
is(card.parentNode, enabledSection,
|
||||
"The new theme card is in the enabled section");
|
||||
is(enabledSection.querySelectorAll("addon-card").length,
|
||||
1, "There is one enabled theme");
|
||||
is(
|
||||
card.parentNode,
|
||||
enabledSection,
|
||||
"The new theme card is in the enabled section"
|
||||
);
|
||||
is(
|
||||
enabledSection.querySelectorAll("addon-card").length,
|
||||
1,
|
||||
"There is one enabled theme"
|
||||
);
|
||||
|
||||
let themesChanged = waitForThemeChange(list);
|
||||
card.querySelector('[action="toggle-disabled"]').click();
|
||||
await themesChanged;
|
||||
|
||||
await TestUtils.waitForCondition(() =>
|
||||
enabledSection.querySelectorAll("addon-card").length == 1);
|
||||
await TestUtils.waitForCondition(
|
||||
() => enabledSection.querySelectorAll("addon-card").length == 1
|
||||
);
|
||||
|
||||
is(card.parentNode, disabledSection,
|
||||
"The card is now in the disabled section");
|
||||
is(enabledSection.querySelectorAll("addon-card").length,
|
||||
1, "There is one enabled theme");
|
||||
is(
|
||||
card.parentNode,
|
||||
disabledSection,
|
||||
"The card is now in the disabled section"
|
||||
);
|
||||
is(
|
||||
enabledSection.querySelectorAll("addon-card").length,
|
||||
1,
|
||||
"There is one enabled theme"
|
||||
);
|
||||
|
||||
await theme.unload();
|
||||
await closeView(win);
|
||||
|
@ -563,8 +660,9 @@ add_task(async function testBuiltInThemeButtons() {
|
|||
darkButtons.toggleDisabled.click();
|
||||
await themesChanged;
|
||||
|
||||
await TestUtils.waitForCondition(() =>
|
||||
enabledSection.querySelectorAll("addon-card").length == 1);
|
||||
await TestUtils.waitForCondition(
|
||||
() => enabledSection.querySelectorAll("addon-card").length == 1
|
||||
);
|
||||
|
||||
// Check the buttons.
|
||||
is(defaultButtons.toggleDisabled.hidden, false, "Enable is visible");
|
||||
|
@ -577,8 +675,9 @@ add_task(async function testBuiltInThemeButtons() {
|
|||
darkButtons.toggleDisabled.click();
|
||||
await themesChanged;
|
||||
|
||||
await TestUtils.waitForCondition(() =>
|
||||
enabledSection.querySelectorAll("addon-card").length == 1);
|
||||
await TestUtils.waitForCondition(
|
||||
() => enabledSection.querySelectorAll("addon-card").length == 1
|
||||
);
|
||||
|
||||
// The themes are back to their starting posititons.
|
||||
is(defaultTheme.parentNode, enabledSection, "Default is enabled");
|
||||
|
@ -597,13 +696,16 @@ add_task(async function testOnlyTypeIsShown() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test extension",
|
||||
applications: {gecko: {id: "test@mochi.test"}},
|
||||
applications: { gecko: { id: "test@mochi.test" } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
||||
let skipped = BrowserTestUtils.waitForEvent(
|
||||
list, "skip-add", (e) => e.detail == "type-mismatch");
|
||||
list,
|
||||
"skip-add",
|
||||
e => e.detail == "type-mismatch"
|
||||
);
|
||||
await extension.startup();
|
||||
await skipped;
|
||||
|
||||
|
|
|
@ -3,18 +3,18 @@
|
|||
/* eslint max-len: ["error", 80] */
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
AddonTestUtils,
|
||||
} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
|
||||
function makeResult({guid, type}) {
|
||||
function makeResult({ guid, type }) {
|
||||
return {
|
||||
addon: {
|
||||
authors: [{name: "Some author"}],
|
||||
authors: [{ name: "Some author" }],
|
||||
current_version: {
|
||||
files: [{platform: "all", url: "data:,"}],
|
||||
files: [{ platform: "all", url: "data:," }],
|
||||
},
|
||||
url: "data:,",
|
||||
guid,
|
||||
|
@ -26,10 +26,12 @@ function makeResult({guid, type}) {
|
|||
function mockResults() {
|
||||
let types = ["extension", "theme", "extension", "extension", "theme"];
|
||||
return {
|
||||
results: types.map((type, i) => makeResult({
|
||||
guid: `${type}${i}@mochi.test`,
|
||||
type,
|
||||
})),
|
||||
results: types.map((type, i) =>
|
||||
makeResult({
|
||||
guid: `${type}${i}@mochi.test`,
|
||||
type,
|
||||
})
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -41,8 +43,10 @@ add_task(async function setup() {
|
|||
["browser.discovery.enabled", false],
|
||||
["extensions.htmlaboutaddons.enabled", true],
|
||||
["extensions.getAddons.discovery.api_url", `data:;base64,${results}`],
|
||||
["extensions.recommendations.themeRecommendationUrl",
|
||||
"https://example.com/theme"],
|
||||
[
|
||||
"extensions.recommendations.themeRecommendationUrl",
|
||||
"https://example.com/theme",
|
||||
],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
@ -62,7 +66,6 @@ function checkExtraContents(doc, type, opts = {}) {
|
|||
|
||||
is_element_visible(footer, "The footer is visible");
|
||||
|
||||
|
||||
if (type == "extension") {
|
||||
ok(taarNotice, "There is a TAAR notice");
|
||||
if (showAmoButton) {
|
||||
|
@ -81,26 +84,40 @@ function checkExtraContents(doc, type, opts = {}) {
|
|||
|
||||
if (showThemeRecommendationFooter) {
|
||||
is_element_visible(
|
||||
themeRecommendationFooter, "There's a theme recommendation footer");
|
||||
themeRecommendationFooter,
|
||||
"There's a theme recommendation footer"
|
||||
);
|
||||
is_element_visible(themeRecommendationLink, "There's a link to the theme");
|
||||
is(themeRecommendationLink.target, "_blank", "The link opens in a new tab");
|
||||
is(themeRecommendationLink.href, "https://example.com/theme",
|
||||
"The link goes to the pref's URL");
|
||||
is(doc.l10n.getAttributes(themeRecommendationFooter).id,
|
||||
"recommended-theme-1", "The recommendation has the right l10n-id");
|
||||
is(
|
||||
themeRecommendationLink.href,
|
||||
"https://example.com/theme",
|
||||
"The link goes to the pref's URL"
|
||||
);
|
||||
is(
|
||||
doc.l10n.getAttributes(themeRecommendationFooter).id,
|
||||
"recommended-theme-1",
|
||||
"The recommendation has the right l10n-id"
|
||||
);
|
||||
} else {
|
||||
ok(!themeRecommendationFooter || themeRecommendationFooter.hidden,
|
||||
"There's no theme recommendation");
|
||||
ok(
|
||||
!themeRecommendationFooter || themeRecommendationFooter.hidden,
|
||||
"There's no theme recommendation"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function installAddon({card, recommendedList, manifestExtra = {}}) {
|
||||
async function installAddon({ card, recommendedList, manifestExtra = {} }) {
|
||||
// Install an add-on to hide the card.
|
||||
let hidden = BrowserTestUtils.waitForEvent(
|
||||
recommendedList, "card-hidden", false, e => e.detail.card == card);
|
||||
recommendedList,
|
||||
"card-hidden",
|
||||
false,
|
||||
e => e.detail.card == card
|
||||
);
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id: card.addonId}},
|
||||
applications: { gecko: { id: card.addonId } },
|
||||
...manifestExtra,
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
|
@ -110,7 +127,7 @@ async function installAddon({card, recommendedList, manifestExtra = {}}) {
|
|||
return extension;
|
||||
}
|
||||
|
||||
async function testListRecommendations({type, manifestExtra = {}}) {
|
||||
async function testListRecommendations({ type, manifestExtra = {} }) {
|
||||
Services.telemetry.clearEvents();
|
||||
|
||||
let win = await loadInitialView(type);
|
||||
|
@ -131,13 +148,13 @@ async function testListRecommendations({type, manifestExtra = {}}) {
|
|||
}
|
||||
|
||||
// Install an add-on for the first card, verify it is hidden.
|
||||
let {addonId} = cards[0];
|
||||
let { addonId } = cards[0];
|
||||
ok(addonId, "The card has an addonId");
|
||||
|
||||
// Installing the add-on will fail since the URL doesn't point to a valid
|
||||
// XPI. This will trigger the telemetry though.
|
||||
let installButton = cards[0].querySelector('[action="install-addon"]');
|
||||
let {panel} = PopupNotifications;
|
||||
let { panel } = PopupNotifications;
|
||||
let popupId = "addon-install-failed-notification";
|
||||
let failPromise = TestUtils.topicObserved("addon-install-failed");
|
||||
installButton.click();
|
||||
|
@ -151,7 +168,7 @@ async function testListRecommendations({type, manifestExtra = {}}) {
|
|||
panel.firstElementChild.button.click();
|
||||
await BrowserTestUtils.waitForPopupEvent(panel, "hidden");
|
||||
|
||||
let extension = await installAddon({card: cards[0], recommendedList});
|
||||
let extension = await installAddon({ card: cards[0], recommendedList });
|
||||
is_element_hidden(cards[0], "The card is now hidden");
|
||||
|
||||
// Switch away and back, there should still be a hidden card.
|
||||
|
@ -182,20 +199,28 @@ async function testListRecommendations({type, manifestExtra = {}}) {
|
|||
|
||||
await closeView(win);
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{action: "installFromRecommendation", view: "list", addonId, type}],
|
||||
], {methods: ["action"]});
|
||||
assertAboutAddonsTelemetryEvents(
|
||||
[
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ action: "installFromRecommendation", view: "list", addonId, type },
|
||||
],
|
||||
],
|
||||
{ methods: ["action"] }
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function testExtensionList() {
|
||||
await testListRecommendations({type: "extension"});
|
||||
await testListRecommendations({ type: "extension" });
|
||||
});
|
||||
|
||||
add_task(async function testThemeList() {
|
||||
await testListRecommendations({
|
||||
type: "theme",
|
||||
manifestExtra: {theme: {}},
|
||||
manifestExtra: { theme: {} },
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -215,10 +240,11 @@ add_task(async function testInstallAllExtensions() {
|
|||
is(cards.length, 3, "We found some cards");
|
||||
|
||||
let extensions = await Promise.all(
|
||||
cards.map(card => installAddon({card, recommendedList})));
|
||||
cards.map(card => installAddon({ card, recommendedList }))
|
||||
);
|
||||
|
||||
// The find more on AMO button is now shown.
|
||||
checkExtraContents(doc, type, {showAmoButton: true});
|
||||
checkExtraContents(doc, type, { showAmoButton: true });
|
||||
|
||||
// Uninstall one of the extensions, the button should be hidden again.
|
||||
let extension = extensions.pop();
|
||||
|
@ -235,9 +261,7 @@ add_task(async function testInstallAllExtensions() {
|
|||
|
||||
add_task(async function testError() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.getAddons.discovery.api_url", "data:,"],
|
||||
],
|
||||
set: [["extensions.getAddons.discovery.api_url", "data:,"]],
|
||||
});
|
||||
|
||||
let win = await loadInitialView("extension");
|
||||
|
@ -247,7 +271,7 @@ add_task(async function testError() {
|
|||
let recommendedList = doc.querySelector("recommended-addon-list");
|
||||
await recommendedList.cardsReady;
|
||||
|
||||
checkExtraContents(doc, "extension", {showAmoButton: true});
|
||||
checkExtraContents(doc, "extension", { showAmoButton: true });
|
||||
|
||||
await closeView(win);
|
||||
await SpecialPowers.popPrefEnv();
|
||||
|
@ -265,7 +289,7 @@ add_task(async function testThemesNoRecommendationUrl() {
|
|||
let recommendedList = doc.querySelector("recommended-addon-list");
|
||||
await recommendedList.cardsReady;
|
||||
|
||||
checkExtraContents(doc, "theme", {showThemeRecommendationFooter: false});
|
||||
checkExtraContents(doc, "theme", { showThemeRecommendationFooter: false });
|
||||
|
||||
await closeView(win);
|
||||
await SpecialPowers.popPrefEnv();
|
||||
|
|
|
@ -12,7 +12,7 @@ function clickElement(el) {
|
|||
el.dispatchEvent(new CustomEvent("click"));
|
||||
}
|
||||
|
||||
function createMessageBar(messageBarStack, {attrs, children, onclose} = {}) {
|
||||
function createMessageBar(messageBarStack, { attrs, children, onclose } = {}) {
|
||||
const win = messageBarStack.ownerGlobal;
|
||||
const messageBar = win.document.createElementNS(HTML_NS, "message-bar");
|
||||
if (attrs) {
|
||||
|
@ -27,16 +27,14 @@ function createMessageBar(messageBarStack, {attrs, children, onclose} = {}) {
|
|||
messageBar.append(children);
|
||||
}
|
||||
}
|
||||
messageBar.addEventListener("message-bar:close", onclose, {once: true});
|
||||
messageBar.addEventListener("message-bar:close", onclose, { once: true });
|
||||
messageBarStack.append(messageBar);
|
||||
return messageBar;
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.htmlaboutaddons.enabled", true],
|
||||
],
|
||||
set: [["extensions.htmlaboutaddons.enabled", true]],
|
||||
});
|
||||
|
||||
htmlAboutAddonsWindow = await loadInitialView("extension");
|
||||
|
@ -52,11 +50,17 @@ add_task(async function test_message_bar_stack() {
|
|||
|
||||
ok(messageBarStack, "Got a message-bar-stack in HTML about:addons page");
|
||||
|
||||
is(messageBarStack.maxMessageBarCount, 3,
|
||||
"Got the expected max-message-bar-count property");
|
||||
is(
|
||||
messageBarStack.maxMessageBarCount,
|
||||
3,
|
||||
"Got the expected max-message-bar-count property"
|
||||
);
|
||||
|
||||
is(messageBarStack.childElementCount, 0,
|
||||
"message-bar-stack is initially empty");
|
||||
is(
|
||||
messageBarStack.childElementCount,
|
||||
0,
|
||||
"message-bar-stack is initially empty"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_create_message_bar_create_and_onclose() {
|
||||
|
@ -76,16 +80,28 @@ add_task(async function test_create_message_bar_create_and_onclose() {
|
|||
});
|
||||
});
|
||||
|
||||
is(messageBarStack.childElementCount, 1,
|
||||
"message-bar-stack has a child element");
|
||||
is(messageBarStack.firstElementChild, messageBar,
|
||||
"newly created message-bar added as message-bar-stack child element");
|
||||
is(
|
||||
messageBarStack.childElementCount,
|
||||
1,
|
||||
"message-bar-stack has a child element"
|
||||
);
|
||||
is(
|
||||
messageBarStack.firstElementChild,
|
||||
messageBar,
|
||||
"newly created message-bar added as message-bar-stack child element"
|
||||
);
|
||||
|
||||
const slot = messageBar.shadowRoot.querySelector("slot");
|
||||
is(slot.assignedNodes()[0], messageEl,
|
||||
"Got the expected span element assigned to the message-bar slot");
|
||||
is(slot.assignedNodes()[1], buttonEl,
|
||||
"Got the expected button element assigned to the message-bar slot");
|
||||
is(
|
||||
slot.assignedNodes()[0],
|
||||
messageEl,
|
||||
"Got the expected span element assigned to the message-bar slot"
|
||||
);
|
||||
is(
|
||||
slot.assignedNodes()[1],
|
||||
buttonEl,
|
||||
"Got the expected button element assigned to the message-bar slot"
|
||||
);
|
||||
|
||||
info("Click the close icon on the newly created message-bar");
|
||||
clickElement(messageBar.shadowRoot.querySelector("button.close"));
|
||||
|
@ -93,8 +109,11 @@ add_task(async function test_create_message_bar_create_and_onclose() {
|
|||
info("Expect the onclose function to be called");
|
||||
await onceMessageBarClosed;
|
||||
|
||||
is(messageBarStack.childElementCount, 0,
|
||||
"message-bar-stack has no child elements");
|
||||
is(
|
||||
messageBarStack.childElementCount,
|
||||
0,
|
||||
"message-bar-stack has no child elements"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_max_message_bar_count() {
|
||||
|
@ -112,26 +131,34 @@ add_task(async function test_max_message_bar_count() {
|
|||
});
|
||||
});
|
||||
|
||||
is(messageBarStack.childElementCount, 1,
|
||||
"message-bar-stack has the expected number of children");
|
||||
is(
|
||||
messageBarStack.childElementCount,
|
||||
1,
|
||||
"message-bar-stack has the expected number of children"
|
||||
);
|
||||
|
||||
info("Create 3 more message bars");
|
||||
const allBarsPromises = [];
|
||||
for (let i = 2; i <= 4; i++) {
|
||||
allBarsPromises.push(new Promise(resolve => {
|
||||
createMessageBar(messageBarStack, {
|
||||
attrs: {dismissable: ""},
|
||||
children: [messageElement, i],
|
||||
onclose: resolve,
|
||||
});
|
||||
}));
|
||||
allBarsPromises.push(
|
||||
new Promise(resolve => {
|
||||
createMessageBar(messageBarStack, {
|
||||
attrs: { dismissable: "" },
|
||||
children: [messageElement, i],
|
||||
onclose: resolve,
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
info("Expect first message-bar to closed automatically");
|
||||
await onceMessageBarClosed;
|
||||
|
||||
is(messageBarStack.childElementCount, 3,
|
||||
"message-bar-stack has the expected number of children");
|
||||
is(
|
||||
messageBarStack.childElementCount,
|
||||
3,
|
||||
"message-bar-stack has the expected number of children"
|
||||
);
|
||||
|
||||
info("Click on close icon for the second message-bar");
|
||||
clickElement(messageBarStack.firstElementChild._closeIcon);
|
||||
|
@ -139,8 +166,11 @@ add_task(async function test_max_message_bar_count() {
|
|||
info("Expect the second message-bar to be closed");
|
||||
await allBarsPromises[0];
|
||||
|
||||
is(messageBarStack.childElementCount, 2,
|
||||
"message-bar-stack has the expected number of children");
|
||||
is(
|
||||
messageBarStack.childElementCount,
|
||||
2,
|
||||
"message-bar-stack has the expected number of children"
|
||||
);
|
||||
|
||||
info("Clear the entire message-bar-stack content");
|
||||
messageBarStack.textContent = "";
|
||||
|
@ -148,6 +178,9 @@ add_task(async function test_max_message_bar_count() {
|
|||
info("Expect all the created message-bar to be closed automatically");
|
||||
await Promise.all(allBarsPromises);
|
||||
|
||||
is(messageBarStack.childElementCount, 0,
|
||||
"message-bar-stack has no child elements");
|
||||
is(
|
||||
messageBarStack.childElementCount,
|
||||
0,
|
||||
"message-bar-stack has no child elements"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@ add_task(async function enableHtmlViews() {
|
|||
|
||||
const DEFAULT_SECTION_NAMES = ["one", "two", "three"];
|
||||
|
||||
function makeButton({doc, name, deckId}) {
|
||||
function makeButton({ doc, name, deckId }) {
|
||||
let button = doc.createElement("named-deck-button");
|
||||
button.setAttribute("name", name);
|
||||
button.deckId = deckId;
|
||||
|
@ -20,23 +20,23 @@ function makeButton({doc, name, deckId}) {
|
|||
return button;
|
||||
}
|
||||
|
||||
function makeSection({doc, name}) {
|
||||
function makeSection({ doc, name }) {
|
||||
let view = doc.createElement("section");
|
||||
view.setAttribute("name", name);
|
||||
view.textContent = name + name;
|
||||
return view;
|
||||
}
|
||||
|
||||
function addSection({name, deck, buttons}) {
|
||||
function addSection({ name, deck, buttons }) {
|
||||
let doc = deck.ownerDocument;
|
||||
let button = makeButton({doc, name, deckId: deck.id});
|
||||
let button = makeButton({ doc, name, deckId: deck.id });
|
||||
buttons.appendChild(button);
|
||||
let view = makeSection({doc, name});
|
||||
let view = makeSection({ doc, name });
|
||||
deck.appendChild(view);
|
||||
return {button, view};
|
||||
return { button, view };
|
||||
}
|
||||
|
||||
async function runTests({deck, buttons}) {
|
||||
async function runTests({ deck, buttons }) {
|
||||
const selectedSlot = deck.shadowRoot.querySelector('slot[name="selected"]');
|
||||
const getButtonByName = name => buttons.querySelector(`[name="${name}"]`);
|
||||
|
||||
|
@ -50,8 +50,11 @@ async function runTests({deck, buttons}) {
|
|||
is(slottedEls.length, 0, "The deck is empty");
|
||||
} else {
|
||||
is(slottedEls.length, 1, "There's one visible view");
|
||||
is(slottedEls[0].getAttribute("name"), name,
|
||||
"The correct view is in the slot");
|
||||
is(
|
||||
slottedEls[0].getAttribute("name"),
|
||||
name,
|
||||
"The correct view is in the slot"
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the hidden properties are set.
|
||||
|
@ -71,8 +74,11 @@ async function runTests({deck, buttons}) {
|
|||
for (let button of buttons.children) {
|
||||
let buttonName = button.getAttribute("name");
|
||||
let selected = buttonName == name;
|
||||
is(button.hasAttribute("selected"), selected,
|
||||
`${buttonName} is ${selected ? "selected" : "not selected"}`);
|
||||
is(
|
||||
button.hasAttribute("selected"),
|
||||
selected,
|
||||
`${buttonName} is ${selected ? "selected" : "not selected"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +92,7 @@ async function runTests({deck, buttons}) {
|
|||
|
||||
// Add a new section, nothing changes.
|
||||
info("Add section last");
|
||||
let last = addSection({name: "last", deck, buttons});
|
||||
let last = addSection({ name: "last", deck, buttons });
|
||||
checkState("three", 4);
|
||||
|
||||
// We can switch to the new section.
|
||||
|
@ -125,27 +131,29 @@ async function runTests({deck, buttons}) {
|
|||
info("Add the missing view, it should be shown");
|
||||
shown = BrowserTestUtils.waitForEvent(selectedSlot, "slotchange");
|
||||
let viewChangedEvent = false;
|
||||
let viewChangedFn = () => { viewChangedEvent = true; };
|
||||
let viewChangedFn = () => {
|
||||
viewChangedEvent = true;
|
||||
};
|
||||
deck.addEventListener("view-changed", viewChangedFn);
|
||||
addSection({name: "missing", deck, buttons});
|
||||
addSection({ name: "missing", deck, buttons });
|
||||
await shown;
|
||||
deck.removeEventListener("view-changed", viewChangedFn);
|
||||
ok(!viewChangedEvent, "The view-changed event didn't fire");
|
||||
checkState("missing", 4);
|
||||
}
|
||||
|
||||
async function setup({doc, beAsync, first}) {
|
||||
async function setup({ doc, beAsync, first }) {
|
||||
const deckId = `${first}-first-${beAsync}`;
|
||||
|
||||
// Make the deck and buttons.
|
||||
const deck = doc.createElement("named-deck");
|
||||
deck.id = deckId;
|
||||
for (let name of DEFAULT_SECTION_NAMES) {
|
||||
deck.appendChild(makeSection({doc, name}));
|
||||
deck.appendChild(makeSection({ doc, name }));
|
||||
}
|
||||
const buttons = doc.createElement("div");
|
||||
for (let name of DEFAULT_SECTION_NAMES) {
|
||||
buttons.appendChild(makeButton({doc, name, deckId}));
|
||||
buttons.appendChild(makeButton({ doc, name, deckId }));
|
||||
}
|
||||
|
||||
let ordered;
|
||||
|
@ -164,7 +172,7 @@ async function setup({doc, beAsync, first}) {
|
|||
}
|
||||
doc.body.appendChild(ordered.shift());
|
||||
|
||||
return {deck, buttons};
|
||||
return { deck, buttons };
|
||||
}
|
||||
|
||||
add_task(async function testNamedDeckAndButtons() {
|
||||
|
@ -173,15 +181,15 @@ add_task(async function testNamedDeckAndButtons() {
|
|||
|
||||
// Check adding the deck first.
|
||||
dump("Running deck first tests synchronously");
|
||||
await runTests(await setup({doc, beAsync: false, first: "deck"}));
|
||||
await runTests(await setup({ doc, beAsync: false, first: "deck" }));
|
||||
dump("Running deck first tests asynchronously");
|
||||
await runTests(await setup({doc, beAsync: true, first: "deck"}));
|
||||
await runTests(await setup({ doc, beAsync: true, first: "deck" }));
|
||||
|
||||
// Check adding the buttons first.
|
||||
dump("Running buttons first tests synchronously");
|
||||
await runTests(await setup({doc, beAsync: false, first: "buttons"}));
|
||||
await runTests(await setup({ doc, beAsync: false, first: "buttons" }));
|
||||
dump("Running buttons first tests asynchronously");
|
||||
await runTests(await setup({doc, beAsync: true, first: "buttons"}));
|
||||
await runTests(await setup({ doc, beAsync: true, first: "buttons" }));
|
||||
|
||||
await closeView(win);
|
||||
});
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
/* eslint max-len: ["error", 80] */
|
||||
|
||||
const {AddonTestUtils} =
|
||||
ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
const {ExtensionParent} =
|
||||
ChromeUtils.import("resource://gre/modules/ExtensionParent.jsm");
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
const { ExtensionParent } = ChromeUtils.import(
|
||||
"resource://gre/modules/ExtensionParent.jsm"
|
||||
);
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
|
||||
|
@ -39,7 +41,7 @@ add_task(async function testInlineOptions() {
|
|||
let id = "inline@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
options_ui: {
|
||||
page: "options.html",
|
||||
},
|
||||
|
@ -94,8 +96,8 @@ add_task(async function testInlineOptions() {
|
|||
// Verify we're on the preferences tab.
|
||||
card = doc.querySelector("addon-card");
|
||||
is(card.addon.id, id, "The right page was loaded");
|
||||
let {deck, tabGroup} = card.details;
|
||||
let {selectedViewName} = deck;
|
||||
let { deck, tabGroup } = card.details;
|
||||
let { selectedViewName } = deck;
|
||||
is(selectedViewName, "preferences", "The preferences tab is shown");
|
||||
|
||||
info("Check that there are two buttons and they're visible");
|
||||
|
@ -110,24 +112,33 @@ add_task(async function testInlineOptions() {
|
|||
// Check the attributes of the options browser.
|
||||
let browser = card.querySelector("inline-options-browser browser");
|
||||
ok(browser, "The visible view has a browser");
|
||||
is(browser.currentURI.spec, card.addon.optionsURL,
|
||||
"The browser has the expected options URL");
|
||||
is(
|
||||
browser.currentURI.spec,
|
||||
card.addon.optionsURL,
|
||||
"The browser has the expected options URL"
|
||||
);
|
||||
is(url, card.addon.optionsURL, "Browser has the expected options URL loaded");
|
||||
let stack = browser.closest("stack");
|
||||
is(browser.clientWidth, stack.clientWidth,
|
||||
"Browser should be the same width as its direct parent");
|
||||
is(
|
||||
browser.clientWidth,
|
||||
stack.clientWidth,
|
||||
"Browser should be the same width as its direct parent"
|
||||
);
|
||||
ok(stack.clientWidth > 0, "The stack has a width");
|
||||
ok(card.querySelector('[action="preferences"]').hidden,
|
||||
"The preferences option is hidden now");
|
||||
ok(
|
||||
card.querySelector('[action="preferences"]').hidden,
|
||||
"The preferences option is hidden now"
|
||||
);
|
||||
|
||||
let lastHeight;
|
||||
let waitForHeightChange = () => TestUtils.waitForCondition(() => {
|
||||
if (browser.clientHeight !== lastHeight) {
|
||||
lastHeight = browser.clientHeight;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
let waitForHeightChange = () =>
|
||||
TestUtils.waitForCondition(() => {
|
||||
if (browser.clientHeight !== lastHeight) {
|
||||
lastHeight = browser.clientHeight;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// The expected heights are 1px taller, to work around bug 1548687.
|
||||
const EXPECTED_HEIGHT_SHORT = HEIGHT_SHORT + 1;
|
||||
|
@ -178,7 +189,7 @@ add_task(async function testCardRerender() {
|
|||
let id = "rerender@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
options_ui: {
|
||||
page: "options.html",
|
||||
},
|
||||
|
@ -210,8 +221,11 @@ add_task(async function testCardRerender() {
|
|||
card.querySelector('named-deck-button[name="preferences"]').click();
|
||||
await browserAdded;
|
||||
|
||||
is(doc.querySelectorAll("inline-options-browser").length, 1,
|
||||
"There is 1 inline-options-browser");
|
||||
is(
|
||||
doc.querySelectorAll("inline-options-browser").length,
|
||||
1,
|
||||
"There is 1 inline-options-browser"
|
||||
);
|
||||
is(doc.querySelectorAll("browser").length, 1, "There is 1 browser");
|
||||
|
||||
info("Reload the add-on and ensure there's still only one browser");
|
||||
|
@ -222,8 +236,11 @@ add_task(async function testCardRerender() {
|
|||
card.addon.reload();
|
||||
await updated;
|
||||
|
||||
is(doc.querySelectorAll("inline-options-browser").length, 1,
|
||||
"There is 1 inline-options-browser");
|
||||
is(
|
||||
doc.querySelectorAll("inline-options-browser").length,
|
||||
1,
|
||||
"There is 1 inline-options-browser"
|
||||
);
|
||||
is(doc.querySelectorAll("browser").length, 1, "There is 1 browser");
|
||||
|
||||
info("Re-rendering card to ensure a second browser isn't added");
|
||||
|
@ -231,19 +248,28 @@ add_task(async function testCardRerender() {
|
|||
card.render();
|
||||
await updated;
|
||||
|
||||
is(card.details.deck.selectedViewName, "details",
|
||||
"Rendering reverted to the details view");
|
||||
is(
|
||||
card.details.deck.selectedViewName,
|
||||
"details",
|
||||
"Rendering reverted to the details view"
|
||||
);
|
||||
|
||||
is(doc.querySelectorAll("inline-options-browser").length, 1,
|
||||
"There is still only 1 inline-options-browser after re-render");
|
||||
is(
|
||||
doc.querySelectorAll("inline-options-browser").length,
|
||||
1,
|
||||
"There is still only 1 inline-options-browser after re-render"
|
||||
);
|
||||
is(doc.querySelectorAll("browser").length, 0, "There is no browser");
|
||||
|
||||
let newBrowserAdded = waitOptionsBrowserInserted();
|
||||
card.showPrefs();
|
||||
await newBrowserAdded;
|
||||
|
||||
is(doc.querySelectorAll("inline-options-browser").length, 1,
|
||||
"There is still only 1 inline-options-browser after opening preferences");
|
||||
is(
|
||||
doc.querySelectorAll("inline-options-browser").length,
|
||||
1,
|
||||
"There is still only 1 inline-options-browser after opening preferences"
|
||||
);
|
||||
is(doc.querySelectorAll("browser").length, 1, "There is 1 browser");
|
||||
|
||||
await closeView(win);
|
||||
|
|
|
@ -13,11 +13,11 @@ add_task(async function enableHtmlViews() {
|
|||
});
|
||||
});
|
||||
|
||||
async function testOptionsInTab({id, options_ui_options}) {
|
||||
async function testOptionsInTab({ id, options_ui_options }) {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Prefs extension",
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
options_ui: {
|
||||
page: "options.html",
|
||||
...options_ui_options,
|
||||
|
@ -25,7 +25,9 @@ async function testOptionsInTab({id, options_ui_options}) {
|
|||
},
|
||||
background() {
|
||||
browser.test.sendMessage(
|
||||
"options-url", browser.runtime.getURL("options.html"));
|
||||
"options-url",
|
||||
browser.runtime.getURL("options.html")
|
||||
);
|
||||
},
|
||||
files: {
|
||||
"options.html": `<script src="options.js"></script>`,
|
||||
|
@ -86,7 +88,7 @@ async function testOptionsInTab({id, options_ui_options}) {
|
|||
|
||||
add_task(async function testPreferencesLink() {
|
||||
let id = "prefs@mochi.test";
|
||||
await testOptionsInTab({id, options_ui_options: {open_in_tab: true}});
|
||||
await testOptionsInTab({ id, options_ui_options: { open_in_tab: true } });
|
||||
});
|
||||
|
||||
add_task(async function testPreferencesInlineDisabled() {
|
||||
|
@ -95,7 +97,7 @@ add_task(async function testPreferencesInlineDisabled() {
|
|||
});
|
||||
|
||||
let id = "inline-disabled@mochi.test";
|
||||
await testOptionsInTab({id, options_ui_options: {}});
|
||||
await testOptionsInTab({ id, options_ui_options: {} });
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
@ -105,7 +107,7 @@ add_task(async function testNoPreferences() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "No Prefs extension",
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
|
|
@ -12,17 +12,19 @@ add_task(async function enableHtmlViews() {
|
|||
});
|
||||
|
||||
let gProvider = new MockProvider();
|
||||
gProvider.createAddons([{
|
||||
id: "no-ask-to-activate@mochi.test",
|
||||
name: "No ask to activate",
|
||||
getFullDescription(doc) {
|
||||
let a = doc.createElement("a");
|
||||
a.textContent = "A link";
|
||||
a.href = "http://example.com/no-ask-to-activate";
|
||||
return a;
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "no-ask-to-activate@mochi.test",
|
||||
name: "No ask to activate",
|
||||
getFullDescription(doc) {
|
||||
let a = doc.createElement("a");
|
||||
a.textContent = "A link";
|
||||
a.href = "http://example.com/no-ask-to-activate";
|
||||
return a;
|
||||
},
|
||||
type: "plugin",
|
||||
},
|
||||
type: "plugin",
|
||||
}]);
|
||||
]);
|
||||
|
||||
Services.telemetry.clearEvents();
|
||||
});
|
||||
|
@ -42,7 +44,8 @@ add_task(async function testAskToActivate() {
|
|||
|
||||
let plugins = await AddonManager.getAddonsByTypes(["plugin"]);
|
||||
let flash = plugins.find(
|
||||
plugin => plugin.description == TEST_PLUGIN_DESCRIPTION);
|
||||
plugin => plugin.description == TEST_PLUGIN_DESCRIPTION
|
||||
);
|
||||
let addonId = flash.id;
|
||||
|
||||
// Reset to default value.
|
||||
|
@ -54,14 +57,19 @@ add_task(async function testAskToActivate() {
|
|||
let card = doc.querySelector(`addon-card[addon-id="${flash.id}"]`);
|
||||
let panelItems = card.querySelectorAll("panel-item:not([hidden])");
|
||||
let actions = Array.from(panelItems).map(item => item.getAttribute("action"));
|
||||
Assert.deepEqual(actions, [
|
||||
"ask-to-activate", "never-activate", "preferences", "expand",
|
||||
], "The panel items are for a plugin");
|
||||
Assert.deepEqual(
|
||||
actions,
|
||||
["ask-to-activate", "never-activate", "preferences", "expand"],
|
||||
"The panel items are for a plugin"
|
||||
);
|
||||
|
||||
checkItems(panelItems, "ask-to-activate");
|
||||
|
||||
is(flash.userDisabled, AddonManager.STATE_ASK_TO_ACTIVATE,
|
||||
"Flash is ask-to-activate");
|
||||
is(
|
||||
flash.userDisabled,
|
||||
AddonManager.STATE_ASK_TO_ACTIVATE,
|
||||
"Flash is ask-to-activate"
|
||||
);
|
||||
ok(flash.isActive, "Flash is active");
|
||||
|
||||
// Switch to never activate.
|
||||
|
@ -77,8 +85,11 @@ add_task(async function testAskToActivate() {
|
|||
card.querySelector("panel-item[action*=ask]").click();
|
||||
await updated;
|
||||
checkItems(panelItems, "ask-to-activate");
|
||||
is(flash.userDisabled, AddonManager.STATE_ASK_TO_ACTIVATE,
|
||||
"Flash is ask-to-activate");
|
||||
is(
|
||||
flash.userDisabled,
|
||||
AddonManager.STATE_ASK_TO_ACTIVATE,
|
||||
"Flash is ask-to-activate"
|
||||
);
|
||||
ok(flash.isActive, "Flash is active");
|
||||
|
||||
// Check the detail view, too.
|
||||
|
@ -93,12 +104,22 @@ add_task(async function testAskToActivate() {
|
|||
await closeView(win);
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "plugin"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "plugin", addonId, view: "list", action: "disable"}],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "plugin" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "plugin", addonId, view: "list", action: "disable" },
|
||||
],
|
||||
// Ask-to-activate doesn't trigger a telemetry event.
|
||||
["addonsManager", "view", "aboutAddons", "detail",
|
||||
{type: "plugin", addonId}],
|
||||
[
|
||||
"addonsManager",
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "plugin", addonId },
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -127,8 +148,10 @@ add_task(async function testNoAskToActivate() {
|
|||
// There's no preferences option.
|
||||
let actions = Array.from(menuItems).map(item => item.getAttribute("action"));
|
||||
Assert.deepEqual(
|
||||
actions, ["ask-to-activate", "always-activate", "never-activate", "expand"],
|
||||
"The panel items are for a plugin");
|
||||
actions,
|
||||
["ask-to-activate", "always-activate", "never-activate", "expand"],
|
||||
"The panel items are for a plugin"
|
||||
);
|
||||
|
||||
// Open the details page.
|
||||
let loaded = waitForViewLoad(win);
|
||||
|
@ -152,8 +175,10 @@ add_task(async function testNoAskToActivate() {
|
|||
// There's no preferences option, and expand is now hidden.
|
||||
actions = Array.from(menuItems).map(item => item.getAttribute("action"));
|
||||
Assert.deepEqual(
|
||||
actions, ["ask-to-activate", "always-activate", "never-activate"],
|
||||
"The panel items are for a detail page plugin");
|
||||
actions,
|
||||
["ask-to-activate", "always-activate", "never-activate"],
|
||||
"The panel items are for a detail page plugin"
|
||||
);
|
||||
|
||||
await closeView(win);
|
||||
});
|
||||
|
|
|
@ -13,57 +13,65 @@ add_task(async function enableHtmlViews() {
|
|||
});
|
||||
|
||||
gProvider = new MockProvider();
|
||||
gProvider.createAddons([{
|
||||
id: "addon-today-2@mochi.test",
|
||||
name: "Updated today two",
|
||||
creator: {name: "The creator"},
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(6),
|
||||
}, {
|
||||
id: "addon-today-3@mochi.test",
|
||||
name: "Updated today three",
|
||||
creator: {name: "The creator"},
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(9),
|
||||
}, {
|
||||
id: "addon-today-1@mochi.test",
|
||||
name: "Updated today",
|
||||
creator: {name: "The creator"},
|
||||
version: "3.1",
|
||||
type: "extension",
|
||||
releaseNotesURI: "http://example.com/notes.txt",
|
||||
updateDate: dateHoursAgo(1),
|
||||
}, {
|
||||
id: "addon-yesterday-1@mochi.test",
|
||||
name: "Updated yesterday one",
|
||||
creator: {name: "The creator"},
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(15),
|
||||
}, {
|
||||
id: "addon-earlier@mochi.test",
|
||||
name: "Updated earlier",
|
||||
creator: {name: "The creator"},
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(49),
|
||||
}, {
|
||||
id: "addon-yesterday-2@mochi.test",
|
||||
name: "Updated yesterday",
|
||||
creator: {name: "The creator"},
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(24),
|
||||
}, {
|
||||
id: "addon-lastweek@mochi.test",
|
||||
name: "Updated last week",
|
||||
creator: {name: "The creator"},
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(192),
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "addon-today-2@mochi.test",
|
||||
name: "Updated today two",
|
||||
creator: { name: "The creator" },
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(6),
|
||||
},
|
||||
{
|
||||
id: "addon-today-3@mochi.test",
|
||||
name: "Updated today three",
|
||||
creator: { name: "The creator" },
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(9),
|
||||
},
|
||||
{
|
||||
id: "addon-today-1@mochi.test",
|
||||
name: "Updated today",
|
||||
creator: { name: "The creator" },
|
||||
version: "3.1",
|
||||
type: "extension",
|
||||
releaseNotesURI: "http://example.com/notes.txt",
|
||||
updateDate: dateHoursAgo(1),
|
||||
},
|
||||
{
|
||||
id: "addon-yesterday-1@mochi.test",
|
||||
name: "Updated yesterday one",
|
||||
creator: { name: "The creator" },
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(15),
|
||||
},
|
||||
{
|
||||
id: "addon-earlier@mochi.test",
|
||||
name: "Updated earlier",
|
||||
creator: { name: "The creator" },
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(49),
|
||||
},
|
||||
{
|
||||
id: "addon-yesterday-2@mochi.test",
|
||||
name: "Updated yesterday",
|
||||
creator: { name: "The creator" },
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(24),
|
||||
},
|
||||
{
|
||||
id: "addon-lastweek@mochi.test",
|
||||
name: "Updated last week",
|
||||
creator: { name: "The creator" },
|
||||
version: "3.3",
|
||||
type: "extension",
|
||||
updateDate: dateHoursAgo(192),
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
add_task(async function testRecentUpdatesList() {
|
||||
|
@ -85,15 +93,22 @@ add_task(async function testRecentUpdatesList() {
|
|||
.filter(id => id.endsWith("@mochi.test"));
|
||||
|
||||
// Verify that the add-ons are in the right order.
|
||||
Assert.deepEqual(addonsInOrder(), [
|
||||
"addon-today-1@mochi.test", "addon-today-2@mochi.test",
|
||||
"addon-today-3@mochi.test", "addon-yesterday-1@mochi.test",
|
||||
"addon-yesterday-2@mochi.test",
|
||||
], "The add-ons are in the right order");
|
||||
Assert.deepEqual(
|
||||
addonsInOrder(),
|
||||
[
|
||||
"addon-today-1@mochi.test",
|
||||
"addon-today-2@mochi.test",
|
||||
"addon-today-3@mochi.test",
|
||||
"addon-yesterday-1@mochi.test",
|
||||
"addon-yesterday-2@mochi.test",
|
||||
],
|
||||
"The add-ons are in the right order"
|
||||
);
|
||||
|
||||
info("Check that release notes are shown on the details page");
|
||||
let card = list.querySelector(
|
||||
'addon-card[addon-id="addon-today-1@mochi.test"]');
|
||||
'addon-card[addon-id="addon-today-1@mochi.test"]'
|
||||
);
|
||||
loaded = waitForViewLoad(win);
|
||||
card.querySelector('[action="expand"]').click();
|
||||
await loaded;
|
||||
|
@ -101,8 +116,10 @@ add_task(async function testRecentUpdatesList() {
|
|||
card = doc.querySelector("addon-card");
|
||||
ok(card.expanded, "The card is expanded");
|
||||
ok(!card.details.tabGroup.hidden, "The tabs are shown");
|
||||
ok(!card.details.tabGroup.querySelector('[name="release-notes"]').hidden,
|
||||
"The release notes button is shown");
|
||||
ok(
|
||||
!card.details.tabGroup.querySelector('[name="release-notes"]').hidden,
|
||||
"The release notes button is shown"
|
||||
);
|
||||
|
||||
info("Go back to the recent updates view");
|
||||
loaded = waitForViewLoad(win);
|
||||
|
@ -117,7 +134,7 @@ add_task(async function testRecentUpdatesList() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "New extension",
|
||||
applications: {gecko: {id: "new@mochi.test"}},
|
||||
applications: { gecko: { id: "new@mochi.test" } },
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
@ -126,11 +143,18 @@ add_task(async function testRecentUpdatesList() {
|
|||
await added;
|
||||
|
||||
// The new extension should now be at the top of the list.
|
||||
Assert.deepEqual(addonsInOrder(), [
|
||||
"new@mochi.test", "addon-today-1@mochi.test", "addon-today-2@mochi.test",
|
||||
"addon-today-3@mochi.test", "addon-yesterday-1@mochi.test",
|
||||
"addon-yesterday-2@mochi.test",
|
||||
], "The new add-on went to the top");
|
||||
Assert.deepEqual(
|
||||
addonsInOrder(),
|
||||
[
|
||||
"new@mochi.test",
|
||||
"addon-today-1@mochi.test",
|
||||
"addon-today-2@mochi.test",
|
||||
"addon-today-3@mochi.test",
|
||||
"addon-yesterday-1@mochi.test",
|
||||
"addon-yesterday-2@mochi.test",
|
||||
],
|
||||
"The new add-on went to the top"
|
||||
);
|
||||
|
||||
// Open the detail view for the new add-on.
|
||||
card = list.querySelector('addon-card[addon-id="new@mochi.test"]');
|
||||
|
@ -138,8 +162,11 @@ add_task(async function testRecentUpdatesList() {
|
|||
card.querySelector('[action="expand"]').click();
|
||||
await loaded;
|
||||
|
||||
is(win.managerWindow.gCategories.selected, "addons://list/extension",
|
||||
"The extensions category is selected");
|
||||
is(
|
||||
win.managerWindow.gCategories.selected,
|
||||
"addons://list/extension",
|
||||
"The extensions category is selected"
|
||||
);
|
||||
|
||||
await closeView(win);
|
||||
await extension.unload();
|
||||
|
|
|
@ -37,7 +37,7 @@ async function checkRecommendedBadge(id, hidden) {
|
|||
add_task(async function testNotRecommended() {
|
||||
let id = "not-recommended@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {applications: {gecko: {id}}},
|
||||
manifest: { applications: { gecko: { id } } },
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
await extension.startup();
|
||||
|
@ -50,12 +50,14 @@ add_task(async function testNotRecommended() {
|
|||
add_task(async function testRecommended() {
|
||||
let id = "recommended@mochi.test";
|
||||
let provider = new MockProvider();
|
||||
provider.createAddons([{
|
||||
id,
|
||||
isRecommended: true,
|
||||
name: "Recommended",
|
||||
type: "extension",
|
||||
}]);
|
||||
provider.createAddons([
|
||||
{
|
||||
id,
|
||||
isRecommended: true,
|
||||
name: "Recommended",
|
||||
type: "extension",
|
||||
},
|
||||
]);
|
||||
|
||||
await checkRecommendedBadge(id, false);
|
||||
});
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/* eslint max-len: ["error", 80] */
|
||||
|
||||
const {AddonTestUtils} =
|
||||
ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
|
||||
|
@ -16,7 +17,7 @@ function loadDetailView(win, id) {
|
|||
let doc = win.document;
|
||||
let card = doc.querySelector(`addon-card[addon-id="${id}"]`);
|
||||
let loaded = waitForViewLoad(win);
|
||||
EventUtils.synthesizeMouseAtCenter(card, {clickCount: 1}, win);
|
||||
EventUtils.synthesizeMouseAtCenter(card, { clickCount: 1 }, win);
|
||||
return loaded;
|
||||
}
|
||||
|
||||
|
@ -25,7 +26,7 @@ add_task(async function testChangeAutoUpdates() {
|
|||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test",
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
},
|
||||
// Use permanent so the add-on can be updated.
|
||||
useAddonManager: "permanent",
|
||||
|
@ -109,24 +110,54 @@ add_task(async function testChangeAutoUpdates() {
|
|||
await extension.unload();
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "view", "aboutAddons", "detail",
|
||||
{type: "extension", addonId: id}],
|
||||
["addonsManager", "action", "aboutAddons", "enabled",
|
||||
{type: "extension", addonId: id, action: "setAddonUpdate"}],
|
||||
["addonsManager", "action", "aboutAddons", "",
|
||||
{type: "extension", addonId: id, action: "setAddonUpdate"}],
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "view", "aboutAddons", "detail",
|
||||
{type: "extension", addonId: id}],
|
||||
["addonsManager", "action", "aboutAddons", "default",
|
||||
{type: "extension", addonId: id, action: "setAddonUpdate"}],
|
||||
["addonsManager", "action", "aboutAddons", "enabled",
|
||||
{type: "extension", addonId: id, action: "setAddonUpdate"}],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: id },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"enabled",
|
||||
{ type: "extension", addonId: id, action: "setAddonUpdate" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"",
|
||||
{ type: "extension", addonId: id, action: "setAddonUpdate" },
|
||||
],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: id },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"default",
|
||||
{ type: "extension", addonId: id, action: "setAddonUpdate" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"enabled",
|
||||
{ type: "extension", addonId: id, action: "setAddonUpdate" },
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
async function setupExtensionWithUpdate(id, {releaseNotes} = {}) {
|
||||
async function setupExtensionWithUpdate(id, { releaseNotes } = {}) {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.checkUpdateSecurity", false]],
|
||||
});
|
||||
|
@ -173,11 +204,13 @@ async function setupExtensionWithUpdate(id, {releaseNotes} = {}) {
|
|||
AddonTestUtils.registerJSON(server, updatesPath, {
|
||||
addons: {
|
||||
[id]: {
|
||||
updates: [{
|
||||
version: "2",
|
||||
update_link: serverHost + xpiFilename,
|
||||
...releaseNotesExtra,
|
||||
}],
|
||||
updates: [
|
||||
{
|
||||
version: "2",
|
||||
update_link: serverHost + xpiFilename,
|
||||
...releaseNotesExtra,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -204,7 +237,7 @@ function disableAutoUpdates(card) {
|
|||
ok(!updateCheckButton.hidden, "The button is now visible");
|
||||
|
||||
// There shouldn't be an update shown to the user.
|
||||
assertUpdateState({card, shown: false});
|
||||
assertUpdateState({ card, shown: false });
|
||||
}
|
||||
|
||||
function checkForUpdate(card, expected) {
|
||||
|
@ -223,24 +256,36 @@ function installUpdate(card, expected) {
|
|||
}
|
||||
|
||||
function assertUpdateState({
|
||||
card, shown, expanded = true, releaseNotes = false,
|
||||
card,
|
||||
shown,
|
||||
expanded = true,
|
||||
releaseNotes = false,
|
||||
}) {
|
||||
let menuButton = card.querySelector(".more-options-button");
|
||||
ok(menuButton.classList.contains("more-options-button-badged") == shown,
|
||||
"The menu button is badged");
|
||||
ok(
|
||||
menuButton.classList.contains("more-options-button-badged") == shown,
|
||||
"The menu button is badged"
|
||||
);
|
||||
let installButton = card.querySelector('panel-item[action="install-update"]');
|
||||
ok(installButton.hidden != shown,
|
||||
`The install button is ${shown ? "hidden" : "shown"}`);
|
||||
ok(
|
||||
installButton.hidden != shown,
|
||||
`The install button is ${shown ? "hidden" : "shown"}`
|
||||
);
|
||||
if (expanded) {
|
||||
let updateCheckButton = card.querySelector('button[action="update-check"]');
|
||||
ok(updateCheckButton.hidden == shown,
|
||||
`The update check button is ${shown ? "hidden" : "shown"}`);
|
||||
ok(
|
||||
updateCheckButton.hidden == shown,
|
||||
`The update check button is ${shown ? "hidden" : "shown"}`
|
||||
);
|
||||
|
||||
let {tabGroup} = card.details;
|
||||
let { tabGroup } = card.details;
|
||||
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"}`);
|
||||
is(
|
||||
notesBtn.hidden,
|
||||
!releaseNotes,
|
||||
`The release notes button is ${releaseNotes ? "shown" : "hidden"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,7 +305,7 @@ add_task(async function testUpdateAvailable() {
|
|||
await checkForUpdate(card, "update-found");
|
||||
|
||||
// There should now be an update.
|
||||
assertUpdateState({card, shown: true});
|
||||
assertUpdateState({ card, shown: true });
|
||||
|
||||
// The version was 1.
|
||||
let versionRow = card.querySelector(".addon-detail-row-version");
|
||||
|
@ -273,7 +318,7 @@ add_task(async function testUpdateAvailable() {
|
|||
is(versionRow.lastChild.textContent, "2", "The version has updated");
|
||||
|
||||
// No update is shown again.
|
||||
assertUpdateState({card, shown: false});
|
||||
assertUpdateState({ card, shown: false });
|
||||
|
||||
// Check for updates again, there shouldn't be an update.
|
||||
await checkForUpdate(card, "no-update");
|
||||
|
@ -308,14 +353,14 @@ add_task(async function testReleaseNotesLoad() {
|
|||
await loadDetailView(win, id);
|
||||
|
||||
let card = doc.querySelector("addon-card");
|
||||
let {deck, tabGroup} = card.details;
|
||||
let { deck, tabGroup } = card.details;
|
||||
|
||||
// Disable updates and then check.
|
||||
disableAutoUpdates(card);
|
||||
await checkForUpdate(card, "update-found");
|
||||
|
||||
// There should now be an update.
|
||||
assertUpdateState({card, shown: true, releaseNotes: true});
|
||||
assertUpdateState({ card, shown: true, releaseNotes: true });
|
||||
|
||||
info("Check release notes");
|
||||
let notesBtn = tabGroup.querySelector('[name="release-notes"]');
|
||||
|
@ -326,8 +371,11 @@ add_task(async function testReleaseNotesLoad() {
|
|||
// See bug 1551621 for more info.
|
||||
EventUtils.synthesizeMouseAtCenter(notesBtn, {}, win);
|
||||
await loading;
|
||||
is(doc.l10n.getAttributes(notes.firstElementChild).id,
|
||||
"release-notes-loading", "The loading message is shown");
|
||||
is(
|
||||
doc.l10n.getAttributes(notes.firstElementChild).id,
|
||||
"release-notes-loading",
|
||||
"The loading message is shown"
|
||||
);
|
||||
await loaded;
|
||||
info("Checking HTML release notes");
|
||||
let [h1, ul, a] = notes.children;
|
||||
|
@ -362,7 +410,9 @@ add_task(async function testReleaseNotesLoad() {
|
|||
// Load release notes again, verify they weren't loaded.
|
||||
viewChanged = BrowserTestUtils.waitForEvent(deck, "view-changed");
|
||||
let notesCached = BrowserTestUtils.waitForEvent(
|
||||
notes, "release-notes-cached");
|
||||
notes,
|
||||
"release-notes-cached"
|
||||
);
|
||||
notesBtn.click();
|
||||
await viewChanged;
|
||||
await notesCached;
|
||||
|
@ -372,29 +422,54 @@ add_task(async function testReleaseNotesLoad() {
|
|||
await installUpdate(card, "update-installed");
|
||||
|
||||
// There's no more update but release notes are still shown.
|
||||
assertUpdateState({card, shown: false, releaseNotes: true});
|
||||
assertUpdateState({ card, shown: false, releaseNotes: true });
|
||||
|
||||
await closeView(win);
|
||||
await extension.unload();
|
||||
|
||||
assertAboutAddonsTelemetryEvents([
|
||||
["addonsManager", "view", "aboutAddons", "list", {type: "extension"}],
|
||||
["addonsManager", "view", "aboutAddons", "detail",
|
||||
{type: "extension", addonId: id}],
|
||||
["addonsManager", "action", "aboutAddons", "",
|
||||
{type: "extension", addonId: id, action: "setAddonUpdate"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: id, action: "checkForUpdate"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: id, action: "releaseNotes"}],
|
||||
["addonsManager", "action", "aboutAddons", null,
|
||||
{type: "extension", addonId: id, action: "releaseNotes"}],
|
||||
["addonsManager", "view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"addonsManager",
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: id },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"",
|
||||
{ type: "extension", addonId: id, action: "setAddonUpdate" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "extension", addonId: id, action: "checkForUpdate" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "extension", addonId: id, action: "releaseNotes" },
|
||||
],
|
||||
[
|
||||
"addonsManager",
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ type: "extension", addonId: id, action: "releaseNotes" },
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
add_task(async function testReleaseNotesError() {
|
||||
let id = "update-with-notes-error@mochi.test";
|
||||
let extension = await setupExtensionWithUpdate(id, {releaseNotes: "ERROR"});
|
||||
let extension = await setupExtensionWithUpdate(id, { releaseNotes: "ERROR" });
|
||||
|
||||
let win = await loadInitialView("extension");
|
||||
let doc = win.document;
|
||||
|
@ -402,14 +477,14 @@ add_task(async function testReleaseNotesError() {
|
|||
await loadDetailView(win, id);
|
||||
|
||||
let card = doc.querySelector("addon-card");
|
||||
let {deck, tabGroup} = card.details;
|
||||
let { deck, tabGroup } = card.details;
|
||||
|
||||
// Disable updates and then check.
|
||||
disableAutoUpdates(card);
|
||||
await checkForUpdate(card, "update-found");
|
||||
|
||||
// There should now be an update.
|
||||
assertUpdateState({card, shown: true, releaseNotes: true});
|
||||
assertUpdateState({ card, shown: true, releaseNotes: true });
|
||||
|
||||
info("Check release notes");
|
||||
let notesBtn = tabGroup.querySelector('[name="release-notes"]');
|
||||
|
@ -420,11 +495,17 @@ add_task(async function testReleaseNotesError() {
|
|||
// See bug 1551621 for more info.
|
||||
EventUtils.synthesizeMouseAtCenter(notesBtn, {}, win);
|
||||
await loading;
|
||||
is(doc.l10n.getAttributes(notes.firstElementChild).id,
|
||||
"release-notes-loading", "The loading message is shown");
|
||||
is(
|
||||
doc.l10n.getAttributes(notes.firstElementChild).id,
|
||||
"release-notes-loading",
|
||||
"The loading message is shown"
|
||||
);
|
||||
await errored;
|
||||
is(doc.l10n.getAttributes(notes.firstElementChild).id,
|
||||
"release-notes-error", "The error message is shown");
|
||||
is(
|
||||
doc.l10n.getAttributes(notes.firstElementChild).id,
|
||||
"release-notes-error",
|
||||
"The error message is shown"
|
||||
);
|
||||
|
||||
info("Switch away and back to release notes");
|
||||
// Load details view.
|
||||
|
@ -436,7 +517,9 @@ add_task(async function testReleaseNotesError() {
|
|||
// Load release notes again, verify they weren't loaded.
|
||||
viewChanged = BrowserTestUtils.waitForEvent(deck, "view-changed");
|
||||
let notesCached = BrowserTestUtils.waitForEvent(
|
||||
notes, "release-notes-cached");
|
||||
notes,
|
||||
"release-notes-cached"
|
||||
);
|
||||
notesBtn.click();
|
||||
await viewChanged;
|
||||
await notesCached;
|
||||
|
@ -463,7 +546,7 @@ add_task(async function testUpdateCancelled() {
|
|||
await checkForUpdate(card, "update-found");
|
||||
|
||||
// There should now be an update.
|
||||
assertUpdateState({card, shown: true});
|
||||
assertUpdateState({ card, shown: true });
|
||||
|
||||
// The add-on starts as version 1.
|
||||
let versionRow = card.querySelector(".addon-detail-row-version");
|
||||
|
@ -481,7 +564,7 @@ add_task(async function testUpdateCancelled() {
|
|||
is(versionRow.lastChild.textContent, "1", "The version hasn't changed");
|
||||
|
||||
// The update has been removed.
|
||||
assertUpdateState({card, shown: false});
|
||||
assertUpdateState({ card, shown: false });
|
||||
|
||||
await closeView(win);
|
||||
await extension.unload();
|
||||
|
@ -498,7 +581,7 @@ add_task(async function testAvailableUpdates() {
|
|||
let doc = win.document;
|
||||
|
||||
let managerDoc = win.managerWindow.document;
|
||||
let {gCategories} = win.managerWindow;
|
||||
let { gCategories } = win.managerWindow;
|
||||
let availableCat = gCategories.get("addons://updates/available");
|
||||
|
||||
ok(availableCat.hidden, "Available updates is hidden");
|
||||
|
@ -527,13 +610,16 @@ add_task(async function testAvailableUpdates() {
|
|||
|
||||
// Each card should have an update.
|
||||
for (let card of cards) {
|
||||
assertUpdateState({card, shown: true, expanded: false});
|
||||
assertUpdateState({ card, shown: true, expanded: false });
|
||||
}
|
||||
|
||||
// Check the detail page for the first add-on.
|
||||
await loadDetailView(win, ids[0]);
|
||||
is(gCategories.selected, "addons://list/extension",
|
||||
"The extensions category is selected");
|
||||
is(
|
||||
gCategories.selected,
|
||||
"addons://list/extension",
|
||||
"The extensions category is selected"
|
||||
);
|
||||
|
||||
// Go back to the last view.
|
||||
loaded = waitForViewLoad(win);
|
||||
|
@ -541,8 +627,11 @@ add_task(async function testAvailableUpdates() {
|
|||
await loaded;
|
||||
|
||||
// We're back on the updates view.
|
||||
is(gCategories.selected, "addons://updates/available",
|
||||
"The available updates category is selected");
|
||||
is(
|
||||
gCategories.selected,
|
||||
"addons://updates/available",
|
||||
"The available updates category is selected"
|
||||
);
|
||||
|
||||
// Find the cards again.
|
||||
cards = doc.querySelectorAll("addon-card");
|
||||
|
@ -550,23 +639,29 @@ add_task(async function testAvailableUpdates() {
|
|||
|
||||
// Install the first update.
|
||||
await installUpdate(cards[0], "update-installed");
|
||||
assertUpdateState({card: cards[0], shown: false, expanded: false});
|
||||
assertUpdateState({ card: cards[0], shown: false, expanded: false });
|
||||
|
||||
// The count goes down but the card stays.
|
||||
is(availableCat.badgeCount, 2, "There are only 2 updates now");
|
||||
is(doc.querySelectorAll("addon-card").length, 3,
|
||||
"All 3 cards are still visible on the updates page");
|
||||
is(
|
||||
doc.querySelectorAll("addon-card").length,
|
||||
3,
|
||||
"All 3 cards are still visible on the updates page"
|
||||
);
|
||||
|
||||
// Install the other two updates.
|
||||
await installUpdate(cards[1], "update-installed");
|
||||
assertUpdateState({card: cards[1], shown: false, expanded: false});
|
||||
assertUpdateState({ card: cards[1], shown: false, expanded: false });
|
||||
await installUpdate(cards[2], "update-installed");
|
||||
assertUpdateState({card: cards[2], shown: false, expanded: false});
|
||||
assertUpdateState({ card: cards[2], shown: false, expanded: false });
|
||||
|
||||
// The count goes down but the card stays.
|
||||
is(availableCat.badgeCount, 0, "There are no more updates");
|
||||
is(doc.querySelectorAll("addon-card").length, 3,
|
||||
"All 3 cards are still visible on the updates page");
|
||||
is(
|
||||
doc.querySelectorAll("addon-card").length,
|
||||
3,
|
||||
"All 3 cards are still visible on the updates page"
|
||||
);
|
||||
|
||||
// Enable global add-on updates again.
|
||||
AddonManager.autoUpdateDefault = true;
|
||||
|
|
|
@ -6,16 +6,21 @@
|
|||
|
||||
let gProvider;
|
||||
const {
|
||||
STATE_BLOCKED, STATE_OUTDATED, STATE_SOFTBLOCKED, STATE_VULNERABLE_NO_UPDATE,
|
||||
STATE_BLOCKED,
|
||||
STATE_OUTDATED,
|
||||
STATE_SOFTBLOCKED,
|
||||
STATE_VULNERABLE_NO_UPDATE,
|
||||
STATE_VULNERABLE_UPDATE_AVAILABLE,
|
||||
} = Ci.nsIBlocklistService;
|
||||
|
||||
const brandBundle =
|
||||
Services.strings.createBundle("chrome://branding/locale/brand.properties");
|
||||
const brandBundle = Services.strings.createBundle(
|
||||
"chrome://branding/locale/brand.properties"
|
||||
);
|
||||
const appName = brandBundle.GetStringFromName("brandShortName");
|
||||
const appVersion = Services.appinfo.version;
|
||||
const SUPPORT_URL = Services.urlFormatter.formatURL(
|
||||
Services.prefs.getStringPref("app.support.baseURL"));
|
||||
Services.prefs.getStringPref("app.support.baseURL")
|
||||
);
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
|
@ -32,12 +37,15 @@ async function checkMessageState(id, addonType, expected) {
|
|||
if (!expected) {
|
||||
ok(messageBar.hidden, "message is hidden");
|
||||
} else {
|
||||
let {linkText, linkUrl, text, type} = expected;
|
||||
let { linkText, linkUrl, text, type } = expected;
|
||||
|
||||
ok(!messageBar.hidden, "message is visible");
|
||||
is(messageBar.getAttribute("type"), type, "message has the right type");
|
||||
is(messageBar.querySelector("span").textContent,
|
||||
text, "message has the right text");
|
||||
is(
|
||||
messageBar.querySelector("span").textContent,
|
||||
text,
|
||||
"message has the right text"
|
||||
);
|
||||
|
||||
let link = messageBar.querySelector("button");
|
||||
if (linkUrl) {
|
||||
|
@ -76,7 +84,7 @@ async function checkMessageState(id, addonType, expected) {
|
|||
add_task(async function testNoMessageExtension() {
|
||||
let id = "no-message@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {applications: {gecko: {id}}},
|
||||
manifest: { applications: { gecko: { id } } },
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
await extension.startup();
|
||||
|
@ -88,13 +96,15 @@ add_task(async function testNoMessageExtension() {
|
|||
|
||||
add_task(async function testNoMessageLangpack() {
|
||||
let id = "no-message@mochi.test";
|
||||
gProvider.createAddons([{
|
||||
appDisabled: true,
|
||||
id,
|
||||
name: "Signed Langpack",
|
||||
signedState: AddonManager.SIGNEDSTATE_SIGNED,
|
||||
type: "locale",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
appDisabled: true,
|
||||
id,
|
||||
name: "Signed Langpack",
|
||||
signedState: AddonManager.SIGNEDSTATE_SIGNED,
|
||||
type: "locale",
|
||||
},
|
||||
]);
|
||||
|
||||
await checkMessageState(id, "locale", null);
|
||||
});
|
||||
|
@ -102,14 +112,16 @@ add_task(async function testNoMessageLangpack() {
|
|||
add_task(async function testBlocked() {
|
||||
let id = "blocked@mochi.test";
|
||||
let linkUrl = "https://example.com/addon-blocked";
|
||||
gProvider.createAddons([{
|
||||
appDisabled: true,
|
||||
blocklistState: STATE_BLOCKED,
|
||||
blocklistURL: linkUrl,
|
||||
id,
|
||||
isActive: false,
|
||||
name: "Blocked",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
appDisabled: true,
|
||||
blocklistState: STATE_BLOCKED,
|
||||
blocklistURL: linkUrl,
|
||||
id,
|
||||
isActive: false,
|
||||
name: "Blocked",
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "extension", {
|
||||
linkText: "More Information",
|
||||
linkUrl,
|
||||
|
@ -124,17 +136,20 @@ add_task(async function testUnsignedDisabled() {
|
|||
});
|
||||
|
||||
let id = "unsigned@mochi.test";
|
||||
gProvider.createAddons([{
|
||||
appDisabled: true,
|
||||
id,
|
||||
name: "Unsigned",
|
||||
signedState: AddonManager.SIGNEDSTATE_MISSING,
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
appDisabled: true,
|
||||
id,
|
||||
name: "Unsigned",
|
||||
signedState: AddonManager.SIGNEDSTATE_MISSING,
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "extension", {
|
||||
linkText: "More Information",
|
||||
linkUrl: SUPPORT_URL + "unsigned-addons",
|
||||
text:
|
||||
"Unsigned could not be verified for use in " + appName +
|
||||
"Unsigned could not be verified for use in " +
|
||||
appName +
|
||||
" and has been disabled.",
|
||||
type: "error",
|
||||
});
|
||||
|
@ -144,18 +159,21 @@ add_task(async function testUnsignedDisabled() {
|
|||
|
||||
add_task(async function testUnsignedLangpackDisabled() {
|
||||
let id = "unsigned-langpack@mochi.test";
|
||||
gProvider.createAddons([{
|
||||
appDisabled: true,
|
||||
id,
|
||||
name: "Unsigned",
|
||||
signedState: AddonManager.SIGNEDSTATE_MISSING,
|
||||
type: "locale",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
appDisabled: true,
|
||||
id,
|
||||
name: "Unsigned",
|
||||
signedState: AddonManager.SIGNEDSTATE_MISSING,
|
||||
type: "locale",
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "locale", {
|
||||
linkText: "More Information",
|
||||
linkUrl: SUPPORT_URL + "unsigned-addons",
|
||||
text:
|
||||
"Unsigned could not be verified for use in " + appName +
|
||||
"Unsigned could not be verified for use in " +
|
||||
appName +
|
||||
" and has been disabled.",
|
||||
type: "error",
|
||||
});
|
||||
|
@ -163,13 +181,15 @@ add_task(async function testUnsignedLangpackDisabled() {
|
|||
|
||||
add_task(async function testIncompatible() {
|
||||
let id = "incompatible@mochi.test";
|
||||
gProvider.createAddons([{
|
||||
appDisabled: true,
|
||||
id,
|
||||
isActive: false,
|
||||
isCompatible: false,
|
||||
name: "Incompatible",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
appDisabled: true,
|
||||
id,
|
||||
isActive: false,
|
||||
isCompatible: false,
|
||||
name: "Incompatible",
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "extension", {
|
||||
text:
|
||||
"Incompatible is incompatible with " + appName + " " + appVersion + ".",
|
||||
|
@ -179,16 +199,19 @@ add_task(async function testIncompatible() {
|
|||
|
||||
add_task(async function testUnsignedEnabled() {
|
||||
let id = "unsigned-allowed@mochi.test";
|
||||
gProvider.createAddons([{
|
||||
id,
|
||||
name: "Unsigned",
|
||||
signedState: AddonManager.SIGNEDSTATE_MISSING,
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id,
|
||||
name: "Unsigned",
|
||||
signedState: AddonManager.SIGNEDSTATE_MISSING,
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "extension", {
|
||||
linkText: "More Information",
|
||||
linkUrl: SUPPORT_URL + "unsigned-addons",
|
||||
text:
|
||||
"Unsigned could not be verified for use in " + appName +
|
||||
"Unsigned could not be verified for use in " +
|
||||
appName +
|
||||
". Proceed with caution.",
|
||||
type: "warning",
|
||||
});
|
||||
|
@ -200,17 +223,20 @@ add_task(async function testUnsignedLangpackEnabled() {
|
|||
});
|
||||
|
||||
let id = "unsigned-allowed-langpack@mochi.test";
|
||||
gProvider.createAddons([{
|
||||
id,
|
||||
name: "Unsigned Langpack",
|
||||
signedState: AddonManager.SIGNEDSTATE_MISSING,
|
||||
type: "locale",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id,
|
||||
name: "Unsigned Langpack",
|
||||
signedState: AddonManager.SIGNEDSTATE_MISSING,
|
||||
type: "locale",
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "locale", {
|
||||
linkText: "More Information",
|
||||
linkUrl: SUPPORT_URL + "unsigned-addons",
|
||||
text:
|
||||
"Unsigned Langpack could not be verified for use in " + appName +
|
||||
"Unsigned Langpack could not be verified for use in " +
|
||||
appName +
|
||||
". Proceed with caution.",
|
||||
type: "warning",
|
||||
});
|
||||
|
@ -221,14 +247,16 @@ add_task(async function testUnsignedLangpackEnabled() {
|
|||
add_task(async function testSoftBlocked() {
|
||||
let id = "softblocked@mochi.test";
|
||||
let linkUrl = "https://example.com/addon-blocked";
|
||||
gProvider.createAddons([{
|
||||
appDisabled: true,
|
||||
blocklistState: STATE_SOFTBLOCKED,
|
||||
blocklistURL: linkUrl,
|
||||
id,
|
||||
isActive: false,
|
||||
name: "Soft Blocked",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
appDisabled: true,
|
||||
blocklistState: STATE_SOFTBLOCKED,
|
||||
blocklistURL: linkUrl,
|
||||
id,
|
||||
isActive: false,
|
||||
name: "Soft Blocked",
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "extension", {
|
||||
linkText: "More Information",
|
||||
linkUrl,
|
||||
|
@ -240,12 +268,14 @@ add_task(async function testSoftBlocked() {
|
|||
add_task(async function testOutdated() {
|
||||
let id = "outdated@mochi.test";
|
||||
let linkUrl = "https://example.com/addon-blocked";
|
||||
gProvider.createAddons([{
|
||||
blocklistState: STATE_OUTDATED,
|
||||
blocklistURL: linkUrl,
|
||||
id,
|
||||
name: "Outdated",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
blocklistState: STATE_OUTDATED,
|
||||
blocklistURL: linkUrl,
|
||||
id,
|
||||
name: "Outdated",
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "extension", {
|
||||
linkText: "Update Now",
|
||||
linkUrl,
|
||||
|
@ -257,12 +287,14 @@ add_task(async function testOutdated() {
|
|||
add_task(async function testVulnerableUpdate() {
|
||||
let id = "vulnerable-update@mochi.test";
|
||||
let linkUrl = "https://example.com/addon-blocked";
|
||||
gProvider.createAddons([{
|
||||
blocklistState: STATE_VULNERABLE_UPDATE_AVAILABLE,
|
||||
blocklistURL: linkUrl,
|
||||
id,
|
||||
name: "Vulnerable Update",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
blocklistState: STATE_VULNERABLE_UPDATE_AVAILABLE,
|
||||
blocklistURL: linkUrl,
|
||||
id,
|
||||
name: "Vulnerable Update",
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "extension", {
|
||||
linkText: "Update Now",
|
||||
linkUrl,
|
||||
|
@ -274,12 +306,14 @@ add_task(async function testVulnerableUpdate() {
|
|||
add_task(async function testVulnerableNoUpdate() {
|
||||
let id = "vulnerable-no-update@mochi.test";
|
||||
let linkUrl = "https://example.com/addon-blocked";
|
||||
gProvider.createAddons([{
|
||||
blocklistState: STATE_VULNERABLE_NO_UPDATE,
|
||||
blocklistURL: linkUrl,
|
||||
id,
|
||||
name: "Vulnerable No Update",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
blocklistState: STATE_VULNERABLE_NO_UPDATE,
|
||||
blocklistURL: linkUrl,
|
||||
id,
|
||||
name: "Vulnerable No Update",
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "extension", {
|
||||
linkText: "More Information",
|
||||
linkUrl,
|
||||
|
@ -290,14 +324,16 @@ add_task(async function testVulnerableNoUpdate() {
|
|||
|
||||
add_task(async function testPluginInstalling() {
|
||||
let id = "plugin-installing@mochi.test";
|
||||
gProvider.createAddons([{
|
||||
id,
|
||||
isActive: true,
|
||||
isGMPlugin: true,
|
||||
isInstalled: false,
|
||||
name: "Plugin Installing",
|
||||
type: "plugin",
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id,
|
||||
isActive: true,
|
||||
isGMPlugin: true,
|
||||
isInstalled: false,
|
||||
name: "Plugin Installing",
|
||||
type: "plugin",
|
||||
},
|
||||
]);
|
||||
await checkMessageState(id, "plugin", {
|
||||
text: "Plugin Installing will be installed shortly.",
|
||||
type: "warning",
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
|
||||
/* globals TestUtils */
|
||||
|
||||
let {ExtensionTestCommon} = ChromeUtils.import("resource://testing-common/ExtensionTestCommon.jsm");
|
||||
let { ExtensionTestCommon } = ChromeUtils.import(
|
||||
"resource://testing-common/ExtensionTestCommon.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.import("resource://testing-common/ContentTask.jsm", {});
|
||||
|
||||
|
@ -22,12 +24,13 @@ var gManagerWindow;
|
|||
var gCategoryUtilities;
|
||||
|
||||
function installAddon(details) {
|
||||
let id = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
|
||||
.generateUUID().number;
|
||||
let id = Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator)
|
||||
.generateUUID().number;
|
||||
if (!details.manifest) {
|
||||
details.manifest = {};
|
||||
}
|
||||
details.manifest.applications = {gecko: {id}};
|
||||
details.manifest.applications = { gecko: { id } };
|
||||
let xpi = ExtensionTestCommon.generateXPI(details);
|
||||
|
||||
return AddonManager.installTemporaryAddon(xpi).then(addon => {
|
||||
|
@ -45,8 +48,8 @@ function installAddon(details) {
|
|||
add_task(async function() {
|
||||
gAddon = await installAddon({
|
||||
manifest: {
|
||||
"options_ui": {
|
||||
"page": "options.html",
|
||||
options_ui: {
|
||||
page: "options.html",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -80,42 +83,63 @@ add_task(async function() {
|
|||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
});
|
||||
|
||||
|
||||
async function openDetailsBrowser(addonId) {
|
||||
var addon = get_addon_element(gManagerWindow, addonId);
|
||||
|
||||
is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE_BROWSER,
|
||||
"Options should be inline browser type");
|
||||
is(
|
||||
addon.mAddon.optionsType,
|
||||
AddonManager.OPTIONS_TYPE_INLINE_BROWSER,
|
||||
"Options should be inline browser type"
|
||||
);
|
||||
|
||||
addon.parentNode.ensureElementIsVisible(addon);
|
||||
|
||||
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
|
||||
var button = gManagerWindow.document.getAnonymousElementByAttribute(
|
||||
addon,
|
||||
"anonid",
|
||||
"preferences-btn"
|
||||
);
|
||||
|
||||
is_element_visible(button, "Preferences button should be visible");
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
|
||||
|
||||
await TestUtils.topicObserved(AddonManager.OPTIONS_NOTIFICATION_DISPLAYED,
|
||||
(subject, data) => data == addonId);
|
||||
await TestUtils.topicObserved(
|
||||
AddonManager.OPTIONS_NOTIFICATION_DISPLAYED,
|
||||
(subject, data) => data == addonId
|
||||
);
|
||||
|
||||
is(gManagerWindow.gViewController.currentViewId,
|
||||
`addons://detail/${encodeURIComponent(addonId)}/preferences`,
|
||||
"Current view should scroll to preferences");
|
||||
is(
|
||||
gManagerWindow.gViewController.currentViewId,
|
||||
`addons://detail/${encodeURIComponent(addonId)}/preferences`,
|
||||
"Current view should scroll to preferences"
|
||||
);
|
||||
|
||||
var browser = gManagerWindow.document.querySelector(
|
||||
"#detail-grid > rows > stack > .inline-options-browser");
|
||||
"#detail-grid > rows > stack > .inline-options-browser"
|
||||
);
|
||||
var rows = browser.parentNode.parentNode;
|
||||
|
||||
let url = await ContentTask.spawn(browser, {}, () => content.location.href);
|
||||
|
||||
ok(browser, "Grid should have a browser descendant");
|
||||
is(browser.localName, "browser", "Grid should have a browser descendant");
|
||||
is(url, addon.mAddon.optionsURL, "Browser has the expected options URL loaded");
|
||||
is(
|
||||
url,
|
||||
addon.mAddon.optionsURL,
|
||||
"Browser has the expected options URL loaded"
|
||||
);
|
||||
|
||||
is(browser.clientWidth, browser.parentNode.clientWidth,
|
||||
"Browser should be the same width as its direct parent");
|
||||
is(browser.clientWidth, rows.clientWidth,
|
||||
"Browser should be the same width as its rows ancestor");
|
||||
is(
|
||||
browser.clientWidth,
|
||||
browser.parentNode.clientWidth,
|
||||
"Browser should be the same width as its direct parent"
|
||||
);
|
||||
is(
|
||||
browser.clientWidth,
|
||||
rows.clientWidth,
|
||||
"Browser should be the same width as its rows ancestor"
|
||||
);
|
||||
|
||||
button = gManagerWindow.document.getElementById("detail-prefs-btn");
|
||||
is_element_hidden(button, "Preferences button should not be visible");
|
||||
|
@ -123,23 +147,35 @@ async function openDetailsBrowser(addonId) {
|
|||
return browser;
|
||||
}
|
||||
|
||||
|
||||
add_task(async function test_inline_browser_addon() {
|
||||
let browser = await openDetailsBrowser(gAddon.id);
|
||||
|
||||
function checkHeights(expected) {
|
||||
let {clientHeight} = browser;
|
||||
return ContentTask.spawn(browser, {expected, clientHeight}, ({expected, clientHeight}) => {
|
||||
let {body} = content.document;
|
||||
let { clientHeight } = browser;
|
||||
return ContentTask.spawn(
|
||||
browser,
|
||||
{ expected, clientHeight },
|
||||
({ expected, clientHeight }) => {
|
||||
let { body } = content.document;
|
||||
|
||||
is(body.clientHeight, expected, `Document body should be ${expected}px tall`);
|
||||
is(body.clientHeight, body.scrollHeight,
|
||||
"Document body should be tall enough to fit its contents");
|
||||
is(
|
||||
body.clientHeight,
|
||||
expected,
|
||||
`Document body should be ${expected}px tall`
|
||||
);
|
||||
is(
|
||||
body.clientHeight,
|
||||
body.scrollHeight,
|
||||
"Document body should be tall enough to fit its contents"
|
||||
);
|
||||
|
||||
let heightDiff = clientHeight - expected;
|
||||
ok(heightDiff >= 0 && heightDiff < 50,
|
||||
`Browser should be slightly taller than the document body (${clientHeight} vs. ${expected})`);
|
||||
});
|
||||
let heightDiff = clientHeight - expected;
|
||||
ok(
|
||||
heightDiff >= 0 && heightDiff < 50,
|
||||
`Browser should be slightly taller than the document body (${clientHeight} vs. ${expected})`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Delay long enough to avoid hitting our resize rate limit.
|
||||
|
@ -149,7 +185,9 @@ add_task(async function test_inline_browser_addon() {
|
|||
|
||||
await checkHeights(300);
|
||||
|
||||
info("Increase the document height, and expect the browser to grow correspondingly");
|
||||
info(
|
||||
"Increase the document height, and expect the browser to grow correspondingly"
|
||||
);
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
content.document.body.classList.toggle("bigger");
|
||||
});
|
||||
|
@ -158,7 +196,9 @@ add_task(async function test_inline_browser_addon() {
|
|||
|
||||
await checkHeights(600);
|
||||
|
||||
info("Decrease the document height, and expect the browser to shrink correspondingly");
|
||||
info(
|
||||
"Decrease the document height, and expect the browser to shrink correspondingly"
|
||||
);
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
content.document.body.classList.toggle("bigger");
|
||||
});
|
||||
|
@ -168,15 +208,14 @@ add_task(async function test_inline_browser_addon() {
|
|||
await checkHeights(300);
|
||||
|
||||
await new Promise(resolve =>
|
||||
gCategoryUtilities.openType("extension", resolve));
|
||||
gCategoryUtilities.openType("extension", resolve)
|
||||
);
|
||||
|
||||
browser = gManagerWindow.document.querySelector(
|
||||
".inline-options-browser");
|
||||
browser = gManagerWindow.document.querySelector(".inline-options-browser");
|
||||
|
||||
is(browser, null, "Options browser should be removed from the document");
|
||||
});
|
||||
|
||||
|
||||
// Test that loading an add-on with no inline browser works as expected
|
||||
// after having viewed our main test add-on.
|
||||
add_task(async function test_plain_addon() {
|
||||
|
@ -186,36 +225,43 @@ add_task(async function test_plain_addon() {
|
|||
|
||||
addon.parentNode.ensureElementIsVisible(addon);
|
||||
|
||||
await EventUtils.synthesizeMouseAtCenter(addon, { clickCount: 1 }, gManagerWindow);
|
||||
await EventUtils.synthesizeMouseAtCenter(
|
||||
addon,
|
||||
{ clickCount: 1 },
|
||||
gManagerWindow
|
||||
);
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(addon, { clickCount: 2 }, gManagerWindow);
|
||||
|
||||
await BrowserTestUtils.waitForEvent(gManagerWindow, "ViewChanged");
|
||||
|
||||
is(gManagerWindow.gViewController.currentViewId,
|
||||
`addons://detail/${encodeURIComponent(gOtherAddon.id)}`,
|
||||
"Detail view should be open");
|
||||
is(
|
||||
gManagerWindow.gViewController.currentViewId,
|
||||
`addons://detail/${encodeURIComponent(gOtherAddon.id)}`,
|
||||
"Detail view should be open"
|
||||
);
|
||||
|
||||
var browser = gManagerWindow.document.querySelector(
|
||||
"#detail-grid > rows > .inline-options-browser");
|
||||
"#detail-grid > rows > .inline-options-browser"
|
||||
);
|
||||
|
||||
is(browser, null, "Detail view should have no inline browser");
|
||||
|
||||
await new Promise(resolve =>
|
||||
gCategoryUtilities.openType("extension", resolve));
|
||||
gCategoryUtilities.openType("extension", resolve)
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
// Test that loading the original add-on details successfully creates a
|
||||
// browser.
|
||||
add_task(async function test_inline_browser_addon_again() {
|
||||
let browser = await openDetailsBrowser(gAddon.id);
|
||||
|
||||
await new Promise(resolve =>
|
||||
gCategoryUtilities.openType("extension", resolve));
|
||||
gCategoryUtilities.openType("extension", resolve)
|
||||
);
|
||||
|
||||
browser = gManagerWindow.document.querySelector(
|
||||
".inline-options-browser");
|
||||
browser = gManagerWindow.document.querySelector(".inline-options-browser");
|
||||
|
||||
is(browser, null, "Options browser should be removed from the document");
|
||||
});
|
||||
|
|
|
@ -14,7 +14,8 @@ const SELFSIGNED = "https://self-signed.example.com/";
|
|||
const UNTRUSTED = "https://untrusted.example.com/";
|
||||
const EXPIRED = "https://expired.example.com/";
|
||||
|
||||
const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
|
||||
const PREF_INSTALL_REQUIREBUILTINCERTS =
|
||||
"extensions.install.requireBuiltInCerts";
|
||||
|
||||
var gTests = [];
|
||||
var gStart = 0;
|
||||
|
@ -27,8 +28,9 @@ function test() {
|
|||
waitForExplicitFinish();
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
var cos = Cc["@mozilla.org/security/certoverride;1"].
|
||||
getService(Ci.nsICertOverrideService);
|
||||
var cos = Cc["@mozilla.org/security/certoverride;1"].getService(
|
||||
Ci.nsICertOverrideService
|
||||
);
|
||||
cos.clearValidityOverride("nocert.example.com", -1);
|
||||
cos.clearValidityOverride("self-signed.example.com", -1);
|
||||
cos.clearValidityOverride("untrusted.example.com", -1);
|
||||
|
@ -36,16 +38,18 @@ function test() {
|
|||
|
||||
try {
|
||||
Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (gPendingInstall) {
|
||||
gTests = [];
|
||||
ok(false, "Timed out in the middle of downloading " + gPendingInstall.sourceURI.spec);
|
||||
ok(
|
||||
false,
|
||||
"Timed out in the middle of downloading " +
|
||||
gPendingInstall.sourceURI.spec
|
||||
);
|
||||
try {
|
||||
gPendingInstall.cancel();
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -72,12 +76,15 @@ function run_install_tests(callback) {
|
|||
let [mainURL, redirectURL, expectedStatus] = gTests.shift();
|
||||
if (redirectURL) {
|
||||
var url = mainURL + redirect + redirectURL + xpi;
|
||||
var message = "Should have seen the right result for an install redirected from " +
|
||||
mainURL + " to " + redirectURL;
|
||||
var message =
|
||||
"Should have seen the right result for an install redirected from " +
|
||||
mainURL +
|
||||
" to " +
|
||||
redirectURL;
|
||||
} else {
|
||||
url = mainURL + xpi;
|
||||
message = "Should have seen the right result for an install from " +
|
||||
mainURL;
|
||||
message =
|
||||
"Should have seen the right result for an install from " + mainURL;
|
||||
}
|
||||
|
||||
let install = await AddonManager.getInstallForURL(url);
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
* and added to the testFns array.
|
||||
*/
|
||||
|
||||
const {AddonTestUtils} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm", {});
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm",
|
||||
{}
|
||||
);
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
|
||||
|
@ -28,7 +31,7 @@ async function installTheme() {
|
|||
let id = "theme@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
manifest_version: 2,
|
||||
name: "atheme",
|
||||
description: "wow. such theme.",
|
||||
|
@ -45,16 +48,16 @@ async function installTheme() {
|
|||
async function installExtension(manifest = {}) {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id: addonId}},
|
||||
applications: { gecko: { id: addonId } },
|
||||
manifest_version: 2,
|
||||
name: "extension",
|
||||
description: "wow. such extension.",
|
||||
author: "Code Pusher",
|
||||
version: "1",
|
||||
chrome_url_overrides: {newtab: "new.html"},
|
||||
options_ui: {page: "options.html", open_in_tab: true},
|
||||
browser_action: {default_popup: "action.html"},
|
||||
page_action: {default_popup: "action.html"},
|
||||
chrome_url_overrides: { newtab: "new.html" },
|
||||
options_ui: { page: "options.html", open_in_tab: true },
|
||||
browser_action: { default_popup: "action.html" },
|
||||
page_action: { default_popup: "action.html" },
|
||||
...manifest,
|
||||
},
|
||||
files: {
|
||||
|
@ -96,9 +99,15 @@ async function enableAndDisable(doc, row) {
|
|||
} else {
|
||||
is(row.getAttribute("active"), "true", "The add-on is enabled");
|
||||
doc.getAnonymousElementByAttribute(row, "anonid", "disable-btn").click();
|
||||
await TestUtils.waitForCondition(() => row.getAttribute("active") == "false", "Wait for disable");
|
||||
await TestUtils.waitForCondition(
|
||||
() => row.getAttribute("active") == "false",
|
||||
"Wait for disable"
|
||||
);
|
||||
doc.getAnonymousElementByAttribute(row, "anonid", "enable-btn").click();
|
||||
await TestUtils.waitForCondition(() => row.getAttribute("active") == "true", "Wait for enable");
|
||||
await TestUtils.waitForCondition(
|
||||
() => row.getAttribute("active") == "true",
|
||||
"Wait for enable"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,17 +120,25 @@ async function removeAddonAndUndo(doc, row) {
|
|||
row.querySelector('[action="remove"]').click();
|
||||
await removed;
|
||||
|
||||
let undoBanner = doc.querySelector(`message-bar[addon-id="${row.addon.id}"]`);
|
||||
let undoBanner = doc.querySelector(
|
||||
`message-bar[addon-id="${row.addon.id}"]`
|
||||
);
|
||||
undoBanner.querySelector('[action="undo"]').click();
|
||||
await TestUtils.waitForCondition(() => getAddonCard(doc, row.addon.id));
|
||||
} else {
|
||||
is(row.getAttribute("status"), "installed", "The add-on is installed");
|
||||
ok(!row.hasAttribute("pending"), "The add-on is not pending");
|
||||
doc.getAnonymousElementByAttribute(row, "anonid", "remove-btn").click();
|
||||
await TestUtils.waitForCondition(() => row.getAttribute("pending") == "uninstall", "Wait for uninstall");
|
||||
await TestUtils.waitForCondition(
|
||||
() => row.getAttribute("pending") == "uninstall",
|
||||
"Wait for uninstall"
|
||||
);
|
||||
|
||||
doc.getAnonymousElementByAttribute(row, "anonid", "undo-btn").click();
|
||||
await TestUtils.waitForCondition(() => !row.hasAttribute("pending"), "Wait for undo");
|
||||
await TestUtils.waitForCondition(
|
||||
() => !row.hasAttribute("pending"),
|
||||
"Wait for undo"
|
||||
);
|
||||
}
|
||||
await started;
|
||||
}
|
||||
|
@ -132,7 +149,11 @@ async function openPrefs(doc, row) {
|
|||
} else {
|
||||
let prefsButton;
|
||||
await TestUtils.waitForCondition(() => {
|
||||
prefsButton = doc.getAnonymousElementByAttribute(row, "anonid", "preferences-btn");
|
||||
prefsButton = doc.getAnonymousElementByAttribute(
|
||||
row,
|
||||
"anonid",
|
||||
"preferences-btn"
|
||||
);
|
||||
return prefsButton;
|
||||
});
|
||||
prefsButton.click();
|
||||
|
@ -155,7 +176,11 @@ function changeAutoUpdates(doc) {
|
|||
autoUpdate.querySelector('[value="0"]').click();
|
||||
// Check for updates.
|
||||
let checkForUpdates = doc.getElementById("detail-findUpdates-btn");
|
||||
is(checkForUpdates.hidden, false, "The check for updates button is visible");
|
||||
is(
|
||||
checkForUpdates.hidden,
|
||||
false,
|
||||
"The check for updates button is visible"
|
||||
);
|
||||
checkForUpdates.click();
|
||||
// Turn on auto update.
|
||||
autoUpdate.querySelector('[value="2"]').click();
|
||||
|
@ -174,7 +199,11 @@ function clickLinks(doc) {
|
|||
// Check links.
|
||||
let creator = doc.getElementById("detail-creator");
|
||||
let label = doc.getAnonymousElementByAttribute(creator, "anonid", "label");
|
||||
let link = doc.getAnonymousElementByAttribute(creator, "anonid", "creator-link");
|
||||
let link = doc.getAnonymousElementByAttribute(
|
||||
creator,
|
||||
"anonid",
|
||||
"creator-link"
|
||||
);
|
||||
// Check that clicking the label doesn't trigger a telemetry event.
|
||||
label.click();
|
||||
assertTelemetryMatches([]);
|
||||
|
@ -198,7 +227,8 @@ async function init(startPage, isHtmlViews) {
|
|||
await gCategoryUtilities.openType(startPage);
|
||||
|
||||
if (isHtmlViews) {
|
||||
return gManagerWindow.document.getElementById("html-view-browser").contentDocument;
|
||||
return gManagerWindow.document.getElementById("html-view-browser")
|
||||
.contentDocument;
|
||||
}
|
||||
return gManagerWindow.document;
|
||||
}
|
||||
|
@ -214,10 +244,7 @@ async function setup(isHtmlViews) {
|
|||
}
|
||||
|
||||
async function testBasicViewTelemetry(isHtmlViews) {
|
||||
let addons = await Promise.all([
|
||||
installTheme(),
|
||||
installExtension(),
|
||||
]);
|
||||
let addons = await Promise.all([installTheme(), installExtension()]);
|
||||
let doc = await init("discover", isHtmlViews);
|
||||
|
||||
await gCategoryUtilities.openType("theme");
|
||||
|
@ -228,13 +255,26 @@ async function testBasicViewTelemetry(isHtmlViews) {
|
|||
openDetailView(doc, "extension@mochi.test");
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
|
||||
assertTelemetryMatches([
|
||||
["view", "aboutAddons", "discover"],
|
||||
["view", "aboutAddons", "list", {type: "theme"}],
|
||||
["view", "aboutAddons", "detail", {type: "theme", addonId: "theme@mochi.test"}],
|
||||
["view", "aboutAddons", "list", {type: "extension"}],
|
||||
["view", "aboutAddons", "detail", {type: "extension", addonId: "extension@mochi.test"}],
|
||||
], {filterMethods: ["view"]});
|
||||
assertTelemetryMatches(
|
||||
[
|
||||
["view", "aboutAddons", "discover"],
|
||||
["view", "aboutAddons", "list", { type: "theme" }],
|
||||
[
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "theme", addonId: "theme@mochi.test" },
|
||||
],
|
||||
["view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: "extension@mochi.test" },
|
||||
],
|
||||
],
|
||||
{ filterMethods: ["view"] }
|
||||
);
|
||||
|
||||
await close_manager(gManagerWindow);
|
||||
await Promise.all(addons.map(addon => addon.unload()));
|
||||
|
@ -246,25 +286,53 @@ async function testExtensionEvents(isHtmlViews) {
|
|||
let doc = await init("extension", isHtmlViews);
|
||||
|
||||
// Check/clear the current telemetry.
|
||||
assertTelemetryMatches([["view", "aboutAddons", "list", {type: "extension"}]],
|
||||
{filterMethods: ["view"]});
|
||||
assertTelemetryMatches(
|
||||
[["view", "aboutAddons", "list", { type: "extension" }]],
|
||||
{ filterMethods: ["view"] }
|
||||
);
|
||||
|
||||
let row = getAddonCard(doc, addonId);
|
||||
|
||||
// Check disable/enable.
|
||||
await enableAndDisable(doc, row);
|
||||
assertTelemetryMatches([
|
||||
["action", "aboutAddons", null, {action: "disable", addonId, type, view: "list"}],
|
||||
["action", "aboutAddons", null, {action: "enable", addonId, type, view: "list"}],
|
||||
], {filterMethods: ["action"]});
|
||||
assertTelemetryMatches(
|
||||
[
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ action: "disable", addonId, type, view: "list" },
|
||||
],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ action: "enable", addonId, type, view: "list" },
|
||||
],
|
||||
],
|
||||
{ filterMethods: ["action"] }
|
||||
);
|
||||
|
||||
// Check remove/undo.
|
||||
await removeAddonAndUndo(doc, row);
|
||||
let uninstallValue = isHtmlViews ? "accepted" : null;
|
||||
assertTelemetryMatches([
|
||||
["action", "aboutAddons", uninstallValue, {action: "uninstall", addonId, type, view: "list"}],
|
||||
["action", "aboutAddons", null, {action: "undo", addonId, type, view: "list"}],
|
||||
], {filterMethods: ["action"]});
|
||||
assertTelemetryMatches(
|
||||
[
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
uninstallValue,
|
||||
{ action: "uninstall", addonId, type, view: "list" },
|
||||
],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ action: "undo", addonId, type, view: "list" },
|
||||
],
|
||||
],
|
||||
{ filterMethods: ["action"] }
|
||||
);
|
||||
|
||||
// Open the preferences page.
|
||||
let waitForNewTab = BrowserTestUtils.waitForNewTab(gBrowser);
|
||||
|
@ -272,25 +340,57 @@ async function testExtensionEvents(isHtmlViews) {
|
|||
row = getAddonCard(doc, addonId);
|
||||
await openPrefs(doc, row);
|
||||
BrowserTestUtils.removeTab(await waitForNewTab);
|
||||
assertTelemetryMatches([
|
||||
["action", "aboutAddons", "external", {action: "preferences", type, addonId, view: "list"}],
|
||||
], {filterMethods: ["action"]});
|
||||
assertTelemetryMatches(
|
||||
[
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"external",
|
||||
{ action: "preferences", type, addonId, view: "list" },
|
||||
],
|
||||
],
|
||||
{ filterMethods: ["action"] }
|
||||
);
|
||||
|
||||
// Go to the detail view.
|
||||
openDetailView(doc, addonId);
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
assertTelemetryMatches([
|
||||
["view", "aboutAddons", "detail", {type, addonId}],
|
||||
], {filterMethods: ["view"]});
|
||||
assertTelemetryMatches(
|
||||
[["view", "aboutAddons", "detail", { type, addonId }]],
|
||||
{ filterMethods: ["view"] }
|
||||
);
|
||||
|
||||
// Check updates.
|
||||
changeAutoUpdates(doc);
|
||||
assertTelemetryMatches([
|
||||
["action", "aboutAddons", "", {action: "setAddonUpdate", type, addonId, view: "detail"}],
|
||||
["action", "aboutAddons", null, {action: "checkForUpdate", type, addonId, view: "detail"}],
|
||||
["action", "aboutAddons", "enabled", {action: "setAddonUpdate", type, addonId, view: "detail"}],
|
||||
["action", "aboutAddons", "default", {action: "setAddonUpdate", type, addonId, view: "detail"}],
|
||||
], {filterMethods: ["action"]});
|
||||
assertTelemetryMatches(
|
||||
[
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"",
|
||||
{ action: "setAddonUpdate", type, addonId, view: "detail" },
|
||||
],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ action: "checkForUpdate", type, addonId, view: "detail" },
|
||||
],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"enabled",
|
||||
{ action: "setAddonUpdate", type, addonId, view: "detail" },
|
||||
],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"default",
|
||||
{ action: "setAddonUpdate", type, addonId, view: "detail" },
|
||||
],
|
||||
],
|
||||
{ filterMethods: ["action"] }
|
||||
);
|
||||
|
||||
// These links don't actually have a URL, so they don't open a tab. They're only
|
||||
// shown when there is a URL though.
|
||||
|
@ -307,26 +407,50 @@ async function testExtensionEvents(isHtmlViews) {
|
|||
await openPrefs(doc, row);
|
||||
BrowserTestUtils.removeTab(await waitForNewTab);
|
||||
|
||||
assertTelemetryMatches([
|
||||
["link", "aboutAddons", "author", {view: "detail"}],
|
||||
["link", "aboutAddons", "homepage", {view: "detail"}],
|
||||
["link", "aboutAddons", "rating", {view: "detail"}],
|
||||
["link", "aboutAddons", "support", {view: "detail"}],
|
||||
["action", "aboutAddons", "external", {action: "preferences", type, addonId, view: "detail"}],
|
||||
], {filterMethods: ["action", "link"]});
|
||||
assertTelemetryMatches(
|
||||
[
|
||||
["link", "aboutAddons", "author", { view: "detail" }],
|
||||
["link", "aboutAddons", "homepage", { view: "detail" }],
|
||||
["link", "aboutAddons", "rating", { view: "detail" }],
|
||||
["link", "aboutAddons", "support", { view: "detail" }],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"external",
|
||||
{ action: "preferences", type, addonId, view: "detail" },
|
||||
],
|
||||
],
|
||||
{ filterMethods: ["action", "link"] }
|
||||
);
|
||||
|
||||
// Update the preferences and check that inline changes.
|
||||
await gCategoryUtilities.openType("extension");
|
||||
let upgraded = await installExtension({options_ui: {page: "options.html"}, version: "2"});
|
||||
let upgraded = await installExtension({
|
||||
options_ui: { page: "options.html" },
|
||||
version: "2",
|
||||
});
|
||||
row = getAddonCard(doc, addonId);
|
||||
await openPrefs(doc, row);
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
|
||||
assertTelemetryMatches([
|
||||
["view", "aboutAddons", "list", {type}],
|
||||
["action", "aboutAddons", "inline", {action: "preferences", type, addonId, view: "list"}],
|
||||
["view", "aboutAddons", "detail", {type: "extension", addonId: "extension@mochi.test"}],
|
||||
], {filterMethods: ["action", "view"]});
|
||||
assertTelemetryMatches(
|
||||
[
|
||||
["view", "aboutAddons", "list", { type }],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"inline",
|
||||
{ action: "preferences", type, addonId, view: "list" },
|
||||
],
|
||||
[
|
||||
"view",
|
||||
"aboutAddons",
|
||||
"detail",
|
||||
{ type: "extension", addonId: "extension@mochi.test" },
|
||||
],
|
||||
],
|
||||
{ filterMethods: ["action", "view"] }
|
||||
);
|
||||
|
||||
await close_manager(gManagerWindow);
|
||||
await addon.unload();
|
||||
|
@ -342,7 +466,9 @@ async function testGeneralActions(isHtmlViews) {
|
|||
let recentUpdates = doc.getElementById("utils-viewUpdates");
|
||||
let debugAddons = doc.getElementById("utils-debugAddons");
|
||||
let updatePolicy = doc.getElementById("utils-autoUpdateDefault");
|
||||
let resetUpdatePolicy = doc.getElementById("utils-resetAddonUpdatesToAutomatic");
|
||||
let resetUpdatePolicy = doc.getElementById(
|
||||
"utils-resetAddonUpdatesToAutomatic"
|
||||
);
|
||||
let manageShortcuts = doc.getElementById("manage-shortcuts");
|
||||
|
||||
async function clickInGearMenu(item) {
|
||||
|
@ -375,18 +501,51 @@ async function testGeneralActions(isHtmlViews) {
|
|||
searchBox.doCommand();
|
||||
BrowserTestUtils.removeTab(await waitForNewTab);
|
||||
|
||||
assertTelemetryMatches([
|
||||
["view", "aboutAddons", "list", {type: "extension"}],
|
||||
["action", "aboutAddons", null, {action: "checkForUpdates", view: "list"}],
|
||||
["view", "aboutAddons", "updates", {type: "recent"}],
|
||||
["action", "aboutAddons", "default,enabled", {action: "setUpdatePolicy", view: "updates"}],
|
||||
["action", "aboutAddons", "enabled", {action: "setUpdatePolicy", view: "updates"}],
|
||||
["action", "aboutAddons", null, {action: "resetUpdatePolicy", view: "updates"}],
|
||||
["view", "aboutAddons", "shortcuts"],
|
||||
["action", "aboutAddons", null, {action: "checkForUpdates", view: "shortcuts"}],
|
||||
["link", "aboutAddons", "about:debugging", {view: "shortcuts"}],
|
||||
["link", "aboutAddons", "search", {view: "shortcuts", type: "shortcuts"}],
|
||||
], {filterMethods: TELEMETRY_METHODS});
|
||||
assertTelemetryMatches(
|
||||
[
|
||||
["view", "aboutAddons", "list", { type: "extension" }],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ action: "checkForUpdates", view: "list" },
|
||||
],
|
||||
["view", "aboutAddons", "updates", { type: "recent" }],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"default,enabled",
|
||||
{ action: "setUpdatePolicy", view: "updates" },
|
||||
],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
"enabled",
|
||||
{ action: "setUpdatePolicy", view: "updates" },
|
||||
],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ action: "resetUpdatePolicy", view: "updates" },
|
||||
],
|
||||
["view", "aboutAddons", "shortcuts"],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{ action: "checkForUpdates", view: "shortcuts" },
|
||||
],
|
||||
["link", "aboutAddons", "about:debugging", { view: "shortcuts" }],
|
||||
[
|
||||
"link",
|
||||
"aboutAddons",
|
||||
"search",
|
||||
{ view: "shortcuts", type: "shortcuts" },
|
||||
],
|
||||
],
|
||||
{ filterMethods: TELEMETRY_METHODS }
|
||||
);
|
||||
|
||||
await close_manager(gManagerWindow);
|
||||
|
||||
|
@ -401,10 +560,14 @@ async function testPreferencesLink(isHtmlViews) {
|
|||
let doc = gManagerWindow.document;
|
||||
|
||||
// Open the about:preferences page from about:addons.
|
||||
let waitForNewTab = BrowserTestUtils.waitForNewTab(gBrowser, "about:preferences");
|
||||
let waitForNewTab = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
"about:preferences"
|
||||
);
|
||||
doc.getElementById("preferencesButton").click();
|
||||
let tab = await waitForNewTab;
|
||||
let getAddonsButton = () => tab.linkedBrowser.contentDocument.getElementById("addonsButton");
|
||||
let getAddonsButton = () =>
|
||||
tab.linkedBrowser.contentDocument.getElementById("addonsButton");
|
||||
|
||||
// Wait for the page to load.
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
@ -415,11 +578,14 @@ async function testPreferencesLink(isHtmlViews) {
|
|||
// Close the about:preferences tab.
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
assertTelemetryMatches([
|
||||
["view", "aboutAddons", "list", {type: "theme"}],
|
||||
["link", "aboutAddons", "about:preferences", {view: "list"}],
|
||||
["link", "aboutPreferences", "about:addons"],
|
||||
], {filterMethods: ["link", "view"]});
|
||||
assertTelemetryMatches(
|
||||
[
|
||||
["view", "aboutAddons", "list", { type: "theme" }],
|
||||
["link", "aboutAddons", "about:preferences", { view: "list" }],
|
||||
["link", "aboutPreferences", "about:addons"],
|
||||
],
|
||||
{ filterMethods: ["link", "view"] }
|
||||
);
|
||||
|
||||
await close_manager(gManagerWindow);
|
||||
}
|
||||
|
@ -443,7 +609,7 @@ function addTestTasks(isHtmlViews) {
|
|||
for (let fn of testFns) {
|
||||
let localTestFnName = fn.name + (isHtmlViews ? "HTML" : "XUL");
|
||||
// Get an informative name for the function in stack traces.
|
||||
let obj = {[localTestFnName]: () => fn(isHtmlViews)};
|
||||
let obj = { [localTestFnName]: () => fn(isHtmlViews) };
|
||||
add_task(obj[localTestFnName]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,20 +18,22 @@ add_task(async function() {
|
|||
|
||||
let provider = new MockProvider();
|
||||
|
||||
provider.createAddons([{
|
||||
id: "signed@tests.mozilla.org",
|
||||
name: "Signed langpack",
|
||||
type: "locale",
|
||||
signedState: AddonManager.SIGNEDSTATE_SIGNED,
|
||||
isCorrectlySigned: true,
|
||||
}, {
|
||||
id: "unsigned@tests.mozilla.org",
|
||||
name: "Unsigned langpack",
|
||||
type: "locale",
|
||||
signedState: AddonManager.SIGNEDSTATE_MISSING,
|
||||
isCorrectlySigned: false,
|
||||
}]);
|
||||
|
||||
provider.createAddons([
|
||||
{
|
||||
id: "signed@tests.mozilla.org",
|
||||
name: "Signed langpack",
|
||||
type: "locale",
|
||||
signedState: AddonManager.SIGNEDSTATE_SIGNED,
|
||||
isCorrectlySigned: true,
|
||||
},
|
||||
{
|
||||
id: "unsigned@tests.mozilla.org",
|
||||
name: "Unsigned langpack",
|
||||
type: "locale",
|
||||
signedState: AddonManager.SIGNEDSTATE_MISSING,
|
||||
isCorrectlySigned: false,
|
||||
},
|
||||
]);
|
||||
|
||||
let mgrWin = await open_manager(null);
|
||||
|
||||
|
@ -58,21 +60,46 @@ add_task(async function() {
|
|||
errorVisible = false;
|
||||
}
|
||||
|
||||
let warning = mgrWin.document.getAnonymousElementByAttribute(item, "anonid", "warning");
|
||||
let warningLink = mgrWin.document.getAnonymousElementByAttribute(item, "anonid", "warning-link");
|
||||
let warning = mgrWin.document.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"warning"
|
||||
);
|
||||
let warningLink = mgrWin.document.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"warning-link"
|
||||
);
|
||||
if (warningVisible) {
|
||||
is_element_visible(warning, `Warning should be visible for ${what}`);
|
||||
is_element_visible(warningLink, `Warning link should be visible for ${what}`);
|
||||
is_element_visible(
|
||||
warningLink,
|
||||
`Warning link should be visible for ${what}`
|
||||
);
|
||||
} else {
|
||||
is_element_hidden(warning, `Warning should be hidden for ${what}`);
|
||||
is_element_hidden(warningLink, `Warning link should be hidden for ${what}`);
|
||||
is_element_hidden(
|
||||
warningLink,
|
||||
`Warning link should be hidden for ${what}`
|
||||
);
|
||||
}
|
||||
|
||||
let error = mgrWin.document.getAnonymousElementByAttribute(item, "anonid", "error");
|
||||
let errorLink = mgrWin.document.getAnonymousElementByAttribute(item, "anonid", "error-link");
|
||||
let error = mgrWin.document.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"error"
|
||||
);
|
||||
let errorLink = mgrWin.document.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"error-link"
|
||||
);
|
||||
if (errorVisible) {
|
||||
is_element_visible(error, `Error should be visible for ${what}`);
|
||||
is_element_visible(errorLink, `Error link should be visible for ${what}`);
|
||||
is_element_visible(
|
||||
errorLink,
|
||||
`Error link should be visible for ${what}`
|
||||
);
|
||||
} else {
|
||||
is_element_hidden(error, `Error should be hidden for ${what}`);
|
||||
is_element_hidden(errorLink, `Error link should be hidden for ${what}`);
|
||||
|
|
|
@ -5,7 +5,9 @@ SpecialPowers.pushPrefEnv({
|
|||
});
|
||||
|
||||
add_task(async function() {
|
||||
const INFO_URL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "webextensions";
|
||||
const INFO_URL =
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
||||
"webextensions";
|
||||
|
||||
// The mochitest framework installs a bunch of legacy extensions.
|
||||
// Fortunately, the extensions.legacy.exceptions preference exists to
|
||||
|
@ -17,7 +19,7 @@ add_task(async function() {
|
|||
];
|
||||
|
||||
let exceptions = Services.prefs.getCharPref("extensions.legacy.exceptions");
|
||||
exceptions = [ exceptions, ...IGNORE ].join(",");
|
||||
exceptions = [exceptions, ...IGNORE].join(",");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
|
@ -100,12 +102,18 @@ add_task(async function() {
|
|||
// Initially, we have two good extensions (a webextension and a
|
||||
// "Mozilla Extensions"-signed extension).
|
||||
await catUtils.openType("extension");
|
||||
checkList("addon-list",
|
||||
["webextension@tests.mozilla.org", "mozilla@tests.mozilla.org"]);
|
||||
checkList("addon-list", [
|
||||
"webextension@tests.mozilla.org",
|
||||
"mozilla@tests.mozilla.org",
|
||||
]);
|
||||
|
||||
let banner = mgrWin.document.getElementById("legacy-extensions-notice");
|
||||
is_element_hidden(banner, "Warning about legacy extensions should be hidden");
|
||||
is(mgrWin.gLegacyView._categoryItem.disabled, true, "Legacy category is hidden");
|
||||
is(
|
||||
mgrWin.gLegacyView._categoryItem.disabled,
|
||||
true,
|
||||
"Legacy category is hidden"
|
||||
);
|
||||
|
||||
// Now add a legacy extension
|
||||
provider.createAddons(disabledAddon);
|
||||
|
@ -120,28 +128,43 @@ add_task(async function() {
|
|||
await catUtils.openType("plugin");
|
||||
await catUtils.openType("extension");
|
||||
|
||||
checkList("addon-list",
|
||||
["webextension@tests.mozilla.org", "mozilla@tests.mozilla.org"]);
|
||||
checkList("addon-list", [
|
||||
"webextension@tests.mozilla.org",
|
||||
"mozilla@tests.mozilla.org",
|
||||
]);
|
||||
|
||||
// But now the legacy banner and category should be visible
|
||||
banner = mgrWin.document.getElementById("legacy-extensions-notice");
|
||||
is_element_visible(banner, "Warning about legacy extensions should be visible");
|
||||
is_element_visible(
|
||||
banner,
|
||||
"Warning about legacy extensions should be visible"
|
||||
);
|
||||
|
||||
let catItem = mgrWin.gLegacyView._categoryItem;
|
||||
is(catItem.disabled, false, "Legacy category is visible");
|
||||
is(catItem.getAttribute("name"), get_string("type.legacy.name"),
|
||||
"Category label with no unsigned extensions is correct");
|
||||
is(
|
||||
catItem.getAttribute("name"),
|
||||
get_string("type.legacy.name"),
|
||||
"Category label with no unsigned extensions is correct"
|
||||
);
|
||||
|
||||
// Follow the link to the legacy extensions page
|
||||
let legacyLink = mgrWin.document.getElementById("legacy-extensions-learnmore-link");
|
||||
let legacyLink = mgrWin.document.getElementById(
|
||||
"legacy-extensions-learnmore-link"
|
||||
);
|
||||
is_element_visible(legacyLink, "Link to legacy extension is visible");
|
||||
|
||||
let loadPromise = new Promise(resolve => wait_for_view_load(mgrWin, resolve, true));
|
||||
let loadPromise = new Promise(resolve =>
|
||||
wait_for_view_load(mgrWin, resolve, true)
|
||||
);
|
||||
legacyLink.click();
|
||||
await loadPromise;
|
||||
|
||||
is(mgrWin.gViewController.currentViewId, "addons://legacy/",
|
||||
"Legacy extensions link leads to the correct view");
|
||||
is(
|
||||
mgrWin.gViewController.currentViewId,
|
||||
"addons://legacy/",
|
||||
"Legacy extensions link leads to the correct view"
|
||||
);
|
||||
|
||||
let link = mgrWin.document.getElementById("legacy-learnmore");
|
||||
is(link.href, INFO_URL, "Learn more link points to the right place");
|
||||
|
@ -152,25 +175,31 @@ add_task(async function() {
|
|||
// Now add some unsigned addons and flip the signing preference
|
||||
provider.createAddons(unsignedAddons);
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["xpinstall.signatures.required", true],
|
||||
],
|
||||
set: [["xpinstall.signatures.required", true]],
|
||||
});
|
||||
|
||||
// The entry on the left side should now read "Unsupported"
|
||||
await mgrWin.gLegacyView.refreshVisibility();
|
||||
is(catItem.disabled, false, "Legacy category is visible");
|
||||
is(catItem.getAttribute("name"), get_string("type.unsupported.name"),
|
||||
"Category label with unsigned extensions is correct");
|
||||
is(
|
||||
catItem.getAttribute("name"),
|
||||
get_string("type.unsupported.name"),
|
||||
"Category label with unsigned extensions is correct"
|
||||
);
|
||||
|
||||
// The main extensions list should still have the original two
|
||||
// good extensions and the legacy banner.
|
||||
await catUtils.openType("extension");
|
||||
checkList("addon-list",
|
||||
["webextension@tests.mozilla.org", "mozilla@tests.mozilla.org"]);
|
||||
checkList("addon-list", [
|
||||
"webextension@tests.mozilla.org",
|
||||
"mozilla@tests.mozilla.org",
|
||||
]);
|
||||
|
||||
banner = mgrWin.document.getElementById("legacy-extensions-notice");
|
||||
is_element_visible(banner, "Warning about legacy extensions should be visible");
|
||||
is_element_visible(
|
||||
banner,
|
||||
"Warning about legacy extensions should be visible"
|
||||
);
|
||||
|
||||
// And the legacy pane should show both legacy and unsigned extensions
|
||||
await catUtils.openType("legacy");
|
||||
|
@ -182,9 +211,7 @@ add_task(async function() {
|
|||
|
||||
// Disable unsigned extensions
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["xpinstall.signatures.required", false],
|
||||
],
|
||||
set: [["xpinstall.signatures.required", false]],
|
||||
});
|
||||
|
||||
await new Promise(executeSoon);
|
||||
|
@ -192,8 +219,11 @@ add_task(async function() {
|
|||
// The name of the pane should go back to "Legacy Extensions"
|
||||
await mgrWin.gLegacyView.refreshVisibility();
|
||||
is(catItem.disabled, false, "Legacy category is visible");
|
||||
is(catItem.getAttribute("name"), get_string("type.legacy.name"),
|
||||
"Category label with no unsigned extensions is correct");
|
||||
is(
|
||||
catItem.getAttribute("name"),
|
||||
get_string("type.legacy.name"),
|
||||
"Category label with no unsigned extensions is correct"
|
||||
);
|
||||
|
||||
// The unsigned extension should be present in the main extensions pane
|
||||
await catUtils.openType("extension");
|
||||
|
@ -217,13 +247,14 @@ add_task(async function() {
|
|||
// now that legacy extensions are enabled, we should jump to the
|
||||
// regular Extensions list.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.legacy.enabled", true],
|
||||
],
|
||||
set: [["extensions.legacy.enabled", true]],
|
||||
});
|
||||
|
||||
mgrWin = await open_manager(null);
|
||||
is(mgrWin.gViewController.currentViewId, "addons://list/extension",
|
||||
"addons manager switched to extensions list");
|
||||
is(
|
||||
mgrWin.gViewController.currentViewId,
|
||||
"addons://list/extension",
|
||||
"addons manager switched to extensions list"
|
||||
);
|
||||
await close_manager(mgrWin);
|
||||
});
|
||||
|
|
|
@ -9,7 +9,9 @@ SpecialPowers.pushPrefEnv({
|
|||
});
|
||||
|
||||
add_task(async function() {
|
||||
const INFO_URL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "webextensions";
|
||||
const INFO_URL =
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
||||
"webextensions";
|
||||
|
||||
const NAMES = {
|
||||
newTheme: "New LWT",
|
||||
|
@ -55,14 +57,19 @@ add_task(async function() {
|
|||
|
||||
let document = mgrWin.document;
|
||||
// First find the entry in the list.
|
||||
let item = Array.from(document.getElementById("addon-list").childNodes)
|
||||
.find(i => i.getAttribute("name") == name);
|
||||
let item = Array.from(
|
||||
document.getElementById("addon-list").childNodes
|
||||
).find(i => i.getAttribute("name") == name);
|
||||
|
||||
ok(item, `Found ${name} in list`);
|
||||
item.parentNode.ensureElementIsVisible(item);
|
||||
|
||||
// Check the badge
|
||||
let badge = document.getAnonymousElementByAttribute(item, "anonid", "legacy");
|
||||
let badge = document.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"anonid",
|
||||
"legacy"
|
||||
);
|
||||
|
||||
if (isLegacy) {
|
||||
is_element_visible(badge, `Legacy badge is visible for ${name}`);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,6 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
const {PromiseTestUtils} = ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm");
|
||||
const { PromiseTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/PromiseTestUtils.jsm"
|
||||
);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Message manager disconnected/);
|
||||
|
||||
let gManagerWindow;
|
||||
|
@ -30,20 +32,20 @@ add_task(async function testUpdatingCommands() {
|
|||
let commands = {
|
||||
commandZero: {},
|
||||
commandOne: {
|
||||
suggested_key: {default: "Shift+Alt+7"},
|
||||
suggested_key: { default: "Shift+Alt+7" },
|
||||
},
|
||||
commandTwo: {
|
||||
description: "Command Two!",
|
||||
suggested_key: {default: "Alt+4"},
|
||||
suggested_key: { default: "Alt+4" },
|
||||
},
|
||||
_execute_browser_action: {
|
||||
suggested_key: {default: "Shift+Alt+9"},
|
||||
suggested_key: { default: "Shift+Alt+9" },
|
||||
},
|
||||
};
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
commands,
|
||||
browser_action: {default_popup: "popup.html"},
|
||||
browser_action: { default_popup: "popup.html" },
|
||||
},
|
||||
background() {
|
||||
browser.commands.onCommand.addListener(commandName => {
|
||||
|
@ -60,12 +62,16 @@ add_task(async function testUpdatingCommands() {
|
|||
async function checkShortcut(name, key, modifiers) {
|
||||
EventUtils.synthesizeKey(key, modifiers);
|
||||
let message = await extension.awaitMessage("oncommand");
|
||||
is(message, name, `Expected onCommand listener to fire with the correct name: ${name}`);
|
||||
is(
|
||||
message,
|
||||
name,
|
||||
`Expected onCommand listener to fire with the correct name: ${name}`
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the original shortcuts work.
|
||||
await checkShortcut("commandOne", "7", {shiftKey: true, altKey: true});
|
||||
await checkShortcut("commandTwo", "4", {altKey: true});
|
||||
await checkShortcut("commandOne", "7", { shiftKey: true, altKey: true });
|
||||
await checkShortcut("commandTwo", "4", { altKey: true });
|
||||
|
||||
let doc = await loadShortcutsView();
|
||||
|
||||
|
@ -73,35 +79,48 @@ add_task(async function testUpdatingCommands() {
|
|||
ok(card, `There is a card for the extension`);
|
||||
|
||||
let inputs = card.querySelectorAll(".shortcut-input");
|
||||
is(inputs.length, Object.keys(commands).length, "There is an input for each command");
|
||||
is(
|
||||
inputs.length,
|
||||
Object.keys(commands).length,
|
||||
"There is an input for each command"
|
||||
);
|
||||
|
||||
let nameOrder = Array.from(inputs).map(input => input.getAttribute("name"));
|
||||
Assert.deepEqual(
|
||||
nameOrder,
|
||||
["commandOne", "commandTwo", "_execute_browser_action", "commandZero"],
|
||||
"commandZero should be last since it is unset");
|
||||
"commandZero should be last since it is unset"
|
||||
);
|
||||
|
||||
let count = 1;
|
||||
for (let input of inputs) {
|
||||
// Change the shortcut.
|
||||
input.focus();
|
||||
EventUtils.synthesizeKey("8", {shiftKey: true, altKey: true});
|
||||
EventUtils.synthesizeKey("8", { shiftKey: true, altKey: true });
|
||||
count++;
|
||||
|
||||
// Wait for the shortcut attribute to change.
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => input.getAttribute("shortcut") == "Alt+Shift+8");
|
||||
() => input.getAttribute("shortcut") == "Alt+Shift+8"
|
||||
);
|
||||
|
||||
// Check that the change worked (but skip if browserAction).
|
||||
if (input.getAttribute("name") != "_execute_browser_action") {
|
||||
await checkShortcut(input.getAttribute("name"), "8", {shiftKey: true, altKey: true});
|
||||
await checkShortcut(input.getAttribute("name"), "8", {
|
||||
shiftKey: true,
|
||||
altKey: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Change it again so it doesn't conflict with the next command.
|
||||
input.focus();
|
||||
EventUtils.synthesizeKey(count.toString(), {shiftKey: true, altKey: true});
|
||||
EventUtils.synthesizeKey(count.toString(), {
|
||||
shiftKey: true,
|
||||
altKey: true,
|
||||
});
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => input.getAttribute("shortcut") == `Alt+Shift+${count}`);
|
||||
() => input.getAttribute("shortcut") == `Alt+Shift+${count}`
|
||||
);
|
||||
}
|
||||
|
||||
// Check that errors can be shown.
|
||||
|
@ -112,7 +131,7 @@ add_task(async function testUpdatingCommands() {
|
|||
|
||||
// Try a shortcut with only shift for a modifier.
|
||||
input.focus();
|
||||
EventUtils.synthesizeKey("J", {shiftKey: true});
|
||||
EventUtils.synthesizeKey("J", { shiftKey: true });
|
||||
let possibleErrors = ["shortcuts-modifier-mac", "shortcuts-modifier-other"];
|
||||
ok(possibleErrors.includes(label.dataset.l10nId), `The message is set`);
|
||||
is(error.style.visibility, "visible", "The error is shown");
|
||||
|
@ -125,7 +144,7 @@ add_task(async function testUpdatingCommands() {
|
|||
|
||||
// Check if assigning already assigned shortcut is prevented.
|
||||
input.focus();
|
||||
EventUtils.synthesizeKey("2", {shiftKey: true, altKey: true});
|
||||
EventUtils.synthesizeKey("2", { shiftKey: true, altKey: true });
|
||||
is(label.dataset.l10nId, "shortcuts-exists", `The message is set`);
|
||||
is(error.style.visibility, "visible", "The error is shown");
|
||||
|
||||
|
@ -188,8 +207,10 @@ add_task(async function testExpanding() {
|
|||
for (let i = 0; i < shortcutRows.length; i++) {
|
||||
let row = shortcutRows[i];
|
||||
if (i < visibleCommands) {
|
||||
ok(getComputedStyle(row).display != "none",
|
||||
`The first ${visibleCommands} rows are visible`);
|
||||
ok(
|
||||
getComputedStyle(row).display != "none",
|
||||
`The first ${visibleCommands} rows are visible`
|
||||
);
|
||||
} else {
|
||||
is(getComputedStyle(row).display, "none", "The other rows are hidden");
|
||||
}
|
||||
|
@ -203,8 +224,11 @@ add_task(async function testExpanding() {
|
|||
ok(expandButton, "There is an expand button");
|
||||
let l10nAttrs = doc.l10n.getAttributes(expandButton);
|
||||
is(l10nAttrs.id, "shortcuts-card-expand-button", "The expand text is shown");
|
||||
is(l10nAttrs.args.numberToShow, numCommands - visibleCommands,
|
||||
"The number to be shown is set on the expand button");
|
||||
is(
|
||||
l10nAttrs.args.numberToShow,
|
||||
numCommands - visibleCommands,
|
||||
"The number to be shown is set on the expand button"
|
||||
);
|
||||
|
||||
// Expand the card.
|
||||
expandButton.click();
|
||||
|
@ -217,14 +241,18 @@ add_task(async function testExpanding() {
|
|||
|
||||
// The collapse text is now shown.
|
||||
l10nAttrs = doc.l10n.getAttributes(expandButton);
|
||||
is(l10nAttrs.id, "shortcuts-card-collapse-button", "The colapse text is shown");
|
||||
is(
|
||||
l10nAttrs.id,
|
||||
"shortcuts-card-collapse-button",
|
||||
"The colapse text is shown"
|
||||
);
|
||||
|
||||
// Collapse the card.
|
||||
expandButton.click();
|
||||
|
||||
ok(!card.hasAttribute("expanded"), "The card is now collapsed again");
|
||||
|
||||
assertCollapsedVisibility({collapsed: true});
|
||||
assertCollapsedVisibility({ collapsed: true });
|
||||
|
||||
await closeView();
|
||||
await extension.unload();
|
||||
|
|
|
@ -23,16 +23,18 @@ async function registerAndStartExtension(mockProvider, ext) {
|
|||
// the add-on manager, e.g. by passing "useAddonManager" to `loadExtension`.
|
||||
// "useAddonManager" can however not be used, because the resulting add-ons
|
||||
// are unsigned, and only add-ons with privileged signatures can be hidden.
|
||||
mockProvider.createAddons([{
|
||||
id: extension.id,
|
||||
name: ext.manifest.name,
|
||||
type: "extension",
|
||||
version: "1",
|
||||
// We use MockProvider because the "hidden" property cannot
|
||||
// be set when "useAddonManager" is passed to loadExtension.
|
||||
hidden: ext.manifest.hidden,
|
||||
isSystem: ext.isSystem,
|
||||
}]);
|
||||
mockProvider.createAddons([
|
||||
{
|
||||
id: extension.id,
|
||||
name: ext.manifest.name,
|
||||
type: "extension",
|
||||
version: "1",
|
||||
// We use MockProvider because the "hidden" property cannot
|
||||
// be set when "useAddonManager" is passed to loadExtension.
|
||||
hidden: ext.manifest.hidden,
|
||||
isSystem: ext.isSystem,
|
||||
},
|
||||
]);
|
||||
return extension;
|
||||
}
|
||||
|
||||
|
@ -46,7 +48,7 @@ function getShortcutByName(doc, extension, name) {
|
|||
}
|
||||
|
||||
function getNoShortcutListItem(doc, extension) {
|
||||
let {id} = extension;
|
||||
let { id } = extension;
|
||||
let li = doc.querySelector(`.shortcuts-no-commands-list [addon-id="${id}"]`);
|
||||
return li && li.textContent;
|
||||
}
|
||||
|
@ -64,10 +66,15 @@ add_task(async function extension_with_shortcuts() {
|
|||
await extension.startup();
|
||||
let doc = await loadShortcutsView();
|
||||
|
||||
ok(getShortcutByName(doc, extension, "theShortcut"),
|
||||
"Extension with shortcuts should have a card");
|
||||
is(getNoShortcutListItem(doc, extension), null,
|
||||
"Extension with shortcuts should not be listed");
|
||||
ok(
|
||||
getShortcutByName(doc, extension, "theShortcut"),
|
||||
"Extension with shortcuts should have a card"
|
||||
);
|
||||
is(
|
||||
getNoShortcutListItem(doc, extension),
|
||||
null,
|
||||
"Extension with shortcuts should not be listed"
|
||||
);
|
||||
|
||||
await closeShortcutsView(doc);
|
||||
await extension.unload();
|
||||
|
@ -83,10 +90,16 @@ add_task(async function extension_without_shortcuts() {
|
|||
await extension.startup();
|
||||
let doc = await loadShortcutsView();
|
||||
|
||||
is(getShortcutCard(doc, extension), null,
|
||||
"Extension without shortcuts should not have a card");
|
||||
is(getNoShortcutListItem(doc, extension), "no shortcut addon",
|
||||
"The add-on's name is set in the list");
|
||||
is(
|
||||
getShortcutCard(doc, extension),
|
||||
null,
|
||||
"Extension without shortcuts should not have a card"
|
||||
);
|
||||
is(
|
||||
getNoShortcutListItem(doc, extension),
|
||||
"no shortcut addon",
|
||||
"The add-on's name is set in the list"
|
||||
);
|
||||
|
||||
await closeShortcutsView(doc);
|
||||
await extension.unload();
|
||||
|
@ -114,13 +127,21 @@ add_task(async function hidden_extension() {
|
|||
|
||||
let doc = await loadShortcutsView();
|
||||
|
||||
ok(getShortcutByName(doc, hiddenExt1, "hiddenShortcut"),
|
||||
"Hidden extension with shortcuts should have a card");
|
||||
ok(
|
||||
getShortcutByName(doc, hiddenExt1, "hiddenShortcut"),
|
||||
"Hidden extension with shortcuts should have a card"
|
||||
);
|
||||
|
||||
is(getShortcutCard(doc, hiddenExt2), null,
|
||||
"Hidden extension without shortcuts should not have a card");
|
||||
is(getNoShortcutListItem(doc, hiddenExt2), null,
|
||||
"Hidden extension without shortcuts should not be listed");
|
||||
is(
|
||||
getShortcutCard(doc, hiddenExt2),
|
||||
null,
|
||||
"Hidden extension without shortcuts should not have a card"
|
||||
);
|
||||
is(
|
||||
getNoShortcutListItem(doc, hiddenExt2),
|
||||
null,
|
||||
"Hidden extension without shortcuts should not be listed"
|
||||
);
|
||||
|
||||
await closeShortcutsView(doc);
|
||||
await hiddenExt1.unload();
|
||||
|
@ -153,13 +174,21 @@ add_task(async function system_addons_and_shortcuts() {
|
|||
|
||||
let doc = await loadShortcutsView();
|
||||
|
||||
ok(getShortcutByName(doc, systemExt1, "systemShortcut"),
|
||||
"System add-on with shortcut should have a card");
|
||||
ok(
|
||||
getShortcutByName(doc, systemExt1, "systemShortcut"),
|
||||
"System add-on with shortcut should have a card"
|
||||
);
|
||||
|
||||
is(getShortcutCard(doc, systemExt2), null,
|
||||
"System add-on without shortcut should not have a card");
|
||||
is(getNoShortcutListItem(doc, systemExt2), null,
|
||||
"System add-on without shortcuts should not be listed");
|
||||
is(
|
||||
getShortcutCard(doc, systemExt2),
|
||||
null,
|
||||
"System add-on without shortcut should not have a card"
|
||||
);
|
||||
is(
|
||||
getNoShortcutListItem(doc, systemExt2),
|
||||
null,
|
||||
"System add-on without shortcuts should not be listed"
|
||||
);
|
||||
|
||||
await closeShortcutsView(doc);
|
||||
await systemExt1.unload();
|
||||
|
|
|
@ -20,12 +20,14 @@ async function test() {
|
|||
|
||||
gProvider = new MockProvider();
|
||||
|
||||
gProvider.createAddons([{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "auto updating addon",
|
||||
version: "1.0",
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_ENABLE,
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "auto updating addon",
|
||||
version: "1.0",
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_ENABLE,
|
||||
},
|
||||
]);
|
||||
|
||||
let aWindow = await open_manager("addons://list/extension");
|
||||
gManagerWindow = aWindow;
|
||||
|
@ -43,47 +45,72 @@ add_test(function clearOldTelemetry() {
|
|||
run_next_test();
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
gAvailableCategory = gManagerWindow.gCategories.get("addons://updates/available");
|
||||
is(gCategoryUtilities.isVisible(gAvailableCategory), false, "Available Updates category should initially be hidden");
|
||||
gAvailableCategory = gManagerWindow.gCategories.get(
|
||||
"addons://updates/available"
|
||||
);
|
||||
is(
|
||||
gCategoryUtilities.isVisible(gAvailableCategory),
|
||||
false,
|
||||
"Available Updates category should initially be hidden"
|
||||
);
|
||||
|
||||
gProvider.createAddons([{
|
||||
id: "addon2@tests.mozilla.org",
|
||||
name: "manually updating addon",
|
||||
version: "1.0",
|
||||
isCompatible: false,
|
||||
operationsRequiringRestart: 0,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "addon2@tests.mozilla.org",
|
||||
name: "manually updating addon",
|
||||
version: "1.0",
|
||||
isCompatible: false,
|
||||
operationsRequiringRestart: 0,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
|
||||
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
|
||||
},
|
||||
]);
|
||||
|
||||
is(gCategoryUtilities.isVisible(gAvailableCategory), false, "Available Updates category should still be hidden");
|
||||
is(
|
||||
gCategoryUtilities.isVisible(gAvailableCategory),
|
||||
false,
|
||||
"Available Updates category should still be hidden"
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
||||
add_test(async function() {
|
||||
let finished = 0;
|
||||
function maybeRunNext() {
|
||||
if (++finished == 2)
|
||||
if (++finished == 2) {
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
|
||||
gAvailableCategory.addEventListener("CategoryBadgeUpdated", function() {
|
||||
is(gCategoryUtilities.isVisible(gAvailableCategory), true, "Available Updates category should now be visible");
|
||||
is(gAvailableCategory.badgeCount, 1, "Badge for Available Updates should now be 1");
|
||||
maybeRunNext();
|
||||
}, {once: true});
|
||||
gAvailableCategory.addEventListener(
|
||||
"CategoryBadgeUpdated",
|
||||
function() {
|
||||
is(
|
||||
gCategoryUtilities.isVisible(gAvailableCategory),
|
||||
true,
|
||||
"Available Updates category should now be visible"
|
||||
);
|
||||
is(
|
||||
gAvailableCategory.badgeCount,
|
||||
1,
|
||||
"Badge for Available Updates should now be 1"
|
||||
);
|
||||
maybeRunNext();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
await gCategoryUtilities.openType("extension");
|
||||
gProvider.createInstalls([{
|
||||
name: "manually updating addon (new and improved!)",
|
||||
existingAddon: gProvider.addons[1],
|
||||
version: "1.1",
|
||||
releaseNotesURI: Services.io.newURI(TESTROOT + "thereIsNoFileHere.xhtml"),
|
||||
}]);
|
||||
gProvider.createInstalls([
|
||||
{
|
||||
name: "manually updating addon (new and improved!)",
|
||||
existingAddon: gProvider.addons[1],
|
||||
version: "1.1",
|
||||
releaseNotesURI: Services.io.newURI(TESTROOT + "thereIsNoFileHere.xhtml"),
|
||||
},
|
||||
]);
|
||||
|
||||
var item = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
|
||||
get_tooltip_info(item).then(({ version }) => {
|
||||
|
@ -92,23 +119,33 @@ add_test(async function() {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
add_test(async function() {
|
||||
Promise.resolve().then(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(gAvailableCategory, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(gAvailableCategory, {}, gManagerWindow);
|
||||
});
|
||||
await wait_for_view_load(gManagerWindow, null, true);
|
||||
is(gManagerWindow.document.getElementById("categories").selectedItem.value, "addons://updates/available", "Available Updates category should now be selected");
|
||||
is(gManagerWindow.gViewController.currentViewId, "addons://updates/available", "Available Updates view should be the current view");
|
||||
is(
|
||||
gManagerWindow.document.getElementById("categories").selectedItem.value,
|
||||
"addons://updates/available",
|
||||
"Available Updates category should now be selected"
|
||||
);
|
||||
is(
|
||||
gManagerWindow.gViewController.currentViewId,
|
||||
"addons://updates/available",
|
||||
"Available Updates view should be the current view"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
||||
add_test(async function() {
|
||||
var list = gManagerWindow.document.getElementById("updates-list");
|
||||
is(list.itemCount, 1, "Should be 1 available update listed");
|
||||
var item = list.firstChild;
|
||||
is(item.mAddon.id, "addon2@tests.mozilla.org", "Update item should be for the manually updating addon");
|
||||
is(
|
||||
item.mAddon.id,
|
||||
"addon2@tests.mozilla.org",
|
||||
"Update item should be for the manually updating addon"
|
||||
);
|
||||
|
||||
// The item in the list will be checking for update information asynchronously
|
||||
// so we have to wait for it to complete. Doing the same async request should
|
||||
|
@ -120,88 +157,172 @@ add_test(async function() {
|
|||
add_test(function() {
|
||||
function checkReleaseNotesTelemetry() {
|
||||
let snapshot = Services.telemetry.snapshotEvents(
|
||||
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true);
|
||||
ok(snapshot.parent && snapshot.parent.length > 0, "Got parent telemetry events in the snapshot");
|
||||
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
|
||||
true
|
||||
);
|
||||
ok(
|
||||
snapshot.parent && snapshot.parent.length > 0,
|
||||
"Got parent telemetry events in the snapshot"
|
||||
);
|
||||
|
||||
let releaseNotesEvents = snapshot.parent
|
||||
.filter(([ts, category, method]) =>
|
||||
category == "addonsManager" && method == "action")
|
||||
.filter(
|
||||
([ts, category, method]) =>
|
||||
category == "addonsManager" && method == "action"
|
||||
)
|
||||
.map(([ts, category, ...rest]) => rest);
|
||||
|
||||
Assert.deepEqual(releaseNotesEvents, [
|
||||
["action", "aboutAddons", null, {
|
||||
action: "releaseNotes",
|
||||
type: "extension",
|
||||
addonId: "addon2@tests.mozilla.org",
|
||||
view: "updates",
|
||||
}],
|
||||
["action", "aboutAddons", null, {
|
||||
action: "releaseNotes",
|
||||
type: "extension",
|
||||
addonId: "addon2@tests.mozilla.org",
|
||||
view: "updates",
|
||||
}],
|
||||
], "The releaseNotes events are tracked");
|
||||
Assert.deepEqual(
|
||||
releaseNotesEvents,
|
||||
[
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{
|
||||
action: "releaseNotes",
|
||||
type: "extension",
|
||||
addonId: "addon2@tests.mozilla.org",
|
||||
view: "updates",
|
||||
},
|
||||
],
|
||||
[
|
||||
"action",
|
||||
"aboutAddons",
|
||||
null,
|
||||
{
|
||||
action: "releaseNotes",
|
||||
type: "extension",
|
||||
addonId: "addon2@tests.mozilla.org",
|
||||
view: "updates",
|
||||
},
|
||||
],
|
||||
],
|
||||
"The releaseNotes events are tracked"
|
||||
);
|
||||
}
|
||||
|
||||
var list = gManagerWindow.document.getElementById("updates-list");
|
||||
var item = list.firstChild;
|
||||
get_tooltip_info(item).then(({ version }) => {
|
||||
is(version, "1.1", "Update item should have version number of the update");
|
||||
var postfix = gManagerWindow.document.getAnonymousElementByAttribute(item, "class", "update-postfix");
|
||||
var postfix = gManagerWindow.document.getAnonymousElementByAttribute(
|
||||
item,
|
||||
"class",
|
||||
"update-postfix"
|
||||
);
|
||||
is_element_visible(postfix, "'Update' postfix should be visible");
|
||||
is_element_visible(item._updateAvailable, "");
|
||||
is_element_visible(item._relNotesToggle, "Release notes toggle should be visible");
|
||||
is_element_visible(
|
||||
item._relNotesToggle,
|
||||
"Release notes toggle should be visible"
|
||||
);
|
||||
is_element_hidden(item._warning, "Incompatible warning should be hidden");
|
||||
is_element_hidden(item._error, "Blocklist error should be hidden");
|
||||
|
||||
info("Opening release notes");
|
||||
item.addEventListener("RelNotesToggle", function() {
|
||||
info("Release notes now open");
|
||||
item.addEventListener(
|
||||
"RelNotesToggle",
|
||||
function() {
|
||||
info("Release notes now open");
|
||||
|
||||
is_element_hidden(item._relNotesLoading, "Release notes loading message should be hidden");
|
||||
is_element_visible(item._relNotesError, "Release notes error message should be visible");
|
||||
is(item._relNotes.childElementCount, 0, "Release notes should be empty");
|
||||
is_element_hidden(
|
||||
item._relNotesLoading,
|
||||
"Release notes loading message should be hidden"
|
||||
);
|
||||
is_element_visible(
|
||||
item._relNotesError,
|
||||
"Release notes error message should be visible"
|
||||
);
|
||||
is(
|
||||
item._relNotes.childElementCount,
|
||||
0,
|
||||
"Release notes should be empty"
|
||||
);
|
||||
|
||||
info("Closing release notes");
|
||||
item.addEventListener("RelNotesToggle", function() {
|
||||
info("Release notes now closed");
|
||||
info("Setting Release notes URI to something that should load");
|
||||
gProvider.installs[0].releaseNotesURI = Services.io.newURI(TESTROOT + "releaseNotes.xhtml");
|
||||
info("Closing release notes");
|
||||
item.addEventListener(
|
||||
"RelNotesToggle",
|
||||
function() {
|
||||
info("Release notes now closed");
|
||||
info("Setting Release notes URI to something that should load");
|
||||
gProvider.installs[0].releaseNotesURI = Services.io.newURI(
|
||||
TESTROOT + "releaseNotes.xhtml"
|
||||
);
|
||||
|
||||
info("Re-opening release notes");
|
||||
item.addEventListener("RelNotesToggle", function() {
|
||||
info("Release notes now open");
|
||||
info("Re-opening release notes");
|
||||
item.addEventListener(
|
||||
"RelNotesToggle",
|
||||
function() {
|
||||
info("Release notes now open");
|
||||
|
||||
is_element_hidden(item._relNotesLoading, "Release notes loading message should be hidden");
|
||||
is_element_hidden(item._relNotesError, "Release notes error message should be hidden");
|
||||
isnot(item._relNotes.childElementCount, 0, "Release notes should have been inserted into container");
|
||||
is_element_hidden(
|
||||
item._relNotesLoading,
|
||||
"Release notes loading message should be hidden"
|
||||
);
|
||||
is_element_hidden(
|
||||
item._relNotesError,
|
||||
"Release notes error message should be hidden"
|
||||
);
|
||||
isnot(
|
||||
item._relNotes.childElementCount,
|
||||
0,
|
||||
"Release notes should have been inserted into container"
|
||||
);
|
||||
|
||||
checkReleaseNotesTelemetry();
|
||||
checkReleaseNotesTelemetry();
|
||||
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
EventUtils.synthesizeMouseAtCenter(item._relNotesToggle, { }, gManagerWindow);
|
||||
is_element_visible(item._relNotesLoading, "Release notes loading message should be visible");
|
||||
}, {once: true});
|
||||
EventUtils.synthesizeMouseAtCenter(item._relNotesToggle, { }, gManagerWindow);
|
||||
}, {once: true});
|
||||
EventUtils.synthesizeMouseAtCenter(item._relNotesToggle, { }, gManagerWindow);
|
||||
is_element_visible(item._relNotesLoading, "Release notes loading message should be visible");
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
item._relNotesToggle,
|
||||
{},
|
||||
gManagerWindow
|
||||
);
|
||||
is_element_visible(
|
||||
item._relNotesLoading,
|
||||
"Release notes loading message should be visible"
|
||||
);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
item._relNotesToggle,
|
||||
{},
|
||||
gManagerWindow
|
||||
);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
item._relNotesToggle,
|
||||
{},
|
||||
gManagerWindow
|
||||
);
|
||||
is_element_visible(
|
||||
item._relNotesLoading,
|
||||
"Release notes loading message should be visible"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
add_test(function() {
|
||||
var badgeUpdated = false;
|
||||
var installCompleted = false;
|
||||
|
||||
gAvailableCategory.addEventListener("CategoryBadgeUpdated", function() {
|
||||
if (installCompleted)
|
||||
run_next_test();
|
||||
else
|
||||
badgeUpdated = true;
|
||||
}, {once: true});
|
||||
gAvailableCategory.addEventListener(
|
||||
"CategoryBadgeUpdated",
|
||||
function() {
|
||||
if (installCompleted) {
|
||||
run_next_test();
|
||||
} else {
|
||||
badgeUpdated = true;
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
var list = gManagerWindow.document.getElementById("updates-list");
|
||||
var item = list.firstChild;
|
||||
|
@ -212,61 +333,107 @@ add_test(function() {
|
|||
var listener = {
|
||||
onInstallStarted() {
|
||||
info("Install started");
|
||||
is_element_visible(item._installStatus, "Install progress widget should be visible");
|
||||
is_element_visible(
|
||||
item._installStatus,
|
||||
"Install progress widget should be visible"
|
||||
);
|
||||
},
|
||||
onInstallEnded(...args) {
|
||||
install.removeTestListener(this);
|
||||
info("Install ended");
|
||||
is_element_hidden(item._installStatus, "Install progress widget should be hidden");
|
||||
is_element_hidden(
|
||||
item._installStatus,
|
||||
"Install progress widget should be hidden"
|
||||
);
|
||||
|
||||
if (badgeUpdated)
|
||||
if (badgeUpdated) {
|
||||
run_next_test();
|
||||
else
|
||||
} else {
|
||||
installCompleted = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
install.addTestListener(listener);
|
||||
EventUtils.synthesizeMouseAtCenter(updateBtn, { }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(updateBtn, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
|
||||
add_test(async function() {
|
||||
is(gCategoryUtilities.isVisible(gAvailableCategory), true, "Available Updates category should still be visible");
|
||||
is(gAvailableCategory.badgeCount, 0, "Badge for Available Updates should now be 0");
|
||||
is(
|
||||
gCategoryUtilities.isVisible(gAvailableCategory),
|
||||
true,
|
||||
"Available Updates category should still be visible"
|
||||
);
|
||||
is(
|
||||
gAvailableCategory.badgeCount,
|
||||
0,
|
||||
"Badge for Available Updates should now be 0"
|
||||
);
|
||||
|
||||
await gCategoryUtilities.openType("extension");
|
||||
is(gCategoryUtilities.isVisible(gAvailableCategory), false, "Available Updates category should be hidden");
|
||||
is(
|
||||
gCategoryUtilities.isVisible(gAvailableCategory),
|
||||
false,
|
||||
"Available Updates category should be hidden"
|
||||
);
|
||||
|
||||
await close_manager(gManagerWindow);
|
||||
let aWindow = await open_manager(null);
|
||||
gManagerWindow = aWindow;
|
||||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
gAvailableCategory = gManagerWindow.gCategories.get("addons://updates/available");
|
||||
gAvailableCategory = gManagerWindow.gCategories.get(
|
||||
"addons://updates/available"
|
||||
);
|
||||
|
||||
is(gCategoryUtilities.isVisible(gAvailableCategory), false, "Available Updates category should be hidden");
|
||||
is(
|
||||
gCategoryUtilities.isVisible(gAvailableCategory),
|
||||
false,
|
||||
"Available Updates category should be hidden"
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function() {
|
||||
gAvailableCategory.addEventListener("CategoryBadgeUpdated", async function() {
|
||||
is(gCategoryUtilities.isVisible(gAvailableCategory), true, "Available Updates category should now be visible");
|
||||
is(gAvailableCategory.badgeCount, 1, "Badge for Available Updates should now be 1");
|
||||
gAvailableCategory.addEventListener(
|
||||
"CategoryBadgeUpdated",
|
||||
async function() {
|
||||
is(
|
||||
gCategoryUtilities.isVisible(gAvailableCategory),
|
||||
true,
|
||||
"Available Updates category should now be visible"
|
||||
);
|
||||
is(
|
||||
gAvailableCategory.badgeCount,
|
||||
1,
|
||||
"Badge for Available Updates should now be 1"
|
||||
);
|
||||
|
||||
gAvailableCategory.addEventListener("CategoryBadgeUpdated", function() {
|
||||
is(gCategoryUtilities.isVisible(gAvailableCategory), false, "Available Updates category should now be hidden");
|
||||
gAvailableCategory.addEventListener(
|
||||
"CategoryBadgeUpdated",
|
||||
function() {
|
||||
is(
|
||||
gCategoryUtilities.isVisible(gAvailableCategory),
|
||||
false,
|
||||
"Available Updates category should now be hidden"
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
let aAddon = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
|
||||
aAddon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_ENABLE;
|
||||
}, {once: true});
|
||||
let aAddon = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
|
||||
aAddon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_ENABLE;
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
gProvider.createInstalls([{
|
||||
name: "manually updating addon (new and even more improved!)",
|
||||
existingAddon: gProvider.addons[1],
|
||||
version: "1.2",
|
||||
releaseNotesURI: Services.io.newURI(TESTROOT + "thereIsNoFileHere.xhtml"),
|
||||
}]);
|
||||
gProvider.createInstalls([
|
||||
{
|
||||
name: "manually updating addon (new and even more improved!)",
|
||||
existingAddon: gProvider.addons[1],
|
||||
version: "1.2",
|
||||
releaseNotesURI: Services.io.newURI(TESTROOT + "thereIsNoFileHere.xhtml"),
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
|
||||
// Tests that state menu is displayed correctly (enabled or disabled) in the add-on manager
|
||||
// when the preference is unlocked / locked
|
||||
const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
|
||||
const gIsLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc) ||
|
||||
("@mozilla.org/gio-service;1" in Cc);
|
||||
const gIsWindows = "@mozilla.org/windows-registry-key;1" in Cc;
|
||||
const gIsLinux =
|
||||
"@mozilla.org/gnome-gconf-service;1" in Cc ||
|
||||
"@mozilla.org/gio-service;1" in Cc;
|
||||
|
||||
var gManagerWindow;
|
||||
var gCategoryUtilities;
|
||||
|
@ -14,10 +15,12 @@ var gPluginElement;
|
|||
|
||||
function getTestPluginPref() {
|
||||
let prefix = "plugin.state.";
|
||||
if (gIsWindows)
|
||||
if (gIsWindows) {
|
||||
return `${prefix}nptest`;
|
||||
if (gIsLinux)
|
||||
}
|
||||
if (gIsLinux) {
|
||||
return `${prefix}libnptest`;
|
||||
}
|
||||
return `${prefix}test`;
|
||||
}
|
||||
|
||||
|
@ -55,32 +58,55 @@ function getTestPlugin(aPlugins) {
|
|||
}
|
||||
|
||||
function checkStateMenu(locked) {
|
||||
Assert.equal(Services.prefs.prefIsLocked(getTestPluginPref()), locked,
|
||||
"Preference lock state should be correct.");
|
||||
let menuList = gManagerWindow.document.getAnonymousElementByAttribute(gPluginElement, "anonid", "state-menulist");
|
||||
Assert.equal(
|
||||
Services.prefs.prefIsLocked(getTestPluginPref()),
|
||||
locked,
|
||||
"Preference lock state should be correct."
|
||||
);
|
||||
let menuList = gManagerWindow.document.getAnonymousElementByAttribute(
|
||||
gPluginElement,
|
||||
"anonid",
|
||||
"state-menulist"
|
||||
);
|
||||
// State menu should always have a selected item which must be visible
|
||||
let selectedMenuItem = menuList.querySelector(".addon-control[selected=\"true\"]");
|
||||
let selectedMenuItem = menuList.querySelector(
|
||||
'.addon-control[selected="true"]'
|
||||
);
|
||||
|
||||
is_element_visible(menuList, "State menu should be visible.");
|
||||
Assert.equal(menuList.disabled, locked,
|
||||
"State menu should" + (locked === true ? "" : " not") + " be disabled.");
|
||||
Assert.equal(
|
||||
menuList.disabled,
|
||||
locked,
|
||||
"State menu should" + (locked === true ? "" : " not") + " be disabled."
|
||||
);
|
||||
|
||||
is_element_visible(selectedMenuItem, "State menu's selected item should be visible.");
|
||||
is_element_visible(
|
||||
selectedMenuItem,
|
||||
"State menu's selected item should be visible."
|
||||
);
|
||||
}
|
||||
|
||||
function checkStateMenuDetail(locked) {
|
||||
Assert.equal(Services.prefs.prefIsLocked(getTestPluginPref()), locked,
|
||||
"Preference should be " + (locked === true ? "" : "un") + "locked.");
|
||||
Assert.equal(
|
||||
Services.prefs.prefIsLocked(getTestPluginPref()),
|
||||
locked,
|
||||
"Preference should be " + (locked === true ? "" : "un") + "locked."
|
||||
);
|
||||
|
||||
// open details menu
|
||||
EventUtils.synthesizeMouseAtCenter(gPluginElement, {}, gManagerWindow);
|
||||
|
||||
return new Promise(async resolve => {
|
||||
await wait_for_view_load(gManagerWindow);
|
||||
let menuList = gManagerWindow.document.getElementById("detail-state-menulist");
|
||||
let menuList = gManagerWindow.document.getElementById(
|
||||
"detail-state-menulist"
|
||||
);
|
||||
is_element_visible(menuList, "Details state menu should be visible.");
|
||||
Assert.equal(menuList.disabled, locked,
|
||||
"Details state menu enabled state should be correct.");
|
||||
Assert.equal(
|
||||
menuList.disabled,
|
||||
locked,
|
||||
"Details state menu enabled state should be correct."
|
||||
);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,23 +17,41 @@ async function test_inline_plugin_prefs() {
|
|||
ok(testPlugin, "Test Plug-in should exist");
|
||||
|
||||
let pluginEl = get_addon_element(gManagerWindow, testPlugin.id);
|
||||
is(testPlugin.optionsType, AddonManager.OPTIONS_TYPE_INLINE_BROWSER, "Options should be inline type");
|
||||
is(
|
||||
testPlugin.optionsType,
|
||||
AddonManager.OPTIONS_TYPE_INLINE_BROWSER,
|
||||
"Options should be inline type"
|
||||
);
|
||||
|
||||
let optionsBrowserPromise =
|
||||
BrowserTestUtils.waitForEvent(pluginEl.ownerDocument, "load", true, event => {
|
||||
let {target} = event;
|
||||
return target.currentURI && target.currentURI.spec === testPlugin.optionsURL;
|
||||
}).then(event => event.target);
|
||||
let optionsBrowserPromise = BrowserTestUtils.waitForEvent(
|
||||
pluginEl.ownerDocument,
|
||||
"load",
|
||||
true,
|
||||
event => {
|
||||
let { target } = event;
|
||||
return (
|
||||
target.currentURI && target.currentURI.spec === testPlugin.optionsURL
|
||||
);
|
||||
}
|
||||
).then(event => event.target);
|
||||
|
||||
if (gManagerWindow.useHtmlViews) {
|
||||
pluginEl.querySelector("panel-item[action='preferences']").click();
|
||||
} else {
|
||||
pluginEl.parentNode.ensureElementIsVisible(pluginEl);
|
||||
|
||||
let button = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "preferences-btn");
|
||||
let button = gManagerWindow.document.getAnonymousElementByAttribute(
|
||||
pluginEl,
|
||||
"anonid",
|
||||
"preferences-btn"
|
||||
);
|
||||
is_element_visible(button, "Preferences button should be visible");
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(pluginEl, { clickCount: 1 }, gManagerWindow);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
pluginEl,
|
||||
{ clickCount: 1 },
|
||||
gManagerWindow
|
||||
);
|
||||
|
||||
await TestUtils.topicObserved(AddonManager.OPTIONS_NOTIFICATION_DISPLAYED);
|
||||
}
|
||||
|
@ -49,11 +67,19 @@ async function test_inline_plugin_prefs() {
|
|||
let pluginLibraries = doc.getElementById("pluginLibraries");
|
||||
ok(pluginLibraries, "Plugin file name row should be displayed");
|
||||
// the file name depends on the platform
|
||||
is(pluginLibraries.textContent, testPlugin.pluginLibraries, "Plugin file name should be displayed");
|
||||
is(
|
||||
pluginLibraries.textContent,
|
||||
testPlugin.pluginLibraries,
|
||||
"Plugin file name should be displayed"
|
||||
);
|
||||
|
||||
let pluginMimeTypes = doc.getElementById("pluginMimeTypes");
|
||||
ok(pluginMimeTypes, "Plugin mime type row should be displayed");
|
||||
is(pluginMimeTypes.textContent, "application/x-test (Test \u2122 mimetype: tst)", "Plugin mime type should be displayed");
|
||||
is(
|
||||
pluginMimeTypes.textContent,
|
||||
"application/x-test (Test \u2122 mimetype: tst)",
|
||||
"Plugin mime type should be displayed"
|
||||
);
|
||||
|
||||
await close_manager(gManagerWindow);
|
||||
}
|
||||
|
|
|
@ -11,15 +11,28 @@ function getTestPlugin(aPlugins) {
|
|||
}
|
||||
|
||||
add_task(async function taskCheckPluginPrefsEnabled() {
|
||||
const [gManagerWindow, plugins] = await Promise.all([open_manager(), AddonManager.getAddonsByTypes(["plugin"])]);
|
||||
const [gManagerWindow, plugins] = await Promise.all([
|
||||
open_manager(),
|
||||
AddonManager.getAddonsByTypes(["plugin"]),
|
||||
]);
|
||||
const testPlugin = getTestPlugin(plugins);
|
||||
const testPluginTag = getTestPluginTag();
|
||||
Assert.ok(testPluginTag, "Test Plug-in tag should exist");
|
||||
const initialTestPluginState = testPluginTag.enabledState;
|
||||
|
||||
Assert.ok(gManagerWindow.gViewController.commands.cmd_showItemPreferences.isEnabled(testPlugin), "Test Plug-in preferences should be enabled");
|
||||
Assert.ok(
|
||||
gManagerWindow.gViewController.commands.cmd_showItemPreferences.isEnabled(
|
||||
testPlugin
|
||||
),
|
||||
"Test Plug-in preferences should be enabled"
|
||||
);
|
||||
testPluginTag.enabledState = Ci.nsIPluginTag.STATE_DISABLED;
|
||||
Assert.ok(gManagerWindow.gViewController.commands.cmd_showItemPreferences.isEnabled(testPlugin), "Test Plug-in preferences should be enabled");
|
||||
Assert.ok(
|
||||
gManagerWindow.gViewController.commands.cmd_showItemPreferences.isEnabled(
|
||||
testPlugin
|
||||
),
|
||||
"Test Plug-in preferences should be enabled"
|
||||
);
|
||||
|
||||
testPluginTag.enabledState = initialTestPluginState;
|
||||
await close_manager(gManagerWindow);
|
||||
|
|
|
@ -13,23 +13,27 @@ async function test() {
|
|||
|
||||
gProvider = new MockProvider();
|
||||
|
||||
gProvider.createAddons([{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "updated 6 hours ago",
|
||||
version: "1.0",
|
||||
updateDate: new Date(Date.now() - (1000 * 60 * 60 * 6)),
|
||||
releaseNotesURI: Services.io.newURI(TESTROOT + "releaseNotes.xhtml"),
|
||||
}, {
|
||||
id: "addon2@tests.mozilla.org",
|
||||
name: "updated 5 seconds ago",
|
||||
version: "1.0",
|
||||
updateDate: new Date(Date.now() - (1000 * 5)),
|
||||
}, {
|
||||
id: "addon3@tests.mozilla.org",
|
||||
name: "updated 1 month ago",
|
||||
version: "1.0",
|
||||
updateDate: new Date(Date.now() - (1000 * 60 * 60 * 25 * 30)),
|
||||
}]);
|
||||
gProvider.createAddons([
|
||||
{
|
||||
id: "addon1@tests.mozilla.org",
|
||||
name: "updated 6 hours ago",
|
||||
version: "1.0",
|
||||
updateDate: new Date(Date.now() - 1000 * 60 * 60 * 6),
|
||||
releaseNotesURI: Services.io.newURI(TESTROOT + "releaseNotes.xhtml"),
|
||||
},
|
||||
{
|
||||
id: "addon2@tests.mozilla.org",
|
||||
name: "updated 5 seconds ago",
|
||||
version: "1.0",
|
||||
updateDate: new Date(Date.now() - 1000 * 5),
|
||||
},
|
||||
{
|
||||
id: "addon3@tests.mozilla.org",
|
||||
name: "updated 1 month ago",
|
||||
version: "1.0",
|
||||
updateDate: new Date(Date.now() - 1000 * 60 * 60 * 25 * 30),
|
||||
},
|
||||
]);
|
||||
|
||||
let aWindow = await open_manager("addons://list/extension");
|
||||
gManagerWindow = aWindow;
|
||||
|
@ -42,28 +46,48 @@ async function end_test() {
|
|||
finish();
|
||||
}
|
||||
|
||||
|
||||
add_test(function() {
|
||||
info("Checking menuitem for Recent Updates opens that pane");
|
||||
var recentCat = gManagerWindow.gCategories.get("addons://updates/recent");
|
||||
is(gCategoryUtilities.isVisible(recentCat), false, "Recent Updates category should initially be hidden");
|
||||
is(
|
||||
gCategoryUtilities.isVisible(recentCat),
|
||||
false,
|
||||
"Recent Updates category should initially be hidden"
|
||||
);
|
||||
|
||||
var utilsBtn = gManagerWindow.document.getElementById("header-utils-btn");
|
||||
utilsBtn.addEventListener("popupshown", async function() {
|
||||
Promise.resolve().then(() => {
|
||||
var menuitem = gManagerWindow.document.getElementById("utils-viewUpdates");
|
||||
EventUtils.synthesizeMouse(menuitem, 2, 2, { }, gManagerWindow);
|
||||
});
|
||||
await wait_for_view_load(gManagerWindow, null, true);
|
||||
is(gCategoryUtilities.isVisible(recentCat), true, "Recent Updates category should now be visible");
|
||||
is(gManagerWindow.document.getElementById("categories").selectedItem.value, "addons://updates/recent", "Recent Updates category should now be selected");
|
||||
is(gManagerWindow.gViewController.currentViewId, "addons://updates/recent", "Recent Updates view should be the current view");
|
||||
run_next_test();
|
||||
}, {once: true});
|
||||
EventUtils.synthesizeMouse(utilsBtn, 2, 2, { }, gManagerWindow);
|
||||
utilsBtn.addEventListener(
|
||||
"popupshown",
|
||||
async function() {
|
||||
Promise.resolve().then(() => {
|
||||
var menuitem = gManagerWindow.document.getElementById(
|
||||
"utils-viewUpdates"
|
||||
);
|
||||
EventUtils.synthesizeMouse(menuitem, 2, 2, {}, gManagerWindow);
|
||||
});
|
||||
await wait_for_view_load(gManagerWindow, null, true);
|
||||
is(
|
||||
gCategoryUtilities.isVisible(recentCat),
|
||||
true,
|
||||
"Recent Updates category should now be visible"
|
||||
);
|
||||
is(
|
||||
gManagerWindow.document.getElementById("categories").selectedItem.value,
|
||||
"addons://updates/recent",
|
||||
"Recent Updates category should now be selected"
|
||||
);
|
||||
is(
|
||||
gManagerWindow.gViewController.currentViewId,
|
||||
"addons://updates/recent",
|
||||
"Recent Updates view should be the current view"
|
||||
);
|
||||
run_next_test();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
EventUtils.synthesizeMouse(utilsBtn, 2, 2, {}, gManagerWindow);
|
||||
});
|
||||
|
||||
|
||||
add_test(async function() {
|
||||
await close_manager(gManagerWindow);
|
||||
let aWindow = await open_manager(null);
|
||||
|
@ -71,7 +95,11 @@ add_test(async function() {
|
|||
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
|
||||
|
||||
var recentCat = gManagerWindow.gCategories.get("addons://updates/recent");
|
||||
is(gCategoryUtilities.isVisible(recentCat), true, "Recent Updates category should still be visible");
|
||||
is(
|
||||
gCategoryUtilities.isVisible(recentCat),
|
||||
true,
|
||||
"Recent Updates category should still be visible"
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
// Tests that upgrading bootstrapped add-ons behaves correctly while the
|
||||
// manager is open
|
||||
|
||||
const {AddonTestUtils} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
|
||||
const ID = "reinstall@tests.mozilla.org";
|
||||
const testIdSuffix = "@tests.mozilla.org";
|
||||
|
@ -22,8 +24,13 @@ function get_test_items_in_list(aManager) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!item.mAddon || item.mAddon.id.substring(item.mAddon.id.length - testIdSuffix.length) == testIdSuffix)
|
||||
if (
|
||||
!item.mAddon ||
|
||||
item.mAddon.id.substring(item.mAddon.id.length - testIdSuffix.length) ==
|
||||
testIdSuffix
|
||||
) {
|
||||
items.push(item);
|
||||
}
|
||||
item = item.nextSibling;
|
||||
}
|
||||
|
||||
|
@ -31,20 +38,24 @@ function get_test_items_in_list(aManager) {
|
|||
}
|
||||
|
||||
function htmlDoc() {
|
||||
return gManagerWindow.document.getElementById("html-view-browser").contentDocument;
|
||||
return gManagerWindow.document.getElementById("html-view-browser")
|
||||
.contentDocument;
|
||||
}
|
||||
|
||||
function get_list_item_count() {
|
||||
if (gManagerWindow.useHtmlViews) {
|
||||
return htmlDoc()
|
||||
.querySelectorAll(`addon-card[addon-id$="${testIdSuffix}"]`)
|
||||
return htmlDoc().querySelectorAll(`addon-card[addon-id$="${testIdSuffix}"]`)
|
||||
.length;
|
||||
}
|
||||
return get_test_items_in_list(gManagerWindow).length;
|
||||
}
|
||||
|
||||
function get_node(parent, anonid) {
|
||||
return parent.ownerDocument.getAnonymousElementByAttribute(parent, "anonid", anonid);
|
||||
return parent.ownerDocument.getAnonymousElementByAttribute(
|
||||
parent,
|
||||
"anonid",
|
||||
anonid
|
||||
);
|
||||
}
|
||||
|
||||
function removeItem(item) {
|
||||
|
@ -54,17 +65,23 @@ function removeItem(item) {
|
|||
button.click();
|
||||
} else {
|
||||
button = get_node(item, "remove-btn");
|
||||
EventUtils.synthesizeMouseAtCenter(button, { }, button.ownerGlobal);
|
||||
EventUtils.synthesizeMouseAtCenter(button, {}, button.ownerGlobal);
|
||||
}
|
||||
}
|
||||
|
||||
function get_class_node(parent, cls) {
|
||||
return parent.ownerDocument.getAnonymousElementByAttribute(parent, "class", cls);
|
||||
return parent.ownerDocument.getAnonymousElementByAttribute(
|
||||
parent,
|
||||
"class",
|
||||
cls
|
||||
);
|
||||
}
|
||||
|
||||
function hasPendingMessage(item, msg) {
|
||||
if (gManagerWindow.useHtmlViews) {
|
||||
let messageBar = htmlDoc().querySelector(`message-bar[addon-id="${item.addon.id}"`);
|
||||
let messageBar = htmlDoc().querySelector(
|
||||
`message-bar[addon-id="${item.addon.id}"`
|
||||
);
|
||||
is_element_visible(messageBar, msg);
|
||||
} else {
|
||||
is_element_visible(get_class_node(item, "pending"), msg);
|
||||
|
@ -72,7 +89,10 @@ function hasPendingMessage(item, msg) {
|
|||
}
|
||||
|
||||
async function install_addon(xpi) {
|
||||
let install = await AddonManager.getInstallForFile(xpi, "application/x-xpinstall");
|
||||
let install = await AddonManager.getInstallForFile(
|
||||
xpi,
|
||||
"application/x-xpinstall"
|
||||
);
|
||||
return install.install();
|
||||
}
|
||||
|
||||
|
@ -90,28 +110,45 @@ async function check_addon(aAddon, aVersion) {
|
|||
is(version, aVersion, "Version should be correct");
|
||||
|
||||
if (gManagerWindow.useHtmlViews) {
|
||||
const l10nAttrs = item.ownerDocument.l10n.getAttributes(item.querySelector(".addon-name"));
|
||||
const l10nAttrs = item.ownerDocument.l10n.getAttributes(
|
||||
item.querySelector(".addon-name")
|
||||
);
|
||||
if (aAddon.userDisabled) {
|
||||
Assert.deepEqual(l10nAttrs, {id: "addon-name-disabled", args: {name: aAddon.name}},
|
||||
"localized addon name is marked as disabled");
|
||||
} else {
|
||||
Assert.deepEqual(l10nAttrs, {id: null, args: null},
|
||||
"localized addon name is not marked as disabled");
|
||||
Assert.deepEqual(
|
||||
l10nAttrs,
|
||||
{ id: "addon-name-disabled", args: { name: aAddon.name } },
|
||||
"localized addon name is marked as disabled"
|
||||
);
|
||||
} else {
|
||||
Assert.deepEqual(
|
||||
l10nAttrs,
|
||||
{ id: null, args: null },
|
||||
"localized addon name is not marked as disabled"
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (aAddon.userDisabled) {
|
||||
is_element_visible(get_class_node(item, "disabled-postfix"), "Disabled postfix should be hidden");
|
||||
is_element_visible(
|
||||
get_class_node(item, "disabled-postfix"),
|
||||
"Disabled postfix should be hidden"
|
||||
);
|
||||
} else {
|
||||
is_element_hidden(get_class_node(item, "disabled-postfix"), "Disabled postfix should be hidden");
|
||||
is_element_hidden(
|
||||
get_class_node(item, "disabled-postfix"),
|
||||
"Disabled postfix should be hidden"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function wait_for_addon_item_added(addonId) {
|
||||
if (gManagerWindow.useHtmlViews) {
|
||||
await BrowserTestUtils.waitForEvent(htmlDoc().querySelector("addon-list"), "add");
|
||||
await BrowserTestUtils.waitForEvent(
|
||||
htmlDoc().querySelector("addon-list"),
|
||||
"add"
|
||||
);
|
||||
const item = get_addon_element(gManagerWindow, addonId);
|
||||
ok(item, `Found addon card for ${addonId}`);
|
||||
}
|
||||
|
@ -119,7 +156,10 @@ async function wait_for_addon_item_added(addonId) {
|
|||
|
||||
async function wait_for_addon_item_removed(addonId) {
|
||||
if (gManagerWindow.useHtmlViews) {
|
||||
await BrowserTestUtils.waitForEvent(htmlDoc().querySelector("addon-list"), "remove");
|
||||
await BrowserTestUtils.waitForEvent(
|
||||
htmlDoc().querySelector("addon-list"),
|
||||
"remove"
|
||||
);
|
||||
const item = get_addon_element(gManagerWindow, addonId);
|
||||
ok(!item, `There shouldn't be an addon card for ${addonId}`);
|
||||
}
|
||||
|
@ -127,7 +167,10 @@ async function wait_for_addon_item_removed(addonId) {
|
|||
|
||||
async function wait_for_addon_item_updated(addonId) {
|
||||
if (gManagerWindow.useHtmlViews) {
|
||||
await BrowserTestUtils.waitForEvent(get_addon_element(gManagerWindow, addonId), "update");
|
||||
await BrowserTestUtils.waitForEvent(
|
||||
get_addon_element(gManagerWindow, addonId),
|
||||
"update"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,7 +250,10 @@ async function test_upgrade_pending_uninstall_v1_to_v2() {
|
|||
|
||||
await promiseItemRemoved;
|
||||
|
||||
ok(!!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
|
||||
ok(
|
||||
!!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL),
|
||||
"Add-on should be pending uninstall"
|
||||
);
|
||||
hasPendingMessage(item, "Pending message should be visible");
|
||||
|
||||
promiseItemAdded = wait_for_addon_item_added(ID);
|
||||
|
@ -249,7 +295,10 @@ async function test_upgrade_pending_uninstall_disabled_v1_to_v2() {
|
|||
item.clientTop;
|
||||
|
||||
await promiseItemRemoved;
|
||||
ok(!!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
|
||||
ok(
|
||||
!!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL),
|
||||
"Add-on should be pending uninstall"
|
||||
);
|
||||
hasPendingMessage(item, "Pending message should be visible");
|
||||
|
||||
promiseItemAdded = wait_for_addon_item_added(ID);
|
||||
|
@ -279,8 +328,11 @@ async function test_upgrades(useHtmlViews) {
|
|||
}
|
||||
|
||||
gManagerWindow = await open_manager("addons://list/extension");
|
||||
is(gManagerWindow.useHtmlViews, useHtmlViews,
|
||||
"Got about:addons window in the expected mode");
|
||||
is(
|
||||
gManagerWindow.useHtmlViews,
|
||||
useHtmlViews,
|
||||
"Got about:addons window in the expected mode"
|
||||
);
|
||||
|
||||
await test_upgrade_v1_to_v2();
|
||||
await test_upgrade_disabled_v1_to_v2();
|
||||
|
@ -297,14 +349,14 @@ add_task(async function setup() {
|
|||
xpi1 = await AddonTestUtils.createTempWebExtensionFile({
|
||||
manifest: {
|
||||
version: "1.0",
|
||||
applications: {gecko: {id: ID}},
|
||||
applications: { gecko: { id: ID } },
|
||||
},
|
||||
});
|
||||
|
||||
xpi2 = await AddonTestUtils.createTempWebExtensionFile({
|
||||
manifest: {
|
||||
version: "2.0",
|
||||
applications: {gecko: {id: ID}},
|
||||
applications: { gecko: { id: ID } },
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -18,168 +18,188 @@ async function test() {
|
|||
waitForExplicitFinish();
|
||||
|
||||
gProvider = new MockProvider();
|
||||
gProvider.createAddons([{
|
||||
// enabledInstalled group
|
||||
// * Enabled
|
||||
// * Incompatible but enabled because compatibility checking is off
|
||||
// * Waiting to be installed
|
||||
// * Waiting to be enabled
|
||||
id: "test1@tests.mozilla.org",
|
||||
name: "Test add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 2, 0, 0, 0),
|
||||
pendingOperations: AddonManager.PENDING_NONE,
|
||||
}, {
|
||||
id: "test2@tests.mozilla.org",
|
||||
name: "a first add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 1, 23, 59, 59),
|
||||
pendingOperations: AddonManager.PENDING_UPGRADE,
|
||||
isActive: true,
|
||||
isCompatible: false,
|
||||
}, {
|
||||
id: "test3@tests.mozilla.org",
|
||||
name: "\u010Cesk\u00FD slovn\u00EDk", // Český slovník
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 2, 0, 0, 1),
|
||||
pendingOperations: AddonManager.PENDING_INSTALL,
|
||||
isActive: false,
|
||||
}, {
|
||||
id: "test4@tests.mozilla.org",
|
||||
name: "canadian dictionary",
|
||||
updateDate: new Date(1970, 0, 1, 0, 0, 0),
|
||||
description: "foo",
|
||||
isActive: true,
|
||||
}, {
|
||||
id: "test5@tests.mozilla.org",
|
||||
name: "croatian dictionary",
|
||||
description: "foo",
|
||||
updateDate: new Date(2012, 12, 12, 0, 0, 0),
|
||||
pendingOperations: AddonManager.PENDING_ENABLE,
|
||||
isActive: false,
|
||||
}, {
|
||||
// pendingDisable group
|
||||
// * Waiting to be disabled
|
||||
id: "test6@tests.mozilla.org",
|
||||
name: "orange Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 2, 0, 0, 0),
|
||||
isCompatible: false,
|
||||
isActive: true,
|
||||
pendingOperations: AddonManager.PENDING_DISABLE,
|
||||
}, {
|
||||
id: "test7@tests.mozilla.org",
|
||||
name: "Blue Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 1, 23, 59, 59),
|
||||
isActive: true,
|
||||
pendingOperations: AddonManager.PENDING_DISABLE,
|
||||
}, {
|
||||
id: "test8@tests.mozilla.org",
|
||||
name: "Green Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 3, 0, 0, 1),
|
||||
pendingOperations: AddonManager.PENDING_DISABLE,
|
||||
}, {
|
||||
id: "test9@tests.mozilla.org",
|
||||
name: "red Add-on",
|
||||
updateDate: new Date(2011, 4, 1, 0, 0, 0),
|
||||
description: "foo",
|
||||
isCompatible: false,
|
||||
pendingOperations: AddonManager.PENDING_DISABLE,
|
||||
}, {
|
||||
id: "test10@tests.mozilla.org",
|
||||
name: "Purple Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2012, 12, 12, 0, 0, 0),
|
||||
isCompatible: false,
|
||||
pendingOperations: AddonManager.PENDING_DISABLE,
|
||||
}, {
|
||||
// pendingUninstall group
|
||||
// * Waiting to be removed
|
||||
id: "test11@tests.mozilla.org",
|
||||
name: "amber Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(1978, 4, 2, 0, 0, 0),
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
pendingOperations: AddonManager.PENDING_UNINSTALL,
|
||||
}, {
|
||||
id: "test12@tests.mozilla.org",
|
||||
name: "Salmon Add-on - pending disable",
|
||||
description: "foo",
|
||||
updateDate: new Date(2054, 4, 1, 23, 59, 59),
|
||||
isActive: true,
|
||||
pendingOperations: AddonManager.PENDING_UNINSTALL,
|
||||
}, {
|
||||
id: "test13@tests.mozilla.org",
|
||||
name: "rose Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 2, 0, 0, 1),
|
||||
isActive: false,
|
||||
userDisabled: true,
|
||||
pendingOperations: AddonManager.PENDING_UNINSTALL,
|
||||
}, {
|
||||
id: "test14@tests.mozilla.org",
|
||||
name: "Violet Add-on",
|
||||
updateDate: new Date(2010, 5, 1, 0, 0, 0),
|
||||
description: "foo",
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
pendingOperations: AddonManager.PENDING_UNINSTALL,
|
||||
}, {
|
||||
id: "test15@tests.mozilla.org",
|
||||
name: "white Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 12, 0, 0, 0),
|
||||
isActive: false,
|
||||
userDisabled: true,
|
||||
pendingOperations: AddonManager.PENDING_UNINSTALL,
|
||||
}, {
|
||||
// disabledIncompatibleBlocked group
|
||||
// * Disabled
|
||||
// * Incompatible
|
||||
// * Blocklisted
|
||||
id: "test16@tests.mozilla.org",
|
||||
name: "grimsby Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 1, 0, 0, 0),
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
}, {
|
||||
id: "test17@tests.mozilla.org",
|
||||
name: "beamsville Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 8, 23, 59, 59),
|
||||
isActive: false,
|
||||
userDisabled: true,
|
||||
}, {
|
||||
id: "test18@tests.mozilla.org",
|
||||
name: "smithville Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 3, 0, 0, 1),
|
||||
isActive: false,
|
||||
userDisabled: true,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_OUTDATED,
|
||||
}, {
|
||||
id: "test19@tests.mozilla.org",
|
||||
name: "dunnville Add-on",
|
||||
updateDate: new Date(2010, 4, 2, 0, 0, 0),
|
||||
description: "foo",
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
isCompatible: false,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_NOT_BLOCKED,
|
||||
}, {
|
||||
id: "test20@tests.mozilla.org",
|
||||
name: "silverdale Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 12, 0, 0, 0),
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
|
||||
}]);
|
||||
|
||||
gProvider.createAddons([
|
||||
{
|
||||
// enabledInstalled group
|
||||
// * Enabled
|
||||
// * Incompatible but enabled because compatibility checking is off
|
||||
// * Waiting to be installed
|
||||
// * Waiting to be enabled
|
||||
id: "test1@tests.mozilla.org",
|
||||
name: "Test add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 2, 0, 0, 0),
|
||||
pendingOperations: AddonManager.PENDING_NONE,
|
||||
},
|
||||
{
|
||||
id: "test2@tests.mozilla.org",
|
||||
name: "a first add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 1, 23, 59, 59),
|
||||
pendingOperations: AddonManager.PENDING_UPGRADE,
|
||||
isActive: true,
|
||||
isCompatible: false,
|
||||
},
|
||||
{
|
||||
id: "test3@tests.mozilla.org",
|
||||
name: "\u010Cesk\u00FD slovn\u00EDk", // Český slovník
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 2, 0, 0, 1),
|
||||
pendingOperations: AddonManager.PENDING_INSTALL,
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
id: "test4@tests.mozilla.org",
|
||||
name: "canadian dictionary",
|
||||
updateDate: new Date(1970, 0, 1, 0, 0, 0),
|
||||
description: "foo",
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
id: "test5@tests.mozilla.org",
|
||||
name: "croatian dictionary",
|
||||
description: "foo",
|
||||
updateDate: new Date(2012, 12, 12, 0, 0, 0),
|
||||
pendingOperations: AddonManager.PENDING_ENABLE,
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
// pendingDisable group
|
||||
// * Waiting to be disabled
|
||||
id: "test6@tests.mozilla.org",
|
||||
name: "orange Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 2, 0, 0, 0),
|
||||
isCompatible: false,
|
||||
isActive: true,
|
||||
pendingOperations: AddonManager.PENDING_DISABLE,
|
||||
},
|
||||
{
|
||||
id: "test7@tests.mozilla.org",
|
||||
name: "Blue Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 1, 23, 59, 59),
|
||||
isActive: true,
|
||||
pendingOperations: AddonManager.PENDING_DISABLE,
|
||||
},
|
||||
{
|
||||
id: "test8@tests.mozilla.org",
|
||||
name: "Green Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 3, 0, 0, 1),
|
||||
pendingOperations: AddonManager.PENDING_DISABLE,
|
||||
},
|
||||
{
|
||||
id: "test9@tests.mozilla.org",
|
||||
name: "red Add-on",
|
||||
updateDate: new Date(2011, 4, 1, 0, 0, 0),
|
||||
description: "foo",
|
||||
isCompatible: false,
|
||||
pendingOperations: AddonManager.PENDING_DISABLE,
|
||||
},
|
||||
{
|
||||
id: "test10@tests.mozilla.org",
|
||||
name: "Purple Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2012, 12, 12, 0, 0, 0),
|
||||
isCompatible: false,
|
||||
pendingOperations: AddonManager.PENDING_DISABLE,
|
||||
},
|
||||
{
|
||||
// pendingUninstall group
|
||||
// * Waiting to be removed
|
||||
id: "test11@tests.mozilla.org",
|
||||
name: "amber Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(1978, 4, 2, 0, 0, 0),
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
pendingOperations: AddonManager.PENDING_UNINSTALL,
|
||||
},
|
||||
{
|
||||
id: "test12@tests.mozilla.org",
|
||||
name: "Salmon Add-on - pending disable",
|
||||
description: "foo",
|
||||
updateDate: new Date(2054, 4, 1, 23, 59, 59),
|
||||
isActive: true,
|
||||
pendingOperations: AddonManager.PENDING_UNINSTALL,
|
||||
},
|
||||
{
|
||||
id: "test13@tests.mozilla.org",
|
||||
name: "rose Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 2, 0, 0, 1),
|
||||
isActive: false,
|
||||
userDisabled: true,
|
||||
pendingOperations: AddonManager.PENDING_UNINSTALL,
|
||||
},
|
||||
{
|
||||
id: "test14@tests.mozilla.org",
|
||||
name: "Violet Add-on",
|
||||
updateDate: new Date(2010, 5, 1, 0, 0, 0),
|
||||
description: "foo",
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
pendingOperations: AddonManager.PENDING_UNINSTALL,
|
||||
},
|
||||
{
|
||||
id: "test15@tests.mozilla.org",
|
||||
name: "white Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 12, 0, 0, 0),
|
||||
isActive: false,
|
||||
userDisabled: true,
|
||||
pendingOperations: AddonManager.PENDING_UNINSTALL,
|
||||
},
|
||||
{
|
||||
// disabledIncompatibleBlocked group
|
||||
// * Disabled
|
||||
// * Incompatible
|
||||
// * Blocklisted
|
||||
id: "test16@tests.mozilla.org",
|
||||
name: "grimsby Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 1, 0, 0, 0),
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
},
|
||||
{
|
||||
id: "test17@tests.mozilla.org",
|
||||
name: "beamsville Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 8, 23, 59, 59),
|
||||
isActive: false,
|
||||
userDisabled: true,
|
||||
},
|
||||
{
|
||||
id: "test18@tests.mozilla.org",
|
||||
name: "smithville Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 3, 0, 0, 1),
|
||||
isActive: false,
|
||||
userDisabled: true,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_OUTDATED,
|
||||
},
|
||||
{
|
||||
id: "test19@tests.mozilla.org",
|
||||
name: "dunnville Add-on",
|
||||
updateDate: new Date(2010, 4, 2, 0, 0, 0),
|
||||
description: "foo",
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
isCompatible: false,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_NOT_BLOCKED,
|
||||
},
|
||||
{
|
||||
id: "test20@tests.mozilla.org",
|
||||
name: "silverdale Add-on",
|
||||
description: "foo",
|
||||
updateDate: new Date(2010, 4, 12, 0, 0, 0),
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
|
||||
},
|
||||
]);
|
||||
|
||||
let aWindow = await open_manager("addons://list/extension");
|
||||
gManagerWindow = aWindow;
|
||||
|
@ -200,8 +220,9 @@ function set_order(aSortBy, aAscending) {
|
|||
node = node.nextSibling;
|
||||
}
|
||||
gManagerWindow.sortElements(elements, ["uiState", aSortBy], aAscending);
|
||||
for (let element of elements)
|
||||
for (let element of elements) {
|
||||
list.appendChild(element);
|
||||
}
|
||||
}
|
||||
|
||||
function check_order(aExpectedOrder) {
|
||||
|
@ -210,12 +231,17 @@ function check_order(aExpectedOrder) {
|
|||
var node = list.firstChild;
|
||||
while (node) {
|
||||
var id = node.getAttribute("value");
|
||||
if (id && id.endsWith("@tests.mozilla.org"))
|
||||
if (id && id.endsWith("@tests.mozilla.org")) {
|
||||
order.push(node.getAttribute("value"));
|
||||
}
|
||||
node = node.nextSibling;
|
||||
}
|
||||
|
||||
is(order.toSource(), aExpectedOrder.toSource(), "Should have seen the right order");
|
||||
is(
|
||||
order.toSource(),
|
||||
aExpectedOrder.toSource(),
|
||||
"Should have seen the right order"
|
||||
);
|
||||
}
|
||||
|
||||
// Tests that ascending name ordering was the default
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче