Bug 985956 - Uplift Add-on SDK to Firefox

This commit is contained in:
Erik Vold 2014-03-20 08:07:16 -07:00
parent 83652b3eef
commit a108e9c2bd
21 changed files with 151 additions and 439 deletions

View File

@ -6,8 +6,7 @@ Before proceeding, please make sure you've installed Python 2.5,
http://python.org/download/
Note that Python 3 is not supported on any platform, and Python 2.7.6
is not supported on Windows.
Note that Python 3 is not supported.
For Windows users, MozillaBuild (https://wiki.mozilla.org/MozillaBuild)
will install the correct version of Python and the MSYS package, which

View File

@ -4,18 +4,6 @@
"use strict";
const { Cu } = require("chrome");
// Because Firefox Holly, we still need to check if `CustomizableUI` is
// available. Once Australis will officially land, we can safely remove it.
// See Bug 959142
try {
Cu.import("resource:///modules/CustomizableUI.jsm", {});
}
catch (e) {
throw Error("Unsupported Application: The module" + module.id +
" does not support this application.");
}
const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
const { receive } = require("../event/utils");
const { InputPort } = require("./system");

View File

@ -138,6 +138,8 @@ function display(panel, options, anchor) {
// menu panel.
// In such cases clicking this widget will hide the overflow/menu panel,
// and the widget's panel will show instead.
// If `CustomizableUI` is not available, it means the anchor is not in a
// chrome browser window, and therefore there is no need for this check.
if (CustomizableUI) {
let node = anchor;
({anchor}) = CustomizableUI.getWidget(anchor.id).forWindow(window);

View File

@ -10,17 +10,6 @@ module.metadata = {
}
};
// Because Firefox Holly, we still need to check if `CustomizableUI` is
// available. Once Australis will officially land, we can safely remove it.
// See Bug 959142
try {
require('chrome').Cu.import('resource:///modules/CustomizableUI.jsm', {});
}
catch (e) {
throw Error('Unsupported Application: The module ' + module.id +
' does not support this application.');
}
const { Class } = require('../../core/heritage');
const { merge } = require('../../util/object');
const { Disposable } = require('../../core/disposable');

View File

@ -10,17 +10,6 @@ module.metadata = {
}
};
// Because Firefox Holly, we still need to check if `CustomizableUI` is
// available. Once Australis will officially land, we can safely remove it.
// See Bug 959142
try {
require('chrome').Cu.import('resource:///modules/CustomizableUI.jsm', {});
}
catch (e) {
throw Error('Unsupported Application: The module ' + module.id +
' does not support this application.');
}
const { Class } = require('../../core/heritage');
const { merge } = require('../../util/object');
const { Disposable } = require('../../core/disposable');

View File

@ -10,17 +10,6 @@ module.metadata = {
}
};
// Because Firefox Holly, we still need to check if `CustomizableUI` is
// available. Once Australis will officially land, we can safely remove it.
// See Bug 959142
try {
require("chrome").Cu.import("resource:///modules/CustomizableUI.jsm", {});
}
catch (e) {
throw Error("Unsupported Application: The module" + module.id +
" does not support this application.");
}
require("./frame/view");
const { Frame } = require("./frame/model");

View File

@ -10,17 +10,6 @@ module.metadata = {
}
};
// Because Firefox Holly, we still need to check if `CustomizableUI` is
// available. Once Australis will officially land, we can safely remove it.
// See Bug 959142
try {
require("chrome").Cu.import("resource:///modules/CustomizableUI.jsm", {});
}
catch (e) {
throw Error("Unsupported Application: The module" + module.id +
" does not support this application.");
}
const { Toolbar } = require("./toolbar/model");
require("./toolbar/view");

View File

