Back out bd0463063293 (bug 982379) for making a more frequent bug 981361 failure in a slightly different place
authorPhil Ringnalda <philringnalda@gmail.com>
Tue, 11 Mar 2014 22:18:17 -0700
changeset 173152 34941dd46be6611af8ba6c741afc7294afe65cd9
parent 173151 31f9a148b33cb6f6eb509df29a339b5de4f65254
child 173153 e7f97fa8a86b2be9e451f33cb15d558134e16231
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
bugs982379, 981361
milestone30.0a1
backs outbd0463063293e9e2fdfcea2dce80bc849316af0f
Back out bd0463063293 (bug 982379) for making a more frequent bug 981361 failure in a slightly different place
addon-sdk/source/lib/sdk/input/customizable-ui.js
addon-sdk/source/lib/sdk/input/system.js
addon-sdk/source/lib/sdk/panel.js
addon-sdk/source/lib/sdk/panel/utils.js
addon-sdk/source/lib/sdk/system.js
addon-sdk/source/lib/sdk/test/runner.js
addon-sdk/source/lib/sdk/ui/button/action.js
addon-sdk/source/lib/sdk/ui/button/toggle.js
addon-sdk/source/lib/sdk/ui/button/view.js
addon-sdk/source/lib/sdk/ui/frame/model.js
addon-sdk/source/lib/sdk/ui/state.js
addon-sdk/source/lib/sdk/ui/toolbar/view.js
addon-sdk/source/lib/sdk/widget.js
addon-sdk/source/lib/sdk/window/utils.js
addon-sdk/source/python-lib/cuddlefish/__init__.py
addon-sdk/source/python-lib/cuddlefish/runner.py
addon-sdk/source/test/addons/addon-page/main.js
addon-sdk/source/test/addons/child_process/index.js
addon-sdk/source/test/addons/places/main.js
addon-sdk/source/test/addons/simple-prefs-l10n/main.js
addon-sdk/source/test/test-functional.js
addon-sdk/source/test/test-ui-frame.js
addon-sdk/source/test/test-ui-toggle-button.js
addon-sdk/source/test/test-ui-toolbar.js
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/input/customizable-ui.js
+++ /dev/null
@@ -1,40 +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 { Cu } = require("chrome");
-
-// Because Firefox Holly, we still need to check if `CustomizableUI` is
-// available. Once Australis will officially land, we can safely remove it.
-// See Bug 959142
-try {
-  Cu.import("resource:///modules/CustomizableUI.jsm", {});
-}
-catch (e) {
-  throw Error("Unsupported Application: The module"  + module.id +
-              " does not support this application.");
-}
-
-const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
-const { receive } = require("../event/utils");
-const { InputPort } = require("./system");
-const { object} = require("../util/sequence");
-const { getOuterId } = require("../window/utils");
-
-const Input = function() {};
-Input.prototype = Object.create(InputPort.prototype);
-
-Input.prototype.onCustomizeStart = function (window) {
-  receive(this, object([getOuterId(window), true]));
-}
-
-Input.prototype.onCustomizeEnd = function (window) {
-  receive(this, object([getOuterId(window), null]));
-}
-
-Input.prototype.addListener = input => CustomizableUI.addListener(input);
-
-Input.prototype.removeListener = input => CustomizableUI.removeListener(input);
-
-exports.CustomizationInput = Input;
--- a/addon-sdk/source/lib/sdk/input/system.js
+++ b/addon-sdk/source/lib/sdk/input/system.js
@@ -43,39 +43,33 @@ const InputPort = function InputPort({id
 
 // InputPort type implements `Input` signal interface.
 InputPort.prototype = new Input();
 InputPort.prototype.constructor = InputPort;
 
 // When port is started (which is when it's subgraph get's
 // first subscriber) actual observer is registered.
 InputPort.start = input => {
-  input.addListener(input);
+  addObserver(input, input.topic, false);
   // Also register add-on unload observer to end this signal
   // when that happens.
   addObserver(input, addonUnloadTopic, false);
 };
 InputPort.prototype[start] = InputPort.start;
 
-InputPort.addListener = input => addObserver(input, input.topic, false);
-InputPort.prototype.addListener = InputPort.addListener;
-
 // When port is stopped (which is when it's subgraph has no
 // no subcribers left) an actual observer unregistered.
 // Note that port stopped once it ends as well (which is when
 // add-on is unloaded).
 InputPort.stop = input => {
-  input.removeListener(input);
+  removeObserver(input, input.topic);
   removeObserver(input, addonUnloadTopic);
 };
 InputPort.prototype[stop] = InputPort.stop;
 
-InputPort.removeListener = input => removeObserver(input, input.topic);
-InputPort.prototype.removeListener = InputPort.removeListener;
-
 // `InputPort` also implements `nsIObserver` interface and
 // `nsISupportsWeakReference` interfaces as it's going to be used as such.
 InputPort.prototype.QueryInterface = function(iid) {
   if (!iid.equals(Ci.nsIObserver) && !iid.equals(Ci.nsISupportsWeakReference))
     throw Cr.NS_ERROR_NO_INTERFACE;
 
   return this;
 };
--- a/addon-sdk/source/lib/sdk/panel.js
+++ b/addon-sdk/source/lib/sdk/panel.js
@@ -8,16 +8,17 @@
 module.metadata = {
   "stability": "stable",
   "engines": {
     "Firefox": "*"
   }
 };
 
 const { Ci } = require("chrome");
+const { validateOptions: valid } = require('./deprecated/api-utils');
 const { setTimeout } = require('./timers');
 const { isPrivateBrowsingSupported } = require('./self');
 const { isWindowPBSupported } = require('./private-browsing/utils');
 const { Class } = require("./core/heritage");
 const { merge } = require("./util/object");
 const { WorkerHost, detach, attach, destroy } = require("./content/utils");
 const { Worker } = require("./content/worker");
 const { Disposable } = require("./core/disposable");
@@ -25,46 +26,39 @@ const { contract: loaderContract } = req
 const { contract } = require("./util/contract");
 const { on, off, emit, setListeners } = require("./event/core");
 const { EventTarget } = require("./event/target");
 const domPanel = require("./panel/utils");
 const { events } = require("./panel/events");
 const systemEvents = require("./system/events");
 const { filter, pipe, stripListeners } = require("./event/utils");
 const { getNodeView, getActiveView } = require("./view/core");
-const { isNil, isObject, isNumber } = require("./lang/type");
+const { isNil, isObject } = require("./lang/type");
 const { getAttachEventType } = require("./content/utils");
-const { number, boolean, object } = require('./deprecated/api-utils');
 
-let isRect = ({top, right, bottom, left}) => [top, right, bottom, left].
-  some(value => isNumber(value) && !isNaN(value));
-
-let isSDKObj = obj => obj instanceof Class;
+let number = { is: ['number', 'undefined', 'null'] };
+let boolean = { is: ['boolean', 'undefined', 'null'] };
 
 let rectContract = contract({
   top: number,
   right: number,
   bottom: number,
   left: number
 });
 
-let position = {
-  is: object,
-  map: v => (isNil(v) || isSDKObj(v) || !isObject(v)) ? v : rectContract(v),
-  ok: v => isNil(v) || isSDKObj(v) || (isObject(v) && isRect(v)),
-  msg: 'The option "position" must be a SDK object registered as anchor; ' +
-        'or an object with one or more of the following keys set to numeric ' +
-        'values: top, right, bottom, left.'
+let rect = {
+  is: ['object', 'undefined', 'null'],
+  map: function(v) isNil(v) || !isObject(v) ? v : rectContract(v)
 }
 
 let displayContract = contract({
   width: number,
   height: number,
   focus: boolean,
-  position: position
+  position: rect
 });
 
 let panelContract = contract(merge({}, displayContract.rules, loaderContract.rules));
 
 
 function isDisposed(panel) !views.has(panel);
 
 let panels = new WeakMap();
@@ -177,32 +171,32 @@ const Panel = Class({
     // reatached once panel content is ready.
     detach(workerFor(this));
   },
 
   /* Public API: Panel.isShowing */
   get isShowing() !isDisposed(this) && domPanel.isOpen(viewFor(this)),
 
   /* Public API: Panel.show */
-  show: function show(options={}, anchor) {
+  show: function show(options, anchor) {
     if (options instanceof Ci.nsIDOMElement) {
       [anchor, options] = [options, null];
     }
 
     if (anchor instanceof Ci.nsIDOMElement) {
       console.warn(
         "Passing a DOM node to Panel.show() method is an unsupported " +
         "feature that will be soon replaced. " +
         "See: https://bugzilla.mozilla.org/show_bug.cgi?id=878877"
       );
     }
 
     let model = modelFor(this);
     let view = viewFor(this);
-    let anchorView = getNodeView(anchor || options.position);
+    let anchorView = getNodeView(anchor);
 
     options = merge({
       position: model.position,
       width: model.width,
       height: model.height,
       defaultWidth: model.defaultWidth,
       defaultHeight: model.defaultHeight,
       focus: model.focus
@@ -240,32 +234,31 @@ const Panel = Class({
   }
 });
 exports.Panel = Panel;
 
 // Note must be defined only after value to `Panel` is assigned.
 getActiveView.define(Panel, viewFor);
 
 // Filter panel events to only panels that are create by this module.
-let panelEvents = filter(events, ({target}) => panelFor(target));
+let panelEvents = filter(events, function({target}) panelFor(target));
 
 // Panel events emitted after panel has being shown.
-let shows = filter(panelEvents, ({type}) => type === "popupshown");
+let shows = filter(panelEvents, function({type}) type === "popupshown");
 
 // Panel events emitted after panel became hidden.
-let hides = filter(panelEvents, ({type}) => type === "popuphidden");
+let hides = filter(panelEvents, function({type}) type === "popuphidden");
 
 // Panel events emitted after content inside panel is ready. For different
 // panels ready may mean different state based on `contentScriptWhen` attribute.
 // Weather given event represents readyness is detected by `getAttachEventType`
 // helper function.
-let ready = filter(panelEvents, ({type, target}) =>
+let ready = filter(panelEvents, function({type, target})
   getAttachEventType(modelFor(panelFor(target))) === type);
 
 // Forward panel show / hide events to panel's own event listeners.
-on(shows, "data", ({target}) => emit(panelFor(target), "show"));
-
-on(hides, "data", ({target}) => emit(panelFor(target), "hide"));
+on(shows, "data", function({target}) emit(panelFor(target), "show"));
+on(hides, "data", function({target}) emit(panelFor(target), "hide"));
 
 on(ready, "data", function({target}) {
   let worker = workerFor(panelFor(target));
   attach(worker, domPanel.getContentDocument(target).defaultView);
 });
--- a/addon-sdk/source/lib/sdk/panel/utils.js
+++ b/addon-sdk/source/lib/sdk/panel/utils.js
@@ -18,18 +18,16 @@ const { create: createFrame, swapFrameLo
 const { window: addonWindow } = require("../addon/window");
 const { isNil } = require("../lang/type");
 const events = require("../system/events");
 
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 function calculateRegion({ position, width, height, defaultWidth, defaultHeight }, rect) {
-  position = position || {};
-
   let x, y;
 
   let hasTop = !isNil(position.top);
   let hasRight = !isNil(position.right);
   let hasBottom = !isNil(position.bottom);
   let hasLeft = !isNil(position.left);
   let hasWidth = !isNil(width);
   let hasHeight = !isNil(height);
@@ -124,42 +122,24 @@ function display(panel, options, anchor)
     // in order to, be positioned properly
     panel.style.margin = "0";
 
     let viewportRect = document.defaultView.gBrowser.getBoundingClientRect();
 
     ({x, y, width, height}) = calculateRegion(options, viewportRect);
   }
   else {
-    // The XUL Panel has an arrow, so the margin needs to be reset
-    // to the default value.
-    panel.style.margin = "";
-    let { CustomizableUI, window } = anchor.ownerDocument.defaultView;
-
-    // In Australis, widgets may be positioned in an overflow panel or the
-    // menu panel.
-    // In such cases clicking this widget will hide the overflow/menu panel,
-    // and the widget's panel will show instead.
-    if (CustomizableUI) {
-      let node = anchor;
-      ({anchor}) = CustomizableUI.getWidget(anchor.id).forWindow(window);
-
-      // if `node` is not the `anchor` itself, it means the widget is
-      // positioned in a panel, therefore we have to hide it before show
-      // the widget's panel in the same anchor
-      if (node !== anchor)
-        CustomizableUI.hidePanelForNode(anchor);
-    }
-
     width = width || defaultWidth;
     height = height || defaultHeight;
 
     // Open the popup by the anchor.
     let rect = anchor.getBoundingClientRect();
 
+    let window = anchor.ownerDocument.defaultView;
+
     let zoom = getScreenPixelsPerCSSPixel(window);
     let screenX = rect.left + window.mozInnerScreenX * zoom;
     let screenY = rect.top + window.mozInnerScreenY * zoom;
 
     // Set up the vertical position of the popup relative to the anchor
     // (always display the arrow on anchor center)
     let horizontal, vertical;
     if (screenY > window.screen.availHeight / 2 + height)
--- a/addon-sdk/source/lib/sdk/system.js
+++ b/addon-sdk/source/lib/sdk/system.js
@@ -7,16 +7,17 @@
 module.metadata = {
   "stability": "unstable"
 };
 
 const { Cc, Ci, CC } = require('chrome');
 const options = require('@loader/options');
 const file = require('./io/file');
 const runtime = require("./system/runtime");
+var cfxArgs = require("@test/options");
 
 const appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
                    getService(Ci.nsIAppStartup);
 const appInfo = Cc["@mozilla.org/xre/app-info;1"].
                 getService(Ci.nsIXULAppInfo);
 const directoryService = Cc['@mozilla.org/file/directory_service;1'].
                          getService(Ci.nsIProperties);
 
@@ -64,22 +65,23 @@ exports.exit = function exit(code) {
   // This is used by 'cfx' to find out exit code.
   if ('resultFile' in options && options.resultFile) {
     let mode = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
     let stream = openFile(options.resultFile, mode);
     let status = code ? 'FAIL' : 'OK';
     stream.write(status, status.length);
     stream.flush();
     stream.close();
+    if (cfxArgs.parseable) {
+      console.log('wrote to resultFile');
+    }
   }
 
-  if (code == 0) {
-    forcedExit = true;
-  }
-  appStartup.quit(code ? E_ATTEMPT : E_FORCE);
+  forcedExit = true;
+  appStartup.quit(E_FORCE);
 };
 
 // Adapter for nodejs's stdout & stderr:
 // http://nodejs.org/api/process.html#process_process_stdout
 let stdout = Object.freeze({ write: dump, end: dump });
 exports.stdout = stdout;
 exports.stderr = stdout;
 
--- a/addon-sdk/source/lib/sdk/test/runner.js
+++ b/addon-sdk/source/lib/sdk/test/runner.js
@@ -2,31 +2,39 @@
  * 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"
 };
 
+var { setTimeout } = require("../timers");
 var { exit, stdout } = require("../system");
 var cfxArgs = require("@test/options");
 
 function runTests(findAndRunTests) {
   var harness = require("./harness");
 
   function onDone(tests) {
     stdout.write("\n");
     var total = tests.passed + tests.failed;
     stdout.write(tests.passed + " of " + total + " tests passed.\n");
 
     if (tests.failed == 0) {
-      if (tests.passed === 0)
+      if (tests.passed === 0) {
         stdout.write("No tests were run\n");
-      exit(0);
+      }
+
+      setTimeout(function() {
+        if (cfxArgs.parseable) {
+          console.log('calling exit(0)');
+        }
+        exit(0);
+      }, 0);
     } else {
       if (cfxArgs.verbose || cfxArgs.parseable)
         printFailedTests(tests, stdout.write);
       exit(1);
     }
   };
 
   // We may have to run test on next cycle, otherwise XPCOM components
--- a/addon-sdk/source/lib/sdk/ui/button/action.js
+++ b/addon-sdk/source/lib/sdk/ui/button/action.js
@@ -21,17 +21,16 @@ catch (e) {
               ' does not support this application.');
 }
 
 const { Class } = require('../../core/heritage');
 const { merge } = require('../../util/object');
 const { Disposable } = require('../../core/disposable');
 const { on, off, emit, setListeners } = require('../../event/core');
 const { EventTarget } = require('../../event/target');
-const { getNodeView } = require('../../view/core');
 
 const view = require('./view');
 const { buttonContract, stateContract } = require('./contract');
 const { properties, render, state, register, unregister,
         getDerivedStateFor } = require('../state');
 const { events: stateEvents } = require('../state/events');
 const { events: viewEvents } = require('./view/events');
 const events = require('../../event/utils');
@@ -85,20 +84,16 @@ const ActionButton = Class({
   get id() this.state().id,
 
   click: function click() { view.click(toWidgetId(this.id)) }
 });
 exports.ActionButton = ActionButton;
 
 identify.define(ActionButton, ({id}) => toWidgetId(id));
 
-getNodeView.define(ActionButton, button =>
-  view.nodeFor(toWidgetId(button.id))
-);
-
 let actionButtonStateEvents = events.filter(stateEvents,
   e => e.target instanceof ActionButton);
 
 let actionButtonViewEvents = events.filter(viewEvents,
   e => buttons.has(e.target));
 
 let clickEvents = events.filter(actionButtonViewEvents, e => e.type === 'click');
 let updateEvents = events.filter(actionButtonViewEvents, e => e.type === 'update');
--- a/addon-sdk/source/lib/sdk/ui/button/toggle.js
+++ b/addon-sdk/source/lib/sdk/ui/button/toggle.js
@@ -21,17 +21,16 @@ catch (e) {
               ' does not support this application.');
 }
 
 const { Class } = require('../../core/heritage');
 const { merge } = require('../../util/object');
 const { Disposable } = require('../../core/disposable');
 const { on, off, emit, setListeners } = require('../../event/core');
 const { EventTarget } = require('../../event/target');
-const { getNodeView } = require('../../view/core');
 
 const view = require('./view');
 const { toggleButtonContract, toggleStateContract } = require('./contract');
 const { properties, render, state, register, unregister,
   setStateFor, getStateFor, getDerivedStateFor } = require('../state');
 const { events: stateEvents } = require('../state/events');
 const { events: viewEvents } = require('./view/events');
 const events = require('../../event/utils');
@@ -86,20 +85,16 @@ const ToggleButton = Class({
   get id() this.state().id,
 
   click: function click() view.click(toWidgetId(this.id))
 });
 exports.ToggleButton = ToggleButton;
 
 identify.define(ToggleButton, ({id}) => toWidgetId(id));
 
-getNodeView.define(ToggleButton, button =>
-  view.nodeFor(toWidgetId(button.id))
-);
-
 let toggleButtonStateEvents = events.filter(stateEvents,
   e => e.target instanceof ToggleButton);
 
 let toggleButtonViewEvents = events.filter(viewEvents,
   e => buttons.has(e.target));
 
 let clickEvents = events.filter(toggleButtonViewEvents, e => e.type === 'click');
 let updateEvents = events.filter(toggleButtonViewEvents, e => e.type === 'update');
--- a/addon-sdk/source/lib/sdk/ui/button/view.js
+++ b/addon-sdk/source/lib/sdk/ui/button/view.js
@@ -103,21 +103,16 @@ function getImage(icon, isInToolbar, pix
   }
 
   if (image.indexOf('./') === 0)
     return data.url(image.substr(2));
 
   return image;
 }
 
-function nodeFor(id, window=getMostRecentBrowserWindow()) {
-  return customizedWindows.has(window) ? null : getNode(id, window);
-};
-exports.nodeFor = nodeFor;
-
 function create(options) {
   let { id, label, icon, type } = options;
 
   if (views.has(id))
     throw new Error('The ID "' + id + '" seems already used.');
 
   CustomizableUI.createWidget({
     id: id,
@@ -183,40 +178,41 @@ function setIcon(id, window, icon) {
     let image = getImage(icon, isInToolbar(id), window.devicePixelRatio);
 
     node.setAttribute('image', image);
   }
 }
 exports.setIcon = setIcon;
 
 function setLabel(id, window, label) {
-  let node = nodeFor(id, window);
+  let node = customizedWindows.has(window) ? null : getNode(id, window);
 
   if (node) {
     node.setAttribute('label', label);
     node.setAttribute('tooltiptext', label);
   }
 }
 exports.setLabel = setLabel;
 
 function setDisabled(id, window, disabled) {
-  let node = nodeFor(id, window);
+  let node = customizedWindows.has(window) ? null : getNode(id, window);
 
   if (node)
     node.disabled = disabled;
 }
 exports.setDisabled = setDisabled;
 
 function setChecked(id, window, checked) {
-  let node = nodeFor(id, window);
+  let node = customizedWindows.has(window) ? null : getNode(id, window);
 
   if (node)
     node.checked = checked;
 }
 exports.setChecked = setChecked;
 
 function click(id) {
-  let node = nodeFor(id);
+  let window = getMostRecentBrowserWindow();
+  let node = customizedWindows.has(window) ? null : getNode(id, window);
 
   if (node)
     node.click();
 }
 exports.click = click;
--- a/addon-sdk/source/lib/sdk/ui/frame/model.js
+++ b/addon-sdk/source/lib/sdk/ui/frame/model.js
@@ -27,27 +27,27 @@ const { id: addonID, data: { url: resolv
 const { Frames } = require("../../input/frame");
 
 
 const output = new OutputPort({ id: "frame-change" });
 const mailbox = new OutputPort({ id: "frame-mailbox" });
 const input = Frames;
 
 
-const makeID = url =>
+const urlToId = url =>
   ("frame-" + addonID + "-" + url).
     split("/").join("-").
     split(".").join("-").
     replace(/[^A-Za-z0-9_\-]/g, "");
 
 const validate = contract({
-  name: {
+  id: {
     is: ["string", "undefined"],
     ok: x => /^[a-z][a-z0-9-_]+$/i.test(x),
-    msg: "The `option.name` must be a valid alphanumeric string (hyphens and " +
+    msg: "The `option.id` must be a valid alphanumeric string (hyphens and " +
          "underscores are allowed) starting with letter."
   },
   url: {
     map: x => x.toString(),
     is: ["string"],
     ok: x => isLocalURL(x),
     msg: "The `options.url` must be a valid local URI."
   }
@@ -83,17 +83,17 @@ const Message = function({type, data, so
 const frames = new Map();
 const sources = new Map();
 
 const Frame = Class({
   extends: EventTarget,
   implements: [Disposable, Source],
   initialize: function(params={}) {
     const options = validate(params);
-    const id = makeID(options.name || options.url);
+    const id = options.id || urlToId(options.url);
 
     if (frames.has(id))
       throw Error("Frame with this id already exists: " + id);
 
     const initial = { id: id, url: resolve(options.url) };
     this.id = id;
 
     setListeners(this, params);
--- a/addon-sdk/source/lib/sdk/ui/state.js
+++ b/addon-sdk/source/lib/sdk/ui/state.js
@@ -14,17 +14,17 @@ module.metadata = {
 
 const { Ci } = require('chrome');
 
 const events = require('../event/utils');
 const { events: browserEvents } = require('../browser/events');
 const { events: tabEvents } = require('../tab/events');
 const { events: stateEvents } = require('./state/events');
 
-const { windows, isInteractive, getFocusedBrowser } = require('../window/utils');
+const { windows, isInteractive, getMostRecentBrowserWindow } = require('../window/utils');
 const { getActiveTab, getOwnerWindow } = require('../tabs/utils');
 
 const { ignoreWindow } = require('../private-browsing/utils');
 
 const { freeze } = Object;
 const { merge } = require('../util/object');
 const { on, off, emit } = require('../event/core');
 
@@ -42,17 +42,17 @@ const ERR_INVALID_TARGET = 'The state ca
   'Only window, tab and registered component are valid targets.';
 
 const isWindow = thing => thing instanceof Ci.nsIDOMWindow;
 const isTab = thing => thing.tagName && thing.tagName.toLowerCase() === 'tab';
 const isActiveTab = thing => isTab(thing) && thing === getActiveTab(getOwnerWindow(thing));
 const isEnumerable = window => !ignoreWindow(window);
 const browsers = _ =>
   windows('navigator:browser', { includePrivate: true }).filter(isInteractive);
-const getMostRecentTab = _ => getActiveTab(getFocusedBrowser());
+const getMostRecentTab = _ => getActiveTab(getMostRecentBrowserWindow());
 
 function getStateFor(component, target) {
   if (!isRegistered(component))
     throw new Error(ERR_UNREGISTERED);
 
   if (!components.has(component))
     return null;
 
@@ -167,17 +167,17 @@ function properties(contract) {
 
   return Object.create(Object.prototype, descriptor);
 }
 exports.properties = properties;
 
 function state(contract) {
   return {
     state: function state(target, state) {
-      let nativeTarget = target === 'window' ? getFocusedBrowser()
+      let nativeTarget = target === 'window' ? getMostRecentBrowserWindow()
                           : target === 'tab' ? getMostRecentTab()
                           : viewFor(target);
 
       if (!nativeTarget && target !== this && !isNil(target))
         throw new Error('target not allowed.');
 
       target = nativeTarget || target;
 
--- a/addon-sdk/source/lib/sdk/ui/toolbar/view.js
+++ b/addon-sdk/source/lib/sdk/ui/toolbar/view.js
@@ -11,23 +11,21 @@ module.metadata = {
 };
 
 const { Cu } = require("chrome");
 const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
 const { subscribe, send, Reactor, foldp, lift, merges } = require("../../event/utils");
 const { InputPort } = require("../../input/system");
 const { OutputPort } = require("../../output/system");
 const { Interactive } = require("../../input/browser");
-const { CustomizationInput } = require("../../input/customizable-ui");
 const { pairs, map, isEmpty, object,
         each, keys, values } = require("../../util/sequence");
 const { curry, flip } = require("../../lang/functional");
 const { patch, diff } = require("diffpatcher/index");
 const prefs = require("../../preferences/service");
-const { getByOuterId } = require("../../window/utils");
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const PREF_ROOT = "extensions.sdk-toolbar-collapsed.";
 
 
 // There are two output ports one for publishing changes that occured
 // and the other for change requests. Later is synchronous and is only
 // consumed here. Note: it needs to be synchronous to avoid race conditions
@@ -35,19 +33,18 @@ const PREF_ROOT = "extensions.sdk-toolba
 // toolbar is destroyed between the ticks.
 const output = new OutputPort({ id: "toolbar-changed" });
 const syncoutput = new OutputPort({ id: "toolbar-change", sync: true });
 
 // Merge disptached changes and recevied changes from models to keep state up to
 // date.
 const Toolbars = foldp(patch, {}, merges([new InputPort({ id: "toolbar-changed" }),
                                           new InputPort({ id: "toolbar-change" })]));
-const State = lift((toolbars, windows, customizable) =>
-  ({windows: windows, toolbars: toolbars, customizable: customizable}),
-  Toolbars, Interactive, new CustomizationInput());
+const State = lift((toolbars, windows) => ({windows: windows, toolbars: toolbars}),
+                   Toolbars, Interactive);
 
 // Shared event handler that makes `event.target.parent` collapsed.
 // Used as toolbar's close buttons click handler.
 const collapseToolbar = event => {
   const toolbar = event.target.parentNode;
   toolbar.collapsed = true;
 };
 
@@ -86,111 +83,77 @@ const attributesChanged = mutations => {
 // it back. In addition it set's up a listener and observer to communicate
 // state changes.
 const addView = curry((options, {document}) => {
   let view = document.createElementNS(XUL_NS, "toolbar");
   view.setAttribute("id", options.id);
   view.setAttribute("collapsed", options.collapsed);
   view.setAttribute("toolbarname", options.title);
   view.setAttribute("pack", "end");
-  view.setAttribute("customizable", "false");
-  view.setAttribute("style", "padding: 2px 0; max-height: 40px;");
+  view.setAttribute("defaultset", options.items.join(","));
+  view.setAttribute("customizable", true);
+  view.setAttribute("style", "max-height: 40px;");
   view.setAttribute("mode", "icons");
   view.setAttribute("iconsize", "small");
   view.setAttribute("context", "toolbar-context-menu");
-  view.setAttribute("class", "toolbar-primary chromeclass-toolbar");
-
-  let label = document.createElementNS(XUL_NS, "label");
-  label.setAttribute("value", options.title);
-  label.setAttribute("collapsed", "true");
-  view.appendChild(label);
 
   let closeButton = document.createElementNS(XUL_NS, "toolbarbutton");
   closeButton.setAttribute("id", "close-" + options.id);
   closeButton.setAttribute("class", "close-icon");
   closeButton.setAttribute("customizable", false);
   closeButton.addEventListener("command", collapseToolbar);
 
   view.appendChild(closeButton);
 
-  // In order to have a close button not costumizable, aligned on the right,
-  // leaving the customizable capabilities of Australis, we need to create
-  // a toolbar inside a toolbar.
-  // This is should be a temporary hack, we should have a proper XBL for toolbar
-  // instead. See:
-  // https://bugzilla.mozilla.org/show_bug.cgi?id=982005
-  let toolbar = document.createElementNS(XUL_NS, "toolbar");
-  toolbar.setAttribute("id", "inner-" + options.id);
-  toolbar.setAttribute("defaultset", options.items.join(","));
-  toolbar.setAttribute("customizable", "true");
-  toolbar.setAttribute("style", "-moz-appearance: none; overflow: hidden");
-  toolbar.setAttribute("mode", "icons");
-  toolbar.setAttribute("iconsize", "small");
-  toolbar.setAttribute("context", "toolbar-context-menu");
-  toolbar.setAttribute("flex", "1");
-
-  view.insertBefore(toolbar, closeButton);
-
   const observer = new document.defaultView.MutationObserver(attributesChanged);
   observer.observe(view, { attributes: true,
                            attributeFilter: ["collapsed", "toolbarname"] });
 
   const toolbox = document.getElementById("navigator-toolbox");
   toolbox.appendChild(view);
 });
 const viewAdd = curry(flip(addView));
 
 const removeView = curry((id, {document}) => {
   const view = document.getElementById(id);
   if (view) view.remove();
 });
 
-const updateView = curry((id, {title, collapsed, isCustomizing}, {document}) => {
+const updateView = curry((id, {title, collapsed}, {document}) => {
   const view = document.getElementById(id);
-
-  if (!view)
-    return;
-
-  if (title)
+  if (view && title)
     view.setAttribute("toolbarname", title);
-
-  if (collapsed !== void(0))
+  if (view && collapsed !== void(0))
     view.setAttribute("collapsed", Boolean(collapsed));
-
-  if (isCustomizing !== void(0)) {
-    view.querySelector("label").collapsed = !isCustomizing;
-    view.querySelector("toolbar").style.visibility = isCustomizing
-                                                ? "hidden" : "visible";
-  }
 });
 
-const viewUpdate = curry(flip(updateView));
+
 
 // Utility function used to register toolbar into CustomizableUI.
 const registerToolbar = state => {
   // If it's first additon register toolbar as customizableUI component.
-  CustomizableUI.registerArea("inner-" + state.id, {
+  CustomizableUI.registerArea(state.id, {
     type: CustomizableUI.TYPE_TOOLBAR,
     legacy: true,
-    defaultPlacements: [...state.items]
+    defaultPlacements: [...state.items, "close-" + state.id]
   });
 };
 // Utility function used to unregister toolbar from the CustomizableUI.
 const unregisterToolbar = CustomizableUI.unregisterArea;
 
 const reactor = new Reactor({
   onStep: (present, past) => {
     const delta = diff(past, present);
 
     each(([id, update]) => {
       // If update is `null` toolbar is removed, in such case
       // we unregister toolbar and remove it from each window
       // it was added to.
       if (update === null) {
-        unregisterToolbar("inner-" + id);
+        unregisterToolbar(id);
         each(removeView(id), values(past.windows));
 
         send(output, object([id, null]));
       }
       else if (past.toolbars[id]) {
         // If `collapsed` state for toolbar was updated, persist
         // it for a future sessions.
         if (update.collapsed !== void(0))
@@ -222,23 +185,17 @@ const reactor = new Reactor({
       }
     }, pairs(delta.toolbars));
 
     // Add views to every window that was added.
     each(window => {
       if (window)
         each(viewAdd(window), values(past.toolbars));
     }, values(delta.windows));
-
-    each(([id, isCustomizing]) => {
-      each(viewUpdate(getByOuterId(id), {isCustomizing: !!isCustomizing}),
-        keys(present.toolbars));
-
-    }, pairs(delta.customizable))
   },
   onEnd: state => {
     each(id => {
-      unregisterToolbar("inner-" + id);
+      unregisterToolbar(id);
       each(removeView(id), values(state.windows));
     }, keys(state.toolbars));
   }
 });
 reactor.run(State);
--- a/addon-sdk/source/lib/sdk/widget.js
+++ b/addon-sdk/source/lib/sdk/widget.js
@@ -439,20 +439,38 @@ const WidgetViewTrait = LightTrait.compo
     if ("click" == type || type.indexOf("mouse") == 0)
       this._baseWidget._onEvent(type, this._public);
     else
       this._baseWidget._onEvent(type, eventData);
 
     // Special case for click events: if the widget doesn't have a click
     // handler, but it does have a panel, display the panel.
     if ("click" == type && !this._listeners("click").length && this.panel) {
+      // In Australis, widgets may be positioned in an overflow panel or the
+      // menu panel.
+      // In such cases clicking this widget will hide the overflow/menu panel,
+      // and the widget's panel will show instead.
+
+      let anchor = domNode;
+      let { CustomizableUI, window } = domNode.ownerDocument.defaultView;
+
+      if (CustomizableUI) {
+        ({anchor}) = CustomizableUI.getWidget(domNode.id).forWindow(window);
+
+        // if `anchor` is not the `domNode` itself, it means the widget is
+        // positioned in a panel, therefore we have to hide it before show
+        // the widget's panel in the same anchor
+        if (anchor !== domNode)
+          CustomizableUI.hidePanelForNode(domNode);
+      }
+
       // This kind of ugly workaround, instead we should implement
       // `getNodeView` for the `Widget` class itself, but that's kind of
       // hard without cleaning things up.
-      this.panel.show(null, getNodeView.implement({}, () => domNode));
+      this.panel.show(null, getNodeView.implement({}, () => anchor));
     }
   },
 
   _isInWindow: function WidgetView__isInWindow(window) {
     return windowsAPI.BrowserWindow({
       window: this._chrome.window
     }) == window;
   },
@@ -772,49 +790,38 @@ WidgetChrome.prototype._createNode = fun
 
   node.style.minWidth = this._widget.width + "px";
 
   this.node = node;
 }
 
 // Initial population of a widget's content.
 WidgetChrome.prototype.fill = function WC_fill() {
-  let { node, _doc: document } = this;
-
   // Create element
-  let iframe = document.createElement("iframe");
+  var iframe = this._doc.createElement("iframe");
   iframe.setAttribute("type", "content");
   iframe.setAttribute("transparent", "transparent");
   iframe.style.overflow = "hidden";
   iframe.style.height = "16px";
   iframe.style.maxHeight = "16px";
   iframe.style.width = this._widget.width + "px";
   iframe.setAttribute("flex", "1");
   iframe.style.border = "none";
   iframe.style.padding = "0px";
 
   // Do this early, because things like contentWindow are null
   // until the node is attached to a document.
-  node.appendChild(iframe);
+  this.node.appendChild(iframe);
 
-  let label = document.createElement("label");
+  var label = this._doc.createElement("label");
   label.setAttribute("value", this._widget.label);
   label.className = "toolbarbutton-text";
   label.setAttribute("crop", "right");
   label.setAttribute("flex", "1");
-  node.appendChild(label);
-
-  // This toolbarbutton is created to provide a more consistent user experience
-  // during customization, see:
-  // https://bugzilla.mozilla.org/show_bug.cgi?id=959640
-  let button = document.createElement("toolbarbutton");
-  button.setAttribute("label", this._widget.label);
-  button.setAttribute("crop", "right");
-  button.className = "toolbarbutton-1 chromeclass-toolbar-additional";
-  node.appendChild(button);
+  this.node.appendChild(label);
 
   // add event handlers
   this.addEventHandlers();
 
   // set content
   this.setContent();
 }
 
--- a/addon-sdk/source/lib/sdk/window/utils.js
+++ b/addon-sdk/source/lib/sdk/window/utils.js
@@ -14,18 +14,16 @@ const { defer } = require('sdk/core/prom
 const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
                        getService(Ci.nsIWindowWatcher);
 const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
                         getService(Ci.nsIAppShellService);
 const WM = Cc['@mozilla.org/appshell/window-mediator;1'].
            getService(Ci.nsIWindowMediator);
 const io = Cc['@mozilla.org/network/io-service;1'].
            getService(Ci.nsIIOService);
-const FM = Cc["@mozilla.org/focus-manager;1"].
-              getService(Ci.nsIFocusManager);
 
 const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
 
 const BROWSER = 'navigator:browser',
       URI_BROWSER = 'chrome://browser/content/browser.xul',
       NAME = '_blank',
       FEATURES = 'chrome,all,dialog=no,non-private';
 
@@ -354,28 +352,16 @@ exports.isXULBrowser = isXULBrowser;
 function getFocusedWindow() {
   let window = WM.getMostRecentWindow(BROWSER);
 
   return window ? window.document.commandDispatcher.focusedWindow : null;
 }
 exports.getFocusedWindow = getFocusedWindow;
 
 /**
- * Returns the focused browser window if any, or the most recent one.
- * Opening new window, updates most recent window, but focus window
- * changes later; so most recent window and focused window are not always
- * the same.
- */
-function getFocusedBrowser() {
-  let window = FM.activeWindow;
-  return isBrowser(window) ? window : getMostRecentBrowserWindow()
-}
-exports.getFocusedBrowser = getFocusedBrowser;
-
-/**
  * Returns the focused element in the most recent focused window
  */
 function getFocusedElement() {
   let window = WM.getMostRecentWindow(BROWSER);
 
   return window ? window.document.commandDispatcher.focusedElement : null;
 }
 exports.getFocusedElement = getFocusedElement;
--- a/addon-sdk/source/python-lib/cuddlefish/__init__.py
+++ b/addon-sdk/source/python-lib/cuddlefish/__init__.py
@@ -538,29 +538,33 @@ def initializer(env_root, args, out=sys.
             print >>out, '*', args[1], 'package directory created'
         except OSError:
             print >>out, '*', args[1], 'already exists, testing if directory is empty'
     # avoid clobbering existing files, but we tolerate things like .git
     existing = [fn for fn in os.listdir(path) if not fn.startswith(".")]
     if existing:
         print >>err, 'This command must be run in an empty directory.'
         return {"result":1}
-    for d in ['lib','data','test']:
+    for d in ['lib','data','test','doc']:
         os.mkdir(os.path.join(path,d))
         print >>out, '*', d, 'directory created'
+    open(os.path.join(path,'README.md'),'w').write('')
+    print >>out, '* README.md written'
     jid = create_jid()
     print >>out, '* generated jID automatically:', jid
     open(os.path.join(path,'package.json'),'w').write(PACKAGE_JSON % {'name':addon.lower(),
                                                    'title':addon,
                                                    'id':jid })
     print >>out, '* package.json written'
     open(os.path.join(path,'test','test-main.js'),'w').write(TEST_MAIN_JS)
     print >>out, '* test/test-main.js written'
     open(os.path.join(path,'lib','main.js'),'w').write('')
     print >>out, '* lib/main.js written'
+    open(os.path.join(path,'doc','main.md'),'w').write('')
+    print >>out, '* doc/main.md written'
     if len(args) == 1:
         print >>out, '\nYour sample add-on is now ready.'
         print >>out, 'Do "cfx test" to test it and "cfx run" to try it.  Have fun!'
     else:
         print >>out, '\nYour sample add-on is now ready in the \'' + args[1] +  '\' directory.'
         print >>out, 'Change to that directory, then do "cfx test" to test it, \nand "cfx run" to try it.  Have fun!'
     return {"result":0, "jid":jid}
 
--- a/addon-sdk/source/python-lib/cuddlefish/runner.py
+++ b/addon-sdk/source/python-lib/cuddlefish/runner.py
@@ -731,16 +731,17 @@ def run_app(harness_root_dir, manifest_r
                         sys.stderr.flush()
                         if is_running_tests and parseable:
                             match = PARSEABLE_TEST_NAME.search(new_chars)
                             if match:
                                 test_name = match.group(1)
             if os.path.exists(resultfile):
                 result = open(resultfile).read()
                 if result:
+                    sys.stderr.write("resultfile contained " + "'" + result + "'\n")
                     if result in ['OK', 'FAIL']:
                         done = True
                     else:
                         sys.stderr.write("Hrm, resultfile (%s) contained something weird (%d bytes)\n" % (resultfile, len(result)))
                         sys.stderr.write("'"+result+"'\n")
             if enforce_timeouts:
                 if time.time() - last_output_time > OUTPUT_TIMEOUT:
                     raise Timeout("Test output exceeded timeout (%ds)." %
@@ -749,17 +750,19 @@ def run_app(harness_root_dir, manifest_r
                     raise Timeout("Test run exceeded timeout (%ds)." %
                                   RUN_TIMEOUT, test_name, parseable)
     except:
         runner.stop()
         raise
     else:
         runner.wait(10)
     finally:
+        sys.stderr.write("Done.\n")
         outf.close()
+        sys.stderr.write("Clean the profile.\n")
         if profile:
             profile.cleanup()
 
     print >>sys.stderr, "Total time: %f seconds" % (time.time() - starttime)
 
     if result == 'OK':
         print >>sys.stderr, "Program terminated successfully."
         return 0
--- a/addon-sdk/source/test/addons/addon-page/main.js
+++ b/addon-sdk/source/test/addons/addon-page/main.js
@@ -1,19 +1,25 @@
 /* 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 = {
+  engines: {
+    'Firefox': '*'
+  }
+};
+
 const { isTabOpen, activateTab, openTab,
         closeTab, getTabURL, getWindowHoldingTab } = require('sdk/tabs/utils');
 const windows = require('sdk/deprecated/window-utils');
 const { LoaderWithHookedConsole } = require('sdk/test/loader');
 const { setTimeout } = require('sdk/timers');
-const app = require("sdk/system/xul-app");
+const { is } = require('sdk/system/xul-app');
 const tabs = require('sdk/tabs');
 const isAustralis = "gCustomizeMode" in windows.activeBrowserWindow;
 const { set: setPref } = require("sdk/preferences/service");
 const { defer } = require('sdk/core/promise');
 
 const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
 
 let uri = require('sdk/self').data.url('index.html');
@@ -33,20 +39,16 @@ function closeTabPromise(tab) {
   return promise;
 }
 
 function isChromeVisible(window) {
   let x = window.document.documentElement.getAttribute('disablechrome')
   return x !== 'true';
 }
 
-// Once Bug 903018 is resolved, just move the application testing to
-// module.metadata.engines
-if (app.is('Firefox')) {
-
 exports['test add-on page deprecation message'] = function(assert) {
   let { loader, messages } = LoaderWithHookedConsole(module);
   loader.require('sdk/addon-page');
   setPref(DEPRECATE_PREF, true);
 
   assert.equal(messages.length, 1, "only one error is dispatched");
   assert.equal(messages[0].type, "error", "the console message is an error");
 
@@ -67,17 +69,17 @@ exports['test that add-on page has no ch
 
   assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
 
   // need to do this in another turn to make sure event listener
   // that sets property has time to do that.
   setTimeout(function() {
     activateTab(tab);
 
-    assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis,
+    assert.equal(isChromeVisible(window), is('Fennec') || isAustralis,
       'chrome is not visible for addon page');
 
     closeTabPromise(tab).then(function() {
       assert.ok(isChromeVisible(window), 'chrome is visible again');
       loader.unload();
       assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload');
       done();
     }).then(null, assert.fail);
@@ -93,17 +95,17 @@ exports['test that add-on page with hash
 
   assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
 
   // need to do this in another turn to make sure event listener
   // that sets property has time to do that.
   setTimeout(function() {
     activateTab(tab);
 
-    assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis,
+    assert.equal(isChromeVisible(window), is('Fennec') || isAustralis,
       'chrome is not visible for addon page');
 
     closeTabPromise(tab).then(function() {
       assert.ok(isChromeVisible(window), 'chrome is visible again');
       loader.unload();
       assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload');
       done();
     }).then(null, assert.fail);
@@ -119,17 +121,17 @@ exports['test that add-on page with quer
 
   assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
 
   // need to do this in another turn to make sure event listener
   // that sets property has time to do that.
   setTimeout(function() {
     activateTab(tab);
 
-    assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis,
+    assert.equal(isChromeVisible(window), is('Fennec') || isAustralis,
       'chrome is not visible for addon page');
 
     closeTabPromise(tab).then(function() {
       assert.ok(isChromeVisible(window), 'chrome is visible again');
       loader.unload();
       assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload');
       done();
     }).then(null, assert.fail);
@@ -145,17 +147,17 @@ exports['test that add-on page with hash
 
   assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
 
   // need to do this in another turn to make sure event listener
   // that sets property has time to do that.
   setTimeout(function() {
     activateTab(tab);
 
-    assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis,
+    assert.equal(isChromeVisible(window), is('Fennec') || isAustralis,
       'chrome is not visible for addon page');
 
     closeTabPromise(tab).then(function() {
       assert.ok(isChromeVisible(window), 'chrome is visible again');
       loader.unload();
       assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload');
       done();
     }).then(null, assert.fail);
@@ -178,13 +180,9 @@ exports['test that malformed uri is not 
 
     closeTabPromise(tab).then(function() {
       loader.unload();
       done();
     }).then(null, assert.fail);
   });
 };
 
-} else {
-  exports['test unsupported'] = (assert) => assert.pass('This application is unsupported.');
-}
-
 require('sdk/test/runner').runTestsFromModule(module);
--- a/addon-sdk/source/test/addons/child_process/index.js
+++ b/addon-sdk/source/test/addons/child_process/index.js
@@ -1,39 +1,32 @@
 /* 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";
 
-/**
- * Ensures using child_process and underlying subprocess.jsm
- * works within an addon
- */
-
 const { exec } = require("sdk/system/child_process");
 const { platform, pathFor } = require("sdk/system");
 const PROFILE_DIR = pathFor("ProfD");
 const isWindows = platform.toLowerCase().indexOf("win") === 0;
-const app = require("sdk/system/xul-app");
 
-// Once Bug 903018 is resolved, just move the application testing to
-// module.metadata.engines
-if (app.is("Firefox")) {
-  exports["test child_process in an addon"] = (assert, done) => {
-    exec(isWindows ? "DIR /A-D" : "ls -al", {
-      cwd: PROFILE_DIR
-    }, (err, stdout, stderr) => {
-      assert.ok(!err, "no errors");
-      assert.equal(stderr, "", "stderr is empty");
-      assert.ok(/extensions\.ini/.test(stdout), "stdout output of `ls -al` finds files");
+/**
+ * Ensures using child_process and underlying subprocess.jsm
+ * works within an addon
+ */
+exports["test child_process in an addon"] = (assert, done) => {
+  exec(isWindows ? "DIR /A-D" : "ls -al", {
+    cwd: PROFILE_DIR
+  }, (err, stdout, stderr) => {
+    assert.ok(!err, "no errors");
+    assert.equal(stderr, "", "stderr is empty");
+    assert.ok(/extensions\.ini/.test(stdout), "stdout output of `ls -al` finds files");
 
-      if (isWindows)
-        assert.ok(!/<DIR>/.test(stdout), "passing args works");
-      else
-        assert.ok(/d(r[-|w][-|x]){3}/.test(stdout), "passing args works");
-      done();
-    });
-  };
-} else {
-  exports["test unsupported"] = (assert) => assert.pass("This application is unsupported.");
-}
+    if (isWindows)
+      assert.ok(!/<DIR>/.test(stdout), "passing args works");
+    else
+      assert.ok(/d(r[-|w][-|x]){3}/.test(stdout), "passing args works");
+    done();
+  });
+};
+
 require("sdk/test/runner").runTestsFromModule(module);
--- a/addon-sdk/source/test/addons/places/main.js
+++ b/addon-sdk/source/test/addons/places/main.js
@@ -1,27 +1,24 @@
 /* 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 = {
+  'engines': {
+    'Firefox': '*'
+  }
+};
+
 const { safeMerge: merge } = require('sdk/util/object');
-const app = require("sdk/system/xul-app");
 
-// Once Bug 903018 is resolved, just move the application testing to
-// module.metadata.engines
-if (app.is('Firefox')) {
-  merge(module.exports,
-    require('./tests/test-places-bookmarks'),
-    require('./tests/test-places-events'),
-    require('./tests/test-places-favicon'),
-    require('./tests/test-places-history'),
-    require('./tests/test-places-host'),
-    require('./tests/test-places-utils')
-  );
-} else {
-  exports['test unsupported'] = (assert) => {
-    assert.pass('This application is unsupported.');
-  };
-}
+merge(module.exports,
+  require('./tests/test-places-bookmarks'),
+  require('./tests/test-places-events'),
+  require('./tests/test-places-favicon'),
+  require('./tests/test-places-history'),
+  require('./tests/test-places-host'),
+  require('./tests/test-places-utils')
+);
 
 require('sdk/test/runner').runTestsFromModule(module);
--- a/addon-sdk/source/test/addons/simple-prefs-l10n/main.js
+++ b/addon-sdk/source/test/addons/simple-prefs-l10n/main.js
@@ -7,59 +7,51 @@ 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 { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
 
-// Once Bug 903018 is resolved, just move the application testing to
-// module.metadata.engines
-//
-// This should work in Fennec, needs to be refactored to work, via bug 979645
-if (app.is('Firefox')) {
-  exports.testAOMLocalization = function(assert, done) {
-      tabs.open({
-        url: 'about:addons',
-        onReady: function(tab) {
-          tab.attach({
-            contentScriptWhen: 'end',
-            contentScript: 'function onLoad() {\n' +
-                             'unsafeWindow.removeEventListener("load", onLoad, false);\n' +
-                             'AddonManager.getAddonByID("' + self.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..
-                                     'self.postMessage({\n' +
-                                       'somePreference: getAttributes(unsafeWindow.document.querySelector("setting[data-jetpack-id=\'' + self.id + '\']"))\n' +
-                                     '});\n' +
-                                 '}, 250);\n' +
-                               '}, false);\n' +
-                               'unsafeWindow.gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);\n' +
-                             '});\n' +
-                             'function getAttributes(ele) {\n' +
-                               'if (!ele) return {};\n' +
-                               'return {\n' +
-                                 'title: ele.getAttribute("title")\n' +
-                               '}\n' +
+exports.testAOMLocalization = function(assert, done) {
+    tabs.open({
+    	url: 'about:addons',
+    	onReady: function(tab) {
+        tab.attach({
+          contentScriptWhen: 'end',
+        	contentScript: 'function onLoad() {\n' +
+                           'unsafeWindow.removeEventListener("load", onLoad, false);\n' +
+                           'AddonManager.getAddonByID("' + self.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..
+                                   'self.postMessage({\n' +
+                                     'somePreference: getAttributes(unsafeWindow.document.querySelector("setting[data-jetpack-id=\'' + self.id + '\']"))\n' +
+                                   '});\n' +
+                               '}, 250);\n' +
+                             '}, false);\n' +
+                             'unsafeWindow.gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);\n' +
+                           '});\n' +
+                           'function getAttributes(ele) {\n' +
+                             'if (!ele) return {};\n' +
+                             'return {\n' +
+                               'title: ele.getAttribute("title")\n' +
                              '}\n' +
                            '}\n' +
-                           // Wait for the load event ?
-                           'if (document.readyState == "complete") {\n' +
-                             'onLoad()\n' +
-                           '} else {\n' +
-                             'unsafeWindow.addEventListener("load", onLoad, false);\n' +
-                           '}\n',
-            onMessage: function(msg) {
-              // test somePreference
-              assert.equal(msg.somePreference.title, 'A', 'somePreference title is correct');
-              tab.close(done);
-            }
-          });
-        }
-      });
-  }
-} else {
-  exports['test unsupported'] = (assert) => assert.pass('This test is unsupported.');
+                         '}\n' +
+                         // Wait for the load event ?
+                         'if (document.readyState == "complete") {\n' +
+                           'onLoad()\n' +
+                         '} else {\n' +
+                           'unsafeWindow.addEventListener("load", onLoad, false);\n' +
+                         '}\n',
+          onMessage: function(msg) {
+            // test somePreference
+            assert.equal(msg.somePreference.title, 'A', 'somePreference title is correct');
+            tab.close(done);
+          }
+        });
+    	}
+    });
 }
 
 require('sdk/test/runner').runTestsFromModule(module);
--- a/addon-sdk/source/test/test-functional.js
+++ b/addon-sdk/source/test/test-functional.js
@@ -433,38 +433,30 @@ exports["test debounce"] = (assert, done
     setTimeout(() => {
       assert.equal(counter, 2, "function able to be called again after wait");
       done();
     }, 150);
   }, 200);
 };
 
 exports["test throttle"] = (assert, done) => {
-  let counter = 0;
-  let incr = function(){ counter++; };
-  let throttledIncr = throttle(incr, 32);
-  throttledIncr();
-  throttledIncr();
-  throttledIncr();
-  throttledIncr();
+  let called = 0;
+  let attempt = 0;
+  let throttledFn = throttle(() => called++, 100);
+  let fn = () => ++attempt && throttledFn();
+
+  new Array(11).join(0).split("").forEach((_, i) => {
+    setTimeout(fn, 20 * (i+1));
+  });
 
-  assert.equal(counter, 1, 'incr was called immediately');
   setTimeout(() => {
-    assert.equal(counter, 2, 'incr was throttled');
+    assert.equal(called, 1, "function called atleast once during first throttle period");
+    assert.ok(attempt >= 2, "function attempted to be called several times during first period");
+  }, 50);
+
+  setTimeout(() => {
+    assert.equal(called, 3, "function called again during second throttle period");
+    assert.equal(attempt, 10, "function attempted to be called several times during second period");
     done();
-  }, 64);
-};
-
-exports["test throttle args"] = (assert, done) => {
-  let value = 0;
-  let update = function(val){ value = val; };
-  let throttledUpdate = throttle(update, 32);
-  throttledUpdate(1);
-  throttledUpdate(2);
-  setTimeout(() => throttledUpdate(3), 64);
-  assert.equal(value, 1, 'updated to latest value');
-  setTimeout(() => {
-    assert.equal(value, 3, 'updated to latest value');
-    done();
-  }, 96);
+  }, 300);
 };
 
 require('test').run(exports);
--- a/addon-sdk/source/test/test-ui-frame.js
+++ b/addon-sdk/source/test/test-ui-frame.js
@@ -41,36 +41,36 @@ exports["test frame API"] = function*(as
   assert.throws(() => new Frame(),
                 /The `options.url`/,
                 "must provide url");
 
   assert.throws(() => new Frame({ url: "http://mozilla.org/" }),
                 /The `options.url`/,
                 "options.url must be local url");
 
-  assert.throws(() => new Frame({url: url, name: "4you" }),
-                /The `option.name` must be a valid/,
-                "can only take valid names");
+  assert.throws(() => new Frame({url: url, id: "4you" }),
+                /The `option.id` must be a valid/,
+                "can only take valid ID's");
 
   const f1 = new Frame({ url: url });
 
   assert.ok(f1.id, "frame has an id");
   assert.equal(f1.url, void(0), "frame has no url until it's loaded");
   assert.equal(typeof(f1.postMessage), "function",
                "frames can postMessages");
 
   const p1 = wait(f1, "register");
 
   assert.throws(() => new Frame({ url: url }),
                 /Frame with this id already exists/,
                 "can't have two identical frames");
 
 
-  const f2 = new Frame({ name: "frame-2", url: url });
-  assert.pass("can create frame with same url but diff name");
+  const f2 = new Frame({ id: "frame-2", url: url });
+  assert.pass("can create frame with same url but diff id");
   const p2 = wait(f2, "register");
 
   yield p1;
   assert.pass("frame#1 was registered");
   assert.equal(f1.url, url, "once registered it get's url");
 
   yield p2;
   assert.pass("frame#2 was registered");
@@ -140,17 +140,17 @@ exports["test frame in toolbar"] = funct
 
 exports["test host to content messaging"] = function*(assert) {
   const url = "data:text/html,<script>new " + function() {
     window.addEventListener("message", (event) => {
       if (event.data === "ping!")
         event.source.postMessage("pong!", event.origin);
     });
   } + "</script>";
-  const f1 = new Frame({ name: "mailbox", url: url });
+  const f1 = new Frame({ id: "mailbox", url: url });
   const t1 = new Toolbar({ title: "mailbox", items: [f1] });
 
   const e1 = yield wait(f1, "ready");
   e1.source.postMessage("ping!", e1.origin);
 
   const pong = yield wait(f1, "message");
   assert.equal(pong.data, "pong!", "received ping back");
   t1.destroy();
@@ -164,17 +164,17 @@ exports["test content to host messaging"
     window.addEventListener("message", (event) => {
       if (event.data === "pong!")
         event.source.postMessage("end", event.origin);
     });
 
     window.parent.postMessage("ping!", "*");
   } + "</script>";
 
-  const f1 = new Frame({ name: "inbox", url: url });
+  const f1 = new Frame({ id: "inbox", url: url });
   const t1 = new Toolbar({ title: "inbox", items: [f1] });
 
   const e1 = yield wait(f1, "message");
   assert.equal(e1.data, "ping!", "received ping from content");
 
   e1.source.postMessage("pong!", e1.origin);
 
   const e2 = yield wait(f1, "message");
@@ -192,17 +192,17 @@ exports["test direct messaging"] = funct
       if (event.data === "inc")
         n = n + 1;
       if (event.data === "print")
         event.source.postMessage({ n: n }, event.origin);
     });
   } + "</script>";
 
   const w1 = getMostRecentBrowserWindow();
-  const f1 = new Frame({ url: url, name: "mail-cluster" });
+  const f1 = new Frame({ url: url, id: "mail-cluster" });
   const t1 = new Toolbar({ title: "claster", items: [f1] });
 
   yield wait(f1, "ready");
   assert.pass("document loaded in window#1");
 
   const w2 = open();
 
   yield wait(f1, "ready");
--- a/addon-sdk/source/test/test-ui-toggle-button.js
+++ b/addon-sdk/source/test/test-ui-toggle-button.js
@@ -1015,54 +1015,16 @@ exports['test button click do not messin
   button.state(mainWindow, null);
 
   assert.equal(button.state(activeTab).icon, './icon.png',
     'icon property for tab state, properly derived from window state');
 
   loader.unload();
 }
 
-exports['test buttons can have anchored panels'] = function(assert, done) {
-  let loader = Loader(module);
-  let { ToggleButton } = loader.require('sdk/ui');
-  let { Panel } = loader.require('sdk/panel');
-  let { identify } = loader.require('sdk/ui/id');
-  let { getActiveView } = loader.require('sdk/view/core');
-
-  let button = ToggleButton({
-    id: 'my-button-22',
-    label: 'my button',
-    icon: './icon.png',
-    onChange: ({checked}) => checked && panel.show({position: button})
-  });
-
-  let panel = Panel();
-
-  panel.once('show', () => {
-    let { document } = getMostRecentBrowserWindow();
-    let buttonNode = document.getElementById(identify(button));
-    let panelNode = getActiveView(panel);
-
-    assert.ok(button.state('window').checked,
-      'button is checked');
-
-    assert.equal(panelNode.getAttribute('type'), 'arrow',
-      'the panel is a arrow type');
-
-    assert.strictEqual(buttonNode, panelNode.anchorNode,
-      'the panel is anchored properly to the button');
-
-    loader.unload();
-
-    done();
-  });
-
-  button.click();
-}
-
 // If the module doesn't support the app we're being run in, require() will
 // throw.  In that case, remove all tests above from exports, and add one dummy
 // test that passes.
 try {
   require('sdk/ui/button/toggle');
 }
 catch (err) {
   if (!/^Unsupported Application/.test(err.message))
--- a/addon-sdk/source/test/test-ui-toolbar.js
+++ b/addon-sdk/source/test/test-ui-toolbar.js
@@ -7,22 +7,21 @@ module.metadata = {
   "engines": {
     "Firefox": "*"
   }
 };
 
 const { Toolbar } = require("sdk/ui/toolbar");
 const { Loader } = require("sdk/test/loader");
 const { identify } = require("sdk/ui/id");
-const { getMostRecentBrowserWindow, open, getOuterId } = require("sdk/window/utils");
+const { getMostRecentBrowserWindow, open } = require("sdk/window/utils");
 const { ready, close } = require("sdk/window/helpers");
 const { defer } = require("sdk/core/promise");
-const { send, stop, Reactor } = require("sdk/event/utils");
+const { send } = require("sdk/event/utils");
 const { object } = require("sdk/util/sequence");
-const { CustomizationInput } = require("sdk/input/customizable-ui");
 const { OutputPort } = require("sdk/output/system");
 const output = new OutputPort({ id: "toolbar-change" });
 
 const wait = (toolbar, event) => {
   let { promise, resolve } = defer();
   toolbar.once(event, resolve);
   return promise;
 };
@@ -353,125 +352,9 @@ exports["test title change"] = function*
   assert.equal(readTitle(t1, w2), "second title",
                "title updated in second window");
 
   t1.destroy();
   yield wait(t1, "detach");
   yield close(w2);
 };
 
-exports["test toolbar is not customizable"] = function*(assert, done) {
-  const { window, document, gCustomizeMode } = getMostRecentBrowserWindow();
-  const outerId = getOuterId(window);
-  const input = new CustomizationInput();
-  const customized = defer();
-  const customizedEnd = defer();
-
-  new Reactor({ onStep: value => {
-    if (value[outerId] === true)
-      customized.resolve();
-    if (value[outerId] === null)
-      customizedEnd.resolve();
-  }}).run(input);
-
-  const toolbar = new Toolbar({ title: "foo" });
-
-  yield wait(toolbar, "attach");
-
-  let view = document.getElementById(toolbar.id);
-  let label = view.querySelector("label");
-  let inner = view.querySelector("toolbar");
-
-  assert.equal(view.getAttribute("customizable"), "false",
-    "The outer toolbar is not customizable.");
-
-  assert.ok(label.collapsed,
-    "The label is not displayed.")
-
-  assert.equal(inner.getAttribute("customizable"), "true",
-    "The inner toolbar is customizable.");
-
-  assert.equal(window.getComputedStyle(inner).visibility, "visible",
-    "The inner toolbar is visible.");
-
-  // Enter in customization mode
-  gCustomizeMode.toggle();
-
-  yield customized.promise;
-
-  assert.equal(view.getAttribute("customizable"), "false",
-    "The outer toolbar is not customizable.");
-
-  assert.equal(label.collapsed, false,
-    "The label is displayed.")
-
-  assert.equal(inner.getAttribute("customizable"), "true",
-    "The inner toolbar is customizable.");
-
-  assert.equal(window.getComputedStyle(inner).visibility, "hidden",
-    "The inner toolbar is hidden.");
-
-  // Exit from customization mode
-  gCustomizeMode.toggle();
-
-  yield customizedEnd.promise;
-
-  assert.equal(view.getAttribute("customizable"), "false",
-    "The outer toolbar is not customizable.");
-
-  assert.ok(label.collapsed,
-    "The label is not displayed.")
-
-  assert.equal(inner.getAttribute("customizable"), "true",
-    "The inner toolbar is customizable.");
-
-  assert.equal(window.getComputedStyle(inner).visibility, "visible",
-    "The inner toolbar is visible.");
-
-  toolbar.destroy();
-};
-
-exports["test button are attached to toolbar"] = function*(assert) {
-  const { document } = getMostRecentBrowserWindow();
-  const { ActionButton, ToggleButton } = require("sdk/ui");
-  const { identify } = require("sdk/ui/id");
-
-  let action = ActionButton({
-    id: "btn-1",
-    label: "action",
-    icon: "./placeholder.png"
-  });
-
-  let toggle = ToggleButton({
-    id: "btn-2",
-    label: "toggle",
-    icon: "./placeholder.png"
-  });
-
-  const toolbar = new Toolbar({
-    title: "foo",
-    items: [action, toggle]
-  });
-
-  yield wait(toolbar, "attach");
-
-  let actionNode = document.getElementById(identify(action));
-  let toggleNode = document.getElementById(identify(toggle));
-
-  assert.notEqual(actionNode, null,
-    "action button exists in the document");
-
-  assert.notEqual(actionNode, null,
-    "action button exists in the document");
-
-  assert.notEqual(toggleNode, null,
-    "toggle button exists in the document");
-
-  assert.equal(actionNode.nextElementSibling, toggleNode,
-    "action button is placed before toggle button");
-
-  assert.equal(actionNode.parentNode.parentNode.id, toolbar.id,
-    "buttons are placed in the correct toolbar");
-
-  toolbar.destroy();
-};
-
 require("sdk/test").run(exports);