Bug 1346009 - Convert 'defer' to 'new Promise' in client/webide; r?tromey draft
authorMatt R <matthieu.rigolot@gmail.com>
Sat, 20 May 2017 13:31:10 +0100
changeset 583570 6fc17cb71a033c0b4881ace4dea3abff07a0b1a2
parent 577084 96b36c5f527dd42e680a230839519eee1fc2c9f3
child 630110 5422421401246adeb4ea35ec17d70bc810be5ba1
push id60450
push userbmo:matthieu.rigolot@gmail.com
push dateWed, 24 May 2017 08:34:51 +0000
reviewerstromey
bugs1346009
milestone55.0a1
Bug 1346009 - Convert 'defer' to 'new Promise' in client/webide; r?tromey MozReview-Commit-ID: 1adrD8A96Dx
devtools/client/webide/modules/addons.js
devtools/client/webide/modules/app-manager.js
devtools/client/webide/modules/app-projects.js
devtools/client/webide/modules/app-validator.js
devtools/client/webide/modules/build.js
devtools/client/webide/modules/project-list.js
devtools/client/webide/modules/simulator-process.js
devtools/client/webide/modules/simulators.js
devtools/client/webide/modules/tab-store.js
devtools/client/webide/test/browser_tabs.js
devtools/client/webide/test/head.js
devtools/client/webide/test/test_addons.html
devtools/client/webide/test/test_autoconnect_runtime.html
devtools/client/webide/test/test_basic.html
devtools/client/webide/test/test_fullscreenToolbox.html
devtools/client/webide/test/test_runtime.html
devtools/client/webide/test/test_simulators.html
devtools/client/webide/test/test_toolbox.html
--- a/devtools/client/webide/modules/addons.js
+++ b/devtools/client/webide/modules/addons.js
@@ -1,15 +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 promise = require("promise");
 const {AddonManager} = require("resource://gre/modules/AddonManager.jsm");
 const Services = require("Services");
 const {getJSON} = require("devtools/client/shared/getjson");
 const EventEmitter = require("devtools/shared/event-emitter");
 
 const ADDONS_URL = "devtools.webide.addonsURL";
 
 var SIMULATOR_LINK = Services.prefs.getCharPref("devtools.webide.simulatorAddonsURL");