@ -620,76 +620,21 @@ BrowserWindow.prototype = {
let palette = toolbox.palette;
palette.appendChild(node);
if (this.window.CustomizableUI) {
let placement = this.window.CustomizableUI.getPlacementOfWidget(node.id);
if (!placement) {
if (haveInserted(node.id)) {
return;
}
placement = {area: 'nav-bar', position: undefined};
saveInserted(node.id);
}
this.window.CustomizableUI.addWidgetToArea(node.id, placement.area, placement.position);
this.window.CustomizableUI.ensureWidgetPlacedInWindow(node.id, this.window);
return;
}
let { CustomizableUI } = this.window;
let { id } = node;
// Search for widget toolbar by reading toolbar's currentset attribute
let container = null;
let toolbars = this.doc.getElementsByTagName("toolbar");
let id = node.getAttribute("id");
for (let i = 0, l = toolbars.length; i < l; i++) {
let toolbar = toolbars[i];
if (toolbar.getAttribute("currentset").indexOf(id) == -1)
continue;
container = toolbar;
}
let placement = CustomizableUI.getPlacementOfWidget(id);
// if widget isn't in any toolbar, add it to the addon-bar
let needToPropagateCurrentset = false;
if (!container) {
if (haveInserted(node.id)) {
if (!placement) {
if (haveInserted(id))
return;
}
container = this.doc.getElementById("addon-bar");
saveInserted(node.id);
needToPropagateCurrentset = true;
// TODO: find a way to make the following code work when we use "cfx run":
// http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#8586
// until then, force display of addon bar directly from sdk code
// https://bugzilla.mozilla.org/show_bug.cgi?id=627484
if (container.collapsed)
this.window.toggleAddonBar();
placement = {area: 'nav-bar', position: undefined};
saveInserted(id);
}
// Now retrieve a reference to the next toolbar item
// by reading currentset attribute on the toolbar
let nextNode = null;
let currentSet = container.getAttribute("currentset");
let ids = (currentSet == "__empty") ? [] : currentSet.split(",");
let idx = ids.indexOf(id);
if (idx != -1) {
for (let i = idx; i < ids.length; i++) {
nextNode = this.doc.getElementById(ids[i]);
if (nextNode)
break;
}
}
// Finally insert our widget in the right toolbar and in the right position
container.insertItem(id, nextNode, null, false);
// Update DOM in order to save position: which toolbar, and which position
// in this toolbar. But only do this the first time we add it to the toolbar
// Otherwise, this code will collide with other instance of Widget module
// during Firefox startup. See bug 685929.
if (ids.indexOf(id) == -1) {
let set = container.currentSet;
container.setAttribute("currentset", set);
// Save DOM attribute in order to save position on new window opened
this.window.document.persist(container.id, "currentset");
browserManager.propagateCurrentset(container.id, set);
}
CustomizableUI.addWidgetToArea(id, placement.area, placement.position);
CustomizableUI.ensureWidgetPlacedInWindow(id, this.window);
}
}
@ -756,9 +701,8 @@ WidgetChrome.prototype._createNode = function WC__createNode() {
// For use in styling by the browser
node.setAttribute("sdkstylewidget", "true");
// Mark wide widgets as such:
if (this.window.CustomizableUI &&
this._widget.width > AUSTRALIS_PANEL_WIDE_WIDGET_CUTOFF) {
if (this._widget.width > AUSTRALIS_PANEL_WIDE_WIDGET_CUTOFF) {
node.classList.add("panel-wide-item");
}

View File

@ -224,17 +224,11 @@ const Sandbox = iced(function Sandbox(options) {
wantGlobalProperties: 'wantGlobalProperties' in options ?
options.wantGlobalProperties : [],
sandboxPrototype: 'prototype' in options ? options.prototype : {},
sameGroupAs: 'sandbox' in options ? options.sandbox : null,
invisibleToDebugger: 'invisibleToDebugger' in options ?
options.invisibleToDebugger : false,
metadata: 'metadata' in options ? options.metadata : {}
};
// Make `options.sameGroupAs` only if `sandbox` property is passed,
// otherwise `Cu.Sandbox` will throw.
if (!options.sameGroupAs)
delete options.sameGroupAs;
let sandbox = Cu.Sandbox(options.principal, options);
// Each sandbox at creation gets set of own properties that will be shadowing
@ -291,9 +285,6 @@ const load = iced(function load(loader, module) {
let sandbox = sandboxes[module.uri] = Sandbox({
name: module.uri,
// Get an existing module sandbox, if any, so we can reuse its compartment
// when creating the new one to reduce memory consumption.
sandbox: sandboxes[keys(sandboxes).shift()],
prototype: create(globals, descriptors),
wantXrays: false,
wantGlobalProperties: module.id == "sdk/indexed-db" ? ["indexedDB"] : [],

View File

@ -11,7 +11,8 @@ const { setTimeout } = require('sdk/timers');
const app = require("sdk/system/xul-app");
const tabs = require('sdk/tabs');
const isAustralis = "gCustomizeMode" in windows.activeBrowserWindow;
const { set: setPref } = require("sdk/preferences/service");
const { set: setPref, get: getPref } = require("sdk/preferences/service");
const { PrefsTarget } = require("sdk/preferences/event-target");
const { defer } = require('sdk/core/promise');
const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
@ -42,20 +43,31 @@ function isChromeVisible(window) {
// module.metadata.engines
if (app.is('Firefox')) {
exports['test add-on page deprecation message'] = function(assert) {
exports['test add-on page deprecation message'] = function(assert, done) {
let { loader, messages } = LoaderWithHookedConsole(module);
loader.require('sdk/addon-page');
loader.require('sdk/preferences/event-target').PrefsTarget({
branchName: "devtools.errorconsole."
}).on("deprecation_warnings", function() {
if (!getPref(DEPRECATE_PREF, false)) {
return undefined;
}
loader.require('sdk/addon-page');
assert.equal(messages.length, 1, "only one error is dispatched");
assert.equal(messages[0].type, "error", "the console message is an error");
let msg = messages[0].msg;
assert.ok(msg.indexOf("DEPRECATED") === 0,
"The message is deprecation message");
loader.unload();
done();
return undefined;
});
setPref(DEPRECATE_PREF, false);
setPref(DEPRECATE_PREF, true);
assert.equal(messages.length, 1, "only one error is dispatched");
assert.equal(messages[0].type, "error", "the console message is an error");
let msg = messages[0].msg;
assert.ok(msg.indexOf("DEPRECATED") === 0,
"The message is deprecation message");
loader.unload();
};
exports['test that add-on page has no chrome'] = function(assert, done) {

View File

@ -921,7 +921,6 @@ exports['test unique tab ids'] = function(assert, done) {
var { all, defer } = require('sdk/core/promise');
function openWindow() {
// console.log('in openWindow');
let deferred = defer();
let win = windows.open({
url: "data:text/html;charset=utf-8,<html>foo</html>",

View File

@ -260,8 +260,7 @@ exports["test Object Listener 2"] = createProxyTest("", function (helper) {
let html = '<input id="input" type="text" /><input id="input3" type="checkbox" />' +
'<input id="input2" type="checkbox" />';
/* Disable test to keep tree green until Bug 756214 is fixed.
exports.testStringOverload = createProxyTest(html, function (helper, test) {
exports.testStringOverload = createProxyTest(html, function (helper, assert) {
// Proxy - toString error
let originalString = "string";
let p = Proxy.create({
@ -271,10 +270,10 @@ exports.testStringOverload = createProxyTest(html, function (helper, test) {
return originalString[name];
}
});
assert.okRaises(function () {
assert.throws(function () {
p.toString();
},
/String.prototype.toString called on incompatible Proxy/,
/toString method called on incompatible Proxy/,
"toString can't be called with this being the proxy");
assert.equal(p.binded(), "string", "but it works if we bind this to the original string");
@ -296,7 +295,6 @@ exports.testStringOverload = createProxyTest(html, function (helper, test) {
}
);
});
*/
exports["test MozMatchedSelector"] = createProxyTest("", function (helper) {
helper.createWorker(
@ -517,8 +515,6 @@ exports["test Window Frames"] = createProxyTest(html, function (helper) {
let iframe = document.getElementById("iframe");
//assert(window.frames.length == 1, "The iframe is reported in window.frames check1");
//assert(window.frames[0] == iframe.contentWindow, "The iframe is reported in window.frames check2");
//console.log(window.test+ "-"+iframe.contentWindow);
//console.log(window);
assert(window.test == iframe.contentWindow, "window[frameName] is valid");
done();
}

View File

@ -76,7 +76,7 @@ exports["test:communication with worker global scope"] = function(assert, done)
let window = makeWindow();
let contentSymbiont;
console.log(window)
assert.ok(!!window, 'there is a window');
function onMessage1(message) {
assert.equal(message, 1, "Program gets message via onMessage.");

View File

@ -543,7 +543,6 @@ exports.testPageReload = function (assert, done) {
label: "item",
contentScript: 'self.postMessage("loaded"); self.on("detach", function () { console.log("saw detach"); self.postMessage("detach") });',
onMessage: function (msg) {
console.log("Saw " + msg)
switch (msg) {
case "loaded":
assert.ok(loadExpected, "Should have seen the load event at the right time");
@ -3490,7 +3489,7 @@ exports.testPredicateContextTargetSrcSet = function (assert, done) {
let test = new TestHelper(assert, done);
let loader = test.newLoader();
let image;
let items = [loader.cm.Item({
label: "item",
context: loader.cm.PredicateContext(function (data) {
@ -3512,7 +3511,7 @@ exports.testPredicateContextTargetSrcSet = function (assert, done) {
exports.testPredicateContextTargetSrcNotSet = function (assert, done) {
let test = new TestHelper(assert, done);
let loader = test.newLoader();
let items = [loader.cm.Item({
label: "item",
context: loader.cm.PredicateContext(function (data) {
@ -3535,7 +3534,7 @@ exports.testPredicateContextTargetLinkSet = function (assert, done) {
let test = new TestHelper(assert, done);
let loader = test.newLoader();
let image;
let items = [loader.cm.Item({
label: "item",
context: loader.cm.PredicateContext(function (data) {
@ -3556,7 +3555,7 @@ exports.testPredicateContextTargetLinkSet = function (assert, done) {
exports.testPredicateContextTargetLinkNotSet = function (assert, done) {
let test = new TestHelper(assert, done);
let loader = test.newLoader();
let items = [loader.cm.Item({
label: "item",
context: loader.cm.PredicateContext(function (data) {
@ -3578,7 +3577,7 @@ exports.testPredicateContextTargetValueSet = function (assert, done) {
let test = new TestHelper(assert, done);
let loader = test.newLoader();
let image;
let items = [loader.cm.Item({
label: "item",
context: loader.cm.PredicateContext(function (data) {
@ -3599,7 +3598,7 @@ exports.testPredicateContextTargetValueSet = function (assert, done) {
exports.testPredicateContextTargetValueNotSet = function (assert, done) {
let test = new TestHelper(assert, done);
let loader = test.newLoader();
let items = [loader.cm.Item({
label: "item",
context: loader.cm.PredicateContext(function (data) {

View File

@ -440,23 +440,24 @@ exports["test debounce"] = (assert, done) => {
exports["test throttle"] = (assert, done) => {
let called = 0;
let attempt = 0;
let throttledFn = throttle(() => called++, 100);
let atleast100ms = false;
let throttledFn = throttle(() => {
called++;
if (called === 2) {
assert.equal(attempt, 10, "called twice, but attempted 10 times");
fn();
}
if (called === 3) {
assert.ok(atleast100ms, "atleast 100ms have passed");
assert.equal(attempt, 11, "called third, waits for delay to happen");
done();
}
}, 200);
let fn = () => ++attempt && throttledFn();
new Array(11).join(0).split("").forEach((_, i) => {
setTimeout(fn, 20 * (i+1));
});
setTimeout(() => atleast100ms = true, 100);
setTimeout(() => {
assert.equal(called, 1, "function called atleast once during first throttle period");
assert.ok(attempt >= 2, "function attempted to be called several times during first period");
}, 50);
setTimeout(() => {
assert.equal(called, 3, "function called again during second throttle period");
assert.equal(attempt, 10, "function attempted to be called several times during second period");
done();
}, 300);
new Array(11).join(0).split("").forEach(fn);
};
require('test').run(exports);

View File

@ -532,7 +532,7 @@ exports.testContentScriptWhenForNewTabs = function(assert, done) {
handleReadyState(url, 'start', {
onLoading: (tab) => {
assert.pass("PageMod is attached while document is loading");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onInteractive: () => assert.fail("onInteractive should not be called with 'start'."),
@ -542,7 +542,7 @@ exports.testContentScriptWhenForNewTabs = function(assert, done) {
handleReadyState(url, 'ready', {
onInteractive: (tab) => {
assert.pass("PageMod is attached while document is interactive");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onLoading: () => assert.fail("onLoading should not be called with 'ready'."),
@ -552,7 +552,7 @@ exports.testContentScriptWhenForNewTabs = function(assert, done) {
handleReadyState(url, 'end', {
onComplete: (tab) => {
assert.pass("PageMod is attached when document is complete");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onLoading: () => assert.fail("onLoading should not be called with 'end'."),
@ -575,7 +575,7 @@ exports.testContentScriptWhenOnTabOpen = function(assert, done) {
handleReadyState(url, 'start', {
onLoading: () => {
assert.pass("PageMod is attached while document is loading");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onInteractive: () => assert.fail("onInteractive should not be called with 'start'."),
@ -585,7 +585,7 @@ exports.testContentScriptWhenOnTabOpen = function(assert, done) {
handleReadyState(url, 'ready', {
onInteractive: () => {
assert.pass("PageMod is attached while document is interactive");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onLoading: () => assert.fail("onLoading should not be called with 'ready'."),
@ -595,7 +595,7 @@ exports.testContentScriptWhenOnTabOpen = function(assert, done) {
handleReadyState(url, 'end', {
onComplete: () => {
assert.pass("PageMod is attached when document is complete");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onLoading: () => assert.fail("onLoading should not be called with 'end'."),
@ -619,7 +619,7 @@ exports.testContentScriptWhenOnTabReady = function(assert, done) {
handleReadyState(url, 'start', {
onInteractive: () => {
assert.pass("PageMod is attached while document is interactive");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onLoading: () => assert.fail("onLoading should not be called with 'start'."),
@ -629,7 +629,7 @@ exports.testContentScriptWhenOnTabReady = function(assert, done) {
handleReadyState(url, 'ready', {
onInteractive: () => {
assert.pass("PageMod is attached while document is interactive");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onLoading: () => assert.fail("onLoading should not be called with 'ready'."),
@ -639,7 +639,7 @@ exports.testContentScriptWhenOnTabReady = function(assert, done) {
handleReadyState(url, 'end', {
onComplete: () => {
assert.pass("PageMod is attached when document is complete");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onLoading: () => assert.fail("onLoading should not be called with 'end'."),
@ -663,7 +663,7 @@ exports.testContentScriptWhenOnTabLoad = function(assert, done) {
handleReadyState(url, 'start', {
onComplete: () => {
assert.pass("PageMod is attached when document is complete");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onLoading: () => assert.fail("onLoading should not be called with 'start'."),
@ -673,7 +673,7 @@ exports.testContentScriptWhenOnTabLoad = function(assert, done) {
handleReadyState(url, 'ready', {
onComplete: () => {
assert.pass("PageMod is attached when document is complete");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onLoading: () => assert.fail("onLoading should not be called with 'ready'."),
@ -683,7 +683,7 @@ exports.testContentScriptWhenOnTabLoad = function(assert, done) {
handleReadyState(url, 'end', {
onComplete: () => {
assert.pass("PageMod is attached when document is complete");
if (++count === 3)
if (++count === 3)
tab.close(done);
},
onLoading: () => assert.fail("onLoading should not be called with 'end'."),
@ -764,7 +764,6 @@ exports.testAutomaticDestroy = function(assert, done) {
};
exports.testAttachToTabsOnly = function(assert, done) {
let { PageMod } = require('sdk/page-mod');
let openedTab = null; // Tab opened in openTabWithIframe()
let workerCount = 0;
@ -789,6 +788,7 @@ exports.testAttachToTabsOnly = function(assert, done) {
});
function openHiddenFrame() {
assert.pass('Open iframe in hidden window');
let hiddenFrames = require('sdk/frame/hidden-frame');
let hiddenFrame = hiddenFrames.add(hiddenFrames.HiddenFrame({
onReady: function () {
@ -810,6 +810,7 @@ exports.testAttachToTabsOnly = function(assert, done) {
}
function openToplevelWindow() {
assert.pass('Open toplevel window');
let win = open('data:text/html;charset=utf-8,bar');
win.addEventListener('DOMContentLoaded', function onload() {
win.removeEventListener('DOMContentLoaded', onload, false);
@ -819,6 +820,7 @@ exports.testAttachToTabsOnly = function(assert, done) {
}
function openBrowserIframe() {
assert.pass('Open iframe in browser window');
let window = require('sdk/deprecated/window-utils').activeBrowserWindow;
let document = window.document;
let iframe = document.createElement('iframe');
@ -834,6 +836,7 @@ exports.testAttachToTabsOnly = function(assert, done) {
// Only these three documents will be accepted by the page-mod
function openTabWithIframes() {
assert.pass('Open iframes in a tab');
let subContent = '<iframe src="data:text/html;charset=utf-8,sub frame" />'
let content = '<iframe src="data:text/html;charset=utf-8,' +
encodeURIComponent(subContent) + '" />';
@ -1368,6 +1371,8 @@ exports.testWorkerTabClose = function(assert, done) {
include: "about:",
contentScript: '',
onAttach: function(worker) {
assert.pass("The page-mod was attached");
worker.tab.close(function () {
// On Fennec, tab is completely destroyed right after close event is
// dispatch, so we need to wait for the next event loop cycle to

View File

@ -123,7 +123,6 @@ exports['test the weird objects, that they get parsed properly'] = function(asse
exports['test non munge test cases'] = function(assert) {
qsNoMungeTestCases.forEach(function(testCase) {
//console.log(testCase[0], JSON.stringify(testCase[1]), qs.stringify(testCase[1], '&', '=', false));
assert.deepEqual(testCase[0], qs.stringify(testCase[1], '&', '=', false),
'stringify ' + JSON.stringify(testCase[1]) + ' -> & =');
});

View File

@ -859,19 +859,4 @@ exports['test button after destroy'] = function(assert) {
loader.unload();
};
// If the module doesn't support the app we're being run in, require() will
// throw. In that case, remove all tests above from exports, and add one dummy
// test that passes.
try {
require('sdk/ui/button/action');
}
catch (err) {
if (!/^Unsupported Application/.test(err.message))
throw err;
module.exports = {
'test Unsupported Application': assert => assert.pass(err.message)
}
}
require('sdk/test').run(exports);

View File

@ -1058,19 +1058,4 @@ exports['test buttons can have anchored panels'] = function(assert, done) {
button.click();
}
// If the module doesn't support the app we're being run in, require() will
// throw. In that case, remove all tests above from exports, and add one dummy
// test that passes.
try {
require('sdk/ui/button/toggle');
}
catch (err) {
if (!/^Unsupported Application/.test(err.message))
throw err;
module.exports = {
'test Unsupported Application': assert => assert.pass(err.message)
}
}
require('sdk/test').run(exports);

View File

@ -28,8 +28,6 @@ try {
jetpackID = require("sdk/self").id;
} catch(e) {}
const australis = !!require("sdk/window/utils").getMostRecentBrowserWindow().CustomizableUI;
function openNewWindowTab(url, options) {
return open('chrome://browser/content/browser.xul', {
features: {
@ -49,23 +47,19 @@ exports.testConstructor = function(assert, done) {
let browserWindow = windowUtils.activeBrowserWindow;
let doc = browserWindow.document;
let AddonsMgrListener;
if (australis) {
AddonsMgrListener = {
onInstalling: () => {},
onInstalled: () => {},
onUninstalling: () => {},
onUninstalled: () => {}
};
}
else {
AddonsMgrListener = browserWindow.AddonsMgrListener;
}
function container() australis ? doc.getElementById("nav-bar") : doc.getElementById("addon-bar");
function getWidgets() container() ? container().querySelectorAll('[id^="widget\:"]') : [];
function widgetCount() getWidgets().length;
AddonsMgrListener = {
onInstalling: () => {},
onInstalled: () => {},
onUninstalling: () => {},
onUninstalled: () => {}
};
let container = () => doc.getElementById("nav-bar");
let getWidgets = () => container() ? container().querySelectorAll('[id^="widget\:"]') : [];
let widgetCount = () => getWidgets().length;
let widgetStartCount = widgetCount();
function widgetNode(index) getWidgets()[index];
let widgetNode = (index) => getWidgets()[index];
// Test basic construct/destroy
AddonsMgrListener.onInstalling();
@ -172,38 +166,13 @@ exports.testConstructor = function(assert, done) {
w3.destroy();
AddonsMgrListener.onUninstalled();
// Test concurrent widget module instances on addon-bar hiding
if (!australis) {
let loader = Loader(module);
let anotherWidgetsInstance = loader.require("sdk/widget");
assert.ok(container().collapsed, "UI is hidden when no widgets");
AddonsMgrListener.onInstalling();
let w1 = widgets.Widget({id: "ui-unhide", label: "foo", content: "bar"});
// Ideally we would let AddonsMgrListener display the addon bar
// But, for now, addon bar is immediatly displayed by sdk code
// https://bugzilla.mozilla.org/show_bug.cgi?id=627484
assert.ok(!container().collapsed, "UI is already visible when we just added the widget");
AddonsMgrListener.onInstalled();
assert.ok(!container().collapsed, "UI become visible when we notify AddonsMgrListener about end of addon installation");
let w2 = anotherWidgetsInstance.Widget({id: "ui-stay-open", label: "bar", content: "foo"});
assert.ok(!container().collapsed, "UI still visible when we add a second widget");
AddonsMgrListener.onUninstalling();
w1.destroy();
AddonsMgrListener.onUninstalled();
assert.ok(!container().collapsed, "UI still visible when we remove one of two widgets");
AddonsMgrListener.onUninstalling();
w2.destroy();
assert.ok(!container().collapsed, "UI is still visible when we have removed all widget but still not called onUninstalled");
AddonsMgrListener.onUninstalled();
assert.ok(container().collapsed, "UI is hidden when we have removed all widget and called onUninstalled");
}
// Helper for testing a single widget.
// Confirms proper addition and content setup.
function testSingleWidget(widgetOptions) {
// We have to display which test is being run, because here we do not
// use the regular test framework but rather a custom one that iterates
// the `tests` array.
console.info("executing: " + widgetOptions.id);
assert.pass("executing: " + widgetOptions.id);
let startCount = widgetCount();
let widget = widgets.Widget(widgetOptions);
@ -530,13 +499,13 @@ exports.testConstructor = function(assert, done) {
// test multiple windows
tests.push(function testMultipleWindows() {
console.log('executing test multiple windows');
assert.pass('executing test multiple windows');
openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) {
let browserWindow = e.target.defaultView;
assert.ok(browserWindow, 'window was opened');
let doc = browserWindow.document;
function container() australis ? doc.getElementById("nav-bar") : doc.getElementById("addon-bar");
function widgetCount2() container() ? container().querySelectorAll('[id^="widget\:"]').length : 0;
let container = () => doc.getElementById("nav-bar");
let widgetCount2 = () => container() ? container().querySelectorAll('[id^="widget\:"]').length : 0;
let widgetStartCount2 = widgetCount2();
let w1Opts = {id:"first-multi-window", label: "first widget", content: "first content"};
@ -777,17 +746,7 @@ exports.testPanelWidget3 = function testPanelWidget3(assert, done) {
};
exports.testWidgetWithPanelInMenuPanel = function(assert, done) {
let CustomizableUI;
try {
({CustomizableUI}) = Cu.import("resource:///modules/CustomizableUI.jsm", {});
}
catch (e) {
assert.pass("Test skipped: no CustomizableUI object found.");
done();
return;
}
const { CustomizableUI } = Cu.import("resource:///modules/CustomizableUI.jsm", {});
const widgets = require("sdk/widget");
let widget1 = widgets.Widget({
@ -1141,15 +1100,8 @@ exports.testReinsertion = function(assert, done) {
});
let realWidgetId = "widget:" + jetpackID + "-" + WIDGETID;
// Remove the widget:
if (australis) {
browserWindow.CustomizableUI.removeWidgetFromArea(realWidgetId);
} else {
let widget = browserWindow.document.getElementById(realWidgetId);
let container = widget.parentNode;
container.currentSet = container.currentSet.replace("," + realWidgetId, "");
container.setAttribute("currentset", container.currentSet);
container.ownerDocument.persist(container.id, "currentset");
}
browserWindow.CustomizableUI.removeWidgetFromArea(realWidgetId);
openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) {
assert.equal(e.target.defaultView.document.getElementById(realWidgetId), null);
@ -1157,91 +1109,4 @@ exports.testReinsertion = function(assert, done) {
}});
};
if (!australis) {
exports.testNavigationBarWidgets = function testNavigationBarWidgets(assert, done) {
let w1 = widgets.Widget({id: "1st", label: "1st widget", content: "1"});
let w2 = widgets.Widget({id: "2nd", label: "2nd widget", content: "2"});
let w3 = widgets.Widget({id: "3rd", label: "3rd widget", content: "3"});
// First wait for all 3 widgets to be added to the current browser window
let firstAttachCount = 0;
function onAttachFirstWindow(widget) {
if (++firstAttachCount<3)
return;
onWidgetsReady();
}
w1.once("attach", onAttachFirstWindow);
w2.once("attach", onAttachFirstWindow);
w3.once("attach", onAttachFirstWindow);
function getWidgetNode(toolbar, position) {
return toolbar.getElementsByTagName("toolbaritem")[position];
}
function openBrowserWindow() {
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
let urlString = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
urlString.data = "about:blank";
return ww.openWindow(null, "chrome://browser/content/browser.xul",
"_blank", "chrome,all,dialog=no", urlString);
}
// Then move them before openeing a new browser window
function onWidgetsReady() {
// Hack to move 2nd and 3rd widgets manually to the navigation bar right after
// the search box.
let browserWindow = windowUtils.activeBrowserWindow;
let doc = browserWindow.document;
let addonBar = doc.getElementById("addon-bar");
let w2ToolbarItem = getWidgetNode(addonBar, 1);
let w3ToolbarItem = getWidgetNode(addonBar, 2);
let navBar = doc.getElementById("nav-bar");
let searchBox = doc.getElementById("search-container");
// Insert 3rd at the right of search box by adding it before its right sibling
navBar.insertItem(w3ToolbarItem.id, searchBox.nextSibling, null, false);
// Then insert 2nd before 3rd
navBar.insertItem(w2ToolbarItem.id, w3ToolbarItem, null, false);
// Widget and Firefox codes rely on this `currentset` attribute,
// so ensure it is correctly saved
navBar.setAttribute("currentset", navBar.currentSet);
doc.persist(navBar.id, "currentset");
// Update addonbar too as we removed widget from there.
// Otherwise, widgets may still be added to this toolbar.
addonBar.setAttribute("currentset", addonBar.currentSet);
doc.persist(addonBar.id, "currentset");
// Wait for all widget to be attached to this new window before checking
// their position
let attachCount = 0;
let browserWindow2;
function onAttach(widget) {
if (++attachCount < 3)
return;
let doc = browserWindow2.document;
let addonBar = doc.getElementById("addon-bar");
let searchBox = doc.getElementById("search-container");
// Ensure that 1st is in addon bar
assert.equal(getWidgetNode(addonBar, 0).getAttribute("label"), w1.label);
// And that 2nd and 3rd keep their original positions in navigation bar,
// i.e. right after search box
assert.equal(searchBox.nextSibling.getAttribute("label"), w2.label);
assert.equal(searchBox.nextSibling.nextSibling.getAttribute("label"), w3.label);
w1.destroy();
w2.destroy();
w3.destroy();
close(browserWindow2).then(done);
}
w1.on("attach", onAttach);
w2.on("attach", onAttach);
w3.on("attach", onAttach);
browserWindow2 = openBrowserWindow(browserWindow);
}
};
}
require("sdk/test").run(exports);

View File

@ -18,6 +18,14 @@ const { open, close, focus } = require('sdk/window/helpers');
const WM = Cc['@mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator);
const { isPrivate } = require('sdk/private-browsing');
const { fromIterator: toArray } = require('sdk/util/array');
const { defer } = require('sdk/core/promise');
const { setTimeout } = require('sdk/timers');
function tick() {
let deferred = defer();
setTimeout(deferred.resolve);
return deferred.promise;
}
function makeEmptyBrowserWindow(options) {
options = options || {};
@ -64,31 +72,26 @@ exports.testWindowTrackerIgnoresPrivateWindows = function(assert, done) {
assert.equal(getWindowTitle(window), window.document.title,
'getWindowTitle works');
close(window).then(function() {
makeEmptyBrowserWindow().then(function(window) {
return close(window).then(function() {
return makeEmptyBrowserWindow().then(function(window) {
myNonPrivateWindow = window;
assert.pass('opened new window');
window.close();
return close(window);
});
});
});
}).then(null, assert.fail);
};
// Test setting activeWIndow and onFocus for private windows
exports.testSettingActiveWindowDoesNotIgnorePrivateWindow = function(assert, done) {
let browserWindow = WM.getMostRecentWindow("navigator:browser");
let testSteps;
assert.equal(windowUtils.activeBrowserWindow, browserWindow,
"Browser window is the active browser window.");
assert.ok(!isPrivate(browserWindow), "Browser window is not private.");
// make a new private window
makeEmptyBrowserWindow({
private: true
}).then(focus).then(function(window) {
let continueAfterFocus = function(window) onFocus(window).then(nextTest);
makeEmptyBrowserWindow({ private: true }).then(focus).then(window => {
// PWPB case
if (isWindowPBSupported) {
assert.ok(isPrivate(window), "window is private");
@ -104,59 +107,42 @@ exports.testSettingActiveWindowDoesNotIgnorePrivateWindow = function(assert, don
assert.notStrictEqual(browserWindow, window,
"The window is not the old browser window");
testSteps = [
function() {
// test setting a non private window
continueAfterFocus(windowUtils.activeWindow = browserWindow);
},
function() {
assert.strictEqual(windowUtils.activeWindow, browserWindow,
"Correct active window [1]");
assert.strictEqual(windowUtils.activeBrowserWindow, browserWindow,
"Correct active browser window [1]");
// test focus(window)
focus(window).then(nextTest);
},
function(w) {
return onFocus(windowUtils.activeWindow = browserWindow).then(_ => {
assert.strictEqual(windowUtils.activeWindow, browserWindow,
"Correct active window [1]");
assert.strictEqual(windowUtils.activeBrowserWindow, browserWindow,
"Correct active browser window [1]");
// test focus(window)
return focus(window).then(w => {
assert.strictEqual(w, window, 'require("sdk/window/helpers").focus on window works');
assert.strictEqual(windowUtils.activeBrowserWindow, window,
"Correct active browser window [2]");
assert.strictEqual(windowUtils.activeWindow, window,
"Correct active window [2]");
}).then(tick);
}).then(_ => {
assert.strictEqual(windowUtils.activeBrowserWindow, window,
"Correct active browser window [2]");
assert.strictEqual(windowUtils.activeWindow, window,
"Correct active window [2]");
// test setting a private window
continueAfterFocus(windowUtils.activeWindow = window);
},
function() {
assert.deepEqual(windowUtils.activeBrowserWindow, window,
"Correct active browser window [3]");
assert.deepEqual(windowUtils.activeWindow, window,
"Correct active window [3]");
// test setting a private window
return onFocus(windowUtils.activeWindow = window);
}).then(function() {
assert.deepEqual(windowUtils.activeBrowserWindow, window,
"Correct active browser window [3]");
assert.deepEqual(windowUtils.activeWindow, window,
"Correct active window [3]");
// just to get back to original state
continueAfterFocus(windowUtils.activeWindow = browserWindow);
},
function() {
assert.deepEqual(windowUtils.activeBrowserWindow, browserWindow,
"Correct active browser window when pb mode is supported [4]");
assert.deepEqual(windowUtils.activeWindow, browserWindow,
"Correct active window when pb mode is supported [4]");
// just to get back to original state
return onFocus(windowUtils.activeWindow = browserWindow);
}).then(_ => {
assert.deepEqual(windowUtils.activeBrowserWindow, browserWindow,
"Correct active browser window when pb mode is supported [4]");
assert.deepEqual(windowUtils.activeWindow, browserWindow,
"Correct active window when pb mode is supported [4]");
close(window).then(done);
}
];
function nextTest() {
let args = arguments;
if (testSteps.length) {
require('sdk/timers').setTimeout(function() {
(testSteps.shift()).apply(null, args);
}, 0);
}
}
nextTest();
});
return close(window);
})
}).then(done).then(null, assert.fail);
};
exports.testActiveWindowDoesNotIgnorePrivateWindow = function(assert, done) {
@ -195,8 +181,8 @@ exports.testActiveWindowDoesNotIgnorePrivateWindow = function(assert, done) {
assert.equal(isPrivate(window), false, "window is not private");
}
close(window).then(done);
});
return close(window);
}).then(done).then(null, assert.fail);
}
exports.testWindowIteratorIgnoresPrivateWindows = function(assert, done) {
@ -214,11 +200,11 @@ exports.testWindowIteratorIgnoresPrivateWindows = function(assert, done) {
else {
assert.equal(isWindowPrivate(window), false, "window is not private");
assert.ok(toArray(windowUtils.windowIterator()).indexOf(window) > -1,
"window is in windowIterator()");
"window is in windowIterator()");
}
close(window).then(done);
});
return close(window);
}).then(done).then(null, assert.fail);
};
require("test").run(exports);
require("sdk/test").run(exports);