diff --git a/addon-sdk/moz.build b/addon-sdk/moz.build index 5bd2ffa4563..562d2ad86bc 100644 --- a/addon-sdk/moz.build +++ b/addon-sdk/moz.build @@ -1,4 +1,4 @@ -# AUTOMATICALLY GENERATED FROM moz.build.in AND mach. DO NOT EDIT. +# AUTOMATICALLY GENERATED FROM mozbuild.template AND mach. DO NOT EDIT. # 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/. @@ -13,12 +13,15 @@ BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] JETPACK_PACKAGE_MANIFESTS += ['source/test/jetpack-package.ini'] JETPACK_ADDON_MANIFESTS += ['source/test/addons/jetpack-addon.ini'] -DIRS += ["source/modules/system"] - EXTRA_JS_MODULES.sdk += [ 'source/app-extension/bootstrap.js', ] +EXTRA_JS_MODULES.sdk.system += [ + 'source/modules/system/Startup.js', + 'source/modules/system/XulApp.js', +] + if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk": EXTRA_JS_MODULES.commonjs.method.test += [ 'source/lib/method/test/browser.js', @@ -148,6 +151,10 @@ EXTRA_JS_MODULES.commonjs.dev += [ 'source/lib/dev/volcan.js', ] +EXTRA_JS_MODULES.commonjs.dev.panel += [ + 'source/lib/dev/panel/view.js', +] + EXTRA_JS_MODULES.commonjs.diffpatcher += [ 'source/lib/diffpatcher/diff.js', 'source/lib/diffpatcher/index.js', @@ -211,6 +218,7 @@ EXTRA_JS_MODULES.commonjs.sdk.addon += [ 'source/lib/sdk/addon/events.js', 'source/lib/sdk/addon/host.js', 'source/lib/sdk/addon/installer.js', + 'source/lib/sdk/addon/manager.js', 'source/lib/sdk/addon/runner.js', 'source/lib/sdk/addon/window.js', ] diff --git a/addon-sdk/source/app-extension/bootstrap.js b/addon-sdk/source/app-extension/bootstrap.js index 8f80a0b8a0c..e31c75f84c4 100644 --- a/addon-sdk/source/app-extension/bootstrap.js +++ b/addon-sdk/source/app-extension/bootstrap.js @@ -229,6 +229,10 @@ function startup(data, reasonCode) { resultFile: options.resultFile, // Arguments passed as --static-args staticArgs: options.staticArgs, + + // Option to prevent automatic kill of firefox during tests + noQuit: options.no_quit, + // Add-on preferences branch name preferencesBranch: options.preferencesBranch, diff --git a/addon-sdk/source/examples/actor-repl/data/index.html b/addon-sdk/source/examples/actor-repl/data/index.html index 07c47299d12..250ece24953 100644 --- a/addon-sdk/source/examples/actor-repl/data/index.html +++ b/addon-sdk/source/examples/actor-repl/data/index.html @@ -18,40 +18,73 @@ diff --git a/addon-sdk/source/examples/ui-button-apis/lib/main.js b/addon-sdk/source/examples/ui-button-apis/lib/main.js new file mode 100644 index 00000000000..7688a7445be --- /dev/null +++ b/addon-sdk/source/examples/ui-button-apis/lib/main.js @@ -0,0 +1,39 @@ +/* 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/. */ +"use strict"; + +var data = require('sdk/self').data; +var tabs = require('sdk/tabs'); +var { notify } = require('sdk/notifications'); +var { ActionButton, ToggleButton } = require('sdk/ui'); + +var icon = 'chrome://mozapps/skin/extensions/extensionGeneric.png'; +exports.icon = icon; + +// your basic action button +var action = ActionButton({ + id: 'test-action-button', + label: 'Action Button', + icon: icon, + onClick: function (state) { + notify({ + title: "Action!", + text: "This notification was triggered from an action button!", + }); + } +}); +exports.actionButton = action; + +var toggle = ToggleButton({ + id: 'test-toggle-button', + label: 'Toggle Button', + icon: icon, + onClick: function (state) { + notify({ + title: "Toggled!", + text: "The current state of the button is " + state.checked, + }); + } +}); +exports.toggleButton = toggle; diff --git a/addon-sdk/source/examples/ui-button-apis/package.json b/addon-sdk/source/examples/ui-button-apis/package.json new file mode 100644 index 00000000000..2905031e417 --- /dev/null +++ b/addon-sdk/source/examples/ui-button-apis/package.json @@ -0,0 +1,9 @@ +{ + "name": "ui-button-apis", + "title": "Australis Button API Examples", + "id": "ui-button-apis@mozilla.org", + "description": "A Button API example", + "author": "jeff@canuckistani.ca (Jeff Griffiths | @canuckistani)", + "license": "MPL 2.0", + "version": "0.1" +} diff --git a/addon-sdk/source/examples/ui-button-apis/tests/test-main.js b/addon-sdk/source/examples/ui-button-apis/tests/test-main.js new file mode 100644 index 00000000000..88ece12b685 --- /dev/null +++ b/addon-sdk/source/examples/ui-button-apis/tests/test-main.js @@ -0,0 +1,21 @@ +/* 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/. */ +"use strict"; + +var { actionButton, toggleButton, icon } = require("main"); +var self = require("sdk/self"); + +exports.testActionButton = function(assert) { + assert.equal(actionButton.id, "test-action-button", "action button id is correct"); + assert.equal(actionButton.label, "Action Button", "action button label is correct"); + assert.equal(actionButton.icon, icon, "action button icon is correct"); +} + +exports.testToggleButton = function(assert) { + assert.equal(toggleButton.id, "test-toggle-button", "toggle button id is correct"); + assert.equal(toggleButton.label, "Toggle Button", "toggle button label is correct"); + assert.equal(toggleButton.icon, icon, "toggle button icon is correct"); +} + +require("sdk/test").run(exports); diff --git a/addon-sdk/source/lib/dev/debuggee.js b/addon-sdk/source/lib/dev/debuggee.js index 9c852de74a2..fbefe317c0b 100644 --- a/addon-sdk/source/lib/dev/debuggee.js +++ b/addon-sdk/source/lib/dev/debuggee.js @@ -22,7 +22,6 @@ const inputFor = port => inputs.get(port); const outputFor = port => outputs.get(port); const transportFor = port => transports.get(port); - const fromTarget = target => { const debuggee = new Debuggee(); const { port1, port2 } = new MessageChannel(); diff --git a/addon-sdk/source/lib/dev/panel.js b/addon-sdk/source/lib/dev/panel.js index c6624932898..1fc3fe14299 100644 --- a/addon-sdk/source/lib/dev/panel.js +++ b/addon-sdk/source/lib/dev/panel.js @@ -8,7 +8,6 @@ module.metadata = { "stability": "experimental" }; - const { Cu } = require("chrome"); const { Class } = require("../sdk/core/heritage"); const { curry } = require("../sdk/lang/functional"); @@ -21,12 +20,13 @@ const { contract, validate } = require("../sdk/util/contract"); const { data: { url: resolve }} = require("../sdk/self"); const { identify } = require("../sdk/ui/id"); const { isLocalURL, URL } = require("../sdk/url"); -const { defer } = require("../sdk/core/promise"); const { encode } = require("../sdk/base64"); const { marshal, demarshal } = require("./ports"); const { fromTarget } = require("./debuggee"); const { removed } = require("../sdk/dom/events"); const { id: addonID } = require("../sdk/self"); +const { viewFor } = require("../sdk/view/core"); +const { createView } = require("./panel/view"); const OUTER_FRAME_URI = module.uri.replace(/\.js$/, ".html"); const FRAME_SCRIPT = module.uri.replace("/panel.js", "/frame-script.js"); @@ -56,6 +56,9 @@ const panelFor = frame => panels.get(frame); const debuggees = new WeakMap(); const debuggeeFor = panel => debuggees.get(panel); +const frames = new WeakMap(); +const frameFor = panel => frames.get(panel); + const setAttributes = (node, attributes) => { for (var key in attributes) node.setAttribute(key, attributes[key]); @@ -165,22 +168,29 @@ setup.define(Panel, (panel, {window, toolbox, url}) => { // we obtain original iframe and replace it with the one that has // desired configuration. const original = getFrameElement(window); - const frame = original.cloneNode(true); + const container = original.parentNode; + original.remove(); + const frame = createView(panel, container.ownerDocument); + // Following modifications are a temporary workaround until Bug 1049188 + // is fixed. + // Enforce certain iframe customizations regardless of users request. setAttributes(frame, { + "id": original.id, "src": url, - "sandbox": "allow-scripts", - // It would be great if we could allow remote iframes for sandboxing - // panel documents in a content process, but for now platform implementation - // is buggy on linux so this is disabled. - // "remote": true, - "type": "content", - "transparent": true, - "seamless": "seamless" + "flex": 1, + "forceOwnRefreshDriver": "", + "tooltip": "aHTMLTooltip" }); - - original.parentNode.replaceChild(frame, original); frame.style.visibility = "hidden"; + frame.classList.add("toolbox-panel-iframe"); + // Inject iframe into designated node until add-on author decides + // to inject it elsewhere instead. + if (!frame.parentNode) + container.appendChild(frame); + + // associate view with a panel + frames.set(panel, frame); // associate panel model with a frame view. panels.set(frame, panel); @@ -213,11 +223,29 @@ setup.define(Panel, (panel, {window, toolbox, url}) => { panel.setup({ debuggee: debuggee }); }); +createView.define(Panel, (panel, document) => { + const frame = document.createElement("iframe"); + setAttributes(frame, { + "sandbox": "allow-scripts", + // It would be great if we could allow remote iframes for sandboxing + // panel documents in a content process, but for now platform implementation + // is buggy on linux so this is disabled. + // "remote": true, + "type": "content", + "transparent": true, + "seamless": "seamless", + }); + return frame; +}); + dispose.define(Panel, function(panel) { debuggeeFor(panel).close(); debuggees.delete(panel); managers.delete(panel); + frames.delete(panel); panel.readyState = "destroyed"; panel.dispose(); }); + +viewFor.define(Panel, frameFor); diff --git a/addon-sdk/source/lib/dev/panel/view.js b/addon-sdk/source/lib/dev/panel/view.js new file mode 100644 index 00000000000..41cf9c221f9 --- /dev/null +++ b/addon-sdk/source/lib/dev/panel/view.js @@ -0,0 +1,14 @@ +/* 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/. */ + +"use strict"; + +module.metadata = { + "stability": "experimental" +}; + +const { method } = require("method/core"); + +const createView = method("dev/panel/view#createView"); +exports.createView = createView; diff --git a/addon-sdk/source/lib/sdk/addon/manager.js b/addon-sdk/source/lib/sdk/addon/manager.js new file mode 100644 index 00000000000..7ac0a7d6eb7 --- /dev/null +++ b/addon-sdk/source/lib/sdk/addon/manager.js @@ -0,0 +1,18 @@ +/* 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/. */ +"use strict"; + +module.metadata = { + "stability": "experimental" +}; + +const { AddonManager } = require("resource://gre/modules/AddonManager.jsm"); +const { defer } = require("../core/promise"); + +function getAddonByID(id) { + let { promise, resolve } = defer(); + AddonManager.getAddonByID(id, resolve); + return promise; +} +exports.getAddonByID = getAddonByID; diff --git a/addon-sdk/source/lib/sdk/content/content-worker.js b/addon-sdk/source/lib/sdk/content/content-worker.js index de595616b36..4fef8c84307 100644 --- a/addon-sdk/source/lib/sdk/content/content-worker.js +++ b/addon-sdk/source/lib/sdk/content/content-worker.js @@ -46,15 +46,9 @@ Object.freeze({ } return results; } - function hasListenerFor(name) { - if (!(name in listeners)) - return false; - return listeners[name].length > 0; - } return { eventEmitter: eventEmitter, - emit: onEvent, - hasListenerFor: hasListenerFor + emit: onEvent }; }, @@ -83,7 +77,7 @@ Object.freeze({ emitToChrome(str); } - let { eventEmitter, emit, hasListenerFor } = + let { eventEmitter, emit } = ContentWorker.createEventEmitter(onEvent); return { @@ -95,8 +89,7 @@ Object.freeze({ // and modules (only used for context-menu API) let args = typeof array == "string" ? JSON.parse(array) : array; return emit.apply(null, args); - }, - hasListenerFor: hasListenerFor + } }; }, @@ -325,7 +318,7 @@ Object.freeze({ inject: function (exports, chromeAPI, emitToChrome, options) { let ContentWorker = this; - let { pipe, onChromeEvent, hasListenerFor } = + let { pipe, onChromeEvent } = ContentWorker.createPipe(emitToChrome); ContentWorker.injectConsole(exports, pipe); @@ -337,9 +330,6 @@ Object.freeze({ Object.freeze( exports.self ); - return { - emitToContent: onChromeEvent, - hasListenerFor: hasListenerFor - }; + return onChromeEvent; } }); diff --git a/addon-sdk/source/lib/sdk/content/sandbox.js b/addon-sdk/source/lib/sdk/content/sandbox.js index abbd437a196..d63ca8c5416 100644 --- a/addon-sdk/source/lib/sdk/content/sandbox.js +++ b/addon-sdk/source/lib/sdk/content/sandbox.js @@ -77,15 +77,6 @@ const WorkerSandbox = Class({ return emitToContent(this, args); }, - /** - * Tells if content script has at least one listener registered for one event, - * through `self.on('xxx', ...)`. - * /!\ Shouldn't be used. Implemented to avoid breaking context-menu API. - */ - hasListenerFor: function hasListenerFor(name) { - return modelFor(this).hasListenerFor(name); - }, - /** * Configures sandbox and loads content scripts into it. * @param {Worker} worker @@ -190,10 +181,9 @@ const WorkerSandbox = Class({ let chromeAPI = createChromeAPI(); let result = Cu.waiveXrays(ContentWorker).inject(content, chromeAPI, onEvent, options); - // Merge `emitToContent` and `hasListenerFor` into our private - // model of the WorkerSandbox so we can communicate with content - // script - merge(model, result); + // Merge `emitToContent` into our private model of the + // WorkerSandbox so we can communicate with content script + model.emitToContent = result; let console = new PlainTextConsole(null, getInnerId(window)); diff --git a/addon-sdk/source/lib/sdk/context-menu.js b/addon-sdk/source/lib/sdk/context-menu.js index 29d53a85717..4fe0baffc66 100644 --- a/addon-sdk/source/lib/sdk/context-menu.js +++ b/addon-sdk/source/lib/sdk/context-menu.js @@ -48,8 +48,9 @@ const OVERFLOW_THRESH_PREF = // The label of the overflow sub-xul:menu. // -// TODO: Localize this. +// TODO: Localize these. const OVERFLOW_MENU_LABEL = "Add-ons"; +const OVERFLOW_MENU_ACCESSKEY = "A"; // The class of the overflow sub-xul:menu. const OVERFLOW_MENU_CLASS = "addon-content-menu-overflow-menu"; @@ -277,7 +278,7 @@ function removeItemFromArray(array, item) { // Converts anything that isn't false, null or undefined into a string function stringOrNull(val) val ? String(val) : val; -// Shared option validation rules for Item and Menu +// Shared option validation rules for Item, Menu, and Separator let baseItemRules = { parentMenu: { is: ["object", "undefined"], @@ -313,6 +314,17 @@ let labelledItemRules = mix(baseItemRules, { ok: function (v) !!v, msg: "The item must have a non-empty string label." }, + accesskey: { + map: stringOrNull, + is: ["string", "undefined", "null"], + ok: (v) => { + if (!v) { + return true; + } + return typeof v == "string" && v.length === 1; + }, + msg: "The item must have a single character accesskey, or no accesskey." + }, image: { map: stringOrNull, is: ["string", "undefined", "null"], @@ -352,18 +364,15 @@ let menuRules = mix(labelledItemRules, { let ContextWorker = Class({ implements: [ Worker ], - //Returns true if any context listeners are defined in the worker's port. - anyContextListeners: function anyContextListeners() { - return this.getSandbox().hasListenerFor("context"); - }, - // Calls the context workers context listeners and returns the first result // that is either a string or a value that evaluates to true. If all of the - // listeners returned false then returns false. If there are no listeners - // then returns null. + // listeners returned false then returns false. If there are no listeners, + // returns true (show the menu item by default). getMatchedContext: function getCurrentContexts(popupNode) { let results = this.getSandbox().emitSync("context", popupNode); - return results.reduce(function(val, result) val || result, null); + if (!results.length) + return true; + return results.reduce((val, result) => val || result); }, // Emits a click event in the worker's port. popupNode is the node that was @@ -389,7 +398,7 @@ function hasMatchingContext(contexts, popupNode) { // or no matched context then returns false. function getCurrentWorkerContext(item, popupNode) { let worker = getItemWorkerForWindow(item, popupNode.ownerDocument.defaultView); - if (!worker || !worker.anyContextListeners()) + if (!worker) return true; return worker.getMatchedContext(popupNode); } @@ -399,7 +408,7 @@ function getCurrentWorkerContext(item, popupNode) { function isItemVisible(item, popupNode, defaultVisibility) { if (!item.context.length) { let worker = getItemWorkerForWindow(item, popupNode.ownerDocument.defaultView); - if (!worker || !worker.anyContextListeners()) + if (!worker) return defaultVisibility; } @@ -445,7 +454,7 @@ function getItemWorkerForWindow(item, window) { // Called when an item is clicked to send out click events to the content // scripts -function itemClicked(item, clickedItem, popupNode) { +function itemActivated(item, clickedItem, popupNode) { let worker = getItemWorkerForWindow(item, popupNode.ownerDocument.defaultView); if (worker) { @@ -456,7 +465,7 @@ function itemClicked(item, clickedItem, popupNode) { } if (item.parentMenu) - itemClicked(item.parentMenu, clickedItem, popupNode); + itemActivated(item.parentMenu, clickedItem, popupNode); } // All things that appear in the context menu extend this @@ -533,6 +542,16 @@ let LabelledItem = Class({ MenuManager.updateItem(this); }, + get accesskey() { + return internal(this).options.accesskey; + }, + + set accesskey(val) { + internal(this).options.accesskey = val; + + MenuManager.updateItem(this); + }, + get image() { return internal(this).options.image; }, @@ -874,6 +893,8 @@ let MenuWrapper = Class({ xulNode.setAttribute("class", ITEM_CLASS); if (item instanceof LabelledItem) { xulNode.setAttribute("label", item.label); + if (item.accesskey) + xulNode.setAttribute("accesskey", item.accesskey); if (item.image) { xulNode.setAttribute("image", item.image); if (item instanceof Menu) @@ -890,7 +911,7 @@ let MenuWrapper = Class({ if (event.target !== xulNode) return; - itemClicked(item, item, self.contextMenu.triggerNode); + itemActivated(item, item, self.contextMenu.triggerNode); }, false); } @@ -915,6 +936,7 @@ let MenuWrapper = Class({ // TODO figure out why this requires setAttribute xulNode.setAttribute("label", item.label); + xulNode.setAttribute("accesskey", item.accesskey || ""); if (item.image) { xulNode.setAttribute("image", item.image); @@ -1050,6 +1072,7 @@ let MenuWrapper = Class({ let overflowMenu = this.window.document.createElement("menu"); overflowMenu.setAttribute("class", OVERFLOW_MENU_CLASS); overflowMenu.setAttribute("label", OVERFLOW_MENU_LABEL); + overflowMenu.setAttribute("accesskey", OVERFLOW_MENU_ACCESSKEY); this.contextMenu.insertBefore(overflowMenu, this.separator.nextSibling); overflowPopup = this.window.document.createElement("menupopup"); diff --git a/addon-sdk/source/lib/sdk/deprecated/traits-worker.js b/addon-sdk/source/lib/sdk/deprecated/traits-worker.js index ea7ca2d73f4..69b55995820 100644 --- a/addon-sdk/source/lib/sdk/deprecated/traits-worker.js +++ b/addon-sdk/source/lib/sdk/deprecated/traits-worker.js @@ -86,15 +86,6 @@ const WorkerSandbox = EventEmitter.compose({ return this._emitToContent(args); }, - /** - * Tells if content script has at least one listener registered for one event, - * through `self.on('xxx', ...)`. - * /!\ Shouldn't be used. Implemented to avoid breaking context-menu API. - */ - hasListenerFor: function hasListenerFor(name) { - return this._hasListenerFor(name); - }, - /** * Method called by the worker sandbox when it needs to send a message */ @@ -223,8 +214,7 @@ const WorkerSandbox = EventEmitter.compose({ }; let onEvent = this._onContentEvent.bind(this); let result = Cu.waiveXrays(ContentWorker).inject(content, chromeAPI, onEvent, options); - this._emitToContent = result.emitToContent; - this._hasListenerFor = result.hasListenerFor; + this._emitToContent = result; // Handle messages send by this script: let self = this; diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test.js b/addon-sdk/source/lib/sdk/deprecated/unit-test.js index 899c0cb0443..009acb4a9b2 100644 --- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js +++ b/addon-sdk/source/lib/sdk/deprecated/unit-test.js @@ -12,8 +12,9 @@ const timer = require("../timers"); const cfxArgs = require("../test/options"); const { getTabs, closeTab, getURI } = require("../tabs/utils"); const { windows, isBrowser, getMostRecentBrowserWindow } = require("../window/utils"); -const { defer, all, Debugging: PromiseDebugging } = require("../core/promise"); +const { defer, all, Debugging: PromiseDebugging, resolve } = require("../core/promise"); const { getInnerId } = require("../window/utils"); +const { cleanUI } = require("../test/utils") const findAndRunTests = function findAndRunTests(options) { var TestFinder = require("./unit-test-finder").TestFinder; @@ -268,88 +269,91 @@ TestRunner.prototype = { }, done: function done() { - if (!this.isDone) { - this.isDone = true; - if(this.test.teardown) { - this.test.teardown(this); - } - if (this.waitTimeout !== null) { - timer.clearTimeout(this.waitTimeout); - this.waitTimeout = null; - } - // Do not leave any callback set when calling to `waitUntil` - this.waitUntilCallback = null; - if (this.test.passed == 0 && this.test.failed == 0) { - this._logTestFailed("empty test"); - if ("testMessage" in this.console) { - this.console.testMessage(false, false, this.test.name, "Empty test"); - } - else { - this.console.error("fail:", "Empty test") - } - this.failed++; - this.test.failed++; - } - - let wins = windows(null, { includePrivate: true }); - let winPromises = wins.map(win => { - let { promise, resolve } = defer(); - if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) { - resolve() - } - else { - win.addEventListener("DOMContentLoaded", function onLoad() { - win.removeEventListener("DOMContentLoaded", onLoad, false); - resolve(); - }, false); - } - return promise; - }); - - PromiseDebugging.flushUncaughtErrors(); - - all(winPromises).then(_ => { - let tabs = []; - for (let win of wins.filter(isBrowser)) { - for (let tab of getTabs(win)) { - tabs.push(tab); - } - } - let leftover = tabs.slice(1); - - if (wins.length != 1 || getInnerId(wins[0]) !== runnerWindows.get(this)) - this.fail("Should not be any unexpected windows open"); - if (tabs.length != 1) - this.fail("Should not be any unexpected tabs open"); - if (tabs.length != 1 || wins.length != 1) { - console.log("Windows open:"); - for (let win of wins) { - if (isBrowser(win)) { - tabs = getTabs(win); - console.log(win.location + " - " + tabs.map(getURI).join(", ")); - } - else { - console.log(win.location); - } - } - } - - leftover.forEach(closeTab); - - this.testRunSummary.push({ - name: this.test.name, - passed: this.test.passed, - failed: this.test.failed, - errors: [error for (error in this.test.errors)].join(", ") - }); - - if (this.onDone !== null) { - let onDone = this.onDone; - this.onDone = null; - timer.setTimeout(_ => onDone(this), 0); - } - }); + if (this.isDone) { + return resolve(); } + + this.isDone = true; + if (this.test.teardown) { + this.test.teardown(this); + } + if (this.waitTimeout !== null) { + timer.clearTimeout(this.waitTimeout); + this.waitTimeout = null; + } + // Do not leave any callback set when calling to `waitUntil` + this.waitUntilCallback = null; + if (this.test.passed == 0 && this.test.failed == 0) { + this._logTestFailed("empty test"); + if ("testMessage" in this.console) { + this.console.testMessage(false, false, this.test.name, "Empty test"); + } + else { + this.console.error("fail:", "Empty test") + } + this.failed++; + this.test.failed++; + } + + let wins = windows(null, { includePrivate: true }); + let winPromises = wins.map(win => { + let { promise, resolve } = defer(); + if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) { + resolve() + } + else { + win.addEventListener("DOMContentLoaded", function onLoad() { + win.removeEventListener("DOMContentLoaded", onLoad, false); + resolve(); + }, false); + } + return promise; + }); + + PromiseDebugging.flushUncaughtErrors(); + + return all(winPromises).then(() => { + let browserWins = wins.filter(isBrowser); + let tabs = browserWins.reduce((tabs, window) => tabs.concat(getTabs(window)), []); + + if (wins.length != 1 || getInnerId(wins[0]) !== runnerWindows.get(this)) + this.fail("Should not be any unexpected windows open"); + + let hasMoreTabsOpen = browserWins.length && tabs.length != 1; + if (hasMoreTabsOpen) + this.fail("Should not be any unexpected tabs open"); + + if (hasMoreTabsOpen || wins.length != 1) { + console.log("Windows open:"); + for (let win of wins) { + if (isBrowser(win)) { + tabs = getTabs(win); + console.log(win.location + " - " + tabs.map(getURI).join(", ")); + } + else { + console.log(win.location); + } + } + } + + return null; + }). + then(cleanUI). + then(() => { + this.testRunSummary.push({ + name: this.test.name, + passed: this.test.passed, + failed: this.test.failed, + errors: [error for (error in this.test.errors)].join(", ") + }); + + if (this.onDone !== null) { + let onDone = this.onDone; + this.onDone = null; + timer.setTimeout(_ => onDone(this)); + } + }). + catch(e => console.exception(e)); }, // Set of assertion functions to wait for an assertion to become true diff --git a/addon-sdk/source/lib/sdk/deprecated/window-utils.js b/addon-sdk/source/lib/sdk/deprecated/window-utils.js index f077aba07c9..f8faf501b58 100644 --- a/addon-sdk/source/lib/sdk/deprecated/window-utils.js +++ b/addon-sdk/source/lib/sdk/deprecated/window-utils.js @@ -16,7 +16,7 @@ const { getInnerId, getOuterId, windows, isDocumentLoaded, isBrowser, getMostRecentBrowserWindow, getMostRecentWindow } = require('../window/utils'); const errors = require('../deprecated/errors'); const { deprecateFunction } = require('../util/deprecate'); -const { ignoreWindow, isGlobalPBSupported } = require('sdk/private-browsing/utils'); +const { ignoreWindow } = require('sdk/private-browsing/utils'); const { isPrivateBrowsingSupported } = require('../self'); const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1']. @@ -25,7 +25,7 @@ const appShellService = Cc['@mozilla.org/appshell/appShellService;1']. getService(Ci.nsIAppShellService); // Bug 834961: ignore private windows when they are not supported -function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported || isGlobalPBSupported }); +function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported }); /** * An iterator for XUL windows currently in the application. diff --git a/addon-sdk/source/lib/sdk/io/buffer.js b/addon-sdk/source/lib/sdk/io/buffer.js index 4d95c472216..77a480597a9 100644 --- a/addon-sdk/source/lib/sdk/io/buffer.js +++ b/addon-sdk/source/lib/sdk/io/buffer.js @@ -137,6 +137,7 @@ Buffer.concat = function(list, length) { // that typically can be used in combination with `DataView` while preserving // access by index. Since in SDK each module has it's own set of bult-ins it // ok to patch ours to make it nodejs Buffer compatible. +const Uint8ArraySet = Uint8Array.prototype.set Buffer.prototype = Uint8Array.prototype; Object.defineProperties(Buffer.prototype, { parent: { @@ -204,7 +205,7 @@ Object.defineProperties(Buffer.prototype, { end = start + remainingTarget; } - Uint8Array.set(target, this.subarray(start, end), offset); + Uint8ArraySet.call(target, this.subarray(start, end), offset); return end - start; } }, @@ -267,7 +268,7 @@ Object.defineProperties(Buffer.prototype, { if (buffer.length !== length) buffer = buffer.subarray(0, length); - Uint8Array.set(this, buffer, offset); + Uint8ArraySet.call(this, buffer, offset); return result; } }, diff --git a/addon-sdk/source/lib/sdk/io/fs.js b/addon-sdk/source/lib/sdk/io/fs.js index 08fc1fb449b..7a8db312b9d 100644 --- a/addon-sdk/source/lib/sdk/io/fs.js +++ b/addon-sdk/source/lib/sdk/io/fs.js @@ -647,26 +647,26 @@ exports.close = close; /** * Synchronous open(2). */ -function openSync(path, flags, mode) { - let [ fd, flags_, mode_, file ] = - [ { path: path }, Flags(flags), Mode(mode), nsILocalFile(path) ]; +function openSync(aPath, aFlag, aMode) { + let [ fd, flags, mode, file ] = + [ { path: aPath }, Flags(aFlag), Mode(aMode), nsILocalFile(aPath) ]; nsIFile(fd, file); // If trying to open file for just read that does not exists // need to throw exception as node does. - if (!file.exists() && !isWritable(flags_)) - throw FSError("open", "ENOENT", 34, path); + if (!file.exists() && !isWritable(flags)) + throw FSError("open", "ENOENT", 34, aPath); // If we want to open file in read mode we initialize input stream. - if (isReadable(flags_)) { - let input = FileInputStream(file, flags_, mode_, DEFER_OPEN); + if (isReadable(flags)) { + let input = FileInputStream(file, flags, mode, DEFER_OPEN); nsIFileInputStream(fd, input); } // If we want to open file in write mode we initialize output stream for it. - if (isWritable(flags_)) { - let output = FileOutputStream(file, flags_, mode_, DEFER_OPEN); + if (isWritable(flags)) { + let output = FileOutputStream(file, flags, mode, DEFER_OPEN); nsIFileOutputStream(fd, output); } @@ -822,7 +822,8 @@ function readFile(path, encoding, callback) { readStream.destroy(); callback(null, buffer); }); - } catch (error) { + } + catch (error) { setTimeout(callback, 0, error); } }; diff --git a/addon-sdk/source/lib/sdk/panel/window.js b/addon-sdk/source/lib/sdk/panel/window.js index e2fb1d3e35e..47ca21d64f1 100644 --- a/addon-sdk/source/lib/sdk/panel/window.js +++ b/addon-sdk/source/lib/sdk/panel/window.js @@ -15,12 +15,11 @@ module.metadata = { const { getMostRecentBrowserWindow, windows: getWindows } = require('../window/utils'); const { ignoreWindow } = require('../private-browsing/utils'); const { isPrivateBrowsingSupported } = require('../self'); -const { isGlobalPBSupported } = require('../private-browsing/utils'); function getWindow(anchor) { let window; let windows = getWindows("navigator:browser", { - includePrivate: isPrivateBrowsingSupported || isGlobalPBSupported + includePrivate: isPrivateBrowsingSupported }); if (anchor) { diff --git a/addon-sdk/source/lib/sdk/private-browsing.js b/addon-sdk/source/lib/sdk/private-browsing.js index da0ee394735..29ca161850f 100644 --- a/addon-sdk/source/lib/sdk/private-browsing.js +++ b/addon-sdk/source/lib/sdk/private-browsing.js @@ -7,43 +7,6 @@ module.metadata = { "stability": "stable" }; -const { setMode, getMode, on: onStateChange, isPrivate } = require('./private-browsing/utils'); -const { emit, on, once, off } = require('./event/core'); -const { when: unload } = require('./system/unload'); -const { deprecateFunction, deprecateEvent } = require('./util/deprecate'); - -onStateChange('start', function onStart() { - emit(exports, 'start'); -}); - -onStateChange('stop', function onStop() { - emit(exports, 'stop'); -}); - -Object.defineProperty(exports, "isActive", { - get: deprecateFunction(getMode, 'require("private-browsing").isActive is deprecated.') -}); - -exports.activate = function activate() setMode(true); -exports.deactivate = function deactivate() setMode(false); - -exports.on = deprecateEvents(on.bind(null, exports)); -exports.once = deprecateEvents(once.bind(null, exports)); -exports.removeListener = deprecateEvents(function removeListener(type, listener) { - // Note: We can't just bind `off` as we do it for other methods cause skipping - // a listener argument will remove all listeners for the given event type - // causing misbehavior. This way we make sure all arguments are passed. - off(exports, type, listener); -}); +const { isPrivate } = require('./private-browsing/utils'); exports.isPrivate = isPrivate; - -function deprecateEvents(func) deprecateEvent( - func, - 'The require("sdk/private-browsing") module\'s "start" and "stop" events ' + - 'are deprecated.', - ['start', 'stop'] -); - -// Make sure listeners are cleaned up. -unload(function() off(exports)); diff --git a/addon-sdk/source/lib/sdk/private-browsing/utils.js b/addon-sdk/source/lib/sdk/private-browsing/utils.js index fbc66232b06..25ee4645a70 100644 --- a/addon-sdk/source/lib/sdk/private-browsing/utils.js +++ b/addon-sdk/source/lib/sdk/private-browsing/utils.js @@ -8,51 +8,28 @@ module.metadata = { }; const { Cc, Ci, Cu } = require('chrome'); -const { defer } = require('../lang/functional'); -const { emit, on, once, off } = require('../event/core'); -const { when: unload } = require('../system/unload'); -const events = require('../system/events'); -const { deprecateFunction } = require('../util/deprecate'); -const { isOneOf, is, satisfiesVersion, version } = require('../system/xul-app'); +const { is } = require('../system/xul-app'); const { isWindowPrivate } = require('../window/utils'); const { isPrivateBrowsingSupported } = require('../self'); const { dispatcher } = require("../util/dispatcher"); -let deferredEmit = defer(emit); -let pbService; let PrivateBrowsingUtils; // Private browsing is only supported in Fx -if (isOneOf(['Firefox', 'Fennec'])) { - // get the nsIPrivateBrowsingService if it exists - try { - pbService = Cc["@mozilla.org/privatebrowsing;1"]. - getService(Ci.nsIPrivateBrowsingService); - - // a dummy service exists for the moment (Fx20 atleast), but will be removed eventually - // ie: the service will exist, but it won't do anything and the global private browing - // feature is not really active. See Bug 818800 and Bug 826037 - if (!('privateBrowsingEnabled' in pbService)) - pbService = undefined; - } - catch(e) { /* Private Browsing Service has been removed (Bug 818800) */ } - - try { - PrivateBrowsingUtils = Cu.import('resource://gre/modules/PrivateBrowsingUtils.jsm', {}).PrivateBrowsingUtils; - } - catch(e) { /* if this file DNE then an error will be thrown */ } +try { + PrivateBrowsingUtils = Cu.import('resource://gre/modules/PrivateBrowsingUtils.jsm', {}).PrivateBrowsingUtils; } +catch (e) {} -// checks that global private browsing is implemented -let isGlobalPBSupported = exports.isGlobalPBSupported = !!pbService && is('Firefox'); +exports.isGlobalPBSupported = false; // checks that per-window private browsing is implemented let isWindowPBSupported = exports.isWindowPBSupported = - !pbService && !!PrivateBrowsingUtils && is('Firefox'); + !!PrivateBrowsingUtils && is('Firefox'); // checks that per-tab private browsing is implemented let isTabPBSupported = exports.isTabPBSupported = - !pbService && !!PrivateBrowsingUtils && is('Fennec') && satisfiesVersion(version, '>=20.0*'); + !!PrivateBrowsingUtils && is('Fennec'); function isPermanentPrivateBrowsing() { return !!(PrivateBrowsingUtils && PrivateBrowsingUtils.permanentPrivateBrowsing); @@ -60,58 +37,18 @@ function isPermanentPrivateBrowsing() { exports.isPermanentPrivateBrowsing = isPermanentPrivateBrowsing; function ignoreWindow(window) { - return !isPrivateBrowsingSupported && isWindowPrivate(window) && !isGlobalPBSupported; + return !isPrivateBrowsingSupported && isWindowPrivate(window); } exports.ignoreWindow = ignoreWindow; -function onChange() { - // Emit event with in next turn of event loop. - deferredEmit(exports, pbService.privateBrowsingEnabled ? 'start' : 'stop'); -} - -// Currently, only Firefox implements the private browsing service. -if (isGlobalPBSupported) { - // set up an observer for private browsing switches. - events.on('private-browsing-transition-complete', onChange); -} - -// We toggle private browsing mode asynchronously in order to work around -// bug 659629. Since private browsing transitions are asynchronous -// anyway, this doesn't significantly change the behavior of the API. -let setMode = defer(function setMode(value) { - value = !!value; // Cast to boolean. - - // default - return pbService && (pbService.privateBrowsingEnabled = value); -}); -exports.setMode = deprecateFunction( - setMode, - 'require("sdk/private-browsing").activate and ' + - 'require("sdk/private-browsing").deactivate ' + - 'are deprecated.' -); - let getMode = function getMode(chromeWin) { - if (chromeWin !== undefined && isWindowPrivate(chromeWin)) - return true; - - // default - return isGlobalPrivateBrowsing(); + return (chromeWin !== undefined && isWindowPrivate(chromeWin)); }; exports.getMode = getMode; -function isGlobalPrivateBrowsing() { - return pbService ? pbService.privateBrowsingEnabled : false; -} - const isPrivate = dispatcher("isPrivate"); isPrivate.when(isPermanentPrivateBrowsing, _ => true); isPrivate.when(x => x instanceof Ci.nsIDOMWindow, isWindowPrivate); isPrivate.when(x => Ci.nsIPrivateBrowsingChannel && x instanceof Ci.nsIPrivateBrowsingChannel, x => x.isChannelPrivate); -isPrivate.define(isGlobalPrivateBrowsing); +isPrivate.define(() => false); exports.isPrivate = isPrivate; - -exports.on = on.bind(null, exports); - -// Make sure listeners are cleaned up. -unload(function() off(exports)); diff --git a/addon-sdk/source/lib/sdk/system.js b/addon-sdk/source/lib/sdk/system.js index afef91bab89..bf5c3c515c6 100644 --- a/addon-sdk/source/lib/sdk/system.js +++ b/addon-sdk/source/lib/sdk/system.js @@ -1,7 +1,6 @@ /* 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/. */ - 'use strict'; module.metadata = { @@ -12,6 +11,7 @@ const { Cc, Ci, CC } = require('chrome'); const options = require('@loader/options'); const file = require('./io/file'); const runtime = require("./system/runtime"); +const { when: unload } = require("./system/unload"); const appStartup = Cc['@mozilla.org/toolkit/app-startup;1']. getService(Ci.nsIAppStartup); @@ -61,8 +61,9 @@ exports.exit = function exit(code) { return; } - // This is used by 'cfx' to find out exit code. - if ('resultFile' in options && options.resultFile) { + let resultsFile = 'resultFile' in options && options.resultFile; + function unloader() { + // This is used by 'cfx' to find out exit code. let mode = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE; let stream = openFile(options.resultFile, mode); let status = code ? 'FAIL' : 'OK'; @@ -74,6 +75,16 @@ exports.exit = function exit(code) { if (code == 0) { forcedExit = true; } + + // Bug 856999: Prevent automatic kill of Firefox when running tests + if (options.noQuit) { + if (resultsFile) { + unload(unloader); + } + return; + } + + unloader(); appStartup.quit(code ? E_ATTEMPT : E_FORCE); }; @@ -109,7 +120,7 @@ exports.pathFor = function pathFor(id) { */ exports.platform = runtime.OS.toLowerCase(); -const [, architecture, compiler] = runtime.XPCOMABI ? +const [, architecture, compiler] = runtime.XPCOMABI ? runtime.XPCOMABI.match(/^([^-]*)-(.*)$/) : [, null, null]; diff --git a/addon-sdk/source/lib/sdk/tabs/utils.js b/addon-sdk/source/lib/sdk/tabs/utils.js index c5754d69732..427f3d997dc 100644 --- a/addon-sdk/source/lib/sdk/tabs/utils.js +++ b/addon-sdk/source/lib/sdk/tabs/utils.js @@ -15,10 +15,9 @@ const { Ci } = require('chrome'); const { defer } = require("../lang/functional"); const { windows, isBrowser } = require('../window/utils'); const { isPrivateBrowsingSupported } = require('../self'); -const { isGlobalPBSupported } = require('../private-browsing/utils'); // Bug 834961: ignore private windows when they are not supported -function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported || isGlobalPBSupported }); +function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported }); const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; diff --git a/addon-sdk/source/lib/sdk/test/utils.js b/addon-sdk/source/lib/sdk/test/utils.js index c4cb9e7cddf..67522a2df6e 100644 --- a/addon-sdk/source/lib/sdk/test/utils.js +++ b/addon-sdk/source/lib/sdk/test/utils.js @@ -1,7 +1,6 @@ /* 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/. */ - 'use strict'; module.metadata = { @@ -10,6 +9,9 @@ module.metadata = { const { defer } = require('../core/promise'); const { setInterval, clearInterval } = require('../timers'); +const { getTabs, closeTab } = require("../tabs/utils"); +const { windows: getWindows } = require("../window/utils"); +const { close: closeWindow } = require("../window/helpers"); function getTestNames (exports) Object.keys(exports).filter(name => /^test/.test(name)) @@ -107,3 +109,19 @@ function waitUntil (predicate, delay) { return promise; } exports.waitUntil = waitUntil; + +let cleanUI = function cleanUI() { + let { promise, resolve } = defer(); + + let windows = getWindows(null, { includePrivate: true }); + if (windows.length > 1) { + return closeWindow(windows[1]).then(cleanUI); + } + + getTabs(windows[0]).slice(1).forEach(closeTab); + + resolve(); + + return promise; +} +exports.cleanUI = cleanUI; diff --git a/addon-sdk/source/lib/sdk/util/match-pattern.js b/addon-sdk/source/lib/sdk/util/match-pattern.js index e31d923e619..4a414cba373 100644 --- a/addon-sdk/source/lib/sdk/util/match-pattern.js +++ b/addon-sdk/source/lib/sdk/util/match-pattern.js @@ -1,7 +1,6 @@ /* 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/. */ - "use strict"; module.metadata = { @@ -15,17 +14,12 @@ function MatchPattern(pattern) { if (cache[pattern]) return cache[pattern]; if (typeof pattern.test == "function") { - // For compatibility with -moz-document rules, we require the RegExp's // global, ignoreCase, and multiline flags to be set to false. if (pattern.global) { throw new Error("A RegExp match pattern cannot be set to `global` " + "(i.e. //g)."); } - if (pattern.ignoreCase) { - throw new Error("A RegExp match pattern cannot be set to `ignoreCase` " + - "(i.e. //i)."); - } if (pattern.multiline) { throw new Error("A RegExp match pattern cannot be set to `multiline` " + "(i.e. //m)."); @@ -71,7 +65,6 @@ function MatchPattern(pattern) { } MatchPattern.prototype = { - test: function MatchPattern_test(urlStr) { try { var url = URL(urlStr); @@ -88,13 +81,13 @@ MatchPattern.prototype = { // Assuming most URLs don't match most match patterns, we call `test` for // speed when determining whether or not the URL matches, then call `exec` // for the small subset that match to make sure the entire URL matches. - // if (this.regexp && this.regexp.test(urlStr) && this.regexp.exec(urlStr)[0] == urlStr) return true; if (this.anyWebPage && /^(https?|ftp)$/.test(url.scheme)) return true; + if (this.exactURL && this.exactURL == urlStr) return true; @@ -107,6 +100,7 @@ MatchPattern.prototype = { (url.host === this.domain || url.host.slice(-this.domain.length - 1) === "." + this.domain)) return true; + if (this.urlPrefix && 0 == urlStr.indexOf(this.urlPrefix)) return true; @@ -114,7 +108,6 @@ MatchPattern.prototype = { }, toString: function () '[object MatchPattern]' - }; exports.MatchPattern = MatchPattern; diff --git a/addon-sdk/source/lib/sdk/windows/dom.js b/addon-sdk/source/lib/sdk/windows/dom.js index 11148b69f46..2c9a9aa4a5d 100644 --- a/addon-sdk/source/lib/sdk/windows/dom.js +++ b/addon-sdk/source/lib/sdk/windows/dom.js @@ -4,8 +4,7 @@ 'use strict'; const { Trait } = require('../deprecated/traits'); -const { isWindowPrivate, getWindowTitle } = require('../window/utils'); -const { deprecateUsage } = require('../util/deprecate'); +const { getWindowTitle } = require('../window/utils'); module.metadata = { "stability": "unstable" @@ -25,13 +24,6 @@ const WindowDom = Trait.compose({ let window = this._window; if (window) window.focus(); return this._public; - }, - get isPrivateBrowsing() { - deprecateUsage('`browserWindow.isPrivateBrowsing` is deprecated, please ' + - 'consider using ' + - '`require("sdk/private-browsing").isPrivate(browserWindow)` ' + - 'instead.'); - return isWindowPrivate(this._window); } }); exports.WindowDom = WindowDom; diff --git a/addon-sdk/source/lib/toolkit/loader.js b/addon-sdk/source/lib/toolkit/loader.js index cc05728886f..b5e15191aca 100644 --- a/addon-sdk/source/lib/toolkit/loader.js +++ b/addon-sdk/source/lib/toolkit/loader.js @@ -229,6 +229,10 @@ const Sandbox = iced(function Sandbox(options) { metadata: 'metadata' in options ? options.metadata : {} }; + if (options.metadata && options.metadata.addonID) { + options.addonId = options.metadata.addonID; + } + let sandbox = Cu.Sandbox(options.principal, options); // Each sandbox at creation gets set of own properties that will be shadowing @@ -393,6 +397,49 @@ const resolve = iced(function resolve(id, base) { }); exports.resolve = resolve; +function fileExists(uri) { + let url = NetUtil.newURI(uri); + + switch (url.scheme) { + case "jar": + let jarfile = url.QueryInterface(Ci.nsIJARURI).JARFile; + + // Don't support nested JARs for now + if (!(jarfile instanceof Ci.nsIFileURL)) + return false; + + let zipcache = Cc["@mozilla.org/libjar/zip-reader-cache;1"]. + getService(Ci.nsIZipReaderCache); + let zipreader = zipcache.getZip(jarfile.file); + return zipreader.hasEntry(jarfile.JAREntry); + + case "file": + return url.QueryInterface(Ci.nsIFileURL).file.exists(); + + case "chrome": + let registry = Cc["@mozilla.org/chrome/chrome-registry;1"]. + getService(Ci.nsIChromeRegistry) + return fileExists(ChromeRegistry.convertChromeURL(url).spec); + + case "resource": + let handler = Cc["@mozilla.org/network/protocol;1?name=resource"]. + getService(Ci.nsIResProtocolHandler); + let resolved; + try { + resolved = handler.resolveURI(url); + } + catch (e) { + // Resource protocol handler throws for unknown mappings + return false; + } + return fileExists(resolved); + + default: + // Don't handle other URI schemes for now + return false; + } +} + // Node-style module lookup // Takes an id and path and attempts to load a file using node's resolving // algorithm. @@ -407,7 +454,7 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) { let fullId = join(rootURI, id); let resolvedPath; - if ((resolvedPath = loadAsFile(fullId))) + if ((resolvedPath = findFile(fullId))) return stripBase(rootURI, resolvedPath); if ((resolvedPath = loadAsDirectory(fullId))) @@ -417,7 +464,7 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) { // in the `dependencies` list let dirs = getNodeModulePaths(dirname(join(rootURI, requirer))).map(dir => join(dir, id)); for (let i = 0; i < dirs.length; i++) { - if ((resolvedPath = loadAsFile(dirs[i]))) + if ((resolvedPath = findFile(dirs[i]))) return stripBase(rootURI, resolvedPath); if ((resolvedPath = loadAsDirectory(dirs[i]))) @@ -431,23 +478,20 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) { }); exports.nodeResolve = nodeResolve; -// Attempts to load `path` and then `path.js` +// Attempts to find `path` and then `path.js` // Returns `path` with valid file, or `undefined` otherwise -function loadAsFile (path) { - let found; - +function findFile (path) { // As per node's loader spec, // we first should try and load 'path' (with no extension) // before trying 'path.js'. We will not support this feature // due to performance, but may add it if necessary for adoption. - try { - // Append '.js' to path name unless it's another support filetype - path = normalizeExt(path); - readURI(path); - found = path; - } catch (e) {} - return found; + // Append '.js' to path name unless it's another support filetype + path = normalizeExt(path); + if (fileExists(path)) + return path; + + return null; } // Attempts to load `path/package.json`'s `main` entry, @@ -456,25 +500,21 @@ function loadAsDirectory (path) { try { // If `path/package.json` exists, parse the `main` entry // and attempt to load that - let main = getManifestMain(JSON.parse(readURI(path + '/package.json'))); - if (main != null) { - let tmpPath = join(path, main); - let found = loadAsFile(tmpPath); - if (found) - return found + if (fileExists(path + '/package.json')) { + let main = getManifestMain(JSON.parse(readURI(path + '/package.json'))); + if (main != null) { + let tmpPath = join(path, main); + let found = findFile(tmpPath); + if (found) + return found + } } - try { - let tmpPath = path + '/index.js'; - readURI(tmpPath); - return tmpPath; - } catch (e) {} - } catch (e) { - try { - let tmpPath = path + '/index.js'; - readURI(tmpPath); - return tmpPath; - } catch (e) {} - } + } catch (e) { } + + let tmpPath = path + '/index.js'; + if (fileExists(tmpPath)) + return tmpPath; + return void 0; } diff --git a/addon-sdk/source/python-lib/cuddlefish/__init__.py b/addon-sdk/source/python-lib/cuddlefish/__init__.py index d08aedb4efd..7fda2003d59 100644 --- a/addon-sdk/source/python-lib/cuddlefish/__init__.py +++ b/addon-sdk/source/python-lib/cuddlefish/__init__.py @@ -152,7 +152,7 @@ parser_groups = ( "thunderbird"), metavar=None, type="choice", - choices=["firefox", "fennec", + choices=["firefox", "fennec-on-device", "thunderbird", "xulrunner"], default="firefox", @@ -189,6 +189,12 @@ parser_groups = ( action="store_true", default=False, cmds=['run', 'test'])), + (("", "--no-quit",), dict(dest="no_quit", + help=("Prevent from killing Firefox when" + "running tests"), + action="store_true", + default=False, + cmds=['run', 'test'])), (("", "--no-strip-xpi",), dict(dest="no_strip_xpi", help="retain unused modules in XPI", action="store_true", @@ -664,7 +670,7 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None, use_main = False inherited_options = ['verbose', 'enable_e10s', 'parseable', 'check_memory', - 'abort_on_missing'] + 'no_quit', 'abort_on_missing'] enforce_timeouts = False if command == "xpi": @@ -855,7 +861,8 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None, jid=jid, update_url=options.update_url, bootstrap=True, - enable_mobile=options.enable_mobile) + enable_mobile=options.enable_mobile, + harness_options=harness_options) if command == "xpi" and options.update_link: if not options.update_link.startswith("https"): @@ -936,6 +943,7 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None, args=options.cmdargs, extra_environment=extra_environment, norun=options.no_run, + noquit=options.no_quit, used_files=used_files, enable_mobile=options.enable_mobile, mobile_app_name=options.mobile_app_name, diff --git a/addon-sdk/source/python-lib/cuddlefish/mobile-utils/bootstrap.js b/addon-sdk/source/python-lib/cuddlefish/mobile-utils/bootstrap.js index 3fb3624e459..7d6235521bc 100644 --- a/addon-sdk/source/python-lib/cuddlefish/mobile-utils/bootstrap.js +++ b/addon-sdk/source/python-lib/cuddlefish/mobile-utils/bootstrap.js @@ -1,25 +1,18 @@ /* 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/. */ - "use strict"; -const Cc = Components.classes; -const Ci = Components.interfaces; const Cu = Components.utils; -const Cr = Components.results; -Components.utils.import("resource://gre/modules/Services.jsm"); - -const DEBUG = false; - -let log = DEBUG ? dump : function (){}; +Cu.import("resource://gre/modules/Services.jsm"); +let { log } = console; function startup(data, reason) { // This code allow to make all stdIO work try { - Components.utils.import("resource://gre/modules/ctypes.jsm"); + Cu.import("resource://gre/modules/ctypes.jsm"); let libdvm = ctypes.open("libdvm.so"); let dvmStdioConverterStartup; // Starting with Android ICS, dalvik uses C++. @@ -32,7 +25,7 @@ function startup(data, reason) { dvmStdioConverterStartup = libdvm.declare("dvmStdioConverterStartup", ctypes.default_abi, ctypes.void_t); } dvmStdioConverterStartup(); - log("MU: console redirected to adb logcat.\n"); + log("MU: console redirected to adb logcat."); } catch(e) { Cu.reportError("MU: unable to execute jsctype hack: "+e); } @@ -45,9 +38,9 @@ function startup(data, reason) { } }; Services.obs.addObserver(QuitObserver, "quit-application", false); - log("MU: ready to watch firefox exit.\n"); + log("MU: ready to watch firefox exit."); } catch(e) { - log("MU: unable to register quit-application observer: " + e + "\n"); + log("MU: unable to register quit-application observer: " + e); } } diff --git a/addon-sdk/source/python-lib/cuddlefish/prefs.py b/addon-sdk/source/python-lib/cuddlefish/prefs.py index 4d3f4807d9d..6a5cc86dad9 100644 --- a/addon-sdk/source/python-lib/cuddlefish/prefs.py +++ b/addon-sdk/source/python-lib/cuddlefish/prefs.py @@ -85,7 +85,7 @@ DEFAULT_FIREFOX_PREFS = { # Point the url-classifier to a nonexistent local URL for fast failures. 'browser.safebrowsing.provider.0.gethashURL' : 'http://localhost/safebrowsing-dummy/gethash', 'browser.safebrowsing.provider.0.updateURL' : 'http://localhost/safebrowsing-dummy/update', - } +} # When launching a temporary new Thunderbird profile, use these preferences. # Note that these were taken from: @@ -139,4 +139,9 @@ DEFAULT_THUNDERBIRD_PREFS = { 'mail.smtpservers' : "smtp1", 'mail.startup.enabledMailCheckOnce' : True, 'mailnews.start_page_override.mstone' : "ignore", - } +} + +DEFAULT_TEST_PREFS = { + 'general.useragent.locale': "en-US", + 'intl.locale.matchOS': "en-US" +} diff --git a/addon-sdk/source/python-lib/cuddlefish/rdf.py b/addon-sdk/source/python-lib/cuddlefish/rdf.py index fb9bb76f6d6..c80be82ed83 100644 --- a/addon-sdk/source/python-lib/cuddlefish/rdf.py +++ b/addon-sdk/source/python-lib/cuddlefish/rdf.py @@ -5,6 +5,8 @@ import os import xml.dom.minidom import StringIO +import codecs +import glob RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" EM_NS = "http://www.mozilla.org/2004/em-rdf#" @@ -20,9 +22,10 @@ class RDF(object): # have .encoding hardwired to "ascii" and put only bytes in # the backing store, so we can't use them here). # - # The encoding= argument to dom.writexml() merely sets the XML header's - # encoding= attribute. It still writes unencoded unicode to the output file, - # so we have to encode it for real afterwards. + # The encoding= argument to dom.writexml() merely sets the + # XML header's encoding= attribute. It still writes unencoded + # unicode to the output file, so we have to encode it for + # real afterwards. # # Also see: https://bugzilla.mozilla.org/show_bug.cgi?id=567660 @@ -112,7 +115,12 @@ class RDFManifest(RDF): return True; -def gen_manifest(template_root_dir, target_cfg, jid, + def add_node(self, node): + top = self.dom.documentElement.getElementsByTagName("Description")[0]; + top.appendChild(node) + + +def gen_manifest(template_root_dir, target_cfg, jid, harness_options={}, update_url=None, bootstrap=True, enable_mobile=False): install_rdf = os.path.join(template_root_dir, "install.rdf") manifest = RDFManifest(install_rdf) @@ -121,13 +129,51 @@ def gen_manifest(template_root_dir, target_cfg, jid, manifest.set("em:id", jid) manifest.set("em:version", target_cfg.get('version', '1.0')) + + if "locale" in harness_options: + # addon_title -> + # addon_author -> + # addon_description -> + # addon_homepageURL -> + localizable_in = ["title", "author", "description", "homepage"] + localized_out = ["name", "creator", "description", "homepageURL"] + for lang in harness_options["locale"]: + desc = dom.createElement("Description") + + for value_in in localizable_in: + key_in = "extensions." + target_cfg.get("id", "") + "." + value_in + tag_out = localized_out[localizable_in.index(value_in)] + + if key_in in harness_options["locale"][lang]: + elem = dom.createElement("em:" + tag_out) + elem_value = harness_options["locale"][lang][key_in] + elem.appendChild(dom.createTextNode(elem_value)) + desc.appendChild(elem) + + # Don't add language if no localizeable field was localized + if desc.hasChildNodes(): + locale = dom.createElement("em:locale") + locale.appendChild(dom.createTextNode(lang)) + desc.appendChild(locale) + + localized = dom.createElement("em:localized") + localized.appendChild(desc) + manifest.add_node(localized) + manifest.set("em:name", target_cfg.get('title', target_cfg.get('fullName', target_cfg['name']))) manifest.set("em:description", target_cfg.get("description", "")) manifest.set("em:creator", target_cfg.get("author", "")) + + if target_cfg.get("homepage"): + manifest.set("em:homepageURL", target_cfg.get("homepage")) + else: + manifest.remove("em:homepageURL") + manifest.set("em:bootstrap", str(bootstrap).lower()) + # XPIs remain packed by default, but package.json can override that. The # RDF format accepts "true" as True, anything else as False. We expect # booleans in the .json file, not strings. @@ -136,7 +182,7 @@ def gen_manifest(template_root_dir, target_cfg, jid, for translator in target_cfg.get("translators", [ ]): elem = dom.createElement("em:translator"); elem.appendChild(dom.createTextNode(translator)) - dom.documentElement.getElementsByTagName("Description")[0].appendChild(elem) + manifest.add_node(elem) for developer in target_cfg.get("developers", [ ]): elem = dom.createElement("em:developer"); @@ -146,7 +192,7 @@ def gen_manifest(template_root_dir, target_cfg, jid, for contributor in target_cfg.get("contributors", [ ]): elem = dom.createElement("em:contributor"); elem.appendChild(dom.createTextNode(contributor)) - dom.documentElement.getElementsByTagName("Description")[0].appendChild(elem) + manifest.add_node(elem) if update_url: manifest.set("em:updateURL", update_url) @@ -169,7 +215,7 @@ def gen_manifest(template_root_dir, target_cfg, jid, if enable_mobile: target_app = dom.createElement("em:targetApplication") - dom.documentElement.getElementsByTagName("Description")[0].appendChild(target_app) + manifest.add_node(target_app) ta_desc = dom.createElement("Description") target_app.appendChild(ta_desc) @@ -186,11 +232,6 @@ def gen_manifest(template_root_dir, target_cfg, jid, elem.appendChild(dom.createTextNode("30.0a1")) ta_desc.appendChild(elem) - if target_cfg.get("homepage"): - manifest.set("em:homepageURL", target_cfg.get("homepage")) - else: - manifest.remove("em:homepageURL") - return manifest if __name__ == "__main__": diff --git a/addon-sdk/source/python-lib/cuddlefish/runner.py b/addon-sdk/source/python-lib/cuddlefish/runner.py index 6a5f881f0c4..868b08e4a6c 100644 --- a/addon-sdk/source/python-lib/cuddlefish/runner.py +++ b/addon-sdk/source/python-lib/cuddlefish/runner.py @@ -18,6 +18,7 @@ from cuddlefish.prefs import DEFAULT_FIREFOX_PREFS from cuddlefish.prefs import DEFAULT_THUNDERBIRD_PREFS from cuddlefish.prefs import DEFAULT_FENNEC_PREFS from cuddlefish.prefs import DEFAULT_NO_CONNECTIONS_PREFS +from cuddlefish.prefs import DEFAULT_TEST_PREFS # Used to remove noise from ADB output CLEANUP_ADB = re.compile(r'^(I|E)/(stdout|stderr|GeckoConsole)\s*\(\s*\d+\):\s*(.*)$') @@ -104,30 +105,6 @@ class FennecProfile(mozrunner.Profile): preferences = {} names = ['fennec'] -class FennecRunner(mozrunner.Runner): - profile_class = FennecProfile - - names = ['fennec'] - - __DARWIN_PATH = '/Applications/Fennec.app/Contents/MacOS/fennec' - - def __init__(self, binary=None, **kwargs): - if sys.platform == 'darwin' and binary and binary.endswith('.app'): - # Assume it's a Fennec app dir. - binary = os.path.join(binary, 'Contents/MacOS/fennec') - - self.__real_binary = binary - - mozrunner.Runner.__init__(self, **kwargs) - - def find_binary(self): - if not self.__real_binary: - if sys.platform == 'darwin': - if os.path.exists(self.__DARWIN_PATH): - return self.__DARWIN_PATH - self.__real_binary = mozrunner.Runner.find_binary(self) - return self.__real_binary - FENNEC_REMOTE_PATH = '/mnt/sdcard/jetpack-profile' class RemoteFennecRunner(mozrunner.Runner): @@ -167,11 +144,11 @@ class RemoteFennecRunner(mozrunner.Runner): # or use name given as cfx `--mobile-app` argument. intents = self.getIntentNames() if not intents: - raise ValueError("Unable to found any Firefox " + raise ValueError("Unable to find any Firefox " "application on your device.") elif mobile_app_name: if not mobile_app_name in intents: - raise ValueError("Unable to found Firefox application " + raise ValueError("Unable to find Firefox application " "with intent name '%s'\n" "Available ones are: %s" % (mobile_app_name, ", ".join(intents))) @@ -412,7 +389,7 @@ def run_app(harness_root_dir, manifest_rdf, harness_options, app_type, binary=None, profiledir=None, verbose=False, parseable=False, enforce_timeouts=False, logfile=None, addons=None, args=None, extra_environment={}, - norun=None, + norun=None, noquit=None, used_files=None, enable_mobile=False, mobile_app_name=None, env_root=None, @@ -433,6 +410,9 @@ def run_app(harness_root_dir, manifest_rdf, harness_options, cmdargs = [] preferences = dict(DEFAULT_COMMON_PREFS) + if is_running_tests: + preferences.update(DEFAULT_TEST_PREFS) + if no_connections: preferences.update(DEFAULT_NO_CONNECTIONS_PREFS) @@ -440,7 +420,7 @@ def run_app(harness_root_dir, manifest_rdf, harness_options, preferences['browser.tabs.remote.autostart'] = True # For now, only allow running on Mobile with --force-mobile argument - if app_type in ["fennec", "fennec-on-device"] and not enable_mobile: + if app_type in ["fennec-on-device"] and not enable_mobile: print """ WARNING: Firefox Mobile support is still experimental. If you would like to run an addon on this platform, use --force-mobile flag: @@ -454,10 +434,6 @@ def run_app(harness_root_dir, manifest_rdf, harness_options, runner_class = RemoteFennecRunner # We pass the intent name through command arguments cmdargs.append(mobile_app_name) - elif enable_mobile or app_type == "fennec": - profile_class = FennecProfile - preferences.update(DEFAULT_FENNEC_PREFS) - runner_class = FennecRunner elif app_type == "xulrunner": profile_class = XulrunnerAppProfile runner_class = XulrunnerAppRunner @@ -763,7 +739,8 @@ def run_app(harness_root_dir, manifest_rdf, harness_options, raise Timeout("Test run exceeded timeout (%ds)." % RUN_TIMEOUT, test_name, parseable) except: - runner.stop() + if not noquit: + runner.stop() raise else: runner.wait(10) diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/noLocalization/locale/en-GB.properties b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/noLocalization/locale/en-GB.properties new file mode 100644 index 00000000000..5a57eb59682 --- /dev/null +++ b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/noLocalization/locale/en-GB.properties @@ -0,0 +1 @@ +some_key = some_value diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/noLocalization/locale/en-US.properties b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/noLocalization/locale/en-US.properties new file mode 100644 index 00000000000..5a57eb59682 --- /dev/null +++ b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/noLocalization/locale/en-US.properties @@ -0,0 +1 @@ +some_key = some_value diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/noLocalization/package.json b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/noLocalization/package.json new file mode 100644 index 00000000000..5b0bb85e358 --- /dev/null +++ b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/noLocalization/package.json @@ -0,0 +1,11 @@ +{ + "name": "nolocalization", + "id": "jid1-TBF7sWF7yT6xSQ", + "license": "MPL 2.0", + "version": "0.1", + + "title": "tilteUnlocalized", + "author": "authorUnlocalized", + "description": "descriptionUnlocalized", + "homepage": "homepageUnlocalized" +} diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/twoLanguages/locale/en-GB.properties b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/twoLanguages/locale/en-GB.properties new file mode 100644 index 00000000000..64d08ab8bf4 --- /dev/null +++ b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/twoLanguages/locale/en-GB.properties @@ -0,0 +1,4 @@ +extensions.jid1-TBF7sWF7yT6xSQ@jetpack.title = title-en-GB +extensions.jid1-TBF7sWF7yT6xSQ@jetpack.author = author-en-GB +extensions.jid1-TBF7sWF7yT6xSQ@jetpack.description = description-en-GB +extensions.jid1-TBF7sWF7yT6xSQ@jetpack.homepage = homepage-en-GB diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/twoLanguages/locale/en-US.properties b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/twoLanguages/locale/en-US.properties new file mode 100644 index 00000000000..a742254ec5d --- /dev/null +++ b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/twoLanguages/locale/en-US.properties @@ -0,0 +1,4 @@ +extensions.jid1-TBF7sWF7yT6xSQ@jetpack.title = title-en-US +extensions.jid1-TBF7sWF7yT6xSQ@jetpack.author = author-en-US +extensions.jid1-TBF7sWF7yT6xSQ@jetpack.description = description-en-US +extensions.jid1-TBF7sWF7yT6xSQ@jetpack.homepage = homepage-en-US diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/twoLanguages/package.json b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/twoLanguages/package.json new file mode 100644 index 00000000000..e6a2f31946d --- /dev/null +++ b/addon-sdk/source/python-lib/cuddlefish/tests/bug-661083-files/packages/twoLanguages/package.json @@ -0,0 +1,11 @@ +{ + "name": "nolocalization", + "id": "jid1-TBF7sWF7yT6xSQ@jetpack", + "license": "MPL 2.0", + "version": "0.1", + + "title": "tilteUnlocalized", + "author": "authorUnlocalized", + "description": "descriptionUnlocalized", + "homepage": "homepageUnlocalized" +} diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/test_linker.py b/addon-sdk/source/python-lib/cuddlefish/tests/test_linker.py old mode 100755 new mode 100644 diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/test_rdf.py b/addon-sdk/source/python-lib/cuddlefish/tests/test_rdf.py index 5d9254e4e06..b4e389391a9 100644 --- a/addon-sdk/source/python-lib/cuddlefish/tests/test_rdf.py +++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_rdf.py @@ -6,7 +6,7 @@ import unittest import xml.dom.minidom import os.path -from cuddlefish import rdf, packaging +from cuddlefish import rdf, packaging, property_parser parent = os.path.dirname test_dir = parent(os.path.abspath(__file__)) @@ -49,6 +49,52 @@ class RDFTests(unittest.TestCase): self.failUnlessEqual(m.get('em:name'), 'a long ' + n) self.failUnlessIn('a long ' + n + '', str(m), n) + def testLocalization(self): + # addon_title -> + # addon_author -> + # addon_description -> + # addon_homepageURL -> + localizable_in = ["title", "author", "description", "homepage"] + localized_out = ["name", "creator", "description", "homepageURL"] + + basedir = os.path.join(test_dir, "bug-661083-files/packages") + for n in ["noLocalization", "twoLanguages"]: + harness_options = { "locale" : {} } + pkgdir = os.path.join(basedir, n) + localedir = os.path.join(pkgdir, "locale") + files = os.listdir(localedir) + + for file in files: + filepath = os.path.join(localedir, file) + if os.path.isfile(filepath) and file.endswith(".properties"): + language = file[:-len(".properties")] + try: + parsed_file = property_parser.parse_file(filepath) + except property_parser.MalformedLocaleFileError, msg: + self.fail(msg) + + harness_options["locale"][language] = parsed_file + + cfg = packaging.get_config_in_dir(pkgdir) + m = rdf.gen_manifest(template_dir, cfg, 'JID', harness_options) + + if n == "noLocalization": + self.failIf("" in str(m)) + continue + + for lang in harness_options["locale"]: + rdfstr = str(m) + node = "" + lang + "" + self.failUnlessIn(node, rdfstr, n) + + for value_in in localizable_in: + key_in = "extensions." + m.get('em:id') + "." + value_in + tag_out = localized_out[localizable_in.index(value_in)] + if key_in in harness_options["locale"][lang]: + # E.g. "author-en-US" + node = "" + value_in + "-" + lang \ + + "" + self.failUnlessIn(node , rdfstr, n) if __name__ == '__main__': unittest.main() diff --git a/addon-sdk/source/test/addons/author-email/main.js b/addon-sdk/source/test/addons/author-email/main.js index 93e1dafbae4..34786475a36 100644 --- a/addon-sdk/source/test/addons/author-email/main.js +++ b/addon-sdk/source/test/addons/author-email/main.js @@ -3,15 +3,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; -const { Cu } = require('chrome'); -const self = require('sdk/self'); -const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {}); +const { id } = require('sdk/self'); +const { getAddonByID } = require('sdk/addon/manager'); -exports.testContributors = function(assert, done) { - AddonManager.getAddonByID(self.id, (addon) => { - assert.equal(addon.creator.name, 'test ', '< and > characters work'); - done(); - }); +exports.testContributors = function*(assert) { + let addon = yield getAddonByID(id); + assert.equal(addon.creator.name, 'test ', '< and > characters work'); } require('sdk/test/runner').runTestsFromModule(module); diff --git a/addon-sdk/source/test/addons/chrome/main.js b/addon-sdk/source/test/addons/chrome/main.js index 1c196135984..c9faf1dee95 100644 --- a/addon-sdk/source/test/addons/chrome/main.js +++ b/addon-sdk/source/test/addons/chrome/main.js @@ -9,6 +9,7 @@ const { WindowTracker } = require('sdk/deprecated/window-utils'); const { close, open } = require('sdk/window/helpers'); const { data } = require('sdk/self'); const { Panel } = require('sdk/panel'); +const { setTimeout } = require("sdk/timers") const XUL_URL = 'chrome://test/content/new-window.xul' @@ -78,11 +79,12 @@ exports.testChromeInPanel = function(assert, done) { panel.port.once('echo', _ => { assert.pass('got echo'); panel.once('hide', _ => { + assert.pass('panel hidden'); panel.destroy(); assert.pass('panel is destroyed'); done(); }); - panel.hide(); + setTimeout(() => panel.hide()); }); panel.port.emit('echo'); }); diff --git a/addon-sdk/source/test/addons/contributors/main.js b/addon-sdk/source/test/addons/contributors/main.js index 915e8314286..3827f277b95 100644 --- a/addon-sdk/source/test/addons/contributors/main.js +++ b/addon-sdk/source/test/addons/contributors/main.js @@ -3,21 +3,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; -const { Cu } = require('chrome'); -const self = require('sdk/self'); -const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {}); +const { id } = require('sdk/self'); +const { getAddonByID } = require('sdk/addon/manager'); -exports.testContributors = function(assert, done) { - AddonManager.getAddonByID(self.id, function(addon) { - let count = 0; - addon.contributors.forEach(function({ name }) { - count++; - assert.equal(name, count == 1 ? 'A' : 'B', 'The contributors keys are correct'); - }); - assert.equal(count, 2, 'The key count is correct'); - assert.equal(addon.contributors.length, 2, 'The key length is correct'); - done(); +exports.testContributors = function*(assert) { + let addon = yield getAddonByID(id); + let count = 0; + addon.contributors.forEach(({ name }) => { + assert.equal(name, ++count == 1 ? 'A' : 'B', 'The contributors keys are correct'); }); + assert.equal(count, 2, 'The key count is correct'); + assert.equal(addon.contributors.length, 2, 'The key length is correct'); } require('sdk/test/runner').runTestsFromModule(module); diff --git a/addon-sdk/source/test/addons/curly-id/lib/main.js b/addon-sdk/source/test/addons/curly-id/lib/main.js index e186f9c04ca..594b16fcd53 100644 --- a/addon-sdk/source/test/addons/curly-id/lib/main.js +++ b/addon-sdk/source/test/addons/curly-id/lib/main.js @@ -6,38 +6,29 @@ const simple = require('sdk/simple-prefs'); const service = require('sdk/preferences/service'); const { id, preferencesBranch } = require('sdk/self'); -const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm'); +const { getAddonByID } = require('sdk/addon/manager'); exports.testCurlyID = function(assert) { assert.equal(id, '{34a1eae1-c20a-464f-9b0e-000000000000}', 'curly ID is curly'); - assert.equal(simple.prefs.test13, 26, 'test13 is 26'); simple.prefs.test14 = '15'; assert.equal(service.get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test14'), '15', 'test14 is 15'); - assert.equal(service.get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test14'), simple.prefs.test14, 'simple test14 also 15'); - } exports.testInvalidPreferencesBranch = function(assert) { assert.notEqual(preferencesBranch, 'invalid^branch*name', 'invalid preferences-branch value ignored'); - assert.equal(preferencesBranch, '{34a1eae1-c20a-464f-9b0e-000000000000}', 'preferences-branch is {34a1eae1-c20a-464f-9b0e-000000000000}'); - } // from `/test/test-self.js`, adapted to `sdk/test/assert` API -exports.testSelfID = function(assert, done) { - +exports.testSelfID = function*(assert) { assert.equal(typeof(id), 'string', 'self.id is a string'); assert.ok(id.length > 0, 'self.id not empty'); - AddonManager.getAddonByID(id, function(addon) { - assert.ok(addon, 'found addon with self.id'); - done(); - }); - + let addon = yield getAddonByID(id); + assert.ok(addon, 'found addon with self.id'); } require('sdk/test/runner').runTestsFromModule(module); diff --git a/addon-sdk/source/test/addons/developers/main.js b/addon-sdk/source/test/addons/developers/main.js index c7a1e5417b8..d42faf643c7 100644 --- a/addon-sdk/source/test/addons/developers/main.js +++ b/addon-sdk/source/test/addons/developers/main.js @@ -3,21 +3,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; -const { Cu } = require('chrome'); const { id } = require('sdk/self'); -const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {}); +const { getAddonByID } = require('sdk/addon/manager'); -exports.testDevelopers = function(assert, done) { - AddonManager.getAddonByID(id, (addon) => { - let count = 0; - addon.developers.forEach(({ name }) => { - count++; - assert.equal(name, count == 1 ? 'A' : 'B', 'The developers keys are correct'); - }); - assert.equal(count, 2, 'The key count is correct'); - assert.equal(addon.developers.length, 2, 'The key length is correct'); - done(); +exports.testDevelopers = function*(assert) { + let addon = yield getAddonByID(id); + let count = 0; + addon.developers.forEach(({ name }) => { + assert.equal(name, ++count == 1 ? 'A' : 'B', 'The developers keys are correct'); }); + assert.equal(count, 2, 'The key count is correct'); + assert.equal(addon.developers.length, 2, 'The key length is correct'); } require('sdk/test/runner').runTestsFromModule(module); diff --git a/addon-sdk/source/test/addons/e10s-tabs/lib/private-browsing/helper.js b/addon-sdk/source/test/addons/e10s-tabs/lib/private-browsing/helper.js index cf4d5a0162c..f581c92c09b 100644 --- a/addon-sdk/source/test/addons/e10s-tabs/lib/private-browsing/helper.js +++ b/addon-sdk/source/test/addons/e10s-tabs/lib/private-browsing/helper.js @@ -39,15 +39,6 @@ function LoaderWithHookedConsole(module) { } } -function deactivate(callback) { - if (pbUtils.isGlobalPBSupported) { - if (callback) - pb.once('stop', callback); - pb.deactivate(); - } -} -exports.deactivate = deactivate; - exports.pb = pb; exports.pbUtils = pbUtils; exports.LoaderWithHookedConsole = LoaderWithHookedConsole; diff --git a/addon-sdk/source/test/addons/e10s-tabs/lib/test-tab-utils.js b/addon-sdk/source/test/addons/e10s-tabs/lib/test-tab-utils.js index cf080e79139..888c8fdd892 100644 --- a/addon-sdk/source/test/addons/e10s-tabs/lib/test-tab-utils.js +++ b/addon-sdk/source/test/addons/e10s-tabs/lib/test-tab-utils.js @@ -4,7 +4,6 @@ const { getTabs } = require('sdk/tabs/utils'); const { isGlobalPBSupported, isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils'); const { browserWindows } = require('sdk/windows'); const tabs = require('sdk/tabs'); -const { pb } = require('./private-browsing/helper'); const { isPrivate } = require('sdk/private-browsing'); const { openTab, closeTab, getTabContentWindow, getOwnerWindow } = require('sdk/tabs/utils'); const { open, close } = require('sdk/window/helpers'); diff --git a/addon-sdk/source/test/addons/jetpack-addon.ini b/addon-sdk/source/test/addons/jetpack-addon.ini index 5f296a2c435..261f3c84d13 100644 --- a/addon-sdk/source/test/addons/jetpack-addon.ini +++ b/addon-sdk/source/test/addons/jetpack-addon.ini @@ -14,6 +14,7 @@ skip-if = true [l10n-properties.xpi] [layout-change.xpi] [main.xpi] +[manifest-localized.xpi] [packaging.xpi] [packed.xpi] [page-mod-debugger-post.xpi] diff --git a/addon-sdk/source/test/addons/manifest-localized/locale/en-US.properties b/addon-sdk/source/test/addons/manifest-localized/locale/en-US.properties new file mode 100644 index 00000000000..f0bb5047777 --- /dev/null +++ b/addon-sdk/source/test/addons/manifest-localized/locale/en-US.properties @@ -0,0 +1,4 @@ +extensions.manifest-localized@jetpack.title = title-en +extensions.manifest-localized@jetpack.author = author-en +extensions.manifest-localized@jetpack.description = description-en +extensions.manifest-localized@jetpack.homepage = homepage-en diff --git a/addon-sdk/source/test/addons/manifest-localized/main.js b/addon-sdk/source/test/addons/manifest-localized/main.js new file mode 100644 index 00000000000..e075839b002 --- /dev/null +++ b/addon-sdk/source/test/addons/manifest-localized/main.js @@ -0,0 +1,17 @@ +/* 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/. */ +"use strict"; + +const { id } = require('sdk/self'); +const { getAddonByID } = require('sdk/addon/manager'); + +exports["test add-on manifest was localized"] = function*(assert) { + let addon = yield getAddonByID(id); + assert.equal(addon.name, "title-en", "title was translated"); + assert.equal(addon.description, "description-en", "description was translated"); + assert.equal(addon.creator, "author-en", "author was translated"); + assert.equal(addon.homepageURL, "homepage-en", "homepage was translated"); +}; + +require("sdk/test/runner").runTestsFromModule(module); diff --git a/addon-sdk/source/test/addons/manifest-localized/package.json b/addon-sdk/source/test/addons/manifest-localized/package.json new file mode 100644 index 00000000000..61011ade33b --- /dev/null +++ b/addon-sdk/source/test/addons/manifest-localized/package.json @@ -0,0 +1,10 @@ +{ + "name": "manifest-localized", + "id": "manifest-localized@jetpack", + "license": "MPL 2.0", + "version": "0.1", + "title": "Manifest Not Localized", + "author": "Manifest Not Localized", + "description": "Manifest Not Localized", + "homepage": "Manifest Not Localized" +} diff --git a/addon-sdk/source/test/addons/places/tests/test-places-bookmarks.js b/addon-sdk/source/test/addons/places/tests/test-places-bookmarks.js index d84a268a3e3..0c52f7ee335 100644 --- a/addon-sdk/source/test/addons/places/tests/test-places-bookmarks.js +++ b/addon-sdk/source/test/addons/places/tests/test-places-bookmarks.js @@ -15,8 +15,7 @@ const { filter } = require('sdk/event/utils'); const { on, off } = require('sdk/event/core'); const { setTimeout } = require('sdk/timers'); const { newURI } = require('sdk/url/utils'); -const { defer, all } = require('sdk/core/promise'); -const { defer: async } = require('sdk/lang/functional'); +const { defer, all, resolve } = require('sdk/core/promise'); const { before, after } = require('sdk/test/utils'); const { @@ -41,6 +40,7 @@ exports.testDefaultFolders = function (assert) { bmsrv.toolbarFolder, bmsrv.unfiledBookmarksFolder ]; + [MENU, TOOLBAR, UNSORTED].forEach(function (g, i) { assert.ok(g.id === ids[i], ' default group matches id'); }); @@ -321,8 +321,7 @@ exports.testAddingToExistingParent = function (assert, done) { secondBatch = data; assert.equal(firstBatch[0].group.id, secondBatch[0].group.id, 'successfully saved to the same parent'); - done(); - }, assert.fail); + }).then(done).catch(assert.fail); }; exports.testUpdateParent = function (assert, done) { @@ -332,8 +331,7 @@ exports.testUpdateParent = function (assert, done) { return saveP(item[0]); }).then(item => { assert.equal(item[0].title, 'mozgroup-resave', 'group saved successfully'); - done(); - }); + }).then(done).catch(assert.fail); }; exports.testUpdateSeparator = function (assert, done) { @@ -343,8 +341,7 @@ exports.testUpdateSeparator = function (assert, done) { return saveP(item[0]); }).then(item => { assert.equal(item[0].index, 2, 'updated index of separator'); - done(); - }); + }).then(done).catch(assert.fail); }; exports.testPromisedSave = function (assert, done) { @@ -369,8 +366,7 @@ exports.testPromisedSave = function (assert, done) { assert.equal(bmsrv.getItemIndex(first.id), 2, 'properly moved bookmark'); assert.equal(bmsrv.getItemIndex(second.id), 0, 'other bookmarks adjusted'); assert.equal(bmsrv.getItemIndex(third.id), 1, 'other bookmarks adjusted'); - done(); - }); + }).then(done).catch(assert.fail); }; exports.testPromisedErrorSave = function (assert, done) { @@ -379,6 +375,7 @@ exports.testPromisedErrorSave = function (assert, done) { { title: 'moz2', url: 'invalidurl', type: 'bookmark'}, { title: 'moz3', url: 'http://moz3.com', type: 'bookmark'} ]; + saveP(bookmarks).then(invalidResolve, reason => { assert.ok( /The `url` property must be a valid URL/.test(reason), @@ -386,13 +383,14 @@ exports.testPromisedErrorSave = function (assert, done) { bookmarks[1].url = 'http://moz2.com'; return saveP(bookmarks); - }).then(res => { - return searchP({ query: 'moz' }); - }).then(res => { + }). + then(res => searchP({ query: 'moz' })). + then(res => { assert.equal(res.length, 3, 'all 3 should be saved upon retry'); res.map(item => assert.ok(/moz\d\.com/.test(item.url), 'correct item')); done(); - }, invalidReject); + }, invalidReject). + catch(assert.fail); }; exports.testMovingChildren = function (assert, done) { @@ -403,6 +401,7 @@ exports.testMovingChildren = function (assert, done) { Bookmark({ title: 'moz2', url: 'http://moz2.com', group: midFolder}), Bookmark({ title: 'moz3', url: 'http://moz3.com', group: midFolder}) ]; + save(bookmarks).on('end', bms => { let first = bms.filter(b => b.title === 'moz1')[0]; let second = bms.filter(b => b.title === 'moz2')[0]; @@ -488,7 +487,7 @@ exports.testRemove = function (assert, done) { }, 'item should no longer exist'); done(); }); - }); + }).catch(assert.fail); }; /* @@ -524,7 +523,7 @@ exports.testResolution = function (assert, done) { assert.ok(item.updated, 'bookmark has updated time'); item.title = 'my title'; // Ensure delay so a different save time is set - return delayed(item); + return resolve(item); }).then(saveP) .then(items => { let item = items[0]; @@ -546,8 +545,7 @@ exports.testResolution = function (assert, done) { }).then((results) => { let result = results[0]; assert.equal(result.title, 'a new title', 'resolve handles results'); - done(); - }); + }).then(done).catch(assert.fail);; }; /* @@ -556,13 +554,15 @@ exports.testResolution = function (assert, done) { exports.testResolutionMapping = function (assert, done) { let bookmark = Bookmark({ title: 'moz', url: 'http://bookmarks4life.com/' }); let saved; + saveP(bookmark).then(data => { saved = data[0]; saved.title = 'updated title'; // Ensure a delay for different updated times - return delayed(saved); - }).then(saveP) - .then(() => { + return resolve(saved); + }). + then(saveP). + then(() => { bookmark.title = 'conflicting title'; return saveP(bookmark, { resolve: (mine, theirs) => { assert.equal(mine.title, 'conflicting title', 'correct data for my object'); @@ -579,8 +579,7 @@ exports.testResolutionMapping = function (assert, done) { }).then((results) => { let result = results[0]; assert.equal(result.title, 'a new title', 'resolve handles results'); - done(); - }); + }).then(done).catch(assert.fail); }; exports.testUpdateTags = function (assert, done) { @@ -595,7 +594,7 @@ exports.testUpdateTags = function (assert, done) { assert.ok(!saved.tags.has('spidermonkey'), 'should not have removed tag'); done(); }); - }); + }).catch(assert.fail); }; /* @@ -625,8 +624,7 @@ exports.testSearchByGroupSimple = function (assert, done) { 'returns all children bookmarks/folders'); assert.ok(results.filter(({url}) => url === 'http://w3schools.com/'), 'returns nested children'); - done(); - }).then(null, assert.fail); + }).then(done).catch(assert.fail); }; exports.testSearchByGroupComplex = function (assert, done) { @@ -643,8 +641,7 @@ exports.testSearchByGroupComplex = function (assert, done) { assert.ok( !results.filter(({url}) => /developer.mozilla/.test(url)).length, 'does not find results from other folders'); - done(); - }, assert.fail); + }).then(done).catch(assert.fail); }; exports.testSearchEmitters = function (assert, done) { @@ -666,7 +663,7 @@ exports.testSearchEmitters = function (assert, done) { assert.equal(data[0] + '', '[object Bookmark]', 'returns bookmarks'); done(); }); - }); + }).catch(assert.fail); }; exports.testSearchTags = function (assert, done) { @@ -685,8 +682,7 @@ exports.testSearchTags = function (assert, done) { // OR tags assert.equal(data.length, 6, 'should return all bookmarks with firefox OR javascript tag'); - done(); - }); + }).then(done).catch(assert.fail); }; /* @@ -724,9 +720,7 @@ exports.testSearchURL = function (assert, done) { assert.equal(data[0].url, 'http://mozilla.org/'); assert.equal(data[1].url, 'http://mozilla.org/thunderbird/'); assert.equal(data[2].url, 'http://component.fm/'); - }).then(() => { - done(); - }); + }).then(done).catch(assert.fail); }; /* @@ -752,9 +746,7 @@ exports.testSearchQuery = function (assert, done) { assert.equal(data.length, 1); assert.equal(data[0].title, 'mdn', 'only one item matches moz query AND has a javascript tag'); - }).then(() => { - done(); - }); + }).then(done).catch(assert.fail); }; /* @@ -804,8 +796,7 @@ exports.testCaching = function (assert, done) { // require a lookup assert.equal(count, 6, 'lookup occurs once for each item and parent'); off(stream, 'data', handle); - done(); - }); + }).then(done).catch(assert.fail); function handle ({data}) count++ }; @@ -822,9 +813,8 @@ exports.testSearchCount = function (assert, done) { .then(testCount(3)) .then(testCount(5)) .then(testCount(10)) - .then(() => { - done(); - }); + .then(done) + .catch(assert.fail);; function testCount (n) { return function () { @@ -901,9 +891,7 @@ exports.testSearchSort = function (assert, done) { }).then(results => { assert.equal(results[0].url, 'http://mozilla.com/webfwd/', 'last modified should be first'); - }).then(() => { - done(); - }); + }).then(done).catch(assert.fail);; function checkOrder (results, nums) { assert.equal(results.length, nums.length, 'expected return count'); @@ -926,8 +914,7 @@ exports.testSearchComplexQueryWithOptions = function (assert, done) { ]; for (let i = 0; i < expected.length; i++) assert.equal(results[i].url, expected[i], 'correct ordering and item'); - done(); - }); + }).then(done).catch(assert.fail);; }; exports.testCheckSaveOrder = function (assert, done) { @@ -943,8 +930,7 @@ exports.testCheckSaveOrder = function (assert, done) { for (let i = 0; i < bookmarks.length; i++) assert.equal(results[i].url, bookmarks[i].url, 'correct ordering of bookmark results'); - done(); - }); + }).then(done).catch(assert.fail);; }; before(exports, (name, assert, done) => resetPlaces(done)); @@ -957,9 +943,3 @@ function saveP () { function searchP () { return promisedEmitter(search.apply(null, Array.slice(arguments))); } - -function delayed (value, ms) { - let { promise, resolve } = defer(); - setTimeout(() => resolve(value), ms || 10); - return promise; -} diff --git a/addon-sdk/source/test/addons/places/tests/test-places-events.js b/addon-sdk/source/test/addons/places/tests/test-places-events.js index d2a1c6f4553..f93c1d8dd44 100644 --- a/addon-sdk/source/test/addons/places/tests/test-places-events.js +++ b/addon-sdk/source/test/addons/places/tests/test-places-events.js @@ -305,8 +305,16 @@ exports['test history-delete-visits'] = function (assert) { assert.pass('TODO test history-delete-visits'); }; +// Bug 1060843 +// Wait a tick before finishing tests, as some bookmark activities require +// completion of a result for events. For example, when creating a bookmark, +// a `bookmark-item-added` event is fired, listened to by the first test here, +// while constructing the bookmark item requires subsequent calls to that bookmark item. +// If we destroy the underlying bookmark immediately, these calls will fail. +// +// The places SDK abstraction around this alleviates it, but these are low level events. +after(exports, (name, assert, done) => setTimeout(() => resetPlaces(done), 1)); before(exports, (name, assert, done) => resetPlaces(done)); -after(exports, (name, assert, done) => resetPlaces(done)); function saveP () { return promisedEmitter(save.apply(null, Array.slice(arguments))); diff --git a/addon-sdk/source/test/addons/predefined-id-with-at/lib/main.js b/addon-sdk/source/test/addons/predefined-id-with-at/lib/main.js index a006383fc54..12748f4eb43 100644 --- a/addon-sdk/source/test/addons/predefined-id-with-at/lib/main.js +++ b/addon-sdk/source/test/addons/predefined-id-with-at/lib/main.js @@ -6,7 +6,7 @@ const { id, preferencesBranch } = require('sdk/self'); const simple = require('sdk/simple-prefs'); const service = require('sdk/preferences/service'); -const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm', {}); +const { getAddonByID } = require('sdk/addon/manager'); const expected_id = 'predefined-id@test'; @@ -21,14 +21,12 @@ exports.testExpectedID = function(assert) { assert.equal(service.get('extensions.'+expected_id+'.test2'), simple.prefs.test2, 'test pref is 25'); } -exports.testSelfID = function(assert, done) { +exports.testSelfID = function*(assert) { assert.equal(typeof(id), 'string', 'self.id is a string'); assert.ok(id.length > 0, 'self.id not empty'); - AddonManager.getAddonByID(id, function(addon) { - assert.equal(addon.id, id, 'found addon with self.id'); - done(); - }); + let addon = yield getAddonByID(id); + assert.equal(addon.id, id, 'found addon with self.id'); } require('sdk/test/runner').runTestsFromModule(module); diff --git a/addon-sdk/source/test/addons/preferences-branch/lib/main.js b/addon-sdk/source/test/addons/preferences-branch/lib/main.js index 1f0433ffabe..659a57e9233 100644 --- a/addon-sdk/source/test/addons/preferences-branch/lib/main.js +++ b/addon-sdk/source/test/addons/preferences-branch/lib/main.js @@ -1,17 +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/. */ - 'use strict'; const { id, preferencesBranch } = require('sdk/self'); const simple = require('sdk/simple-prefs'); const service = require('sdk/preferences/service'); -const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm'); +const { getAddonByID } = require('sdk/addon/manager'); exports.testPreferencesBranch = function(assert) { assert.equal(preferencesBranch, 'human-readable', 'preferencesBranch is human-readable'); - assert.equal(simple.prefs.test42, true, 'test42 is true'); simple.prefs.test43 = 'movie'; @@ -20,16 +18,11 @@ exports.testPreferencesBranch = function(assert) { } // from `/test/test-self.js`, adapted to `sdk/test/assert` API -exports.testSelfID = function(assert, done) { - +exports.testSelfID = function*(assert) { assert.equal(typeof(id), 'string', 'self.id is a string'); assert.ok(id.length > 0, 'self.id not empty'); - - AddonManager.getAddonByID(id, function(addon) { - assert.ok(addon, 'found addon with self.id'); - done(); - }); - + let addon = yield getAddonByID(id); + assert.ok(addon, 'found addon with self.id'); } require('sdk/test/runner').runTestsFromModule(module); diff --git a/addon-sdk/source/test/addons/private-browsing-supported/main.js b/addon-sdk/source/test/addons/private-browsing-supported/main.js index ce1d6e0dcca..290427dc274 100644 --- a/addon-sdk/source/test/addons/private-browsing-supported/main.js +++ b/addon-sdk/source/test/addons/private-browsing-supported/main.js @@ -5,14 +5,12 @@ const { merge } = require('sdk/util/object'); const app = require('sdk/system/xul-app'); -const { isGlobalPBSupported } = require('sdk/private-browsing/utils'); merge(module.exports, require('./test-tabs'), require('./test-page-mod'), require('./test-private-browsing'), - require('./test-sidebar'), - isGlobalPBSupported ? require('./test-global-private-browsing') : {} + require('./test-sidebar') ); // Doesn't make sense to test window-utils and windows on fennec, diff --git a/addon-sdk/source/test/addons/private-browsing-supported/test-global-private-browsing.js b/addon-sdk/source/test/addons/private-browsing-supported/test-global-private-browsing.js deleted file mode 100644 index b29bc5447d8..00000000000 --- a/addon-sdk/source/test/addons/private-browsing-supported/test-global-private-browsing.js +++ /dev/null @@ -1,150 +0,0 @@ -/* 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/. */ -'use strict'; - -const windowUtils = require('sdk/deprecated/window-utils'); -const { isWindowPBSupported, isGlobalPBSupported } = require('sdk/private-browsing/utils'); -const { getFrames, getWindowTitle, onFocus, isWindowPrivate, windows, isBrowser } = require('sdk/window/utils'); -const { open, close, focus } = require('sdk/window/helpers'); -const { isPrivate } = require('sdk/private-browsing'); -const { Panel } = require('sdk/panel'); -const { Widget } = require('sdk/widget'); -const { fromIterator: toArray } = require('sdk/util/array'); - -let { Loader } = require('sdk/test/loader'); -let loader = Loader(module, { - console: Object.create(console, { - error: { - value: function(e) !/DEPRECATED:/.test(e) ? console.error(e) : undefined - } - }) -}); -const pb = loader.require('sdk/private-browsing'); - -function makeEmptyBrowserWindow(options) { - options = options || {}; - return open('chrome://browser/content/browser.xul', { - features: { - chrome: true, - private: !!options.private, - toolbar: true - } - }); -} - -exports.testShowPanelAndWidgetOnPrivateWindow = function(assert, done) { - var myPrivateWindow; - var finished = false; - var privateWindow; - var privateWindowClosed = false; - - pb.once('start', function() { - assert.pass('private browsing mode started'); - - // make a new private window - makeEmptyBrowserWindow().then(function(window) { - myPrivateWindow = window; - - let wt = windowUtils.WindowTracker({ - onTrack: function(window) { - if (!isBrowser(window) || window !== myPrivateWindow) return; - - assert.ok(isWindowPrivate(window), 'window is private onTrack!'); - let panel = Panel({ - onShow: function() { - assert.ok(this.isShowing, 'the panel is showing on the private window'); - - let count = 0; - let widget = Widget({ - id: "testShowPanelAndWidgetOnPrivateWindow-id", - label: "My Hello Widget", - content: "Hello!", - onAttach: function(mod) { - count++; - if (count == 2) { - panel.destroy(); - widget.destroy(); - close(window); - } - } - }); - } - }).show(null, window.gBrowser); - }, - onUntrack: function(window) { - if (window === myPrivateWindow) { - wt.unload(); - - pb.once('stop', function() { - assert.pass('private browsing mode end'); - done(); - }); - - pb.deactivate(); - } - } - }); - - assert.equal(isWindowPrivate(window), true, 'the opened window is private'); - assert.equal(isPrivate(window), true, 'the opened window is private'); - assert.ok(getFrames(window).length > 1, 'there are frames for private window'); - assert.equal(getWindowTitle(window), window.document.title, - 'getWindowTitle works'); - }); - }); - pb.activate(); -}; - -exports.testWindowTrackerDoesNotIgnorePrivateWindows = function(assert, done) { - var myPrivateWindow; - var count = 0; - - let wt = windowUtils.WindowTracker({ - onTrack: function(window) { - if (!isBrowser(window) || !isWindowPrivate(window)) return; - assert.ok(isWindowPrivate(window), 'window is private onTrack!'); - if (++count == 1) - close(window); - }, - onUntrack: function(window) { - if (count == 1 && isWindowPrivate(window)) { - wt.unload(); - - pb.once('stop', function() { - assert.pass('private browsing mode end'); - done(); - }); - pb.deactivate(); - } - } - }); - - pb.once('start', function() { - assert.pass('private browsing mode started'); - makeEmptyBrowserWindow(); - }); - pb.activate(); -} - -exports.testWindowIteratorDoesNotIgnorePrivateWindows = function(assert, done) { - pb.once('start', function() { - // make a new private window - makeEmptyBrowserWindow().then(function(window) { - assert.ok(isWindowPrivate(window), "window is private"); - assert.equal(isPrivate(window), true, 'the opened window is private'); - assert.ok(toArray(windowUtils.windowIterator()).indexOf(window) > -1, - "window is in windowIterator()"); - assert.ok(windows(null, { includePrivate: true }).indexOf(window) > -1, - "window is in windows()"); - - return close(window).then(function() { - pb.once('stop', function() { - done(); - }); - pb.deactivate(); - }); - }).then(null, assert.fail); - }); - pb.activate(); -}; diff --git a/addon-sdk/source/test/addons/simple-prefs-regression/lib/main.js b/addon-sdk/source/test/addons/simple-prefs-regression/lib/main.js index d36a441fbd6..757759dcb32 100644 --- a/addon-sdk/source/test/addons/simple-prefs-regression/lib/main.js +++ b/addon-sdk/source/test/addons/simple-prefs-regression/lib/main.js @@ -6,27 +6,24 @@ const { Cu } = require('chrome'); const sp = require('sdk/simple-prefs'); const app = require('sdk/system/xul-app'); -const self = require('sdk/self'); const tabs = require('sdk/tabs'); -const { preferencesBranch } = require('sdk/self'); - +const { preferencesBranch, id } = require('sdk/self'); +const { getAddonByID } = require('sdk/addon/manager'); const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {}); -exports.testRegression = function(assert) { - assert.equal(self.preferencesBranch, self.id, 'preferencesBranch returns id here'); +exports.testRegression = (assert) => { + assert.equal(preferencesBranch, id, 'preferencesBranch returns id here'); } -exports.testDefaultValues = function (assert) { +exports.testDefaultValues = (assert) => { assert.equal(sp.prefs.myHiddenInt, 5, 'myHiddenInt default is 5'); assert.equal(sp.prefs.myInteger, 8, 'myInteger default is 8'); assert.equal(sp.prefs.somePreference, 'TEST', 'somePreference default is correct'); } -exports.testOptionsType = function(assert, done) { - AddonManager.getAddonByID(self.id, function(aAddon) { - assert.equal(aAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, 'options type is inline'); - done(); - }); +exports.testOptionsType = function*(assert) { + let addon = yield getAddonByID(id); + assert.equal(addon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, 'options type is inline'); } if (app.is('Firefox')) { @@ -38,7 +35,7 @@ if (app.is('Firefox')) { contentScriptWhen: 'end', contentScript: 'function onLoad() {\n' + 'unsafeWindow.removeEventListener("load", onLoad, false);\n' + - 'AddonManager.getAddonByID("' + self.id + '", function(aAddon) {\n' + + 'AddonManager.getAddonByID("' + id + '", function(aAddon) {\n' + 'unsafeWindow.gViewController.viewObjects.detail.node.addEventListener("ViewChanged", function whenViewChanges() {\n' + 'unsafeWindow.gViewController.viewObjects.detail.node.removeEventListener("ViewChanged", whenViewChanges, false);\n' + 'setTimeout(function() {\n' + // TODO: figure out why this is necessary.. @@ -70,13 +67,13 @@ if (app.is('Firefox')) { onMessage: function(msg) { // test somePreference assert.equal(msg.somePreference.type, 'string', 'some pref is a string'); - assert.equal(msg.somePreference.pref, 'extensions.'+self.preferencesBranch+'.somePreference', 'somePreference path is correct'); + assert.equal(msg.somePreference.pref, 'extensions.'+preferencesBranch+'.somePreference', 'somePreference path is correct'); assert.equal(msg.somePreference.title, 'some-title', 'somePreference title is correct'); assert.equal(msg.somePreference.desc, 'Some short description for the preference', 'somePreference description is correct'); // test myInteger assert.equal(msg.myInteger.type, 'integer', 'myInteger is a int'); - assert.equal(msg.myInteger.pref, 'extensions.'+self.preferencesBranch+'.myInteger', 'extensions.test-simple-prefs.myInteger'); + assert.equal(msg.myInteger.pref, 'extensions.'+preferencesBranch+'.myInteger', 'extensions.test-simple-prefs.myInteger'); assert.equal(msg.myInteger.title, 'my-int', 'myInteger title is correct'); assert.equal(msg.myInteger.desc, 'How many of them we have.', 'myInteger desc is correct'); diff --git a/addon-sdk/source/test/addons/simple-prefs/lib/main.js b/addon-sdk/source/test/addons/simple-prefs/lib/main.js index 88d8cfd287f..7dd2f982dee 100644 --- a/addon-sdk/source/test/addons/simple-prefs/lib/main.js +++ b/addon-sdk/source/test/addons/simple-prefs/lib/main.js @@ -6,14 +6,13 @@ const { Cu } = require('chrome'); const sp = require('sdk/simple-prefs'); const app = require('sdk/system/xul-app'); -const self = require('sdk/self'); -const { preferencesBranch } = self; +const { id, preferencesBranch } = require('sdk/self'); const { open } = require('sdk/preferences/utils'); const { getTabForId } = require('sdk/tabs/utils'); const { Tab } = require('sdk/tabs/tab'); -require('sdk/tabs'); - +const { getAddonByID } = require('sdk/addon/manager'); const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {}); +require('sdk/tabs'); exports.testDefaultValues = function (assert) { assert.equal(sp.prefs.myHiddenInt, 5, 'myHiddenInt default is 5'); @@ -21,15 +20,13 @@ exports.testDefaultValues = function (assert) { assert.equal(sp.prefs.somePreference, 'TEST', 'somePreference default is correct'); } -exports.testOptionsType = function(assert, done) { - AddonManager.getAddonByID(self.id, function(aAddon) { - assert.equal(aAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, 'options type is inline'); - done(); - }); +exports.testOptionsType = function*(assert) { + let addon = yield getAddonByID(id); + assert.equal(addon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, 'options type is inline'); } exports.testButton = function(assert, done) { - open(self).then(({ tabId, document }) => { + open({ id: id }).then(({ tabId, document }) => { let tab = Tab({ tab: getTabForId(tabId) }); sp.once('sayHello', _ => { assert.pass('The button was pressed!'); @@ -44,7 +41,7 @@ exports.testButton = function(assert, done) { if (app.is('Firefox')) { exports.testAOM = function(assert, done) { - open(self).then(({ tabId }) => { + open({ id: id }).then(({ tabId }) => { let tab = Tab({ tab: getTabForId(tabId) }); assert.pass('the add-on prefs page was opened.'); @@ -73,17 +70,17 @@ if (app.is('Firefox')) { // test somePreference assert.equal(msg.somePreference.type, 'string', 'some pref is a string'); - assert.equal(msg.somePreference.pref, 'extensions.'+self.id+'.somePreference', 'somePreference path is correct'); + assert.equal(msg.somePreference.pref, 'extensions.' + id + '.somePreference', 'somePreference path is correct'); assert.equal(msg.somePreference.title, 'some-title', 'somePreference title is correct'); assert.equal(msg.somePreference.desc, 'Some short description for the preference', 'somePreference description is correct'); - assert.equal(msg.somePreference['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct'); + assert.equal(msg.somePreference['data-jetpack-id'], id, 'data-jetpack-id attribute value is correct'); // test myInteger assert.equal(msg.myInteger.type, 'integer', 'myInteger is a int'); - assert.equal(msg.myInteger.pref, 'extensions.'+self.id+'.myInteger', 'extensions.test-simple-prefs.myInteger'); + assert.equal(msg.myInteger.pref, 'extensions.' + id + '.myInteger', 'extensions.test-simple-prefs.myInteger'); assert.equal(msg.myInteger.title, 'my-int', 'myInteger title is correct'); assert.equal(msg.myInteger.desc, 'How many of them we have.', 'myInteger desc is correct'); - assert.equal(msg.myInteger['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct'); + assert.equal(msg.myInteger['data-jetpack-id'], id, 'data-jetpack-id attribute value is correct'); // test myHiddenInt assert.equal(msg.myHiddenInt.type, undefined, 'myHiddenInt was not displayed'); @@ -92,7 +89,7 @@ if (app.is('Firefox')) { assert.equal(msg.myHiddenInt.desc, undefined, 'myHiddenInt was not displayed'); // test sayHello - assert.equal(msg.sayHello['data-jetpack-id'], self.id, 'data-jetpack-id attribute value is correct'); + assert.equal(msg.sayHello['data-jetpack-id'], id, 'data-jetpack-id attribute value is correct'); tab.close(done); } @@ -103,11 +100,10 @@ if (app.is('Firefox')) { // run it again, to test against inline options document caching // and duplication of nodes upon re-entry to about:addons exports.testAgainstDocCaching = exports.testAOM; - } exports.testDefaultPreferencesBranch = function(assert) { - assert.equal(preferencesBranch, self.id, 'preferencesBranch default the same as self.id'); + assert.equal(preferencesBranch, id, 'preferencesBranch default the same as self.id'); } require('sdk/test/runner').runTestsFromModule(module); diff --git a/addon-sdk/source/test/addons/standard-id/lib/main.js b/addon-sdk/source/test/addons/standard-id/lib/main.js index ab1db12f222..afb78594a1c 100644 --- a/addon-sdk/source/test/addons/standard-id/lib/main.js +++ b/addon-sdk/source/test/addons/standard-id/lib/main.js @@ -7,7 +7,7 @@ const { id, preferencesBranch } = require('sdk/self'); const simple = require('sdk/simple-prefs'); const service = require('sdk/preferences/service'); -const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm'); +const { getAddonByID } = require('sdk/addon/manager'); exports.testStandardID = function(assert) { assert.equal(id, 'standard-id@jetpack', 'standard ID is standard'); @@ -16,29 +16,20 @@ exports.testStandardID = function(assert) { simple.prefs.test14 = '15'; assert.equal(service.get('extensions.standard-id@jetpack.test14'), '15', 'test14 is 15'); - assert.equal(service.get('extensions.standard-id@jetpack.test14'), simple.prefs.test14, 'simple test14 also 15'); - } exports.testInvalidPreferencesBranch = function(assert) { assert.notEqual(preferencesBranch, 'invalid^branch*name', 'invalid preferences-branch value ignored'); - assert.equal(preferencesBranch, 'standard-id@jetpack', 'preferences-branch is standard-id@jetpack'); - } // from `/test/test-self.js`, adapted to `sdk/test/assert` API -exports.testSelfID = function(assert, done) { - +exports.testSelfID = function*(assert) { assert.equal(typeof(id), 'string', 'self.id is a string'); assert.ok(id.length > 0, 'self.id not empty'); - - AddonManager.getAddonByID(id, function(addon) { - assert.ok(addon, 'found addon with self.id'); - done(); - }); - + let addon = yield getAddonByID(id); + assert.ok(addon, 'found addon with self.id'); } require('sdk/test/runner').runTestsFromModule(module); diff --git a/addon-sdk/source/test/addons/translators/main.js b/addon-sdk/source/test/addons/translators/main.js index 2d43b3beda5..9c7cfff0981 100644 --- a/addon-sdk/source/test/addons/translators/main.js +++ b/addon-sdk/source/test/addons/translators/main.js @@ -3,21 +3,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; -const { Cc, Ci, Cu, Cm, components } = require('chrome'); -const self = require('sdk/self'); -const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {}); +const { id } = require('sdk/self'); +const { getAddonByID } = require('sdk/addon/manager'); -exports.testTranslators = function(assert, done) { - AddonManager.getAddonByID(self.id, function(addon) { - let count = 0; - addon.translators.forEach(function({ name }) { - count++; - assert.equal(name, 'Erik Vold', 'The translator keys are correct'); - }); - assert.equal(count, 1, 'The translator key count is correct'); - assert.equal(addon.translators.length, 1, 'The translator key length is correct'); - done(); +exports.testTranslators = function*(assert) { + let addon = yield getAddonByID(id); + let count = 0; + addon.translators.forEach(function({ name }) { + count++; + assert.equal(name, 'Erik Vold', 'The translator keys are correct'); }); + assert.equal(count, 1, 'The translator key count is correct'); + assert.equal(addon.translators.length, 1, 'The translator key length is correct'); } require('sdk/test/runner').runTestsFromModule(module); diff --git a/addon-sdk/source/test/jetpack-package.ini b/addon-sdk/source/test/jetpack-package.ini index 66a406ae1b7..47b2749895f 100644 --- a/addon-sdk/source/test/jetpack-package.ini +++ b/addon-sdk/source/test/jetpack-package.ini @@ -18,6 +18,7 @@ support-files = test-tmp-file.txt [test-addon-installer.js] +[test-addon-manager.js] [test-addon-window.js] [test-api-utils.js] [test-array.js] @@ -153,7 +154,6 @@ skip-if = true [test-window-events.js] [test-window-loader.js] [test-window-observer.js] -[test-window-utils-global-private-browsing.js] [test-window-utils-private-browsing.js] [test-window-utils.js] [test-window-utils2.js] diff --git a/addon-sdk/source/test/private-browsing/global.js b/addon-sdk/source/test/private-browsing/global.js deleted file mode 100644 index 89d7da4e282..00000000000 --- a/addon-sdk/source/test/private-browsing/global.js +++ /dev/null @@ -1,239 +0,0 @@ -/* 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/. */ -'use strict'; - -const timer = require("sdk/timers"); -const { LoaderWithHookedConsole, deactivate, pb, pbUtils } = require("./helper"); -const tabs = require("sdk/tabs"); -const { getMostRecentBrowserWindow, isWindowPrivate } = require('sdk/window/utils'); -const { set: setPref } = require("sdk/preferences/service"); -const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings"; - -exports["test activate private mode via handler"] = function(assert, done) { - function onReady(tab) { - if (tab.url == "about:robots") - tab.close(function() pb.activate()); - } - function cleanup(tab) { - if (tab.url == "about:") { - tabs.removeListener("ready", cleanup); - tab.close(function onClose() { - done(); - }); - } - } - - tabs.on("ready", onReady); - pb.once("start", function onStart() { - assert.pass("private mode was activated"); - pb.deactivate(); - }); - pb.once("stop", function onStop() { - assert.pass("private mode was deactivated"); - tabs.removeListener("ready", onReady); - tabs.on("ready", cleanup); - }); - tabs.once("open", function onOpen() { - tabs.open("about:robots"); - }); - tabs.open("about:"); -}; - -// tests that isActive has the same value as the private browsing service -// expects -exports.testGetIsActive = function (assert) { - assert.equal(pb.isActive, false, - "private-browsing.isActive is correct without modifying PB service"); - assert.equal(pb.isPrivate(), false, - "private-browsing.sPrivate() is correct without modifying PB service"); - - pb.once("start", function() { - assert.ok(pb.isActive, - "private-browsing.isActive is correct after modifying PB service"); - assert.ok(pb.isPrivate(), - "private-browsing.sPrivate() is correct after modifying PB service"); - // Switch back to normal mode. - pb.deactivate(); - }); - pb.activate(); - - pb.once("stop", function() { - assert.ok(!pb.isActive, - "private-browsing.isActive is correct after modifying PB service"); - assert.ok(!pb.isPrivate(), - "private-browsing.sPrivate() is correct after modifying PB service"); - test.done(); - }); -}; - -exports.testStart = function(assert, done) { - pb.on("start", function onStart() { - assert.equal(this, pb, "`this` should be private-browsing module"); - assert.ok(pbUtils.getMode(), - 'private mode is active when "start" event is emitted'); - assert.ok(pb.isActive, - '`isActive` is `true` when "start" event is emitted'); - assert.ok(pb.isPrivate(), - '`isPrivate` is `true` when "start" event is emitted'); - pb.removeListener("start", onStart); - deactivate(done); - }); - pb.activate(); -}; - -exports.testStop = function(assert, done) { - pb.once("stop", function onStop() { - assert.equal(this, pb, "`this` should be private-browsing module"); - assert.equal(pbUtils.getMode(), false, - "private mode is disabled when stop event is emitted"); - assert.equal(pb.isActive, false, - "`isActive` is `false` when stop event is emitted"); - assert.equal(pb.isPrivate(), false, - "`isPrivate()` is `false` when stop event is emitted"); - done(); - }); - pb.activate(); - pb.once("start", function() { - pb.deactivate(); - }); -}; - -exports.testBothListeners = function(assert, done) { - let stop = false; - let start = false; - - function onStop() { - assert.equal(stop, false, - "stop callback must be called only once"); - assert.equal(pbUtils.getMode(), false, - "private mode is disabled when stop event is emitted"); - assert.equal(pb.isActive, false, - "`isActive` is `false` when stop event is emitted"); - assert.equal(pb.isPrivate(), false, - "`isPrivate()` is `false` when stop event is emitted"); - - pb.on("start", finish); - pb.removeListener("start", onStart); - pb.removeListener("start", onStart2); - pb.activate(); - stop = true; - } - - function onStart() { - assert.equal(false, start, - "stop callback must be called only once"); - assert.ok(pbUtils.getMode(), - "private mode is active when start event is emitted"); - assert.ok(pb.isActive, - "`isActive` is `true` when start event is emitted"); - assert.ok(pb.isPrivate(), - "`isPrivate()` is `true` when start event is emitted"); - - pb.on("stop", onStop); - pb.deactivate(); - start = true; - } - - function onStart2() { - assert.ok(start, "start listener must be called already"); - assert.equal(false, stop, "stop callback must not be called yet"); - } - - function finish() { - assert.ok(pbUtils.getMode(), true, - "private mode is active when start event is emitted"); - assert.ok(pb.isActive, - "`isActive` is `true` when start event is emitted"); - assert.ok(pb.isPrivate(), - "`isPrivate()` is `true` when start event is emitted"); - - pb.removeListener("start", finish); - pb.removeListener("stop", onStop); - - pb.deactivate(); - pb.once("stop", function () { - assert.equal(pbUtils.getMode(), false); - assert.equal(pb.isActive, false); - assert.equal(pb.isPrivate(), false); - - done(); - }); - } - - pb.on("start", onStart); - pb.on("start", onStart2); - pb.activate(); -}; - -exports.testAutomaticUnload = function(assert, done) { - setPref(DEPRECATE_PREF, true); - - // Create another private browsing instance and unload it - let { loader, errors } = LoaderWithHookedConsole(module); - let pb2 = loader.require("sdk/private-browsing"); - let called = false; - pb2.on("start", function onStart() { - called = true; - assert.fail("should not be called:x"); - }); - loader.unload(); - - // Then switch to private mode in order to check that the previous instance - // is correctly destroyed - pb.once("start", function onStart() { - timer.setTimeout(function () { - assert.ok(!called, - "First private browsing instance is destroyed and inactive"); - // Must reset to normal mode, so that next test starts with it. - deactivate(function() { - assert.ok(errors.length, 0, "should have been 1 deprecation error"); - done(); - }); - }, 0); - }); - - pb.activate(); -}; - -exports.testUnloadWhileActive = function(assert, done) { - let called = false; - let { loader, errors } = LoaderWithHookedConsole(module); - let pb2 = loader.require("sdk/private-browsing"); - let ul = loader.require("sdk/system/unload"); - - let unloadHappened = false; - ul.when(function() { - unloadHappened = true; - timer.setTimeout(function() { - pb.deactivate(); - }); - }); - pb2.once("start", function() { - loader.unload(); - }); - pb2.once("stop", function() { - called = true; - assert.ok(unloadHappened, "the unload event should have already occurred."); - assert.fail("stop should not have been fired"); - }); - pb.once("stop", function() { - assert.ok(!called, "stop was not called on unload"); - assert.ok(errors.length, 2, "should have been 2 deprecation errors"); - done(); - }); - - pb.activate(); -}; - -exports.testIgnoreWindow = function(assert, done) { - let window = getMostRecentBrowserWindow(); - - pb.once('start', function() { - assert.ok(isWindowPrivate(window), 'window is private'); - assert.ok(!pbUtils.ignoreWindow(window), 'window is not ignored'); - pb.once('stop', done); - pb.deactivate(); - }); - pb.activate(); -}; diff --git a/addon-sdk/source/test/private-browsing/helper.js b/addon-sdk/source/test/private-browsing/helper.js index cf4d5a0162c..4a400b95b67 100644 --- a/addon-sdk/source/test/private-browsing/helper.js +++ b/addon-sdk/source/test/private-browsing/helper.js @@ -3,12 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; -const { Loader } = require('sdk/test/loader'); - -const { loader } = LoaderWithHookedConsole(module); - -const pb = loader.require('sdk/private-browsing'); -const pbUtils = loader.require('sdk/private-browsing/utils'); const xulApp = require("sdk/system/xul-app"); const { open: openWindow, getMostRecentBrowserWindow } = require('sdk/window/utils'); const { openTab, getTabContentWindow, getActiveTab, setTabURL, closeTab } = require('sdk/tabs/utils'); @@ -16,42 +10,6 @@ const promise = require("sdk/core/promise"); const windowHelpers = require('sdk/window/helpers'); const events = require("sdk/system/events"); -function LoaderWithHookedConsole(module) { - let globals = {}; - let errors = []; - - globals.console = Object.create(console, { - error: { - value: function(e) { - errors.push(e); - if (!/DEPRECATED:/.test(e)) { - console.error(e); - } - } - } - }); - - let loader = Loader(module, globals); - - return { - loader: loader, - errors: errors - } -} - -function deactivate(callback) { - if (pbUtils.isGlobalPBSupported) { - if (callback) - pb.once('stop', callback); - pb.deactivate(); - } -} -exports.deactivate = deactivate; - -exports.pb = pb; -exports.pbUtils = pbUtils; -exports.LoaderWithHookedConsole = LoaderWithHookedConsole; - exports.openWebpage = function openWebpage(url, enablePrivate) { if (xulApp.is("Fennec")) { let chromeWindow = getMostRecentBrowserWindow(); diff --git a/addon-sdk/source/test/private-browsing/windows.js b/addon-sdk/source/test/private-browsing/windows.js index c89a34d53a9..58215ac5a65 100644 --- a/addon-sdk/source/test/private-browsing/windows.js +++ b/addon-sdk/source/test/private-browsing/windows.js @@ -3,10 +3,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; -const { pb, pbUtils } = require('./helper'); const { onFocus, openDialog, open } = require('sdk/window/utils'); const { open: openPromise, close, focus, promise } = require('sdk/window/helpers'); const { isPrivate } = require('sdk/private-browsing'); +const { getMode } = require('sdk/private-browsing/utils'); const { browserWindows: windows } = require('sdk/windows'); const { defer } = require('sdk/core/promise'); const tabs = require('sdk/tabs'); @@ -14,45 +14,31 @@ const tabs = require('sdk/tabs'); // test openDialog() from window/utils with private option // test isActive state in pwpb case // test isPrivate on ChromeWindow -exports.testPerWindowPrivateBrowsingGetter = function(assert, done) { - let win = openDialog({ - private: true - }); +exports.testPerWindowPrivateBrowsingGetter = function*(assert) { + let win = openDialog({ private: true }); - promise(win, 'DOMContentLoaded').then(function onload() { - assert.equal(pbUtils.getMode(win), - true, 'Newly opened window is in PB mode'); - assert.ok(isPrivate(win), 'isPrivate(window) is true'); - assert.equal(pb.isActive, false, 'PB mode is not active'); + yield promise(win, 'DOMContentLoaded'); - close(win).then(function() { - assert.equal(pb.isActive, false, 'PB mode is not active'); - done(); - }); - }); + assert.equal(getMode(win), true, 'Newly opened window is in PB mode'); + assert.ok(isPrivate(win), 'isPrivate(window) is true'); + + yield close(win); } // test open() from window/utils with private feature // test isActive state in pwpb case // test isPrivate on ChromeWindow -exports.testPerWindowPrivateBrowsingGetter = function(assert, done) { +exports.testPerWindowPrivateBrowsingGetter = function*(assert) { let win = open('chrome://browser/content/browser.xul', { features: { private: true } }); - promise(win, 'DOMContentLoaded').then(function onload() { - assert.equal(pbUtils.getMode(win), - true, 'Newly opened window is in PB mode'); - assert.ok(isPrivate(win), 'isPrivate(window) is true'); - assert.equal(pb.isActive, false, 'PB mode is not active'); - - close(win).then(function() { - assert.equal(pb.isActive, false, 'PB mode is not active'); - done(); - }); - }); + yield promise(win, 'DOMContentLoaded'); + assert.equal(getMode(win), true, 'Newly opened window is in PB mode'); + assert.ok(isPrivate(win), 'isPrivate(window) is true'); + yield close(win) } exports.testIsPrivateOnWindowOpen = function(assert, done) { diff --git a/addon-sdk/source/test/test-addon-installer.js b/addon-sdk/source/test/test-addon-installer.js index 788e6872a5f..951155c29e0 100644 --- a/addon-sdk/source/test/test-addon-installer.js +++ b/addon-sdk/source/test/test-addon-installer.js @@ -175,4 +175,4 @@ exports['test Enable failure'] = function (assert, done) { ).then(done, assert.fail); }; -require("test").run(exports); +require("sdk/test").run(exports); diff --git a/addon-sdk/source/test/test-addon-manager.js b/addon-sdk/source/test/test-addon-manager.js new file mode 100644 index 00000000000..adb4145bed2 --- /dev/null +++ b/addon-sdk/source/test/test-addon-manager.js @@ -0,0 +1,14 @@ +/* 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/. */ +"use strict"; + +const { id } = require("sdk/self"); +const { getAddonByID } = require("sdk/addon/manager"); + +exports["test getAddonByID"] = function*(assert) { + let addon = yield getAddonByID(id); + assert.equal(addon.id, id, "getAddonByID works"); +} + +require("sdk/test").run(exports); diff --git a/addon-sdk/source/test/test-buffer.js b/addon-sdk/source/test/test-buffer.js index 1e3379e00cb..c13ce4910b1 100644 --- a/addon-sdk/source/test/test-buffer.js +++ b/addon-sdk/source/test/test-buffer.js @@ -391,7 +391,7 @@ exports.testBufferSlice = function (assert) { assert.equal(buf.slice(0, 65536), '0123456789', 'buffer slice range correct'); assert.equal(buf.slice(65536, 0), '', 'buffer slice range correct'); - let sliceTest = true; + sliceTest = true; for (var i = 0, s = buf.toString(); i < buf.length; ++i) { if (buf.slice(-i) != s.slice(-i)) sliceTest = false; if (buf.slice(0, -i) != s.slice(0, -i)) sliceTest = false; @@ -463,7 +463,7 @@ exports.testBufferConcat = function (assert) { assert.equal(flatZero.length, 0); assert.equal(flatOne.toString(), 'asdf'); assert.equal(flatOne, one[0]); - assert.ok(flatLong.toString(), (new Array(10+1).join('asdf'))); + assert.equal(flatLong.toString(), (new Array(10+1).join('asdf'))); assert.equal(flatLongLen.toString(), (new Array(10+1).join('asdf'))); }; diff --git a/addon-sdk/source/test/test-context-menu.js b/addon-sdk/source/test/test-context-menu.js index 6b732bc5b0b..c29b8849798 100644 --- a/addon-sdk/source/test/test-context-menu.js +++ b/addon-sdk/source/test/test-context-menu.js @@ -10,6 +10,7 @@ require("sdk/context-menu"); const { Loader } = require('sdk/test/loader'); const timer = require("sdk/timers"); const { merge } = require("sdk/util/object"); +const { defer } = require("sdk/core/promise"); // These should match the same constants in the module. const ITEM_CLASS = "addon-context-menu-item"; @@ -2664,6 +2665,58 @@ exports.testItemNoData = function (assert, done) { } +exports.testItemNoAccessKey = function (assert, done) { + let test = new TestHelper(assert, done); + let loader = test.newLoader(); + + let item1 = new loader.cm.Item({ label: "item 1" }); + let item2 = new loader.cm.Item({ label: "item 2", accesskey: null }); + let item3 = new loader.cm.Item({ label: "item 3", accesskey: undefined }); + + assert.equal(item1.accesskey, undefined, "Should be no defined image"); + assert.equal(item2.accesskey, null, "Should be no defined image"); + assert.equal(item3.accesskey, undefined, "Should be no defined image"); + + test.showMenu(). + then((popup) => test.checkMenu([item1, item2, item3], [], [])). + then(test.done). + catch(assert.fail); +} + + +// Test accesskey support. +exports.testItemAccessKey = function (assert, done) { + let test = new TestHelper(assert, done); + let loader = test.newLoader(); + + let item = new loader.cm.Item({ label: "item", accesskey: "i" }); + assert.equal(item.accesskey, "i", "Should have set the image to i"); + + let menu = new loader.cm.Menu({ label: "menu", accesskey: "m", items: [ + loader.cm.Item({ label: "subitem" }) + ]}); + assert.equal(menu.accesskey, "m", "Should have set the accesskey to m"); + + test.showMenu().then((popup) => { + test.checkMenu([item, menu], [], []); + + let accesskey = "e"; + menu.accesskey = item.accesskey = accesskey; + assert.equal(item.accesskey, accesskey, "Should have set the accesskey to " + accesskey); + assert.equal(menu.accesskey, accesskey, "Should have set the accesskey to " + accesskey); + test.checkMenu([item, menu], [], []); + + item.accesskey = null; + menu.accesskey = null; + assert.equal(item.accesskey, null, "Should have set the accesskey to " + accesskey); + assert.equal(menu.accesskey, null, "Should have set the accesskey to " + accesskey); + test.checkMenu([item, menu], [], []); + }). + then(test.done). + catch(assert.fail); +}; + + // Tests that items without an image don't attempt to show one exports.testItemNoImage = function (assert, done) { let test = new TestHelper(assert, done); @@ -3695,6 +3748,7 @@ function TestHelper(assert, done) { getMostRecentWindow("navigator:browser"); this.overflowThreshValue = require("sdk/preferences/service"). get(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT); + this.done = this.done.bind(this); } TestHelper.prototype = { @@ -3753,6 +3807,20 @@ TestHelper.prototype = { if (itemType === "Item" || itemType === "Menu") { this.assert.equal(elt.getAttribute("label"), item.label, "Item should have correct title"); + + // validate accesskey prop + if (item.accesskey) { + this.assert.equal(elt.getAttribute("accesskey"), + item.accesskey, + "Item should have correct accesskey"); + } + else { + this.assert.equal(elt.getAttribute("accesskey"), + "", + "Item should not have accesskey"); + } + + // validate image prop if (typeof(item.image) === "string") { this.assert.equal(elt.getAttribute("image"), item.image, "Item should have correct image"); @@ -4034,11 +4102,16 @@ TestHelper.prototype = { // menu is opened in the top-left corner. onShowncallback is passed the // popup. showMenu: function(targetNode, onshownCallback) { + let { promise, resolve } = defer(); + function sendEvent() { this.delayedEventListener(this.browserWindow, "popupshowing", function (e) { let popup = e.target; - onshownCallback.call(this, popup); + if (onshownCallback) { + onshownCallback.call(this, popup); + } + resolve(popup); }, false); let rect = targetNode ? @@ -4070,6 +4143,8 @@ TestHelper.prototype = { } else sendEvent.call(this); + + return promise; }, hideMenu: function(onhiddenCallback) { diff --git a/addon-sdk/source/test/test-dev-panel.js b/addon-sdk/source/test/test-dev-panel.js index b3cc82d5a1e..5ef886fc3aa 100644 --- a/addon-sdk/source/test/test-dev-panel.js +++ b/addon-sdk/source/test/test-dev-panel.js @@ -15,6 +15,8 @@ const { Class } = require("sdk/core/heritage"); const { openToolbox, closeToolbox, getCurrentPanel } = require("dev/utils"); const { MessageChannel } = require("sdk/messaging"); const { when } = require("sdk/dom/events"); +const { viewFor } = require("sdk/view/core"); +const { createView } = require("dev/panel/view"); const iconURI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAKQWlDQ1BJQ0MgUHJvZmlsZQAASA2dlndUU9kWh8+9N73QEiIgJfQaegkg0jtIFQRRiUmAUAKGhCZ2RAVGFBEpVmRUwAFHhyJjRRQLg4Ji1wnyEFDGwVFEReXdjGsJ7601896a/cdZ39nnt9fZZ+9917oAUPyCBMJ0WAGANKFYFO7rwVwSE8vE9wIYEAEOWAHA4WZmBEf4RALU/L09mZmoSMaz9u4ugGS72yy/UCZz1v9/kSI3QyQGAApF1TY8fiYX5QKUU7PFGTL/BMr0lSkyhjEyFqEJoqwi48SvbPan5iu7yZiXJuShGlnOGbw0noy7UN6aJeGjjAShXJgl4GejfAdlvVRJmgDl9yjT0/icTAAwFJlfzOcmoWyJMkUUGe6J8gIACJTEObxyDov5OWieAHimZ+SKBIlJYqYR15hp5ejIZvrxs1P5YjErlMNN4Yh4TM/0tAyOMBeAr2+WRQElWW2ZaJHtrRzt7VnW5mj5v9nfHn5T/T3IevtV8Sbsz55BjJ5Z32zsrC+9FgD2JFqbHbO+lVUAtG0GQOXhrE/vIADyBQC03pzzHoZsXpLE4gwnC4vs7GxzAZ9rLivoN/ufgm/Kv4Y595nL7vtWO6YXP4EjSRUzZUXlpqemS0TMzAwOl89k/fcQ/+PAOWnNycMsnJ/AF/GF6FVR6JQJhIlou4U8gViQLmQKhH/V4X8YNicHGX6daxRodV8AfYU5ULhJB8hvPQBDIwMkbj96An3rWxAxCsi+vGitka9zjzJ6/uf6Hwtcim7hTEEiU+b2DI9kciWiLBmj34RswQISkAd0oAo0gS4wAixgDRyAM3AD3iAAhIBIEAOWAy5IAmlABLJBPtgACkEx2AF2g2pwANSBetAEToI2cAZcBFfADXALDIBHQAqGwUswAd6BaQiC8BAVokGqkBakD5lC1hAbWgh5Q0FQOBQDxUOJkBCSQPnQJqgYKoOqoUNQPfQjdBq6CF2D+qAH0CA0Bv0BfYQRmALTYQ3YALaA2bA7HAhHwsvgRHgVnAcXwNvhSrgWPg63whfhG/AALIVfwpMIQMgIA9FGWAgb8URCkFgkAREha5EipAKpRZqQDqQbuY1IkXHkAwaHoWGYGBbGGeOHWYzhYlZh1mJKMNWYY5hWTBfmNmYQM4H5gqVi1bGmWCesP3YJNhGbjS3EVmCPYFuwl7ED2GHsOxwOx8AZ4hxwfrgYXDJuNa4Etw/XjLuA68MN4SbxeLwq3hTvgg/Bc/BifCG+Cn8cfx7fjx/GvyeQCVoEa4IPIZYgJGwkVBAaCOcI/YQRwjRRgahPdCKGEHnEXGIpsY7YQbxJHCZOkxRJhiQXUiQpmbSBVElqIl0mPSa9IZPJOmRHchhZQF5PriSfIF8lD5I/UJQoJhRPShxFQtlOOUq5QHlAeUOlUg2obtRYqpi6nVpPvUR9Sn0vR5Mzl/OX48mtk6uRa5Xrl3slT5TXl3eXXy6fJ18hf0r+pvy4AlHBQMFTgaOwVqFG4bTCPYVJRZqilWKIYppiiWKD4jXFUSW8koGStxJPqUDpsNIlpSEaQtOledK4tE20Otpl2jAdRzek+9OT6cX0H+i99AllJWVb5SjlHOUa5bPKUgbCMGD4M1IZpYyTjLuMj/M05rnP48/bNq9pXv+8KZX5Km4qfJUilWaVAZWPqkxVb9UU1Z2qbapP1DBqJmphatlq+9Uuq43Pp893ns+dXzT/5PyH6rC6iXq4+mr1w+o96pMamhq+GhkaVRqXNMY1GZpumsma5ZrnNMe0aFoLtQRa5VrntV4wlZnuzFRmJbOLOaGtru2nLdE+pN2rPa1jqLNYZ6NOs84TXZIuWzdBt1y3U3dCT0svWC9fr1HvoT5Rn62fpL9Hv1t/ysDQINpgi0GbwaihiqG/YZ5ho+FjI6qRq9Eqo1qjO8Y4Y7ZxivE+41smsImdSZJJjclNU9jU3lRgus+0zwxr5mgmNKs1u8eisNxZWaxG1qA5wzzIfKN5m/krCz2LWIudFt0WXyztLFMt6ywfWSlZBVhttOqw+sPaxJprXWN9x4Zq42Ozzqbd5rWtqS3fdr/tfTuaXbDdFrtOu8/2DvYi+yb7MQc9h3iHvQ732HR2KLuEfdUR6+jhuM7xjOMHJ3snsdNJp9+dWc4pzg3OowsMF/AX1C0YctFx4bgccpEuZC6MX3hwodRV25XjWuv6zE3Xjed2xG3E3dg92f24+ysPSw+RR4vHlKeT5xrPC16Il69XkVevt5L3Yu9q76c+Oj6JPo0+E752vqt9L/hh/QL9dvrd89fw5/rX+08EOASsCegKpARGBFYHPgsyCRIFdQTDwQHBu4IfL9JfJFzUFgJC/EN2hTwJNQxdFfpzGC4sNKwm7Hm4VXh+eHcELWJFREPEu0iPyNLIR4uNFksWd0bJR8VF1UdNRXtFl0VLl1gsWbPkRoxajCCmPRYfGxV7JHZyqffS3UuH4+ziCuPuLjNclrPs2nK15anLz66QX8FZcSoeGx8d3xD/iRPCqeVMrvRfuXflBNeTu4f7kufGK+eN8V34ZfyRBJeEsoTRRJfEXYljSa5JFUnjAk9BteB1sl/ygeSplJCUoykzqdGpzWmEtPi000IlYYqwK10zPSe9L8M0ozBDuspp1e5VE6JA0ZFMKHNZZruYjv5M9UiMJJslg1kLs2qy3mdHZZ/KUcwR5vTkmuRuyx3J88n7fjVmNXd1Z752/ob8wTXuaw6thdauXNu5Tnddwbrh9b7rj20gbUjZ8MtGy41lG99uit7UUaBRsL5gaLPv5sZCuUJR4b0tzlsObMVsFWzt3WazrWrblyJe0fViy+KK4k8l3JLr31l9V/ndzPaE7b2l9qX7d+B2CHfc3em681iZYlle2dCu4F2t5czyovK3u1fsvlZhW3FgD2mPZI+0MqiyvUqvakfVp+qk6oEaj5rmvep7t+2d2sfb17/fbX/TAY0DxQc+HhQcvH/I91BrrUFtxWHc4azDz+ui6rq/Z39ff0TtSPGRz0eFR6XHwo911TvU1zeoN5Q2wo2SxrHjccdv/eD1Q3sTq+lQM6O5+AQ4ITnx4sf4H++eDDzZeYp9qukn/Z/2ttBailqh1tzWibakNml7THvf6YDTnR3OHS0/m/989Iz2mZqzymdLz5HOFZybOZ93fvJCxoXxi4kXhzpXdD66tOTSna6wrt7LgZevXvG5cqnbvfv8VZerZ645XTt9nX297Yb9jdYeu56WX+x+aem172296XCz/ZbjrY6+BX3n+l37L972un3ljv+dGwOLBvruLr57/17cPel93v3RB6kPXj/Mejj9aP1j7OOiJwpPKp6qP6391fjXZqm99Oyg12DPs4hnj4a4Qy//lfmvT8MFz6nPK0a0RupHrUfPjPmM3Xqx9MXwy4yX0+OFvyn+tveV0auffnf7vWdiycTwa9HrmT9K3qi+OfrW9m3nZOjk03dp76anit6rvj/2gf2h+2P0x5Hp7E/4T5WfjT93fAn88ngmbWbm3/eE8/syOll+AAAACXBIWXMAAAsTAAALEwEAmpwYAAADqmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6M0ExNEY4NjZBNkU1MTFFMTlGMkFGQ0QyNTUyN0VDRjY8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0YW5jZUlEPnhtcC5paWQ6M0ExNEY4NjNBNkU1MTFFMTlGMkFGQ0QyNTUyN0VDRjY8L3N0UmVmOmluc3RhbmNlSUQ+CiAgICAgICAgICAgIDxzdFJlZjpkb2N1bWVudElEPnhtcC5kaWQ6M0ExNEY4NjRBNkU1MTFFMTlGMkFGQ0QyNTUyN0VDRjY8L3N0UmVmOmRvY3VtZW50SUQ+CiAgICAgICAgIDwveG1wTU06RGVyaXZlZEZyb20+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6M0ExNEY4NjVBNkU1MTFFMTlGMkFGQ0QyNTUyN0VDRjY8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2g8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+ChetDDYAAACaSURBVEgNY2AYboAR3UNnzpx5DxQTQBP/YGJiIogmBuYSq54Ji2Z0S0BKsInBtGKTwxDDZhHMAKrSdLOIqq7GZxjj+fPnBf7+/bseqMgBn0IK5A4wMzMHMtHYEpD7HEB2gOLIAcSjMXCgW2IYtYjsqBwNutGgg4fAaGKABwWpDLoG3QFSXUeG+gNMoEoJqJGWloErPjIcR54WALqPHeiJgl15AAAAAElFTkSuQmCC"; const makeHTML = fn => @@ -233,4 +235,88 @@ exports["test communication with debuggee"] = test(function*(assert) { assert.equal(panel.readyState, "destroyed", "panel is destroyed"); }); + +exports["test viewFor panel"] = test(function*(assert) { + const url = "data:text/html;charset=utf-8,viewFor"; + const MyPanel = Class({ + extends: Panel, + label: "view for panel", + tooltip: "my panel view", + icon: iconURI, + url: url + }); + + const myTool = new Tool({ + panels: { + myPanel: MyPanel + } + }); + + + const toolbox = yield openToolbox(MyPanel); + const panel = yield getCurrentPanel(toolbox); + assert.ok(panel instanceof MyPanel, "is instance of MyPanel"); + + const frame = viewFor(panel); + + assert.equal(frame.nodeName.toLowerCase(), "iframe", + "viewFor(panel) returns associated iframe"); + + yield panel.loaded(); + + assert.equal(frame.contentDocument.URL, url, "is expected iframe"); + + yield closeToolbox(); +}); + + +exports["test createView panel"] = test(function*(assert) { + var frame = null; + var panel = null; + + const url = "data:text/html;charset=utf-8,createView"; + const id = Math.random().toString(16).substr(2); + const MyPanel = Class({ + extends: Panel, + label: "create view", + tooltip: "panel creator", + icon: iconURI, + url: url + }); + + createView.define(MyPanel, (instance, document) => { + var view = document.createElement("iframe"); + view.setAttribute("type", "content"); + + // save instances for later asserts + frame = view; + panel = instance; + + return view; + }); + + const myTool = new Tool({ + panels: { + myPanel: MyPanel + } + }); + + + const toolbox = yield openToolbox(MyPanel); + const myPanel = yield getCurrentPanel(toolbox); + + assert.equal(myPanel, panel, + "panel passed to createView is one instantiated"); + assert.equal(viewFor(panel), frame, + "createView has created an iframe"); + + yield panel.loaded(); + + assert.equal(frame.contentDocument.URL, url, "is expected iframe"); + + yield closeToolbox(); +}); + + require("test").run(exports); + diff --git a/addon-sdk/source/test/test-disposable.js b/addon-sdk/source/test/test-disposable.js index b549fd02a12..c790be9b74c 100644 --- a/addon-sdk/source/test/test-disposable.js +++ b/addon-sdk/source/test/test-disposable.js @@ -254,8 +254,7 @@ exports["test disposables are GC-able"] = function(assert, done) { let foo1 = Foo(arg1, arg2) let foo2 = Foo(arg1, arg2) - let foo1 = null - let foo2 = null + foo1 = foo2 = null; Cu.schedulePreciseGC(function() { loader.unload(); @@ -362,4 +361,4 @@ exports["test multiple destroy"] = function(assert) { assert.equal(disposals, 3, "unload only disposed the remaining instance"); } -require('test').run(exports); +require('sdk/test').run(exports); diff --git a/addon-sdk/source/test/test-loader.js b/addon-sdk/source/test/test-loader.js index 0788d4aded3..44e17270dbf 100644 --- a/addon-sdk/source/test/test-loader.js +++ b/addon-sdk/source/test/test-loader.js @@ -367,11 +367,11 @@ exports['test shared globals'] = function(assert) { } exports["test require#resolve"] = function(assert) { - let root = require.resolve("sdk/tabs").replace(/commonjs\.path\/(.*)$/, "") + "commonjs.path/"; - assert.ok(/^resource:\/\/extensions\.modules\.[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}-at-jetpack\.commonjs\.path\/$/.test(root), "correct resolution root"); + let foundRoot = require.resolve("sdk/tabs").replace(/sdk\/tabs.js$/, ""); + assert.ok(root, foundRoot, "correct resolution root"); - assert.equal(root + "sdk/tabs.js", require.resolve("sdk/tabs"), "correct resolution of sdk module"); - assert.equal(root + "toolkit/loader.js", require.resolve("toolkit/loader"), "correct resolution of sdk module"); + assert.equal(foundRoot + "sdk/tabs.js", require.resolve("sdk/tabs"), "correct resolution of sdk module"); + assert.equal(foundRoot + "toolkit/loader.js", require.resolve("toolkit/loader"), "correct resolution of sdk module"); }; require('test').run(exports); diff --git a/addon-sdk/source/test/test-match-pattern.js b/addon-sdk/source/test/test-match-pattern.js index 7e970899c3b..8776f149a5f 100644 --- a/addon-sdk/source/test/test-match-pattern.js +++ b/addon-sdk/source/test/test-match-pattern.js @@ -30,6 +30,8 @@ exports.testMatchPatternTestTrue = function(assert) { ok("http://example.com/ice-cream", "http://example.com/ice-cream"); ok(/.*zilla.*/, "https://bugzilla.redhat.com/show_bug.cgi?id=569753"); + ok(/.*A.*/i, "http://A.com"); + ok(/.*A.*/i, "http://a.com"); ok(/https:.*zilla.*/, "https://bugzilla.redhat.com/show_bug.cgi?id=569753"); ok('*.sample.com', 'http://ex.sample.com/foo.html'); ok('*.amp.le.com', 'http://ex.amp.le.com'); @@ -108,12 +110,6 @@ exports.testMatchPatternErrors = function(assert) { "MatchPattern throws on a RegExp set to `global` (i.e. //g)." ); - assert.throws( - function() new MatchPattern(/ /i), - /^A RegExp match pattern cannot be set to `ignoreCase` \(i\.e\. \/\/i\)\.$/, - "MatchPattern throws on a RegExp set to `ignoreCase` (i.e. //i)." - ); - assert.throws( function() new MatchPattern( / /m ), /^A RegExp match pattern cannot be set to `multiline` \(i\.e\. \/\/m\)\.$/, diff --git a/addon-sdk/source/test/test-native-loader.js b/addon-sdk/source/test/test-native-loader.js index fd25c3b78ff..081daa0bc41 100644 --- a/addon-sdk/source/test/test-native-loader.js +++ b/addon-sdk/source/test/test-native-loader.js @@ -165,8 +165,7 @@ exports["test require#resolve with relative, dependencies"] = function(assert, d let program = main(loader); let fixtureRoot = program.require.resolve("./").replace(/native-addon-test\/(.*)/, "") + "native-addon-test/"; - assert.ok(/^resource:\/\/[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}-at-jetpack\/addon-sdk\/tests\/fixtures\/native-addon-test\/$/.test(fixtureRoot), - "correct resolution root"); + assert.equal(root + "/fixtures/native-addon-test/", fixtureRoot, "correct resolution root"); assert.equal(program.require.resolve("test-math"), fixtureRoot + "node_modules/test-math/index.js", "works with node_modules"); assert.equal(program.require.resolve("./newmodule"), fixtureRoot + "newmodule/lib/file.js", "works with directory mains"); assert.equal(program.require.resolve("./dir/a"), fixtureRoot + "dir/a.js", "works with normal relative module lookups"); diff --git a/addon-sdk/source/test/test-panel.js b/addon-sdk/source/test/test-panel.js index 7a4a233fe4e..da01cd99123 100644 --- a/addon-sdk/source/test/test-panel.js +++ b/addon-sdk/source/test/test-panel.js @@ -16,11 +16,10 @@ const { setTimeout } = require("sdk/timers"); const self = require('sdk/self'); const { open, close, focus, ready } = require('sdk/window/helpers'); const { isPrivate } = require('sdk/private-browsing'); -const { isWindowPBSupported, isGlobalPBSupported } = require('sdk/private-browsing/utils'); +const { isWindowPBSupported } = require('sdk/private-browsing/utils'); const { defer, all } = require('sdk/core/promise'); const { getMostRecentBrowserWindow } = require('sdk/window/utils'); const { getWindow } = require('sdk/panel/window'); -const { pb } = require('./private-browsing/helper'); const { URL } = require('sdk/url'); const { wait } = require('./event/helpers'); @@ -1006,7 +1005,7 @@ exports['test panel CSS'] = function(assert, done) { assert.equal(div.clientHeight, 100, "Panel contentStyle worked"); - + assert.equal(div.offsetHeight, 120, "Panel contentStyleFile worked"); @@ -1044,7 +1043,7 @@ exports['test panel contentScriptFile'] = function(assert, done) { let panel = Panel({ contentURL: './test.html', - contentScriptFile: "./test-contentScriptFile.js", + contentScriptFile: "./test-contentScriptFile.js", onMessage: (message) => { assert.equal(message, "msg from contentScriptFile", "Panel contentScriptFile with relative path worked"); @@ -1155,7 +1154,7 @@ exports['test panel contextmenu validation'] = function(assert) { assert.equal(panel.contextMenu, false, 'contextMenu option accepts boolean values'); - + assert.throws(() => Panel({contextMenu: 1}), /The option "contextMenu" must be one of the following types: boolean, undefined, null/, @@ -1235,7 +1234,7 @@ exports['test panel contextmenu disabled'] = function*(assert) { assert.equal(contextmenu.state, 'closed', 'contextmenu must be closed'); - + sendMouseEvent('contextmenu', 20, 20, 2, 1, 0); contextmenu.addEventListener('popupshown', listener); @@ -1247,7 +1246,7 @@ exports['test panel contextmenu disabled'] = function*(assert) { assert.equal(contextmenu.state, 'closed', 'contextmenu was never open'); - loader.unload(); + loader.unload(); } exports["test panel addon global object"] = function*(assert) { @@ -1274,7 +1273,7 @@ exports["test panel addon global object"] = function*(assert) { panel.port.emit('addon-to-document', 'ok'); yield wait(panel.port, "document-to-addon"); - + assert.pass("Received an event from the document"); loader.unload(); @@ -1295,28 +1294,5 @@ if (isWindowPBSupported) { }).then(close).then(done).then(null, assert.fail); } } -else if (isGlobalPBSupported) { - exports.testGetWindow = function(assert, done) { - let activeWindow = getMostRecentBrowserWindow(); - assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'non-private window elements returns window'); - pb.once('start', function() { - assert.ok(isPrivate(activeWindow), 'window is private'); - assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'private window elements returns window'); - open(null, { features: { - toolbar: true, - chrome: true - } }).then(window => { - assert.ok(isPrivate(window), 'window is private'); - assert.equal(getWindow(window.gBrowser), window, 'private window elements returns window'); - assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'active window elements returns window'); - - pb.once('stop', done); - pb.deactivate(); - }) - }); - pb.activate(); - } -} - -require("test").run(exports); +require("sdk/test").run(exports); diff --git a/addon-sdk/source/test/test-plain-text-console.js b/addon-sdk/source/test/test-plain-text-console.js index 8bc679b6efe..9a821d17889 100644 --- a/addon-sdk/source/test/test-plain-text-console.js +++ b/addon-sdk/source/test/test-plain-text-console.js @@ -18,6 +18,7 @@ const ORIGINAL_SDK_LOG_LEVEL = prefs.get(SDK_LOG_LEVEL_PREF); exports.testPlainTextConsole = function(assert) { let prints = []; + let tbLines; function print(message) { prints.push(message); } @@ -80,15 +81,15 @@ exports.testPlainTextConsole = function(assert) { assert.equal(lastPrint(), "console.log: " + name + ": testing {}\n", "PlainTextConsole.log() must stringify custom bad toString."); - con.exception(new Error("blah")); - - assert.equal(prints[0], "console.error: " + name + ": \n"); - let tbLines = prints[1].split("\n"); - assert.equal(tbLines[0], " Message: Error: blah"); - assert.equal(tbLines[1], " Stack:"); - assert.ok(prints[1].indexOf(module.uri + ":84") !== -1); + assert.equal(prints[0], "console.error: " + name + ": \n", "prints[0] is correct"); + tbLines = prints[1].split("\n"); + assert.equal(tbLines[0], " Message: Error: blah", "tbLines[0] is correct"); + assert.equal(tbLines[1], " Stack:", "tbLines[1] is correct"); + let lineNumber = prints[1].match(module.uri + ":(\\d+)")[1]; + assert.equal(lineNumber, "84", "line number is correct") + assert.ok(prints[1].indexOf(module.uri + ":84") !== -1, "line number is correct"); prints = [] try { @@ -98,14 +99,14 @@ exports.testPlainTextConsole = function(assert) { catch(e) { con.exception(e); } - assert.equal(prints[0], "console.error: " + name + ": \n"); - assert.equal(prints[1], " Error creating URI (invalid URL scheme?)\n"); + assert.equal(prints[0], "console.error: " + name + ": \n", "prints[0] is correct"); + assert.equal(prints[1], " Error creating URI (invalid URL scheme?)\n", "prints[1] is correct"); prints = []; con.trace(); - let tbLines = prints[0].split("\n"); - assert.equal(tbLines[0], "console.trace: " + name + ": "); - assert.ok(tbLines[1].indexOf("_ain-text-console.js 105") == 0); + tbLines = prints[0].split("\n"); + assert.equal(tbLines[0], "console.trace: " + name + ": ", "contains correct console.trace"); + assert.ok(tbLines[1].indexOf("_ain-text-console.js 106") == 0); prints = []; // Whether or not console methods should print at the various log levels, @@ -167,6 +168,7 @@ exports.testPlainTextConsole = function(assert) { exports.testPlainTextConsoleBoundMethods = function(assert) { let prints = []; + let tbLines; function print(message) { prints.push(message); } @@ -207,24 +209,26 @@ exports.testPlainTextConsoleBoundMethods = function(assert) { debug('testing', 1, [2, 3, 4]); assert.equal(prints[0], "console.debug: " + name + ": \n", "PlainTextConsole.debug() must work."); - assert.equal(prints[1], " testing\n") - assert.equal(prints[2], " 1\n") - assert.equal(prints[3], "Array\n - 0 = 2\n - 1 = 3\n - 2 = 4\n - length = 3\n"); + assert.equal(prints[1], " testing\n", "prints[1] is correct"); + assert.equal(prints[2], " 1\n", "prints[2] is correct"); + assert.equal(prints[3], + "Array\n - 0 = 2\n - 1 = 3\n - 2 = 4\n - length = 3\n", + "prints[3] is correct"); prints = []; exception(new Error("blah")); - assert.equal(prints[0], "console.error: " + name + ": \n"); - let tbLines = prints[1].split("\n"); - assert.equal(tbLines[0], " Message: Error: blah"); - assert.equal(tbLines[1], " Stack:"); - assert.ok(prints[1].indexOf(module.uri + ":215") !== -1); + assert.equal(prints[0], "console.error: " + name + ": \n", "prints[0] is correct"); + tbLines = prints[1].split("\n"); + assert.equal(tbLines[0], " Message: Error: blah", "tbLines[0] is correct"); + assert.equal(tbLines[1], " Stack:", "tbLines[1] is correct"); + assert.ok(prints[1].indexOf(module.uri + ":219") !== -1, "correct line number"); prints = [] trace(); - let tbLines = prints[0].split("\n"); - assert.equal(tbLines[0], "console.trace: " + name + ": "); - assert.ok(tbLines[1].indexOf("_ain-text-console.js 224") === 0); + tbLines = prints[0].split("\n"); + assert.equal(tbLines[0], "console.trace: " + name + ": ", "console.trace is correct"); + assert.ok(tbLines[1].indexOf("_ain-text-console.js 228") === 0, "correct line number"); prints = []; restorePrefs(); @@ -271,4 +275,4 @@ function restorePrefs() { prefs.reset(SDK_LOG_LEVEL_PREF); } -require("test").run(exports); +require("sdk/test").run(exports); diff --git a/addon-sdk/source/test/test-private-browsing.js b/addon-sdk/source/test/test-private-browsing.js index 4b27919ec85..c1d19260514 100644 --- a/addon-sdk/source/test/test-private-browsing.js +++ b/addon-sdk/source/test/test-private-browsing.js @@ -13,26 +13,15 @@ const { isPrivateBrowsingSupported } = require('sdk/self'); const { is } = require('sdk/system/xul-app'); const { isPrivate } = require('sdk/private-browsing'); const { LoaderWithHookedConsole } = require("sdk/test/loader"); -const { getMode, isGlobalPBSupported, - isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils'); +const { getMode, isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils'); const { pb } = require('./private-browsing/helper'); const prefs = require('sdk/preferences/service'); -const { set: setPref } = require("sdk/preferences/service"); -const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings"; const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); const kAutoStartPref = "browser.privatebrowsing.autostart"; -// is global pb is enabled? -if (isGlobalPBSupported) { - safeMerge(module.exports, require('./private-browsing/global')); - - exports.testGlobalOnlyOnFirefox = function(assert) { - assert.ok(is("Firefox"), "isGlobalPBSupported is only true on Firefox"); - } -} -else if (isWindowPBSupported) { +if (isWindowPBSupported) { safeMerge(module.exports, require('./private-browsing/windows')); exports.testPWOnlyOnFirefox = function(assert) { @@ -58,26 +47,19 @@ exports.testIsPrivateDefaults = function(assert) { }; exports.testWindowDefaults = function(assert) { - setPref(DEPRECATE_PREF, true); // Ensure that browserWindow still works while being deprecated let { loader, messages } = LoaderWithHookedConsole(module); let windows = loader.require("sdk/windows").browserWindows; - assert.equal(windows.activeWindow.isPrivateBrowsing, false, - 'window is not private browsing by default'); - assert.ok(/DEPRECATED.+isPrivateBrowsing/.test(messages[0].msg), - 'isPrivateBrowsing is deprecated'); + assert.equal(windows.activeWindow.isPrivateBrowsing, undefined, + 'window.isPrivateBrowsing is undefined'); + assert.equal(undefined, messages[0], + 'isPrivateBrowsing is deprecated'); let chromeWin = winUtils.getMostRecentBrowserWindow(); assert.equal(getMode(chromeWin), false); assert.equal(isWindowPrivate(chromeWin), false); }; -// tests for the case where private browsing doesn't exist -exports.testIsActiveDefault = function(assert) { - assert.equal(pb.isActive, false, - 'pb.isActive returns false when private browsing isn\'t supported'); -}; - exports.testIsPrivateBrowsingFalseDefault = function(assert) { assert.equal(isPrivateBrowsingSupported, false, 'isPrivateBrowsingSupported property is false by default'); diff --git a/addon-sdk/source/test/test-self.js b/addon-sdk/source/test/test-self.js index feecd55090d..b79b731b733 100644 --- a/addon-sdk/source/test/test-self.js +++ b/addon-sdk/source/test/test-self.js @@ -3,14 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -const { Cc, Ci, Cu, Cm, components } = require("chrome"); const xulApp = require("sdk/system/xul-app"); const self = require("sdk/self"); const { Loader, main, unload } = require("toolkit/loader"); const loaderOptions = require("@loader/options"); -const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {}); - exports.testSelf = function(assert) { // Likewise, we can't assert anything about the full URL, because that // depends on self.id . We can only assert that it ends in the right diff --git a/addon-sdk/source/test/test-simple-prefs.js b/addon-sdk/source/test/test-simple-prefs.js index 93aad6330e0..6b57424b840 100644 --- a/addon-sdk/source/test/test-simple-prefs.js +++ b/addon-sdk/source/test/test-simple-prefs.js @@ -17,7 +17,7 @@ const file = require("sdk/io/file"); const { install, uninstall } = require("sdk/addon/installer"); const { open } = require('sdk/preferences/utils'); const { toFilename } = require('sdk/url'); -const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {}); +const { getAddonByID } = require('sdk/addon/manager'); const { ZipWriter } = require('./zip/utils'); const { getTabForId } = require('sdk/tabs/utils'); const { preferencesBranch, id } = require('sdk/self'); @@ -44,7 +44,7 @@ exports.testIterations = function(assert) { delete sp["test"]; delete sp["test.test"]; - let prefAry = []; + prefAry = []; for (var name in sp ) { prefAry.push(name); } @@ -247,7 +247,7 @@ exports.testPrefJSONStringification = function(assert) { "JSON stringification should work."); }; -exports.testUnloadOfDynamicPrefGeneration = function(assert, done) { +exports.testUnloadOfDynamicPrefGeneration = function*(assert) { let loader = Loader(module); let branch = prefsrv.getDefaultBranch('extensions.' + preferencesBranch); @@ -259,92 +259,74 @@ exports.testUnloadOfDynamicPrefGeneration = function(assert, done) { // zip the add-on let zip = new ZipWriter(xpi_path); assert.pass("start creating the xpi"); - zip.addFile("", toFilename(fixtures.url("bootstrap-addon/"))). - then(zip.close()). - then(_ => install(xpi_path)). - // get the addon - then(id => { - let { promise, resolve } = defer(); - AddonManager.getAddonByID(id, resolve); - return promise; - }). + zip.addFile("", toFilename(fixtures.url("bootstrap-addon/"))); + yield zip.close(); + // insatll the add-on - then(addon => { - assert.pass('installed'); + let id = yield install(xpi_path); - assert.pass('addon id: ' + addon.id); - addon.userDisabled = false; - assert.ok(!addon.userDisabled, 'the add-on is enabled'); - assert.ok(addon.isActive, 'the add-on is enabled'); + // get the addon + let addon = yield getAddonByID(id); + + assert.pass('installed'); + + assert.pass('addon id: ' + addon.id); + addon.userDisabled = false; + assert.ok(!addon.userDisabled, 'the add-on is enabled'); + assert.ok(addon.isActive, 'the add-on is enabled'); + + // setup dynamic prefs + yield enable({ + id: addon.id, + preferences: [{ + "name": "test", + "description": "test", + "title": "Test", + "type": "string", + "value": "default" + }, { + "name": "test-int", + "description": "test", + "type": "integer", + "value": 5, + "title": "How Many?" + }] + }); + + assert.pass('enabled'); - // setup dynamic prefs - return enable({ - id: addon.id, - preferences: [{ - "name": "test", - "description": "test", - "title": "Test", - "type": "string", - "value": "default" - }, { - "name": "test-int", - "description": "test", - "type": "integer", - "value": 5, - "title": "How Many?" - }] - }); - }). - then(args => { - assert.pass('enabled'); - return args; - }). // show inline prefs - then(open). - then(args => { - assert.pass('opened'); - return args; - }). + let { tabId, document } = yield open(addon); + + assert.pass('opened'); // confirm dynamic pref generation did occur - then(args => { - let results = args.document.querySelectorAll("*[data-jetpack-id=\"" +args.id + "\"]"); - assert.ok(results.length > 0, "the prefs were setup"); - return args; - }). + let results = document.querySelectorAll("*[data-jetpack-id=\"" + id + "\"]"); + assert.ok(results.length > 0, "the prefs were setup"); + // unload dynamic prefs - then(args => { - loader.unload(); - assert.pass('unload'); - return args; - }). + loader.unload(); + assert.pass('unload'); + // hide and show the inline prefs - then(({ tabId, id, document }) => { - let { promise, resolve } = defer(); - let tab = Tab({ tab: getTabForId(tabId) }); + let { promise, resolve } = defer(); + Tab({ tab: getTabForId(tabId) }).close(resolve); + yield promise; - tab.close(_ => resolve({ id: id })); - - return promise; - }). // reopen the add-on prefs page - then(open). + ({ tabId, document }) = yield open(addon); + // confirm dynamic pref generation did not occur - then(({ id, tabId, document }) => { - let { promise, resolve } = defer(); - let tab = Tab({ tab: getTabForId(tabId) }); + ({ promise, resolve }) = defer(); + results = document.querySelectorAll("*[data-jetpack-id=\"" + id + "\"]"); + assert.equal(0, results.length, "the prefs were not setup after unload"); + Tab({ tab: getTabForId(tabId) }).close(resolve); + yield promise; - let results = document.querySelectorAll("*[data-jetpack-id=\"" + id + "\"]"); - assert.equal(0, results.length, "the prefs were not setup after unload"); - - tab.close(_ => resolve({ id: id })); - - return promise; - }). // uninstall the add-on - then(({ id }) => uninstall(id)). + yield uninstall(id); + // delete the pref branch - then(_ => branch.deleteBranch('')). - then(done, assert.fail); + branch.deleteBranch(''); } require("sdk/test").run(exports); diff --git a/addon-sdk/source/test/test-tab-utils.js b/addon-sdk/source/test/test-tab-utils.js index 412589b1ba0..e417f910b06 100644 --- a/addon-sdk/source/test/test-tab-utils.js +++ b/addon-sdk/source/test/test-tab-utils.js @@ -1,10 +1,9 @@ 'use strict'; const { getTabs } = require('sdk/tabs/utils'); -const { isGlobalPBSupported, isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils'); +const { isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils'); const { browserWindows } = require('sdk/windows'); const tabs = require('sdk/tabs'); -const { pb } = require('./private-browsing/helper'); const { isPrivate } = require('sdk/private-browsing'); const { openTab, closeTab, getTabContentWindow, getOwnerWindow } = require('sdk/tabs/utils'); const { open, close } = require('sdk/window/helpers'); @@ -64,4 +63,4 @@ else if (isTabPBSupported) { }; } -require('test').run(exports); +require('sdk/test').run(exports); diff --git a/addon-sdk/source/test/test-tabs-common.js b/addon-sdk/source/test/test-tabs-common.js index 9101d9318e9..badb1bba439 100644 --- a/addon-sdk/source/test/test-tabs-common.js +++ b/addon-sdk/source/test/test-tabs-common.js @@ -18,6 +18,7 @@ const { Style } = require('sdk/stylesheet/style'); const fixtures = require('./fixtures'); const { viewFor } = require('sdk/view/core'); const app = require("sdk/system/xul-app"); +const { cleanUI } = require('sdk/test/utils'); const URL = 'data:text/html;charset=utf-8,#title#'; diff --git a/addon-sdk/source/test/test-test-utils.js b/addon-sdk/source/test/test-test-utils.js index 6e8561d21ab..9ac761604b0 100644 --- a/addon-sdk/source/test/test-test-utils.js +++ b/addon-sdk/source/test/test-test-utils.js @@ -5,7 +5,8 @@ 'use strict' const { setTimeout } = require('sdk/timers'); -const { waitUntil } = require('sdk/test/utils'); +const { waitUntil, cleanUI } = require('sdk/test/utils'); +const tabs = require('sdk/tabs'); exports.testWaitUntil = function (assert, done) { let bool = false; @@ -43,4 +44,29 @@ exports.testWaitUntilInterval = function (assert, done) { setTimeout(() => { bool = true; }, 10); }; +exports.testCleanUIWithExtraTabAndWindow = function(assert, done) { + tabs.open({ + url: "about:blank", + inNewWindow: true, + onOpen: () => { + cleanUI().then(() => { + assert.pass("the ui was cleaned"); + assert.equal(tabs.length, 1, 'there is only one tab open'); + }).then(done).catch(assert.fail); + } + }); +} + +exports.testCleanUIWithOnlyExtraTab = function(assert, done) { + tabs.open({ + url: "about:blank", + onOpen: () => { + cleanUI().then(() => { + assert.pass("the ui was cleaned"); + assert.equal(tabs.length, 1, 'there is only one tab open'); + }).then(done).catch(assert.fail); + } + }); +} + require('sdk/test').run(exports); diff --git a/addon-sdk/source/test/test-ui-action-button.js b/addon-sdk/source/test/test-ui-action-button.js index 081fbb3fbfa..6dd76ff9a72 100644 --- a/addon-sdk/source/test/test-ui-action-button.js +++ b/addon-sdk/source/test/test-ui-action-button.js @@ -383,6 +383,9 @@ exports['test button window state'] = function(assert, done) { let nodes = [getWidget(button.id).node]; openBrowserWindow().then(focus).then(window => { + let node; + let state; + nodes.push(getWidget(button.id, window).node); let { activeWindow } = browserWindows; @@ -402,7 +405,7 @@ exports['test button window state'] = function(assert, done) { assert.equal(button.disabled, false, 'global disabled unchanged'); - let state = button.state(mainWindow); + state = button.state(mainWindow); assert.equal(state.label, 'my button', 'previous window label unchanged'); @@ -411,7 +414,7 @@ exports['test button window state'] = function(assert, done) { assert.equal(state.disabled, false, 'previous window disabled unchanged'); - let state = button.state(activeWindow); + state = button.state(activeWindow); assert.equal(state.label, 'New label', 'active window label updated'); @@ -439,8 +442,8 @@ exports['test button window state'] = function(assert, done) { 'active window label inherited'); // check the nodes properties - let node = nodes[0]; - let state = button.state(mainWindow); + node = nodes[0]; + state = button.state(mainWindow); assert.equal(node.getAttribute('label'), state.label, 'node label is correct'); @@ -452,8 +455,8 @@ exports['test button window state'] = function(assert, done) { assert.equal(node.hasAttribute('disabled'), state.disabled, 'disabled is correct'); - let node = nodes[1]; - let state = button.state(activeWindow); + node = nodes[1]; + state = button.state(activeWindow); assert.equal(node.getAttribute('label'), state.label, 'node label is correct'); @@ -515,6 +518,8 @@ exports['test button tab state'] = function(assert, done) { // check the states Cu.schedulePreciseGC(() => { + let state; + assert.equal(button.label, 'my button', 'global label unchanged'); assert.equal(button.icon, './icon.png', @@ -522,7 +527,7 @@ exports['test button tab state'] = function(assert, done) { assert.equal(button.disabled, false, 'global disabled unchanged'); - let state = button.state(mainTab); + state = button.state(mainTab); assert.equal(state.label, 'Tab label', 'previous tab label updated'); @@ -531,7 +536,7 @@ exports['test button tab state'] = function(assert, done) { assert.equal(state.disabled, false, 'previous tab disabled unchanged'); - let state = button.state(tab); + state = button.state(tab); assert.equal(state.label, 'Window label', 'active tab inherited from window state'); @@ -561,7 +566,7 @@ exports['test button tab state'] = function(assert, done) { // check the node properties - let state = button.state(tabs.activeTab); + state = button.state(tabs.activeTab); assert.equal(node.getAttribute('label'), state.label, 'node label is correct'); @@ -601,7 +606,7 @@ exports['test button tab state'] = function(assert, done) { }; -exports['test button click'] = function(assert, done) { +exports['test button click'] = function*(assert) { let loader = Loader(module); let { ActionButton } = loader.require('sdk/ui'); let { browserWindows } = loader.require('sdk/windows'); @@ -618,28 +623,28 @@ exports['test button click'] = function(assert, done) { let mainWindow = browserWindows.activeWindow; let chromeWindow = getMostRecentBrowserWindow(); - openBrowserWindow().then(focus).then(window => { - button.state(mainWindow, { label: 'nothing' }); - button.state(mainWindow.tabs.activeTab, { label: 'foo'}) - button.state(browserWindows.activeWindow, { label: 'bar' }); + let window = yield openBrowserWindow().then(focus); - button.click(); + button.state(mainWindow, { label: 'nothing' }); + button.state(mainWindow.tabs.activeTab, { label: 'foo'}) + button.state(browserWindows.activeWindow, { label: 'bar' }); - focus(chromeWindow).then(() => { - button.click(); + button.click(); - assert.deepEqual(labels, ['bar', 'foo'], - 'button click works'); + yield focus(chromeWindow); - close(window). - then(loader.unload). - then(done, assert.fail); - }); - }).then(null, assert.fail); + button.click(); + assert.deepEqual(labels, ['bar', 'foo'], + 'button click works'); + + yield close(window); + + loader.unload(); } exports['test button icon set'] = function(assert) { + let size; const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {}); let loader = Loader(module); let { ActionButton } = loader.require('sdk/ui'); @@ -670,12 +675,12 @@ exports['test button icon set'] = function(assert) { let { node, id: widgetId } = getWidget(button.id); let { devicePixelRatio } = node.ownerDocument.defaultView; - let size = 16 * devicePixelRatio; + size = 16 * devicePixelRatio; assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)), 'the icon is set properly in navbar'); - let size = 32 * devicePixelRatio; + size = 32 * devicePixelRatio; CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL); diff --git a/addon-sdk/source/test/test-ui-frame.js b/addon-sdk/source/test/test-ui-frame.js index d9a841c3501..0c1173c4859 100644 --- a/addon-sdk/source/test/test-ui-frame.js +++ b/addon-sdk/source/test/test-ui-frame.js @@ -201,6 +201,7 @@ exports["test content to host messaging"] = function* (assert) { exports["test direct messaging"] = function* (assert) { + let message; const url = "data:text/html,