@@ -46,34 +45,34 @@ addonsListener.onUninstalled = (updatedA
     }
   });
 };
 AddonManager.addAddonListener(addonsListener);
 
 var GetAvailableAddons_promise = null;
 var GetAvailableAddons = exports.GetAvailableAddons = function () {
   if (!GetAvailableAddons_promise) {
-    let deferred = promise.defer();
-    GetAvailableAddons_promise = deferred.promise;
-    let addons = {
-      simulators: [],
-      adb: null
-    };
-    getJSON(ADDONS_URL).then(json => {
-      for (let stability in json) {
-        for (let version of json[stability]) {
-          addons.simulators.push(new SimulatorAddon(stability, version));
+    GetAvailableAddons_promise = new Promise((resolve, reject) => {
+      let addons = {
+        simulators: [],
+        adb: null
+      };
+      getJSON(ADDONS_URL).then(json => {
+        for (let stability in json) {
+          for (let version of json[stability]) {
+            addons.simulators.push(new SimulatorAddon(stability, version));
+          }
         }
-      }
-      addons.adb = new ADBAddon();
-      addons.adapters = new AdaptersAddon();
-      deferred.resolve(addons);
-    }, e => {
-      GetAvailableAddons_promise = null;
-      deferred.reject(e);
+        addons.adb = new ADBAddon();
+        addons.adapters = new AdaptersAddon();
+        resolve(addons);
+      }, e => {
+        GetAvailableAddons_promise = null;
+        reject(e);
+      });
     });
   }
   return GetAvailableAddons_promise;
 };
 
 exports.ForgetAddonsList = function () {
   GetAvailableAddons_promise = null;
 };
--- a/devtools/client/webide/modules/app-manager.js
+++ b/devtools/client/webide/modules/app-manager.js
@@ -1,15 +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/. */
 
 const {Cu} = require("chrome");
 
-const promise = require("promise");
 const {TargetFactory} = require("devtools/client/framework/target");
 const Services = require("Services");
 const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
 const EventEmitter = require("devtools/shared/event-emitter");
 const {TextEncoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
 const {AppProjects} = require("devtools/client/webide/modules/app-projects");
 const TabStore = require("devtools/client/webide/modules/tab-store");
 const {AppValidator} = require("devtools/client/webide/modules/app-validator");
@@ -272,17 +271,17 @@ var AppManager = exports.AppManager = {
     if (this.selectedProject.type !== "tab") {
       return;
     }
     this.selectedProject = null;
   },
 
   reloadTab: function () {
     if (this.selectedProject && this.selectedProject.type != "tab") {
-      return promise.reject("tried to reload non-tab project");
+      return Promise.reject("tried to reload non-tab project");
     }
     return this.getTarget().then(target => {
       target.activeTab.reload();
     }, console.error.bind(console));
   },
 
   getTarget: function () {
     if (this.selectedProject.type == "mainProcess") {
@@ -308,31 +307,31 @@ var AppManager = exports.AppManager = {
     }
 
     if (this.selectedProject.type == "tab") {
       return this.tabStore.getTargetForTab();
     }
 
     let app = this._getProjectFront(this.selectedProject);
     if (!app) {
-      return promise.reject("Can't find app front for selected project");
+      return Promise.reject("Can't find app front for selected project");
     }
 
     return Task.spawn(function* () {
       // Once we asked the app to launch, the app isn't necessary completely loaded.
       // launch request only ask the app to launch and immediatly returns.
       // We have to keep trying to get app tab actors required to create its target.
 
       for (let i = 0; i < 10; i++) {
         try {
           return yield app.getTarget();
         } catch (e) {}
-        let deferred = promise.defer();
-        setTimeout(deferred.resolve, 500);
-        yield deferred.promise;
+        return new Promise(resolve => {
+          setTimeout(resolve, 500);
+        });
       }
 
       AppManager.reportError("error_cantConnectToApp", app.manifest.manifestURL);
       throw new Error("can't connect to app");
     });
   },
 
   getProjectManifestURL: function (project) {
@@ -455,71 +454,71 @@ var AppManager = exports.AppManager = {
   get selectedRuntime() {
     return this._selectedRuntime;
   },
 
   connectToRuntime: function (runtime) {
 
     if (this.connected && this.selectedRuntime === runtime) {
       // Already connected
-      return promise.resolve();
+      return Promise.resolve();
     }
 
-    let deferred = promise.defer();
-
-    this.disconnectRuntime().then(() => {
-      this.selectedRuntime = runtime;
+    let deferred = new Promise((resolve, reject) => {
+      this.disconnectRuntime().then(() => {
+        this.selectedRuntime = runtime;
 
-      let onConnectedOrDisconnected = () => {
-        this.connection.off(Connection.Events.CONNECTED, onConnectedOrDisconnected);
-        this.connection.off(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
-        if (this.connected) {
-          deferred.resolve();
-        } else {
-          deferred.reject();
+        let onConnectedOrDisconnected = () => {
+          this.connection.off(Connection.Events.CONNECTED, onConnectedOrDisconnected);
+          this.connection.off(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
+          if (this.connected) {
+            resolve();
+          } else {
+            reject();
+          }
+        };
+        this.connection.on(Connection.Events.CONNECTED, onConnectedOrDisconnected);
+        this.connection.on(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
+        try {
+          // Reset the connection's state to defaults
+          this.connection.resetOptions();
+          // Only watch for errors here.  Final resolution occurs above, once
+          // we've reached the CONNECTED state.
+          this.selectedRuntime.connect(this.connection)
+                              .then(null, e => reject(e));
+        } catch (e) {
+          reject(e);
         }
-      };
-      this.connection.on(Connection.Events.CONNECTED, onConnectedOrDisconnected);
-      this.connection.on(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
-      try {
-        // Reset the connection's state to defaults
-        this.connection.resetOptions();
-        // Only watch for errors here.  Final resolution occurs above, once
-        // we've reached the CONNECTED state.
-        this.selectedRuntime.connect(this.connection)
-                            .then(null, e => deferred.reject(e));
-      } catch (e) {
-        deferred.reject(e);
-      }
-    }, deferred.reject);
+      }, reject);
+    });
 
     // Record connection result in telemetry
     let logResult = result => {
       this._telemetry.log("DEVTOOLS_WEBIDE_CONNECTION_RESULT", result);
       if (runtime.type) {
         this._telemetry.log("DEVTOOLS_WEBIDE_" + runtime.type +
                             "_CONNECTION_RESULT", result);
       }
     };
-    deferred.promise.then(() => logResult(true), () => logResult(false));
+    deferred.then(() => logResult(true), () => logResult(false));
 
     // If successful, record connection time in telemetry
-    deferred.promise.then(() => {
+    deferred.then(() => {
       const timerId = "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS";
       this._telemetry.startTimer(timerId);
       this.connection.once(Connection.Events.STATUS_CHANGED, () => {
         this._telemetry.stopTimer(timerId);
       });
     }).catch(() => {
       // Empty rejection handler to silence uncaught rejection warnings
       // |connectToRuntime| caller should listen for rejections.
       // Bug 1121100 may find a better way to silence these.
     });
 
-    return deferred.promise;
+    return deferred;
   },
 
   _recordRuntimeInfo: Task.async(function* () {
     if (!this.connected) {
       return;
     }
     let runtime = this.selectedRuntime;
     this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE",
@@ -565,35 +564,36 @@ var AppManager = exports.AppManager = {
     if (!this._listTabsResponse) {
       return null;
     }
     return getPreferenceFront(this.connection.client, this._listTabsResponse);
   },
 
   disconnectRuntime: function () {
     if (!this.connected) {
-      return promise.resolve();
+      return Promise.resolve();
     }
-    let deferred = promise.defer();
-    this.connection.once(Connection.Events.DISCONNECTED, () => deferred.resolve());
-    this.connection.disconnect();
-    return deferred.promise;
+
+    return new Promise(resolve => {
+      this.connection.once(Connection.Events.DISCONNECTED, () => resolve());
+      this.connection.disconnect();
+    });
   },
 
   launchRuntimeApp: function () {
     if (this.selectedProject && this.selectedProject.type != "runtimeApp") {
-      return promise.reject("attempting to launch a non-runtime app");
+      return Promise.reject("attempting to launch a non-runtime app");
     }
     let app = this._getProjectFront(this.selectedProject);
     return app.launch();
   },
 
   launchOrReloadRuntimeApp: function () {
     if (this.selectedProject && this.selectedProject.type != "runtimeApp") {
-      return promise.reject("attempting to launch / reload a non-runtime app");
+      return Promise.reject("attempting to launch / reload a non-runtime app");
     }
     let app = this._getProjectFront(this.selectedProject);
     if (!app.running) {
       return app.launch();
     } else {
       return app.reload();
     }
   },
@@ -602,27 +602,27 @@ var AppManager = exports.AppManager = {
     return !!this._appsFront;
   },
 
   installAndRunProject: function () {
     let project = this.selectedProject;
 
     if (!project || (project.type != "packaged" && project.type != "hosted")) {
       console.error("Can't install project. Unknown type of project.");
-      return promise.reject("Can't install");
+      return Promise.reject("Can't install");
     }
 
     if (!this._listTabsResponse) {
       this.reportError("error_cantInstallNotFullyConnected");
-      return promise.reject("Can't install");
+      return Promise.reject("Can't install");
     }
 
     if (!this._appsFront) {
       console.error("Runtime doesn't have a webappsActor");
-      return promise.reject("Can't install");
+      return Promise.reject("Can't install");
     }
 
     return Task.spawn(function* () {
       let self = AppManager;
 
       // Package and validate project
       yield self.packageProject(project);
       yield self.validateAndUpdateProject(project);
@@ -630,17 +630,17 @@ var AppManager = exports.AppManager = {
       if (project.errorsCount > 0) {
         self.reportError("error_cantInstallValidationErrors");
         return;
       }
 
       let installPromise;
 
       if (project.type != "packaged" && project.type != "hosted") {
-        return promise.reject("Don't know how to install project");
+        return Promise.reject("Don't know how to install project");
       }
 
       let response;
       if (project.type == "packaged") {
         let packageDir = yield ProjectBuilding.getPackageDir(project);
         console.log("Installing app from " + packageDir);
 
         response = yield self._appsFront.installPackaged(packageDir,
@@ -669,41 +669,42 @@ var AppManager = exports.AppManager = {
       // Addons don't have any document to load (yet?)
       // So that there is no need to run them, installing is enough
       if (project.manifest.manifest_version || project.manifest.role === "addon") {
         return;
       }
 
       let {app} = response;
       if (!app.running) {
-        let deferred = promise.defer();
-        self.on("app-manager-update", function onUpdate(event, what) {
-          if (what == "project-started") {
-            self.off("app-manager-update", onUpdate);
-            deferred.resolve();
-          }
+        let deferred = new Promise(resolve => {
+          self.on("app-manager-update", function onUpdate(event, what) {
+            if (what == "project-started") {
+              self.off("app-manager-update", onUpdate);
+              resolve();
+            }
+          });
         });
         yield app.launch();
-        yield deferred.promise;
+        yield deferred;
       } else {
         yield app.reload();
       }
     });
   },
 
   stopRunningApp: function () {
     let app = this._getProjectFront(this.selectedProject);
     return app.close();
   },
 
   /* PROJECT VALIDATION */
 
   validateAndUpdateProject: function (project) {
     if (!project) {
-      return promise.reject();
+      return Promise.reject();
     }
 
     return Task.spawn(function* () {
 
       let packageDir = yield ProjectBuilding.getPackageDir(project);
       let validation = new AppValidator({
         type: project.type,
         // Build process may place the manifest in a non-root directory
@@ -818,17 +819,17 @@ var AppManager = exports.AppManager = {
     this.update("runtime-details");
     this.update("runtime-list");
   },
 
   /* MANIFEST UTILS */
 
   writeManifest: function (project) {
     if (project.type != "packaged") {
-      return promise.reject("Not a packaged app");
+      return Promise.reject("Not a packaged app");
     }
 
     if (!project.manifest) {
       project.manifest = {};
     }
 
     let folder = project.location;
     let manifestPath = OS.Path.join(folder, "manifest.webapp");
--- a/devtools/client/webide/modules/app-projects.js
+++ b/devtools/client/webide/modules/app-projects.js
@@ -1,14 +1,13 @@
 /* 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/. */
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
-const promise = require("promise");
 
 const EventEmitter = require("devtools/shared/event-emitter");
 const {generateUUID} = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
 const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
 
 /**
  * IndexedDB wrapper that just save project objects
  *
@@ -16,155 +15,145 @@ const {FileUtils} = Cu.import("resource:
  * a unique `location` object.
  */
 
 const IDB = {
   _db: null,
   databaseName: "AppProjects",
 
   open: function () {
-    let deferred = promise.defer();
-
-    let request = indexedDB.open(IDB.databaseName, 5);
-    request.onerror = function (event) {
-      deferred.reject("Unable to open AppProjects indexedDB: " +
-                      this.error.name + " - " + this.error.message);
-    };
-    request.onupgradeneeded = function (event) {
-      let db = event.target.result;
-      db.createObjectStore("projects", { keyPath: "location" });
-    };
+    return new Promise((resolve, reject) => {
+      let request = indexedDB.open(IDB.databaseName, 5);
+      request.onerror = function (event) {
+        reject("Unable to open AppProjects indexedDB: " +
+                        this.error.name + " - " + this.error.message);
+      };
+      request.onupgradeneeded = function (event) {
+        let db = event.target.result;
+        db.createObjectStore("projects", { keyPath: "location" });
+      };
 
-    request.onsuccess = function () {
-      let db = IDB._db = request.result;
-      let objectStore = db.transaction("projects").objectStore("projects");
-      let projects = [];
-      let toRemove = [];
-      objectStore.openCursor().onsuccess = function (event) {
-        let cursor = event.target.result;
-        if (cursor) {
-          if (cursor.value.location) {
+      request.onsuccess = function () {
+        let db = IDB._db = request.result;
+        let objectStore = db.transaction("projects").objectStore("projects");
+        let projects = [];
+        let toRemove = [];
+        objectStore.openCursor().onsuccess = function (event) {
+          let cursor = event.target.result;
+          if (cursor) {
+            if (cursor.value.location) {
 
-            // We need to make sure this object has a `.location` property.
-            // The UI depends on this property.
-            // This should not be needed as we make sure to register valid
-            // projects, but in the past (before bug 924568), we might have
-            // registered invalid objects.
+              // We need to make sure this object has a `.location` property.
+              // The UI depends on this property.
+              // This should not be needed as we make sure to register valid
+              // projects, but in the past (before bug 924568), we might have
+              // registered invalid objects.
 
 
-            // We also want to make sure the location is valid.
-            // If the location doesn't exist, we remove the project.
+              // We also want to make sure the location is valid.
+              // If the location doesn't exist, we remove the project.
 
-            try {
-              let file = FileUtils.File(cursor.value.location);
-              if (file.exists()) {
-                projects.push(cursor.value);
-              } else {
-                toRemove.push(cursor.value.location);
-              }
-            } catch (e) {
-              if (e.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH) {
-                // A URL
-                projects.push(cursor.value);
+              try {
+                let file = FileUtils.File(cursor.value.location);
+                if (file.exists()) {
+                  projects.push(cursor.value);
+                } else {
+                  toRemove.push(cursor.value.location);
+                }
+              } catch (e) {
+                if (e.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH) {
+                  // A URL
+                  projects.push(cursor.value);
+                }
               }
             }
-          }
-          cursor.continue();
-        } else {
-          let removePromises = [];
-          for (let location of toRemove) {
-            removePromises.push(IDB.remove(location));
+            cursor.continue();
+          } else {
+            let removePromises = [];
+            for (let location of toRemove) {
+              removePromises.push(IDB.remove(location));
+            }
+            Promise.all(removePromises).then(() => {
+              resolve(projects);
+            });
           }
-          promise.all(removePromises).then(() => {
-            deferred.resolve(projects);
-          });
-        }
+        };
       };
-    };
-
-    return deferred.promise;
+    });
   },
 
   add: function (project) {
-    let deferred = promise.defer();
-
-    if (!project.location) {
-      // We need to make sure this object has a `.location` property.
-      deferred.reject("Missing location property on project object.");
-    } else {
-      let transaction = IDB._db.transaction(["projects"], "readwrite");
-      let objectStore = transaction.objectStore("projects");
-      let request = objectStore.add(project);
-      request.onerror = function (event) {
-        deferred.reject("Unable to add project to the AppProjects indexedDB: " +
-                        this.error.name + " - " + this.error.message);
-      };
-      request.onsuccess = function () {
-        deferred.resolve();
-      };
-    }
-
-    return deferred.promise;
+    return new Promise((resolve, reject) => {
+      if (!project.location) {
+        // We need to make sure this object has a `.location` property.
+        reject("Missing location property on project object.");
+      } else {
+        let transaction = IDB._db.transaction(["projects"], "readwrite");
+        let objectStore = transaction.objectStore("projects");
+        let request = objectStore.add(project);
+        request.onerror = function (event) {
+          reject("Unable to add project to the AppProjects indexedDB: " +
+                 this.error.name + " - " + this.error.message);
+        };
+        request.onsuccess = function () {
+          resolve();
+        };
+      }
+    });
   },
 
   update: function (project) {
-    let deferred = promise.defer();
-
-    var transaction = IDB._db.transaction(["projects"], "readwrite");
-    var objectStore = transaction.objectStore("projects");
-    var request = objectStore.put(project);
-    request.onerror = function (event) {
-      deferred.reject("Unable to update project to the AppProjects indexedDB: " +
-                      this.error.name + " - " + this.error.message);
-    };
-    request.onsuccess = function () {
-      deferred.resolve();
-    };
-
-    return deferred.promise;
+    return new Promise((resolve, reject) => {
+      var transaction = IDB._db.transaction(["projects"], "readwrite");
+      var objectStore = transaction.objectStore("projects");
+      var request = objectStore.put(project);
+      request.onerror = function (event) {
+        reject("Unable to update project to the AppProjects indexedDB: " +
+               this.error.name + " - " + this.error.message);
+      };
+      request.onsuccess = function () {
+        resolve();
+      };
+    });
   },
 
   remove: function (location) {
-    let deferred = promise.defer();
-
-    let request = IDB._db.transaction(["projects"], "readwrite")
+    return new Promise((resolve, reject) => {
+      let request = IDB._db.transaction(["projects"], "readwrite")
                     .objectStore("projects")
                     .delete(location);
-    request.onsuccess = function (event) {
-      deferred.resolve();
-    };
-    request.onerror = function () {
-      deferred.reject("Unable to delete project to the AppProjects indexedDB: " +
-                      this.error.name + " - " + this.error.message);
-    };
-
-    return deferred.promise;
+      request.onsuccess = function (event) {
+        resolve();
+      };
+      request.onerror = function () {
+        reject("Unable to delete project to the AppProjects indexedDB: " +
+               this.error.name + " - " + this.error.message);
+      };
+    });
   }
 };
 
-var loadDeferred = promise.defer();
-
-loadDeferred.resolve(IDB.open().then(function (projects) {
+var loadDeferred = IDB.open().then(function (projects) {
   AppProjects.projects = projects;
   AppProjects.emit("ready", projects);
-}));
+});
 
 const AppProjects = {
   load: function () {
-    return loadDeferred.promise;
+    return loadDeferred;
   },
 
   addPackaged: function (folder) {
     let file = FileUtils.File(folder.path);
     if (!file.exists()) {
-      return promise.reject("path doesn't exist");
+      return Promise.reject("path doesn't exist");
     }
     let existingProject = this.get(folder.path);
     if (existingProject) {
-      return promise.reject("Already added");
+      return Promise.reject("Already added");
     }
     let project = {
       type: "packaged",
       location: folder.path,
       // We need a unique id, that is the app origin,
       // in order to identify the app when being installed on the device.
       // The packaged app local path is a valid id, but only on the client.
       // This origin will be used to generate the true id of an app:
@@ -177,17 +166,17 @@ const AppProjects = {
       this.projects.push(project);
       return project;
     });
   },
 
   addHosted: function (manifestURL) {
     let existingProject = this.get(manifestURL);
     if (existingProject) {
-      return promise.reject("Already added");
+      return Promise.reject("Already added");
     }
     let project = {
       type: "hosted",
       location: manifestURL
     };
     return IDB.add(project).then(() => {
       this.projects.push(project);
       return project;
--- a/devtools/client/webide/modules/app-validator.js
+++ b/devtools/client/webide/modules/app-validator.js
@@ -1,15 +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";
 
 var {Ci, Cu, CC} = require("chrome");
-const promise = require("promise");
 
 const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
 const Services = require("Services");
 const {Task} = require("devtools/shared/task");
 var XMLHttpRequest = CC("@mozilla.org/xmlextras/xmlhttprequest;1");
 var strings = Services.strings.createBundle("chrome://devtools/locale/app-manager.properties");
 
 function AppValidator({ type, location }) {
@@ -59,127 +58,122 @@ AppValidator.prototype._getPackagedManif
   let manifestFile = this._getPackagedManifestFile();
   if (!manifestFile) {
     return null;
   }
   return Services.io.newFileURI(manifestFile).spec;
 };
 
 AppValidator.checkManifest = function (manifestURL) {
-  let deferred = promise.defer();
-  let error;
+  return new Promise((resolve, reject) => {
+    let error;
 
-  let req = new XMLHttpRequest();
-  req.overrideMimeType("text/plain");
+    let req = new XMLHttpRequest();
+    req.overrideMimeType("text/plain");
 
-  try {
-    req.open("GET", manifestURL, true);
-    req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
-  } catch (e) {
-    error = strings.formatStringFromName("validator.invalidManifestURL", [manifestURL], 1);
-    deferred.reject(error);
-    return deferred.promise;
-  }
-
-  req.onload = function () {
-    let manifest = null;
     try {
-      manifest = JSON.parse(req.responseText);
+      req.open("GET", manifestURL, true);
+      req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
     } catch (e) {
-      error = strings.formatStringFromName("validator.invalidManifestJSON", [e, manifestURL], 2);
-      deferred.reject(error);
+      error = strings.formatStringFromName("validator.invalidManifestURL", [manifestURL], 1);
+      return reject(error);
     }
 
-    deferred.resolve({manifest, manifestURL});
-  };
+    req.onload = function () {
+      let manifest = null;
+      try {
+        manifest = JSON.parse(req.responseText);
+      } catch (e) {
+        error = strings.formatStringFromName("validator.invalidManifestJSON", [e, manifestURL], 2);
+        reject(error);
+      }
 
-  req.onerror = function () {
-    error = strings.formatStringFromName("validator.noAccessManifestURL", [req.statusText, manifestURL], 2);
-    deferred.reject(error);
-  };
+      resolve({manifest, manifestURL});
+    };
 
-  try {
-    req.send(null);
-  } catch (e) {
-    error = strings.formatStringFromName("validator.noAccessManifestURL", [e, manifestURL], 2);
-    deferred.reject(error);
-  }
+    req.onerror = function () {
+      error = strings.formatStringFromName("validator.noAccessManifestURL", [req.statusText, manifestURL], 2);
+      reject(error);
+    };
 
-  return deferred.promise;
+    try {
+      req.send(null);
+    } catch (e) {
+      error = strings.formatStringFromName("validator.noAccessManifestURL", [e, manifestURL], 2);
+      reject(error);
+    }
+  });
 };
 
 AppValidator.findManifestAtOrigin = function (manifestURL) {
   let fixedManifest = Services.io.newURI(manifestURL).prePath + "/manifest.webapp";
   return AppValidator.checkManifest(fixedManifest);
 };
 
 AppValidator.findManifestPath = function (manifestURL) {
-  let deferred = promise.defer();
-
-  if (manifestURL.endsWith("manifest.webapp")) {
-    deferred.reject();
-  } else {
-    let fixedManifest = manifestURL + "/manifest.webapp";
-    deferred.resolve(AppValidator.checkManifest(fixedManifest));
-  }
-
-  return deferred.promise;
+  return new Promise((resolve, reject) => {
+    if (manifestURL.endsWith("manifest.webapp")) {
+      reject();
+    } else {
+      let fixedManifest = manifestURL + "/manifest.webapp";
+      resolve(AppValidator.checkManifest(fixedManifest));
+    }
+  });
 };
 
 AppValidator.checkAlternateManifest = function (manifestURL) {
   return Task.spawn(function* () {
     let result;
     try {
       result = yield AppValidator.findManifestPath(manifestURL);
     } catch (e) {
       result = yield AppValidator.findManifestAtOrigin(manifestURL);
     }
 
     return result;
   });
 };
 
 AppValidator.prototype._fetchManifest = function (manifestURL) {
-  let deferred = promise.defer();
-  this.manifestURL = manifestURL;
+  return new Promise(resolve => {
+    this.manifestURL = manifestURL;
 
-  AppValidator.checkManifest(manifestURL)
-              .then(({manifest, manifestURL}) => {
-                deferred.resolve(manifest);
-              }, error => {
-                AppValidator.checkAlternateManifest(manifestURL)
-                            .then(({manifest, manifestURL}) => {
-                              this.manifestURL = manifestURL;
-                              deferred.resolve(manifest);
-                            }, () => {
-                              this.error(error);
-                              deferred.resolve(null);
-                            });
-              });
-
-  return deferred.promise;
+    AppValidator.checkManifest(manifestURL)
+                .then(({manifest, manifestURL}) => {
+                  resolve(manifest);
+                }, error => {
+                  AppValidator.checkAlternateManifest(manifestURL)
+                              .then(({manifest, manifestURL}) => {
+                                this.manifestURL = manifestURL;
+                                resolve(manifest);
+                              }, () => {
+                                this.error(error);
+                                resolve(null);
+                              });
+                });
+  });
 };
 
 AppValidator.prototype._getManifest = function () {
   let manifestURL;
   if (this.type == "packaged") {
     manifestURL = this._getPackagedManifestURL();
     if (!manifestURL)
-      return promise.resolve(null);
+      return Promise.resolve(null);
   } else if (this.type == "hosted") {
     manifestURL = this.location;
     try {
       Services.io.newURI(manifestURL);
     } catch (e) {
       this.error(strings.formatStringFromName("validator.invalidHostedManifestURL", [manifestURL, e.message], 2));
-      return promise.resolve(null);
+      return Promise.resolve(null);
     }
   } else {
     this.error(strings.formatStringFromName("validator.invalidProjectType", [this.type], 1));
-    return promise.resolve(null);
+    return Promise.resolve(null);
   }
   return this._fetchManifest(manifestURL);
 };
 
 AppValidator.prototype.validateManifest = function (manifest) {
   if (!manifest.name) {
     this.error(strings.GetStringFromName("validator.missNameManifestProperty"));
   }
@@ -196,67 +190,63 @@ AppValidator.prototype._getOriginURL = f
     let manifestURL = Services.io.newURI(this.manifestURL);
     return Services.io.newURI(".", null, manifestURL).spec;
   } else if (this.type == "hosted") {
     return Services.io.newURI(this.location).prePath;
   }
 };
 
 AppValidator.prototype.validateLaunchPath = function (manifest) {
-  let deferred = promise.defer();
-  // The launch_path field has to start with a `/`
-  if (manifest.launch_path && manifest.launch_path[0] !== "/") {
-    this.error(strings.formatStringFromName("validator.nonAbsoluteLaunchPath", [manifest.launch_path], 1));
-    deferred.resolve();
-    return deferred.promise;
-  }
-  let origin = this._getOriginURL();
-  let path;
-  if (this.type == "packaged") {
-    path = "." + (manifest.launch_path || "/index.html");
-  } else if (this.type == "hosted") {
-    path = manifest.launch_path || "/";
-  }
-  let indexURL;
-  try {
-    indexURL = Services.io.newURI(path, null, Services.io.newURI(origin)).spec;
-  } catch (e) {
-    this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [origin + path], 1));
-    deferred.resolve();
-    return deferred.promise;
-  }
+  return new Promise(resolve => {
+    // The launch_path field has to start with a `/`
+    if (manifest.launch_path && manifest.launch_path[0] !== "/") {
+      this.error(strings.formatStringFromName("validator.nonAbsoluteLaunchPath", [manifest.launch_path], 1));
+      resolve();
+    }
+    let origin = this._getOriginURL();
+    let path;
+    if (this.type == "packaged") {
+      path = "." + (manifest.launch_path || "/index.html");
+    } else if (this.type == "hosted") {
+      path = manifest.launch_path || "/";
+    }
+    let indexURL;
+    try {
+      indexURL = Services.io.newURI(path, null, Services.io.newURI(origin)).spec;
+    } catch (e) {
+      this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [origin + path], 1));
+      return resolve();
+    }
 
-  let req = new XMLHttpRequest();
-  req.overrideMimeType("text/plain");
-  try {
-    req.open("HEAD", indexURL, true);
-    req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
-  } catch (e) {
-    this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
-    deferred.resolve();
-    return deferred.promise;
-  }
-  req.onload = () => {
-    if (req.status >= 400)
-      this.error(strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [indexURL, req.status], 2));
-    deferred.resolve();
-  };
-  req.onerror = () => {
-    this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
-    deferred.resolve();
-  };
+    let req = new XMLHttpRequest();
+    req.overrideMimeType("text/plain");
+    try {
+      req.open("HEAD", indexURL, true);
+      req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
+    } catch (e) {
+      this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
+      return resolve();
+    }
+    req.onload = () => {
+      if (req.status >= 400)
+        this.error(strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [indexURL, req.status], 2));
+      resolve();
+    };
+    req.onerror = () => {
+      this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
+      resolve();
+    };
 
-  try {
-    req.send(null);
-  } catch (e) {
-    this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
-    deferred.resolve();
-  }
-
-  return deferred.promise;
+    try {
+      req.send(null);
+    } catch (e) {
+      this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
+      resolve();
+    }
+  });
 };
 
 AppValidator.prototype.validateType = function (manifest) {
   let appType = manifest.type || "web";
   if (["web", "privileged", "certified"].indexOf(appType) === -1) {
     this.error(strings.formatStringFromName("validator.invalidAppType", [appType], 1));
   } else if (this.type == "hosted" &&
              ["certified", "privileged"].indexOf(appType) !== -1) {
@@ -274,17 +264,17 @@ AppValidator.prototype.validate = functi
   this.warnings = [];
   return this._getManifest().
     then((manifest) => {
       if (manifest) {
         this.manifest = manifest;
 
         // Skip validations for add-ons
         if (manifest.role === "addon" || manifest.manifest_version) {
-          return promise.resolve();
+          return Promise.resolve();
         }
 
         this.validateManifest(manifest);
         this.validateType(manifest);
         return this.validateLaunchPath(manifest);
       }
     });
 };
--- a/devtools/client/webide/modules/build.js
+++ b/devtools/client/webide/modules/build.js
@@ -1,15 +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/. */
 
 const {Cu, Cc, Ci} = require("chrome");
 
-const promise = require("promise");
 const { Task } = require("devtools/shared/task");
 const { TextDecoder, OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
 const Subprocess = require("sdk/system/child_process/subprocess");
 
 const ProjectBuilding = exports.ProjectBuilding = {
   fetchPackageManifest: Task.async(function* (project) {
     let manifestPath = OS.Path.join(project.location, "package.json");
     let exists = yield OS.File.exists(manifestPath);
@@ -144,41 +143,40 @@ const ProjectBuilding = exports.ProjectB
       args.unshift("/C");
     } else {
       args.unshift("-c");
     }
 
     // Subprocess changes CWD, we have to save and restore it.
     let originalCwd = yield OS.File.getCurrentDirectory();
     try {
-      let defer = promise.defer();
-      Subprocess.call({
-        command: shell,
-        arguments: args,
-        environment: env,
-        workdir: cwd,
+      yield new Promise((resolve, reject) => {
+        Subprocess.call({
+          command: shell,
+          arguments: args,
+          environment: env,
+          workdir: cwd,
 
-        stdout: data =>
-          logger(data),
-        stderr: data =>
-          logger(data),
+          stdout: data =>
+            logger(data),
+          stderr: data =>
+            logger(data),
 
-        done: result => {
-          logger("Terminated with error code: " + result.exitCode);
-          if (result.exitCode == 0) {
-            defer.resolve();
-          } else {
-            defer.reject("pre-package command failed with error code " + result.exitCode);
+          done: result => {
+            logger("Terminated with error code: " + result.exitCode);
+            if (result.exitCode == 0) {
+              resolve();
+            } else {
+              reject("pre-package command failed with error code " + result.exitCode);
+            }
           }
-        }
-      });
-      defer.promise.then(() => {
+        });
+      }).then(() => {
         OS.File.setCurrentDirectory(originalCwd);
       });
-      yield defer.promise;
     } catch (e) {
       throw new Error("Unable to run pre-package command '" + command + "' " +
                       args.join(" ") + ":\n" + (e.message || e));
     }
   }),
 
   getPackageDir: Task.async(function* (project) {
     let manifest = yield ProjectBuilding.fetchPackageManifest(project);
--- a/devtools/client/webide/modules/project-list.js
+++ b/devtools/client/webide/modules/project-list.js
@@ -2,17 +2,16 @@
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {Cu} = require("chrome");
 
 const Services = require("Services");
 const {AppProjects} = require("devtools/client/webide/modules/app-projects");
 const {AppManager} = require("devtools/client/webide/modules/app-manager");
-const promise = require("promise");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {Task} = require("devtools/shared/task");
 const utils = require("devtools/client/webide/modules/utils");
 const Telemetry = require("devtools/client/shared/telemetry");
 
 const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties");
 
 var ProjectList;
@@ -195,17 +194,17 @@ ProjectList.prototype = {
           app: tab,
           icon: tab.favicon || AppManager.DEFAULT_PROJECT_ICON,
           location: tab.url,
           name: tab.name
         };
       }, true);
     }
 
-    return promise.resolve();
+    return Promise.resolve();
   },
 
   updateApps: function () {
     let doc = this._doc;
     let runtimeappsHeaderNode = doc.querySelector("#panel-header-runtimeapps");
     let sortedApps = [];
     for (let [manifestURL, app] of AppManager.apps) {
       sortedApps.push(app);
@@ -258,17 +257,17 @@ ProjectList.prototype = {
           type: "runtimeApp",
           app: app.manifest,
           icon: app.iconURL || AppManager.DEFAULT_PROJECT_ICON,
           name: app.manifest.name
         };
       }, true);
     }
 
-    return promise.resolve();
+    return Promise.resolve();
   },
 
   updateCommands: function () {
     let doc = this._doc;
     let newAppCmd;
     let packagedAppCmd;
     let hostedAppCmd;
 
@@ -294,79 +293,77 @@ ProjectList.prototype = {
 
   /**
    * Trigger an update of the project and remote runtime list.
    * @param options object (optional)
    *        An |options| object containing a type of |apps| or |tabs| will limit
    *        what is updated to only those sections.
    */
   update: function (options) {
-    let deferred = promise.defer();
-
     if (options && options.type === "apps") {
       return this.updateApps();
     } else if (options && options.type === "tabs") {
       return this.updateTabs();
     }
 
-    let doc = this._doc;
-    let projectsNode = doc.querySelector("#project-panel-projects");
+    return new Promise((resolve, reject) => {
+      let doc = this._doc;
+      let projectsNode = doc.querySelector("#project-panel-projects");
 
-    while (projectsNode.hasChildNodes()) {
-      projectsNode.firstChild.remove();
-    }
+      while (projectsNode.hasChildNodes()) {
+        projectsNode.firstChild.remove();
+      }
 
-    AppProjects.load().then(() => {
-      let projects = AppProjects.projects;
-      for (let i = 0; i < projects.length; i++) {
-        let project = projects[i];
-        let panelItemNode = doc.createElement(this._panelNodeEl);
-        panelItemNode.className = "panel-item";
-        projectsNode.appendChild(panelItemNode);
-        if (!project.validationStatus) {
-          // The result of the validation process (storing names, icons, …) is not stored in
-          // the IndexedDB database when App Manager v1 is used.
-          // We need to run the validation again and update the name and icon of the app.
-          AppManager.validateAndUpdateProject(project).then(() => {
+      AppProjects.load().then(() => {
+        let projects = AppProjects.projects;
+        for (let i = 0; i < projects.length; i++) {
+          let project = projects[i];
+          let panelItemNode = doc.createElement(this._panelNodeEl);
+          panelItemNode.className = "panel-item";
+          projectsNode.appendChild(panelItemNode);
+          if (!project.validationStatus) {
+            // The result of the validation process (storing names, icons, …) is not stored in
+            // the IndexedDB database when App Manager v1 is used.
+            // We need to run the validation again and update the name and icon of the app.
+            AppManager.validateAndUpdateProject(project).then(() => {
+              this._renderProjectItem({
+                panel: panelItemNode,
+                name: project.name,
+                icon: project.icon
+              });
+            });
+          } else {
             this._renderProjectItem({
               panel: panelItemNode,
-              name: project.name,
-              icon: project.icon
+              name: project.name || AppManager.DEFAULT_PROJECT_NAME,
+              icon: project.icon || AppManager.DEFAULT_PROJECT_ICON
             });
-          });
-        } else {
-          this._renderProjectItem({
-            panel: panelItemNode,
-            name: project.name || AppManager.DEFAULT_PROJECT_NAME,
-            icon: project.icon || AppManager.DEFAULT_PROJECT_ICON
-          });
+          }
+          panelItemNode.addEventListener("click", () => {
+            AppManager.selectedProject = project;
+          }, true);
         }
-        panelItemNode.addEventListener("click", () => {
-          AppManager.selectedProject = project;
-        }, true);
-      }
+
+        resolve();
+      }, reject);
 
-      deferred.resolve();
-    }, deferred.reject);
+      // List remote apps and the main process, if they exist
+      this.updateApps();
 
-    // List remote apps and the main process, if they exist
-    this.updateApps();
-
-    // Build the tab list right now, so it's fast...
-    this.updateTabs();
+      // Build the tab list right now, so it's fast...
+      this.updateTabs();
 
-    // But re-list them and rebuild, in case any tabs navigated since the last
-    // time they were listed.
-    if (AppManager.connected) {
-      AppManager.listTabs().then(() => {
-        this.updateTabs();
-      }).catch(console.error);
-    }
-
-    return deferred.promise;
+      // But re-list them and rebuild, in case any tabs navigated since the last
+      // time they were listed.
+      if (AppManager.connected) {
+        AppManager.listTabs().then(() => {
+          this.updateTabs();
+        }).catch(console.error);
+      }
+    });
   },
 
   destroy: function () {
     this._doc = null;
     AppManager.off("app-manager-update", this.appManagerUpdate);
     this._UI.off("webide-update", this.onWebIDEUpdate);
     this._UI = null;
     this._parentWindow = null;
--- a/devtools/client/webide/modules/simulator-process.js
+++ b/devtools/client/webide/modules/simulator-process.js
@@ -4,17 +4,16 @@
  */
 
 "use strict";
 
 const { Cc, Ci, Cu } = require("chrome");
 
 const Environment = require("sdk/system/environment").env;
 const EventEmitter = require("devtools/shared/event-emitter");
-const promise = require("promise");
 const Subprocess = require("sdk/system/child_process/subprocess");
 const Services = require("Services");
 
 loader.lazyGetter(this, "OS", () => {
   const Runtime = require("sdk/system/runtime");
   switch (Runtime.OS) {
     case "Darwin":
       return "mac64";
@@ -99,31 +98,31 @@ SimulatorProcess.prototype = {
         this.process = null;
         this.emit("exit", result.exitCode);
       }
     });
   },
 
   // Request a B2G instance kill.
   kill() {
-    let deferred = promise.defer();
-    if (this.process) {
-      this.once("exit", (e, exitCode) => {
-        this.shuttingDown = false;
-        deferred.resolve(exitCode);
-      });
-      if (!this.shuttingDown) {
-        this.shuttingDown = true;
-        this.emit("kill", null);
-        this.process.kill();
+    return new Promise(resolve => {
+      if (this.process) {
+        this.once("exit", (e, exitCode) => {
+          this.shuttingDown = false;
+          resolve(exitCode);
+        });
+        if (!this.shuttingDown) {
+          this.shuttingDown = true;
+          this.emit("kill", null);
+          this.process.kill();
+        }
+      } else {
+        return resolve(undefined);
       }
-      return deferred.promise;
-    } else {
-      return promise.resolve(undefined);
-    }
+    });
   },
 
   // Maybe log output messages.
   log(level, message) {
     if (!Services.prefs.getBoolPref("devtools.webide.logSimulatorOutput")) {
       return;
     }
     if (level === "stderr" || level === "error") {
--- a/devtools/client/webide/modules/simulators.js
+++ b/devtools/client/webide/modules/simulators.js
@@ -7,17 +7,16 @@
 const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
 const { Task } = require("devtools/shared/task");
 loader.lazyRequireGetter(this, "ConnectionManager", "devtools/shared/client/connection-manager", true);
 loader.lazyRequireGetter(this, "AddonSimulatorProcess", "devtools/client/webide/modules/simulator-process", true);
 loader.lazyRequireGetter(this, "OldAddonSimulatorProcess", "devtools/client/webide/modules/simulator-process", true);
 loader.lazyRequireGetter(this, "CustomSimulatorProcess", "devtools/client/webide/modules/simulator-process", true);
 const asyncStorage = require("devtools/shared/async-storage");
 const EventEmitter = require("devtools/shared/event-emitter");
-const promise = require("promise");
 const Services = require("Services");
 
 const SimulatorRegExp = new RegExp(Services.prefs.getCharPref("devtools.webide.simulatorAddonRegExp"));
 const LocaleCompare = (a, b) => {
   return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
 };
 
 var Simulators = {
@@ -41,28 +40,29 @@ var Simulators = {
       let value = yield asyncStorage.getItem("simulators");
       if (Array.isArray(value)) {
         value.forEach(options => {
           let simulator = new Simulator(options);
           Simulators.add(simulator, true);
 
           // If the simulator had a reference to an addon, fix it.
           if (options.addonID) {
-            let deferred = promise.defer();
-            AddonManager.getAddonByID(options.addonID, addon => {
-              simulator.addon = addon;
-              delete simulator.options.addonID;
-              deferred.resolve();
+            let deferred = new Promise(resolve => {
+              AddonManager.getAddonByID(options.addonID, addon => {
+                simulator.addon = addon;
+                delete simulator.options.addonID;
+                resolve();
+              });
             });
-            jobs.push(deferred.promise);
+            jobs.push(deferred);
           }
         });
       }
 
-      yield promise.all(jobs);
+      yield Promise.all(jobs);
       yield Simulators._addUnusedAddons();
       Simulators.emitUpdated();
       return Simulators._simulators;
     });
 
     return this._loadingPromise;
   },
 
@@ -74,17 +74,17 @@ var Simulators = {
   _addUnusedAddons: Task.async(function* () {
     let jobs = [];
 
     let addons = yield Simulators.findSimulatorAddons();
     addons.forEach(addon => {
       jobs.push(Simulators.addIfUnusedAddon(addon, true));
     });
 
-    yield promise.all(jobs);
+    yield Promise.all(jobs);
   }),
 
   /**
    * Save the current list of configurations.
    *
    * @return Promise.
    */
   _save: Task.async(function* () {
@@ -112,39 +112,39 @@ var Simulators = {
   }),
 
   /**
    * List all installed simulator addons.
    *
    * @return Promised addon list.
    */
   findSimulatorAddons() {
-    let deferred = promise.defer();
-    AddonManager.getAllAddons(all => {
-      let addons = [];
-      for (let addon of all) {
-        if (Simulators.isSimulatorAddon(addon)) {
-          addons.push(addon);
+    return new Promise(resolve => {
+      AddonManager.getAllAddons(all => {
+        let addons = [];
+        for (let addon of all) {
+          if (Simulators.isSimulatorAddon(addon)) {
+            addons.push(addon);
+          }
         }
-      }
-      // Sort simulator addons by name.
-      addons.sort(LocaleCompare);
-      deferred.resolve(addons);
+        // Sort simulator addons by name.
+        addons.sort(LocaleCompare);
+        resolve(addons);
+      });
     });
-    return deferred.promise;
   },
 
   /**
    * Add a new simulator for `addon` if no other simulator uses it.
    */
   addIfUnusedAddon(addon, silently = false) {
     let simulators = this._simulators;
     let matching = simulators.filter(s => s.addon && s.addon.id == addon.id);
     if (matching.length > 0) {
-      return promise.resolve();
+      return Promise.resolve();
     }
     let options = {};
     options.name = addon.name.replace(" Simulator", "");
     // Some addons specify a simulator type at the end of their version string,
     // e.g. "2_5_tv".
     let type = this.simulatorAddonVersion(addon).split("_")[2];
     if (type) {
       // "tv" is shorthand for type "television".
@@ -171,17 +171,17 @@ var Simulators = {
   add(simulator, silently = false) {
     let simulators = this._simulators;
     let uniqueName = this.uniqueName(simulator.options.name);
     simulator.options.name = uniqueName;
     simulators.push(simulator);
     if (!silently) {
       this.emitUpdated();
     }
-    return promise.resolve(simulator);
+    return Promise.resolve(simulator);
   },
 
   /**
    * Remove a simulator from the list.
    */
   remove(simulator) {
     let simulators = this._simulators;
     let remaining = simulators.filter(s => s !== simulator);
@@ -327,23 +327,23 @@ Simulator.prototype = {
       // Recent simulator addon.
       this.process = new AddonSimulatorProcess(this.addon, this.options);
     } else {
       // Old simulator addon.
       this.process = new OldAddonSimulatorProcess(this.addon, this.options);
     }
     this.process.run();
 
-    return promise.resolve(this.options.port);
+    return Promise.resolve(this.options.port);
   },
 
   kill() {
     let process = this.process;
     if (!process) {
-      return promise.resolve();
+      return Promise.resolve();
     }
     this.process = null;
     return process.kill();
   },
 
   get defaults() {
     let defaults = this._defaults;
     return defaults[this.type] || defaults[this._defaultType];
--- a/devtools/client/webide/modules/tab-store.js
+++ b/devtools/client/webide/modules/tab-store.js
@@ -2,17 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const { Cu } = require("chrome");
 
 const { TargetFactory } = require("devtools/client/framework/target");
 const EventEmitter = require("devtools/shared/event-emitter");
 const { Connection } = require("devtools/shared/client/connection-manager");
-const promise = require("promise");
 const { Task } = require("devtools/shared/task");
 
 const _knownTabStores = new WeakMap();
 
 var TabStore;
 
 module.exports = TabStore = function (connection) {
   // If we already know about this connection,
@@ -90,35 +89,36 @@ TabStore.prototype = {
     }
     this._selectedTab.url = url;
     this._selectedTab.title = title;
     this.emit("navigate");
   },
 
   listTabs: function () {
     if (!this._connection || !this._connection.client) {
-      return promise.reject(new Error("Can't listTabs, not connected."));
+      return Promise.reject(new Error("Can't listTabs, not connected."));
     }
-    let deferred = promise.defer();
-    this._connection.client.listTabs(response => {
-      if (response.error) {
-        this._connection.disconnect();
-        deferred.reject(response.error);
-        return;
-      }
-      let tabsChanged = JSON.stringify(this.tabs) !== JSON.stringify(response.tabs);
-      this.response = response;
-      this.tabs = response.tabs;
-      this._checkSelectedTab();
-      if (tabsChanged) {
-        this.emit("tab-list");
-      }
-      deferred.resolve(response);
+
+    return new Promise((resolve, reject) => {
+      this._connection.client.listTabs(response => {
+        if (response.error) {
+          this._connection.disconnect();
+          reject(response.error);
+          return;
+        }
+        let tabsChanged = JSON.stringify(this.tabs) !== JSON.stringify(response.tabs);
+        this.response = response;
+        this.tabs = response.tabs;
+        this._checkSelectedTab();
+        if (tabsChanged) {
+          this.emit("tab-list");
+        }
+        resolve(response);
+      });
     });
-    return deferred.promise;
   },
 
   // TODO: Tab "selection" should really take place by creating a TabProject
   // which is the selected project.  This should be done as part of the
   // project-agnostic work.
   _selectedTab: null,
   _selectedTabTargetPromise: null,
   get selectedTab() {
--- a/devtools/client/webide/test/browser_tabs.js
+++ b/devtools/client/webide/test/browser_tabs.js
@@ -59,22 +59,22 @@ function test() {
     yield win.Cmds.disconnectRuntime();
     yield closeWebIDE(win);
 
     DebuggerServer.destroy();
   }).then(finish, handleError);
 }
 
 function connectToLocal(win, docRuntime) {
-  let deferred = promise.defer();
-  win.AppManager.connection.once(
+  return new Promise(resolve => {
+    win.AppManager.connection.once(
       win.Connection.Events.CONNECTED,
-      () => deferred.resolve());
-  docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
-  return deferred.promise;
+      resolve);
+    docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
+  });
 }
 
 function selectTabProject(win, docProject) {
   return Task.spawn(function* () {
     yield waitForUpdate(win, "runtime-targets");
     let tabsNode = docProject.querySelector("#project-panel-tabs");
     let tabNode = tabsNode.querySelectorAll(".panel-item")[1];
     let project = waitForUpdate(win, "project");
--- a/devtools/client/webide/test/head.js
+++ b/devtools/client/webide/test/head.js
@@ -3,17 +3,16 @@
 
 "use strict";
 
 var {utils: Cu, classes: Cc, interfaces: Ci} = Components;
 
 const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
 const { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
 const { gDevTools } = require("devtools/client/framework/devtools");
-const promise = require("promise");
 const Services = require("Services");
 const { Task } = require("devtools/shared/task");
 const { AppProjects } = require("devtools/client/webide/modules/app-projects");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const { DebuggerServer } = require("devtools/server/main");
 const flags = require("devtools/shared/flags");
 flags.testing = true;
 
@@ -66,130 +65,120 @@ var openWebIDE = Task.async(function* (a
   info("WebIDE open");
 
   return win;
 });
 
 function closeWebIDE(win) {
   info("Closing WebIDE");
 
-  let deferred = promise.defer();
+  return new Promise(resolve => {
+    win.addEventListener("unload", function () {
+      info("WebIDE closed");
+      SimpleTest.executeSoon(resolve);
+    }, {once: true});
 
-  win.addEventListener("unload", function () {
-    info("WebIDE closed");
-    SimpleTest.executeSoon(() => {
-      deferred.resolve();
-    });
-  }, {once: true});
-
-  win.close();
-
-  return deferred.promise;
+    win.close();
+  });
 }
 
 function removeAllProjects() {
   return Task.spawn(function* () {
     yield AppProjects.load();
     // use a new array so we're not iterating over the same
     // underlying array that's being modified by AppProjects
     let projects = AppProjects.projects.map(p => p.location);
     for (let i = 0; i < projects.length; i++) {
       yield AppProjects.remove(projects[i]);
     }
   });
 }
 
 function nextTick() {
-  let deferred = promise.defer();
-  SimpleTest.executeSoon(() => {
-    deferred.resolve();
+  return new Promise(resolve => {
+    SimpleTest.executeSoon(resolve);
   });
-
-  return deferred.promise;
 }
 
 function waitForUpdate(win, update) {
   info("Wait: " + update);
-  let deferred = promise.defer();
-  win.AppManager.on("app-manager-update", function onUpdate(e, what) {
-    info("Got: " + what);
-    if (what !== update) {
-      return;
-    }
-    win.AppManager.off("app-manager-update", onUpdate);
-    deferred.resolve(win.UI._updatePromise);
+  return new Promise(resolve => {
+    win.AppManager.on("app-manager-update", function onUpdate(e, what) {
+      info("Got: " + what);
+      if (what !== update) {
+        return;
+      }
+      win.AppManager.off("app-manager-update", onUpdate);
+      resolve(win.UI._updatePromise);
+    });
   });
-  return deferred.promise;
 }
 
 function waitForTime(time) {
-  let deferred = promise.defer();
-  setTimeout(() => {
-    deferred.resolve();
-  }, time);
-  return deferred.promise;
+  return new Promise(resolve => {
+    setTimeout(resolve, time);
+  });
 }
 
 function documentIsLoaded(doc) {
-  let deferred = promise.defer();
-  if (doc.readyState == "complete") {
-    deferred.resolve();
-  } else {
-    doc.addEventListener("readystatechange", function onChange() {
-      if (doc.readyState == "complete") {
-        doc.removeEventListener("readystatechange", onChange);
-        deferred.resolve();
-      }
-    });
-  }
-  return deferred.promise;
+  return new Promise(resolve => {
+    if (doc.readyState == "complete") {
+      resolve();
+    } else {
+      doc.addEventListener("readystatechange", function onChange() {
+        if (doc.readyState == "complete") {
+          doc.removeEventListener("readystatechange", onChange);
+          resolve();
+        }
+      });
+    }
+  });
 }
 
 function lazyIframeIsLoaded(iframe) {
-  let deferred = promise.defer();
-  iframe.addEventListener("load", function () {
-    deferred.resolve(nextTick());
-  }, {capture: true, once: true});
-  return deferred.promise;
+  return new Promise(resolve => {
+    iframe.addEventListener("load", function () {
+      resolve(nextTick());
+    }, {capture: true, once: true});
+  });
 }
 
 function addTab(aUrl, aWindow) {
   info("Adding tab: " + aUrl);
 
-  let deferred = promise.defer();
-  let targetWindow = aWindow || window;
-  let targetBrowser = targetWindow.gBrowser;
+  return new Promise(resolve => {
+    let targetWindow = aWindow || window;
+    let targetBrowser = targetWindow.gBrowser;
 
-  targetWindow.focus();
-  let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
-  let linkedBrowser = tab.linkedBrowser;
+    targetWindow.focus();
+    let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
+    let linkedBrowser = tab.linkedBrowser;
 
-  BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
-    info("Tab added and finished loading: " + aUrl);
-    deferred.resolve(tab);
+    BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
+      info("Tab added and finished loading: " + aUrl);
+      resolve(tab);
+    });
   });
-
-  return deferred.promise;
 }
 
 function removeTab(aTab, aWindow) {
   info("Removing tab.");
 
-  let deferred = promise.defer();
-  let targetWindow = aWindow || window;
-  let targetBrowser = targetWindow.gBrowser;
-  let tabContainer = targetBrowser.tabContainer;
+  return new Promise(resolve => {
+    let targetWindow = aWindow || window;
+    let targetBrowser = targetWindow.gBrowser;
+    let tabContainer = targetBrowser.tabContainer;
 
-  tabContainer.addEventListener("TabClose", function (aEvent) {
-    info("Tab removed and finished closing.");
-    deferred.resolve();
-  }, {once: true});
+    tabContainer.addEventListener("TabClose", function (aEvent) {
+      info("Tab removed and finished closing.");
+      resolve();
+    }, {once: true});
 
-  targetBrowser.removeTab(aTab);
-  return deferred.promise;
+    targetBrowser.removeTab(aTab);
+  });
 }
 
 function getRuntimeDocument(win) {
   return win.document.querySelector("#runtime-listing-panel-details").contentDocument;
 }
 
 function getProjectDocument(win) {
   return win.document.querySelector("#project-listing-panel-details").contentDocument;
--- a/devtools/client/webide/test/test_addons.html
+++ b/devtools/client/webide/test/test_addons.html
@@ -17,92 +17,93 @@
     <script type="application/javascript">
       window.onload = function() {
         SimpleTest.waitForExplicitFinish();
 
         const {GetAvailableAddons} = require("devtools/client/webide/modules/addons");
         const {Devices} = Cu.import("resource://devtools/shared/apps/Devices.jsm");
         const {Simulators} = require("devtools/client/webide/modules/simulators");
 
-        let adbAddonsInstalled = promise.defer();
-        Devices.on("addon-status-updated", function onUpdate1() {
-          Devices.off("addon-status-updated", onUpdate1);
-          adbAddonsInstalled.resolve();
-        });
+        let adbAddonsInstalled;
 
         function getVersion(name) {
           return name.match(/(\d+\.\d+)/)[0];
         }
 
         function onSimulatorInstalled(name) {
-          let deferred = promise.defer();
-          Simulators.on("updated", function onUpdate() {
-            Simulators.findSimulatorAddons().then(addons => {
-              for (let addon of addons) {
-                if (name == addon.name.replace(" Simulator", "")) {
-                  Simulators.off("updated", onUpdate);
-                  nextTick().then(deferred.resolve);
-                  return;
+          return new Promise(resolve => {
+            Simulators.on("updated", function onUpdate() {
+              Simulators.findSimulatorAddons().then(addons => {
+                for (let addon of addons) {
+                  if (name == addon.name.replace(" Simulator", "")) {
+                    Simulators.off("updated", onUpdate);
+                    nextTick().then(resolve);
+                    return;
+                  }
                 }
-              }
+              });
             });
           });
-          return deferred.promise;
         }
 
         function installSimulatorFromUI(doc, name) {
           let li = doc.querySelector('[addon="simulator-' + getVersion(name) + '"]');
           li.querySelector(".install-button").click();
           return onSimulatorInstalled(name);
         }
 
         function uninstallSimulatorFromUI(doc, name) {
-          let deferred = promise.defer();
-          Simulators.on("updated", function onUpdate() {
-            nextTick().then(() => {
-              let li = doc.querySelector('[status="uninstalled"][addon="simulator-' + getVersion(name) + '"]');
-              if (li) {
-                Simulators.off("updated", onUpdate);
-                deferred.resolve();
-              } else {
-                deferred.reject("Can't find item");
-              }
+          return new Promise((resolve, reject) => {
+            Simulators.on("updated", function onUpdate() {
+              nextTick().then(() => {
+                let li = doc.querySelector('[status="uninstalled"][addon="simulator-' + getVersion(name) + '"]');
+                if (li) {
+                  Simulators.off("updated", onUpdate);
+                  resolve();
+                } else {
+                  reject("Can't find item");
+                }
+              });
             });
+            let li = doc.querySelector('[status="installed"][addon="simulator-' + getVersion(name) + '"]');
+            li.querySelector(".uninstall-button").click();
           });
-          let li = doc.querySelector('[status="installed"][addon="simulator-' + getVersion(name) + '"]');
-          li.querySelector(".uninstall-button").click();
-          return deferred.promise;
         }
 
         function uninstallADBFromUI(doc) {
-          let deferred = promise.defer();
-          Devices.on("addon-status-updated", function onUpdate() {
-            nextTick().then(() => {
-              let li = doc.querySelector('[status="uninstalled"][addon="adb"]');
-              if (li) {
-                Devices.off("addon-status-updated", onUpdate);
-                deferred.resolve();
-              } else {
-                deferred.reject("Can't find item");
-              }
-            })
+          return new Promise((resolve, reject) => {
+            Devices.on("addon-status-updated", function onUpdate() {
+              nextTick().then(() => {
+                let li = doc.querySelector('[status="uninstalled"][addon="adb"]');
+                if (li) {
+                  Devices.off("addon-status-updated", onUpdate);
+                  resolve();
+                } else {
+                  reject("Can't find item");
+                }
+              })
+            });
+            let li = doc.querySelector('[status="installed"][addon="adb"]');
+            li.querySelector(".uninstall-button").click();
           });
-          let li = doc.querySelector('[status="installed"][addon="adb"]');
-          li.querySelector(".uninstall-button").click();
-          return deferred.promise;
         }
 
         Task.spawn(function*() {
 
           ok(!Devices.helperAddonInstalled, "Helper not installed");
 
           let win = yield openWebIDE(true);
           let docRuntime = getRuntimeDocument(win);
 
-          yield adbAddonsInstalled.promise;
+          adbAddonsInstalled = new Promise(resolve => {
+            Devices.on("addon-status-updated", function onUpdate1() {
+              Devices.off("addon-status-updated", onUpdate1);
+              resolve();
+            });
+          });
 
           ok(Devices.helperAddonInstalled, "Helper has been auto-installed");
 
           yield nextTick();
 
           let addons = yield GetAvailableAddons();
 
           is(addons.simulators.length, 3, "3 simulator addons to install");
--- a/devtools/client/webide/test/test_autoconnect_runtime.html
+++ b/devtools/client/webide/test/test_autoconnect_runtime.html
@@ -28,17 +28,17 @@
           let docRuntime = getRuntimeDocument(win);
 
           let fakeRuntime = {
             type: "USB",
             connect: function(connection) {
               is(connection, win.AppManager.connection, "connection is valid");
               connection.host = null; // force connectPipe
               connection.connect();
-              return promise.resolve();
+              return Promise.resolve();
             },
 
             get id() {
               return "fakeRuntime";
             },
 
             get name() {
               return "fakeRuntime";
--- a/devtools/client/webide/test/test_basic.html
+++ b/devtools/client/webide/test/test_basic.html
@@ -30,22 +30,23 @@
             let appmgr = win.AppManager;
             ok(appmgr.connection, "App Manager connection ready");
             ok(appmgr.runtimeList, "Runtime list ready");
 
             // test error reporting
             let nbox = win.document.querySelector("#notificationbox");
             let notification =  nbox.getNotificationWithValue("webide:errornotification");
             ok(!notification, "No notification yet");
-            let deferred = promise.defer();
-            nextTick().then(() => {
-              deferred.reject("BOOM!");
+            let deferred = new Promise((resolve, reject) => {
+              nextTick().then(() => {
+                reject("BOOM!");
+              });
             });
             try {
-              yield win.UI.busyUntil(deferred.promise, "xx");
+              yield win.UI.busyUntil(deferred, "xx");
             } catch(e) {/* This *will* fail */}
             notification =  nbox.getNotificationWithValue("webide:errornotification");
             ok(notification, "Error has been reported");
 
             yield closeWebIDE(win);
 
             SimpleTest.finish();
         });
--- a/devtools/client/webide/test/test_fullscreenToolbox.html
+++ b/devtools/client/webide/test/test_fullscreenToolbox.html
@@ -11,34 +11,34 @@
     <script type="application/javascript" src="head.js"></script>
     <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   </head>
 
   <body>
 
     <script type="application/javascript">
       function connectToLocal(win, docRuntime) {
-        let deferred = promise.defer();
-        win.AppManager.connection.once(
-            win.Connection.Events.CONNECTED,
-            () => deferred.resolve());
-        docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
-        return deferred.promise;
+        return new Promise(resolve => {
+          win.AppManager.connection.once(
+              win.Connection.Events.CONNECTED,
+              resolve);
+          docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
+        });
       }
 
       window.onload = function() {
         SimpleTest.waitForExplicitFinish();
 
         Task.spawn(function* () {
           let win = yield openWebIDE();
           let docProject = getProjectDocument(win);
           let docRuntime = getRuntimeDocument(win);
           win.AppManager.update("runtime-list");
 
-          yield connectToLocal(win, docRuntime);
+          connectToLocal(win, docRuntime);
 
           // Select main process
           yield waitForUpdate(win, "runtime-targets");
           SimpleTest.executeSoon(() => {
             docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
           });
 
           yield waitForUpdate(win, "project");
--- a/devtools/client/webide/test/test_runtime.html
+++ b/devtools/client/webide/test/test_runtime.html
@@ -57,39 +57,37 @@
           yield onValidated;
           yield onDetails;
 
           win.AppManager.runtimeList.usb.push({
             connect: function(connection) {
               is(connection, win.AppManager.connection, "connection is valid");
               connection.host = null; // force connectPipe
               connection.connect();
-              return promise.resolve();
+              return Promise.resolve();
             },
 
             get name() {
               return "fakeRuntime";
             }
           });
 
           win.AppManager.runtimeList.usb.push({
             connect: function(connection) {
-              let deferred = promise.defer();
-              return deferred.promise;
+              return new Promise(() => {});
             },
 
             get name() {
               return "infiniteRuntime";
             }
           });
 
           win.AppManager.runtimeList.usb.push({
             connect: function(connection) {
-              let deferred = promise.defer();
-              return deferred.promise;
+              return new Promise(() => {});
             },
 
             prolongedConnection: true,
 
             get name() {
               return "prolongedRuntime";
             }
           });
@@ -159,45 +157,44 @@
           // Toolbox opens automatically for main process / runtime apps
           ok(win.UI.toolboxPromise, "Toolbox promise exists");
           yield win.UI.toolboxPromise;
 
           yield win.Cmds.disconnectRuntime();
 
           Services.prefs.setIntPref("devtools.webide.busyTimeout", 100);
 
-          // Wait for error message since connection never completes
-          let errorDeferred = promise.defer();
-          win.UI.reportError = errorName => {
-            if (errorName === "error_operationTimeout") {
-              errorDeferred.resolve();
-            }
-          };
-
           // Click the infinite runtime
           items[1].click();
           ok(win.document.querySelector("window").className, "busy", "UI is busy");
-          yield errorDeferred.promise;
 
-          // Check for unexpected error message since this is prolonged
-          let noErrorDeferred = promise.defer();
-          win.UI.reportError = errorName => {
-            if (errorName === "error_operationTimeout") {
-              noErrorDeferred.reject();
-            }
-          };
+          // Wait for error message since connection never completes
+          let errorDeferred = new Promise(resolve => {
+            win.UI.reportError = errorName => {
+              if (errorName === "error_operationTimeout") {
+                resolve();
+              }
+            };
+          });
 
           // Click the prolonged runtime
           items[2].click();
           ok(win.document.querySelector("window").className, "busy", "UI is busy");
 
-          setTimeout(() => {
-            noErrorDeferred.resolve();
-          }, 1000);
+          // Check for unexpected error message since this is prolonged
+          let noErrorDeferred = new Promise((resolve, reject) => {
+            win.UI.reportError = errorName => {
+              if (errorName === "error_operationTimeout") {
+                reject();
+              }
+            };
 
-          yield noErrorDeferred.promise;
+            setTimeout(() => {
+              resolve();
+            }, 1000);
+          });
 
           SimpleTest.finish();
         });
       }
     </script>
   </body>
 </html>
--- a/devtools/client/webide/test/test_simulators.html
+++ b/devtools/client/webide/test/test_simulators.html
@@ -24,75 +24,76 @@
         const { getDevices } = require("devtools/client/shared/devices");
         const { Simulator, Simulators } = require("devtools/client/webide/modules/simulators");
         const { AddonSimulatorProcess,
                 OldAddonSimulatorProcess,
                 CustomSimulatorProcess } = require("devtools/client/webide/modules/simulator-process");
 
         function addonStatus(addon, status) {
           if (addon.status == status) {
-            return promise.resolve();
+            return Promise.resolve();
           }
-          let deferred = promise.defer();
-          addon.on("update", function onUpdate() {
-            if (addon.status == status) {
-              addon.off("update", onUpdate);
-              nextTick().then(() => deferred.resolve());
-            }
+          return new Promise(resolve => {
+            addon.on("update", function onUpdate() {
+              if (addon.status == status) {
+                addon.off("update", onUpdate);
+                nextTick().then(() => resolve());
+              }
+            });
           });
-          return deferred.promise;
         }
 
         function waitForUpdate(length) {
           info(`Wait for update with length ${length}`);
-          let deferred = promise.defer();
-          let handler = (_, data) => {
-            if (data.length != length) {
-              return;
-            }
-            info(`Got update with length ${length}`);
-            Simulators.off("updated", handler);
-            deferred.resolve();
-          };
-          Simulators.on("updated", handler);
-          return deferred.promise;
+          return new Promise(resolve => {
+            let handler = (_, data) => {
+              if (data.length != length) {
+                return;
+              }
+              info(`Got update with length ${length}`);
+              Simulators.off("updated", handler);
+              resolve();
+            };
+            Simulators.on("updated", handler);
+          });
         }
 
         Task.spawn(function* () {
           let win = yield openWebIDE(false);
 
           yield Simulators._load();
 
           let docRuntime = getRuntimeDocument(win);
           let find = win.document.querySelector.bind(docRuntime);
           let findAll = win.document.querySelectorAll.bind(docRuntime);
 
           let simulatorList = find("#runtime-panel-simulator");
           let simulatorPanel = win.document.querySelector("#deck-panel-simulator");
 
           // Hack SimulatorProcesses to spy on simulation parameters.
 
-          let runPromise;
-          function fakeRun() {
-            runPromise.resolve({
+          let resolver;
+	  function fakeRun() {
+            resolver({
               path: this.b2gBinary.path,
               args: this.args
             });
             // Don't actually try to connect to the fake simulator.
             throw new Error("Aborting on purpose before connection.");
           }
 
           AddonSimulatorProcess.prototype.run = fakeRun;
           OldAddonSimulatorProcess.prototype.run = fakeRun;
           CustomSimulatorProcess.prototype.run = fakeRun;
 
           function runSimulator(i) {
-            runPromise = promise.defer();
-            findAll(".runtime-panel-item-simulator")[i].click();
-            return runPromise.promise;
+            return new Promise(resolve => {
+              resolver = resolve;
+              findAll(".runtime-panel-item-simulator")[i].click();
+            });
           }
 
           // Install fake "Firefox OS 1.0" simulator addon.
 
           let addons = yield GetAvailableAddons();
 
           let sim10 = addons.simulators.filter(a => a.version == "1.0")[0];
 
--- a/devtools/client/webide/test/test_toolbox.html
+++ b/devtools/client/webide/test/test_toolbox.html
@@ -37,20 +37,21 @@
           }
 
           win = yield openWebIDE();
           let docRuntime = getRuntimeDocument(win);
           let docProject = getProjectDocument(win);
 
           win.AppManager.update("runtime-list");
 
-          let deferred = promise.defer();
-          win.AppManager.connection.once(
-              win.Connection.Events.CONNECTED,
-              () => deferred.resolve());
+          let deferred = new Promise(resolve => {
+             win.AppManager.connection.once(
+                 win.Connection.Events.CONNECTED,
+                 resolve);
+          });
 
           docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
 
           ok(win.document.querySelector("window").className, "busy", "UI is busy");
           yield win.UI._busyPromise;
 
           is(Object.keys(DebuggerServer._connections).length, 1, "Connected");