Merge m-c to inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 26 Jan 2015 16:51:05 -0500
changeset 239207 c1cb74f492e16bf002bda6196b70fc334d087d8e
parent 239206 47834f1829b9e662995afaf331cc79a3cb6c6cda (current diff)
parent 239185 38e4719e71af140cb95f04f7165d43a34c35a30d (diff)
child 239208 67496f44f4617eda8f650d5c801fd9b327e5ac96
push id489
push usermcmanus@ducksong.com
push dateTue, 27 Jan 2015 01:44:53 +0000
reviewersmerge
milestone38.0a1
Merge m-c to inbound. a=merge
dom/icc/tests/IccInfo.cpp
dom/icc/tests/marionette/icc_header.js
dom/icc/tests/marionette/stk_helper.js
dom/icc/tests/marionette/test_stk_proactive_command.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1087,8 +1087,12 @@ pref("dom.mozSettings.SettingsService.ve
 
 // Controlling whether we want to allow forcing some Settings
 // IndexedDB transactions to be opened as readonly or keep everything as
 // readwrite.
 pref("dom.mozSettings.allowForceReadOnly", false);
 
 // RequestSync API is enabled by default on B2G.
 pref("dom.requestSync.enabled", true);
+
+// Enable hardware vsync compositor
+pref("gfx.vsync.hw-vsync.enabled", true);
+pref("gfx.vsync.compositor", true);
--- a/b2g/chrome/content/devtools/debugger.js
+++ b/b2g/chrome/content/devtools/debugger.js
@@ -36,17 +36,20 @@ let RemoteDebugger = {
     shell.sendChromeEvent({
       "type": "remote-debugger-prompt"
     });
 
     while(!this._promptDone) {
       Services.tm.currentThread.processNextEvent(true);
     }
 
-    return this._promptAnswer;
+    if (this._promptAnswer) {
+      return DebuggerServer.AuthenticationResult.ALLOW;
+    }
+    return DebuggerServer.AuthenticationResult.DENY;
   },
 
   _listen: function() {
     if (this._listening) {
       return;
     }
 
     this.handleEvent = this.handleEvent.bind(this);
@@ -136,19 +139,22 @@ let USBRemoteDebugger = {
     RemoteDebugger.initServer();
 
     let portOrPath =
       Services.prefs.getCharPref("devtools.debugger.unix-domain-socket") ||
       "/data/local/debugger-socket";
 
     try {
       debug("Starting USB debugger on " + portOrPath);
+      let AuthenticatorType = DebuggerServer.Authenticators.get("PROMPT");
+      let authenticator = new AuthenticatorType.Server();
+      authenticator.allowConnection = RemoteDebugger.prompt;
       this._listener = DebuggerServer.createListener();
       this._listener.portOrPath = portOrPath;
-      this._listener.allowConnection = RemoteDebugger.prompt;
+      this._listener.authenticator = authenticator;
       this._listener.open();
       // Temporary event, until bug 942756 lands and offers a way to know
       // when the server is up and running.
       Services.obs.notifyObservers(null, "debugger-server-started", null);
     } catch (e) {
       debug("Unable to start USB debugger server: " + e);
     }
   },
@@ -174,19 +180,22 @@ let WiFiRemoteDebugger = {
     if (this._listener) {
       return;
     }
 
     RemoteDebugger.initServer();
 
     try {
       debug("Starting WiFi debugger");
+      let AuthenticatorType = DebuggerServer.Authenticators.get("OOB_CERT");
+      let authenticator = new AuthenticatorType.Server();
+      authenticator.allowConnection = RemoteDebugger.prompt;
       this._listener = DebuggerServer.createListener();
       this._listener.portOrPath = -1 /* any available port */;
-      this._listener.allowConnection = RemoteDebugger.prompt;
+      this._listener.authenticator = authenticator;
       this._listener.discoverable = true;
       this._listener.encryption = true;
       this._listener.open();
       let port = this._listener.port;
       debug("Started WiFi debugger on " + port);
     } catch (e) {
       debug("Unable to start WiFi debugger server: " + e);
     }
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="05baa465f008e92cdf4db74d62f1e3885e3ee73d"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="05baa465f008e92cdf4db74d62f1e3885e3ee73d"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="05baa465f008e92cdf4db74d62f1e3885e3ee73d"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
@@ -130,12 +130,12 @@
   <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="libnfcemu" path="external/libnfcemu" remote="b2g" revision="125ccf9bd5986c7728ea44508b3e1d1185ac028b"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c5f8d282efe4a4e8b1e31a37300944e338e60e4f"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="0c557e136bb615923aad0f5c69da4e869523efc5"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="13374490fc0c989347448f0b2d6b220adff5e630"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
   <project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
 </manifest>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="05baa465f008e92cdf4db74d62f1e3885e3ee73d"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="05baa465f008e92cdf4db74d62f1e3885e3ee73d"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="05baa465f008e92cdf4db74d62f1e3885e3ee73d"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
@@ -141,13 +141,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="2a1ded216a91bf62a72b1640cf01ab4998f37028"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="a74adcf8d88320d936daa8d20ce88ca0107fb916"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="9883ea57b0668d8f60dba025d4522dfa69a1fbfa"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="a558dc844bf5144fc38603fd8f4df8d9557052a5"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="57ee1320ed7b4a1a1274d8f3f6c177cd6b9becb2"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="12b1977cc704b35f2e9db2bb423fa405348bc2f3"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="985bf15264d865fe7b9c5b45f61c451cbaafa43d"/>
   <project name="platform/system/core" path="system/core" revision="350eac5403124dacb2a5fd9e28ac290a59fc3b8e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="0c557e136bb615923aad0f5c69da4e869523efc5"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="13374490fc0c989347448f0b2d6b220adff5e630"/>
   <project name="platform/system/qcom" path="system/qcom" revision="63e3f6f176caad587d42bba4c16b66d953fb23c2"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="d8952a42771045fca73ec600e2b42a4c7129d723"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4c187c1f3a0dffd8e51a961735474ea703535b99"/>
 </manifest>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="05baa465f008e92cdf4db74d62f1e3885e3ee73d"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
@@ -140,13 +140,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="5e110615212302c5d798a3c223dcee458817651c"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="fa9ffd47948eb24466de227e48fe9c4a7c5e7711"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="cd76b19aafd4229ccf83853d02faef8c51ca8b34"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
   <project name="platform/system/core" path="system/core" revision="adc485d8755af6a61641d197de7cfef667722580"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="0c557e136bb615923aad0f5c69da4e869523efc5"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="13374490fc0c989347448f0b2d6b220adff5e630"/>
   <project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="ce18b47b4a4f93a581d672bbd5cb6d12fe796ca9"/>
 </manifest>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "793773bb2944b42a85dd160049e605cbd880c4da", 
+        "git_revision": "b02ec9713e6de8d96c6954d2c0dfd0442b0656ac", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "23aac85cce8d5d0435b7d5639e4ff6410c2dd121", 
+    "revision": "bdc67bb5e9be1469a96158d657a1829373c4152a", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,21 +12,21 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="05baa465f008e92cdf4db74d62f1e3885e3ee73d"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="05baa465f008e92cdf4db74d62f1e3885e3ee73d"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
@@ -125,17 +125,17 @@
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
   <!-- Nexus 4 specific things -->
   <project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="0c557e136bb615923aad0f5c69da4e869523efc5"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="13374490fc0c989347448f0b2d6b220adff5e630"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
   <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/>
   <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="793773bb2944b42a85dd160049e605cbd880c4da"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b02ec9713e6de8d96c6954d2c0dfd0442b0656ac"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="05baa465f008e92cdf4db74d62f1e3885e3ee73d"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/browser/base/content/browser-gestureSupport.js
+++ b/browser/base/content/browser-gestureSupport.js
@@ -1,14 +1,12 @@
 # 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/.
 
-Cu.import("resource://gre/modules/TelemetryStopwatch.jsm", this);
-
 // Simple gestures support
 //
 // As per bug #412486, web content must not be allowed to receive any
 // simple gesture events.  Multi-touch gesture APIs are in their
 // infancy and we do NOT want to be forced into supporting an API that
 // will probably have to change in the future.  (The current Mac OS X
 // API is undocumented and was reverse-engineered.)  Until support is
 // implemented in the event dispatcher to keep these events as
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -1187,16 +1187,20 @@ toolbarpaletteitem[place="palette"][hidd
 
 #customization-palette .toolbarpaletteitem-box {
   -moz-box-pack: center;
   -moz-box-flex: 1;
   width: 10em;
   max-width: 10em;
 }
 
+#main-window[customizing=true] #PanelUI-update-status {
+  display: none;
+}
+
 /* UI Tour */
 
 @keyframes uitour-wobble {
   from {
     transform: rotate(0deg) translateX(3px) rotate(0deg);
   }
   50% {
     transform: rotate(360deg) translateX(3px) rotate(-360deg);
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1267,17 +1267,17 @@
           let installCallback = {
             onSuccess: function(engine) {
               event.target.hidePopup();
               BrowserSearch.searchBar.openSuggestionsPanel();
             }
           }
           Services.search.addEngine(target.getAttribute("uri"),
                                     Ci.nsISearchEngine.DATA_XML,
-                                    target.getAttribute("src"), false,
+                                    target.getAttribute("image"), false,
                                     installCallback);
         }
       ]]></handler>
 
       <handler event="popuphiding"><![CDATA[
         this._isHiding = true;
         setTimeout(() => {
           this._isHiding = false;
--- a/browser/components/loop/README.txt
+++ b/browser/components/loop/README.txt
@@ -7,40 +7,16 @@ modern browser that supports WebRTC.
 
 The standalone client is a set of web pages intended to be hosted on a
 standalone server referenced by the loop-server.
 
 The standalone client exists in standalone/ but shares items
 (from content/shared/) with the desktop implementation. See the README.md
 file in the standalone/ directory for how to run the server locally.
 
-
-Hacking
-=======
-Please be sure to execute
-
-  browser/components/loop/run-all-loop-tests.sh
-
-from the top level before requesting review on a patch.
-
-
-Functional Tests
-================
-These are currently a work in progress, but it's already possible to run a test
-if you have a [loop-server](https://github.com/mozilla-services/loop-server)
-install that is properly configured.  From the top-level gecko directory,
-execute:
-
-  export LOOP_SERVER=/Users/larry/src/loop-server
-  ./mach marionette-test browser/components/loop/test/functional/manifest.ini
-
-Once the automation is complete, we'll include this in run-all-loop-tests.sh
-as well.
-
-
 Working with React JSX files
 ============================
 
 Our views use [React](http://facebook.github.io/react/) written in JSX files
 and transpiled to JS before we commit. You need to install the JSX compiler
 using npm in order to compile the .jsx files into regular .js ones:
 
     npm install -g react-tools
@@ -49,8 +25,53 @@ Once installed, run build-jsx with the -
 browser/components/loop, eg.:
 
     cd browser/components/loop
     ./build-jsx --watch
 
 build-jsx can also be do a one-time compile pass instead of watching if
 the --watch argument is omitted.  Be sure to commit any transpiled files
 at the same time as changes to their sources.
+
+
+Hacking
+=======
+Please be sure to execute
+
+  browser/components/loop/run-all-loop-tests.sh
+
+from the top level before requesting review on a patch.
+
+
+Front-End Unit Tests
+====================
+The unit tests for Loop reside in three directories:
+
+- test/desktop-local
+- test/shared
+- test/standalone
+
+You can run these as part of the run-all-loop-tests.sh command above, or you can run these individually in Firefox. To run them individually, start the standalone client (see standalone/README.md) and load:
+
+  http://localhost:3000/test/
+
+
+Functional Tests
+================
+These are currently a work in progress, but it's already possible to run a test
+if you have a [loop-server](https://github.com/mozilla-services/loop-server)
+install that is properly configured.  From the top-level gecko directory,
+execute:
+
+  export LOOP_SERVER=/Users/larry/src/loop-server
+  ./mach marionette-test browser/components/loop/test/functional/manifest.ini
+
+Once the automation is complete, we'll include this in run-all-loop-tests.sh
+as well.
+
+
+UI-Showcase
+===========
+This is a tool giving the layouts for all the frontend views of Loop, allowing debugging and testing of css layouts and local component behavior.
+
+To access it, start the standalone client (see standalone/README.md) and load:
+
+  http://localhost:3000/ui/
--- a/browser/components/preferences/in-content/search.xul
+++ b/browser/components/preferences/in-content/search.xul
@@ -40,19 +40,20 @@
     <groupbox id="oneClickSearchProvidersGroup" data-category="paneSearch">
       <caption label="&oneClickSearchEngines.label;"/>
       <label>&chooseWhichOneToDisplay.label;</label>
 
       <tree id="engineList" flex="1" rows="8" hidecolumnpicker="true" editable="true"
             seltype="single">
         <treechildren id="engineChildren" flex="1"/>
         <treecols>
-          <treecol id="engineShown" type="checkbox" editable="true"/>
-          <treecol id="engineName" flex="4" label="&engineNameColumn.label;"/>
-          <treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"/>
+          <treecol id="engineShown" type="checkbox" editable="true" sortable="false"/>
+          <treecol id="engineName" flex="4" label="&engineNameColumn.label;" sortable="false"/>
+          <treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"
+                   sortable="false"/>
         </treecols>
       </tree>
 
       <hbox>
         <button id="restoreDefaultSearchEngines"
                 label="&restoreDefaultSearchEngines.label;"
                 accesskey="&restoreDefaultSearchEngines.accesskey;"
                 />
--- a/browser/components/preferences/search.xul
+++ b/browser/components/preferences/search.xul
@@ -54,19 +54,21 @@
       <label>&chooseWhichOneToDisplay.label;</label>
 
       <tree id="engineList" flex="1" rows="8" hidecolumnpicker="true" editable="true"
             seltype="single" onselect="gSearchPane.onTreeSelect();"
             onkeypress="gSearchPane.onTreeKeyPress(event);">
         <treechildren id="engineChildren" flex="1"
                       ondragstart="onDragEngineStart(event);"/>
         <treecols>
-          <treecol id="engineShown" type="checkbox" style="min-width: 26px;" editable="true"/>
-          <treecol id="engineName" flex="4" label="&engineNameColumn.label;"/>
-          <treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"/>
+          <treecol id="engineShown" type="checkbox" style="min-width: 26px;" editable="true"
+                   sortable="false"/>
+          <treecol id="engineName" flex="4" label="&engineNameColumn.label;" sortable="false"/>
+          <treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"
+                   sortable="false"/>
         </treecols>
       </tree>
 
       <hbox>
         <button id="restoreDefaultSearchEngines"
                 label="&restoreDefaultSearchEngines.label;"
                 accesskey="&restoreDefaultSearchEngines.accesskey;"
                 oncommand="gSearchPane.onRestoreDefaults();"/>
--- a/browser/devtools/shared/test/browser.ini
+++ b/browser/devtools/shared/test/browser.ini
@@ -1,10 +1,9 @@
 [DEFAULT]
-skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
 subsuite = devtools
 support-files =
   browser_layoutHelpers.html
   browser_layoutHelpers-getBoxQuads.html
   browser_layoutHelpers_iframe.html
   browser_templater_basic.html
   browser_toolbar_basic.html
   browser_toolbar_webconsole_errors_count.html
@@ -45,31 +44,37 @@ support-files =
 [browser_graphs-10b.js]
 [browser_graphs-11a.js]
 [browser_graphs-11b.js]
 [browser_graphs-12.js]
 [browser_graphs-13.js]
 [browser_graphs-14.js]
 [browser_inplace-editor.js]
 [browser_layoutHelpers.js]
+skip-if = e10s # Layouthelpers test should not run in a content page.
 [browser_layoutHelpers-getBoxQuads.js]
+skip-if = e10s # Layouthelpers test should not run in a content page.
 [browser_num-l10n.js]
 [browser_observableobject.js]
+[browser_options-view-01.js]
 [browser_outputparser.js]
+skip-if = e10s # Test intermittently fails with e10s. Bug 1124162.
 [browser_prefs.js]
 [browser_require_basic.js]
 [browser_spectrum.js]
 [browser_theme.js]
 [browser_tableWidget_basic.js]
 [browser_tableWidget_keyboard_interaction.js]
 [browser_tableWidget_mouse_interaction.js]
 skip-if = buildapp == 'mulet'
 [browser_telemetry_button_eyedropper.js]
 [browser_telemetry_button_paintflashing.js]
+skip-if = e10s # Bug 937167 - e10s paintflashing
 [browser_telemetry_button_responsive.js]
+skip-if = e10s # Bug 1067145 - e10s responsiveview
 [browser_telemetry_button_scratchpad.js]
 [browser_telemetry_button_tilt.js]
 skip-if = e10s # Bug 1086492 - Disable tilt for e10s
                # Bug 937166 - Make tilt work in E10S mode
 [browser_telemetry_sidebar.js]
 [browser_telemetry_toolbox.js]
 [browser_telemetry_toolboxtabs_canvasdebugger.js]
 [browser_telemetry_toolboxtabs_inspector.js]
@@ -81,13 +86,12 @@ skip-if = e10s # Bug 1086492 - Disable t
 [browser_telemetry_toolboxtabs_storage.js]
 [browser_telemetry_toolboxtabs_styleeditor.js]
 [browser_telemetry_toolboxtabs_webaudioeditor.js]
 [browser_telemetry_toolboxtabs_webconsole.js]
 [browser_templater_basic.js]
 [browser_toolbar_basic.js]
 [browser_toolbar_tooltip.js]
 [browser_toolbar_webconsole_errors_count.js]
-skip-if = buildapp == 'mulet'
+skip-if = buildapp == 'mulet' || e10s # The developertoolbar error count isn't correct with e10s
 [browser_treeWidget_basic.js]
 [browser_treeWidget_keyboard_interaction.js]
 [browser_treeWidget_mouse_interaction.js]
-[browser_options-view-01.js]
--- a/browser/devtools/shared/test/browser_css_color.js
+++ b/browser/devtools/shared/test/browser_css_color.js
@@ -1,90 +1,78 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const COLOR_UNIT_PREF = "devtools.defaultColorUnit";
-
+const TEST_URI = "data:text/html;charset=utf-8,browser_css_color.js";
+let {colorUtils} = devtools.require("devtools/css-color");
 let origColorUnit;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-let {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
-let {colorUtils} = devtools.require("devtools/css-color");
 
-function test() {
-  waitForExplicitFinish();
+add_task(function*() {
+  yield promiseTab("about:blank");
+  let [host, win, doc] = yield createHost("bottom", TEST_URI);
+  origColorUnit = Services.prefs.getCharPref(COLOR_UNIT_PREF);
 
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function onload() {
-    gBrowser.selectedBrowser.removeEventListener("load", onload, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = "data:text/html;charset=utf-8,browser_css_color.js";
-}
+  info("Creating a test canvas element to test colors");
+  let canvas = createTestCanvas(doc);
+  info("Starting the test");
+  testColorUtils(canvas);
 
-function init() {
-  origColorUnit = Services.prefs.getCharPref(COLOR_UNIT_PREF);
-  createDocument();
-}
+  host.destroy();
+  gBrowser.removeCurrentTab();
+});
 
-function createDocument()
-{
-  let doc = content.document;
-
+function createTestCanvas(doc) {
   let canvas = doc.createElement("canvas");
   canvas.width = canvas.height = 10;
   doc.body.appendChild(canvas);
-
-  testColorUtils();
+  return canvas;
 }
 
-function testColorUtils() {
+function testColorUtils(canvas) {
   let data = getTestData();
 
   for (let {authored, name, hex, hsl, rgb} of data) {
     let color = new colorUtils.CssColor(authored);
 
     // Check all values.
     info("Checking values for " + authored);
     is(color.name, name, "color.name === name");
     is(color.hex, hex, "color.hex === hex");
     is(color.hsl, hsl, "color.hsl === hsl");
     is(color.rgb, rgb, "color.rgb === rgb");
 
     testToString(color, name, hex, hsl, rgb);
-    testColorMatch(name, hex, hsl, rgb, color.rgba);
+    testColorMatch(name, hex, hsl, rgb, color.rgba, canvas);
   }
+
   testProcessCSSString();
   testSetAlpha();
-  finishUp();
 }
 
 function testToString(color, name, hex, hsl, rgb) {
   switchColorUnit(colorUtils.CssColor.COLORUNIT.name);
   is(color.toString(), name, "toString() with authored type");
 
   switchColorUnit(colorUtils.CssColor.COLORUNIT.hex);
   is(color.toString(), hex, "toString() with hex type");
 
   switchColorUnit(colorUtils.CssColor.COLORUNIT.hsl);
   is(color.toString(), hsl, "toString() with hsl type");
 
   switchColorUnit(colorUtils.CssColor.COLORUNIT.rgb);
   is(color.toString(), rgb, "toString() with rgb type");
-
 }
 
 function switchColorUnit(unit) {
   Services.prefs.setCharPref(COLOR_UNIT_PREF, unit);
 }
 
-function testColorMatch(name, hex, hsl, rgb, rgba) {
+function testColorMatch(name, hex, hsl, rgb, rgba, canvas) {
   let target;
-
-  let canvas = content.document.querySelector("canvas");
   let ctx = canvas.getContext("2d");
 
   let clearCanvas = function() {
     canvas.width = 1;
   };
   let setColor = function(aColor) {
     ctx.fillStyle = aColor;
     ctx.fillRect(0, 0, 1, 1);
@@ -157,22 +145,16 @@ function testSetAlpha() {
     ok(false, "Should fail when passing in an invalid color.");
   } catch (e) {
     ok(true, "Fails when setAlpha receives an invalid color.");
   }
 
   is(colorUtils.setAlpha("#fff"), "rgba(255, 255, 255, 1)", "sets alpha to 1 if invalid.");
 }
 
-function finishUp() {
-  Services = colorUtils = Loader = null;
-  gBrowser.removeCurrentTab();
-  finish();
-}
-
 function getTestData() {
   return [
     {authored: "aliceblue", name: "aliceblue", hex: "#F0F8FF", hsl: "hsl(208, 100%, 97%)", rgb: "rgb(240, 248, 255)"},
     {authored: "antiquewhite", name: "antiquewhite", hex: "#FAEBD7", hsl: "hsl(34, 78%, 91%)", rgb: "rgb(250, 235, 215)"},
     {authored: "aqua", name: "aqua", hex: "#0FF", hsl: "hsl(180, 100%, 50%)", rgb: "rgb(0, 255, 255)"},
     {authored: "aquamarine", name: "aquamarine", hex: "#7FFFD4", hsl: "hsl(160, 100%, 75%)", rgb: "rgb(127, 255, 212)"},
     {authored: "azure", name: "azure", hex: "#F0FFFF", hsl: "hsl(180, 100%, 97%)", rgb: "rgb(240, 255, 255)"},
     {authored: "beige", name: "beige", hex: "#F5F5DC", hsl: "hsl(60, 56%, 91%)", rgb: "rgb(245, 245, 220)"},
--- a/browser/devtools/shared/test/browser_cubic-bezier-01.js
+++ b/browser/devtools/shared/test/browser_cubic-bezier-01.js
@@ -4,21 +4,22 @@
 
 "use strict";
 
 // Tests that the CubicBezierWidget generates content in a given parent node
 
 const TEST_URI = "chrome://browser/content/devtools/cubic-bezier-frame.xhtml";
 const {CubicBezierWidget} = devtools.require("devtools/shared/widgets/CubicBezierWidget");
 
-let test = Task.async(function*() {
-  yield promiseTab(TEST_URI);
+add_task(function*() {
+  yield promiseTab("about:blank");
+  let [host, win, doc] = yield createHost("bottom", TEST_URI);
 
   info("Checking that the markup is created in the parent");
-  let container = content.document.querySelector("#container");
+  let container = doc.querySelector("#container");
   let w = new CubicBezierWidget(container);
 
   ok(container.querySelector(".coordinate-plane"),
     "The coordinate plane has been added");
   let buttons = container.querySelectorAll("button");
   is(buttons.length, 2,
     "The 2 control points have been added");
   is(buttons[0].className, "control-point");
@@ -26,11 +27,11 @@ let test = Task.async(function*() {
   is(buttons[1].className, "control-point");
   is(buttons[1].id, "P2");
   ok(container.querySelector("canvas"), "The curve canvas has been added");
 
   info("Destroying the widget");
   w.destroy();
   is(container.children.length, 0, "All nodes have been removed");
 
+  host.destroy();
   gBrowser.removeCurrentTab();
-  finish();
 });
--- a/browser/devtools/shared/test/browser_cubic-bezier-02.js
+++ b/browser/devtools/shared/test/browser_cubic-bezier-02.js
@@ -5,66 +5,63 @@
 "use strict";
 
 // Tests the CubicBezierWidget events
 
 const TEST_URI = "chrome://browser/content/devtools/cubic-bezier-frame.xhtml";
 const {CubicBezierWidget, PREDEFINED} =
   devtools.require("devtools/shared/widgets/CubicBezierWidget");
 
-let test = Task.async(function*() {
-  yield promiseTab(TEST_URI);
+add_task(function*() {
+  yield promiseTab("about:blank");
+  let [host, win, doc] = yield createHost("bottom", TEST_URI);
 
-  let container = content.document.querySelector("#container");
+  let container = doc.querySelector("#container");
   let w = new CubicBezierWidget(container, PREDEFINED.linear);
 
-  yield pointsCanBeDragged(w);
-  yield curveCanBeClicked(w);
-  yield pointsCanBeMovedWithKeyboard(w);
+  yield pointsCanBeDragged(w, win, doc);
+  yield curveCanBeClicked(w, win, doc);
+  yield pointsCanBeMovedWithKeyboard(w, win, doc);
 
   w.destroy();
+  host.destroy();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
-function* pointsCanBeDragged(widget) {
+function* pointsCanBeDragged(widget, win, doc) {
   info("Checking that the control points can be dragged with the mouse");
 
   info("Listening for the update event");
   let onUpdated = widget.once("updated");
 
   info("Generating a mousedown/move/up on P1");
   widget._onPointMouseDown({target: widget.p1});
-  EventUtils.synthesizeMouse(content.document.documentElement, 0, 100,
-    {type: "mousemove"}, content.window);
-  EventUtils.synthesizeMouse(content.document.documentElement, 0, 100,
-    {type: "mouseup"}, content.window);
+  doc.onmousemove({pageX: 0, pageY: 100});
+  doc.onmouseup();
 
   let bezier = yield onUpdated;
   ok(true, "The widget fired the updated event");
   ok(bezier, "The updated event contains a bezier argument");
   is(bezier.P1[0], 0, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 1, "The new P1 progress coordinate is correct");
 
   info("Listening for the update event");
   onUpdated = widget.once("updated");
 
   info("Generating a mousedown/move/up on P2");
   widget._onPointMouseDown({target: widget.p2});
-  EventUtils.synthesizeMouse(content.document.documentElement, 200, 300,
-    {type: "mousemove"}, content.window);
-  EventUtils.synthesizeMouse(content.document.documentElement, 200, 300,
-    {type: "mouseup"}, content.window);
+  doc.onmousemove({pageX: 200, pageY: 300});
+  doc.onmouseup();
 
   bezier = yield onUpdated;
   is(bezier.P2[0], 1, "The new P2 time coordinate is correct");
   is(bezier.P2[1], 0, "The new P2 progress coordinate is correct");
 }
 
-function* curveCanBeClicked(widget) {
+function* curveCanBeClicked(widget, win, doc) {
   info("Checking that clicking on the curve moves the closest control point");
 
   info("Listening for the update event");
   let onUpdated = widget.once("updated");
 
   info("Click close to P1");
   widget._onCurveClick({pageX: 50, pageY: 150});
 
@@ -83,17 +80,17 @@ function* curveCanBeClicked(widget) {
 
   bezier = yield onUpdated;
   is(bezier.P2[0], 0.75, "The new P2 time coordinate is correct");
   is(bezier.P2[1], 0.25, "The new P2 progress coordinate is correct");
   is(bezier.P1[0], 0.25, "P1 time coordinate remained unchanged");
   is(bezier.P1[1], 0.75, "P1 progress coordinate remained unchanged");
 }
 
-function* pointsCanBeMovedWithKeyboard(widget) {
+function* pointsCanBeMovedWithKeyboard(widget, win, doc) {
   info("Checking that points respond to keyboard events");
 
   info("Moving P1 to the left");
   let onUpdated = widget.once("updated");
   widget._onPointKeyDown(getKeyEvent(widget.p1, 37));
   let bezier = yield onUpdated;
   is(bezier.P1[0], 0.235, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 0.75, "The new P1 progress coordinate is correct");
--- a/browser/devtools/shared/test/browser_cubic-bezier-03.js
+++ b/browser/devtools/shared/test/browser_cubic-bezier-03.js
@@ -5,28 +5,29 @@
 "use strict";
 
 // Tests that coordinates can be changed programatically in the CubicBezierWidget
 
 const TEST_URI = "chrome://browser/content/devtools/cubic-bezier-frame.xhtml";
 const {CubicBezierWidget, PREDEFINED} =
   devtools.require("devtools/shared/widgets/CubicBezierWidget");
 
-let test = Task.async(function*() {
-  yield promiseTab(TEST_URI);
+add_task(function*() {
+  yield promiseTab("about:blank");
+  let [host, win, doc] = yield createHost("bottom", TEST_URI);
 
-  let container = content.document.querySelector("#container");
+  let container = doc.querySelector("#container");
   let w = new CubicBezierWidget(container, PREDEFINED.linear);
 
   yield coordinatesCanBeChangedByProvidingAnArray(w);
   yield coordinatesCanBeChangedByProvidingAValue(w);
 
   w.destroy();
+  host.destroy();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* coordinatesCanBeChangedByProvidingAnArray(widget) {
   info("Listening for the update event");
   let onUpdated = widget.once("updated");
 
   info("Setting new coordinates");
   widget.coordinates = [0,1,1,0];
--- a/browser/devtools/shared/test/browser_flame-graph-01.js
+++ b/browser/devtools/shared/test/browser_flame-graph-01.js
@@ -1,23 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that flame graph widget works properly.
 
 let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
 
   let graph = new FlameGraph(doc.body);
 
--- a/browser/devtools/shared/test/browser_flame-graph-02.js
+++ b/browser/devtools/shared/test/browser_flame-graph-02.js
@@ -1,23 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that flame graph widgets may have a fixed width or height.
 
 let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
 
   let graph = new FlameGraph(doc.body);
   graph.fixedWidth = 200;
--- a/browser/devtools/shared/test/browser_flame-graph-03a.js
+++ b/browser/devtools/shared/test/browser_flame-graph-03a.js
@@ -4,25 +4,22 @@
 // Tests that selections in the flame graph widget work properly.
 
 let TEST_DATA = [{ color: "#f00", blocks: [{ x: 0, y: 0, width: 50, height: 20, text: "FOO" }, { x: 50, y: 0, width: 100, height: 20, text: "BAR" }] }, { color: "#00f", blocks: [{ x: 0, y: 30, width: 30, height: 20, text: "BAZ" }] }];
 let TEST_BOUNDS = { startTime: 0, endTime: 150 };
 let TEST_WIDTH = 200;
 let TEST_HEIGHT = 100;
 
 let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
 
   let graph = new FlameGraph(doc.body, 1);
   graph.fixedWidth = TEST_WIDTH;
--- a/browser/devtools/shared/test/browser_flame-graph-03b.js
+++ b/browser/devtools/shared/test/browser_flame-graph-03b.js
@@ -5,25 +5,22 @@
 
 let TEST_DATA = [{ color: "#f00", blocks: [{ x: 0, y: 0, width: 50, height: 20, text: "FOO" }, { x: 50, y: 0, width: 100, height: 20, text: "BAR" }] }, { color: "#00f", blocks: [{ x: 0, y: 30, width: 30, height: 20, text: "BAZ" }] }];
 let TEST_BOUNDS = { startTime: 0, endTime: 150 };
 let TEST_WIDTH = 200;
 let TEST_HEIGHT = 100;
 let TEST_DPI_DENSITIY = 2;
 
 let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
 
   let graph = new FlameGraph(doc.body, TEST_DPI_DENSITIY);
   graph.fixedWidth = TEST_WIDTH;
--- a/browser/devtools/shared/test/browser_flame-graph-04.js
+++ b/browser/devtools/shared/test/browser_flame-graph-04.js
@@ -3,27 +3,24 @@
 
 // Tests that text metrics in the flame graph widget work properly.
 
 let HTML_NS = "http://www.w3.org/1999/xhtml";
 let FLAME_GRAPH_BLOCK_TEXT_FONT_SIZE = 8; // px
 let FLAME_GRAPH_BLOCK_TEXT_FONT_FAMILY = "sans-serif";
 let {ViewHelpers} = Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {});
 let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
 let L10N = new ViewHelpers.L10N();
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new FlameGraph(doc.body, 1);
   yield graph.ready();
 
   testGraph(graph);
--- a/browser/devtools/shared/test/browser_flame-graph-utils-01.js
+++ b/browser/devtools/shared/test/browser_flame-graph-utils-01.js
@@ -1,21 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that text metrics and data conversion from profiler samples
 // widget work properly in the flame graph.
 
 let {FlameGraphUtils} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {});
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let out = FlameGraphUtils.createFlameGraphDataFromSamples(TEST_DATA);
 
   ok(out, "Some data was outputted properly");
   is(out.length, 10, "The outputted length is correct.");
 
--- a/browser/devtools/shared/test/browser_flame-graph-utils-02.js
+++ b/browser/devtools/shared/test/browser_flame-graph-utils-02.js
@@ -1,20 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests consecutive duplicate frames are removed from the flame graph data.
 
 let {FlameGraphUtils} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {});
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let out = FlameGraphUtils.createFlameGraphDataFromSamples(TEST_DATA, {
     flattenRecursion: true
   });
 
   ok(out, "Some data was outputted properly");
--- a/browser/devtools/shared/test/browser_flame-graph-utils-03.js
+++ b/browser/devtools/shared/test/browser_flame-graph-utils-03.js
@@ -1,21 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if platform frames are removed from the flame graph data.
 
 let {FlameGraphUtils} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {});
 let {FrameNode} = devtools.require("devtools/profiler/tree-model");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let out = FlameGraphUtils.createFlameGraphDataFromSamples(TEST_DATA, {
     filterFrames: FrameNode.isContent
   });
 
   ok(out, "Some data was outputted properly");
--- a/browser/devtools/shared/test/browser_flame-graph-utils-04.js
+++ b/browser/devtools/shared/test/browser_flame-graph-utils-04.js
@@ -1,21 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if (idle) nodes are added when necessary in the flame graph data.
 
 let {FlameGraphUtils} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {});
 let {FrameNode} = devtools.require("devtools/profiler/tree-model");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let out = FlameGraphUtils.createFlameGraphDataFromSamples(TEST_DATA, {
     flattenRecursion: true,
     filterFrames: FrameNode.isContent,
     showIdleBlocks: "\m/"
   });
--- a/browser/devtools/shared/test/browser_graphs-01.js
+++ b/browser/devtools/shared/test/browser_graphs-01.js
@@ -1,19 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets works properly.
 
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
   finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
--- a/browser/devtools/shared/test/browser_graphs-02.js
+++ b/browser/devtools/shared/test/browser_graphs-02.js
@@ -1,25 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets can properly add data, regions and highlights.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
   yield graph.once("ready");
 
   testDataAndRegions(graph);
--- a/browser/devtools/shared/test/browser_graphs-03.js
+++ b/browser/devtools/shared/test/browser_graphs-03.js
@@ -1,24 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets can handle clients getting/setting the
 // selection or cursor.
 
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
   yield graph.once("ready");
 
   yield testSelection(graph);
--- a/browser/devtools/shared/test/browser_graphs-04.js
+++ b/browser/devtools/shared/test/browser_graphs-04.js
@@ -1,23 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets can correctly compare selections and cursors.
 
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
   yield graph.once("ready");
 
   testGraph(graph);
--- a/browser/devtools/shared/test/browser_graphs-05.js
+++ b/browser/devtools/shared/test/browser_graphs-05.js
@@ -1,25 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets can correctly determine which regions are hovered.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
   yield graph.once("ready");
 
   testGraph(graph);
--- a/browser/devtools/shared/test/browser_graphs-06.js
+++ b/browser/devtools/shared/test/browser_graphs-06.js
@@ -1,25 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if clicking on regions adds a selection spanning that region.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
   yield graph.once("ready");
 
   testGraph(graph);
--- a/browser/devtools/shared/test/browser_graphs-07a.js
+++ b/browser/devtools/shared/test/browser_graphs-07a.js
@@ -1,24 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if selecting, resizing, moving selections and zooming in/out works.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
   yield graph.once("ready");
 
   testGraph(graph);
--- a/browser/devtools/shared/test/browser_graphs-07b.js
+++ b/browser/devtools/shared/test/browser_graphs-07b.js
@@ -1,24 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if selections can't be added via clicking, while not allowed.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
   yield graph.once("ready");
 
   testGraph(graph);
--- a/browser/devtools/shared/test/browser_graphs-08.js
+++ b/browser/devtools/shared/test/browser_graphs-08.js
@@ -1,24 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if a selection is dropped when clicking outside of it.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
   yield graph.once("ready");
 
   testGraph(graph);
--- a/browser/devtools/shared/test/browser_graphs-09a.js
+++ b/browser/devtools/shared/test/browser_graphs-09a.js
@@ -1,24 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that line graphs properly create the gutter and tooltips.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, { metric: "fps" });
 
   yield testGraph(graph);
 
--- a/browser/devtools/shared/test/browser_graphs-09b.js
+++ b/browser/devtools/shared/test/browser_graphs-09b.js
@@ -1,24 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that line graphs properly use the tooltips configuration properties.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
   graph.withTooltipArrows = false;
   graph.withFixedTooltipPositions = true;
 
--- a/browser/devtools/shared/test/browser_graphs-09c.js
+++ b/browser/devtools/shared/test/browser_graphs-09c.js
@@ -1,24 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that line graphs hide the tooltips when there's no data available.
 
 const TEST_DATA = [];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
 
   yield testGraph(graph);
 
--- a/browser/devtools/shared/test/browser_graphs-09d.js
+++ b/browser/devtools/shared/test/browser_graphs-09d.js
@@ -1,25 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that line graphs hide the 'max' tooltip when the distance between
 // the 'min' and 'max' tooltip is too small.
 
 const TEST_DATA = [{ delta: 100, value: 60 }, { delta: 200, value: 59.9 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
 
   yield testGraph(graph);
 
--- a/browser/devtools/shared/test/browser_graphs-09e.js
+++ b/browser/devtools/shared/test/browser_graphs-09e.js
@@ -3,25 +3,22 @@
 
 // Tests that line graphs hide the gutter and tooltips when there's no data,
 // but show them when there is.
 
 const NO_DATA = [];
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
 
   yield testGraph(graph);
 
--- a/browser/devtools/shared/test/browser_graphs-09f.js
+++ b/browser/devtools/shared/test/browser_graphs-09f.js
@@ -1,25 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests the constructor options for `min`, `max` and `avg` on displaying the
 // gutter/tooltips and lines.
 
 const TEST_DATA = [{ delta: 100, value: 60 }, { delta: 200, value: 1 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
 
   yield testGraph(doc.body, { avg: false });
   yield testGraph(doc.body, { min: false });
   yield testGraph(doc.body, { max: false });
--- a/browser/devtools/shared/test/browser_graphs-10a.js
+++ b/browser/devtools/shared/test/browser_graphs-10a.js
@@ -1,24 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graphs properly handle resizing.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost("window");
   doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
 
   let graph = new LineGraphWidget(doc.body, "fps");
   yield graph.once("ready");
--- a/browser/devtools/shared/test/browser_graphs-10b.js
+++ b/browser/devtools/shared/test/browser_graphs-10b.js
@@ -1,25 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graphs aren't refreshed when the owner window resizes but
 // the graph dimensions stay the same.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost("window");
   doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
 
   let graph = new LineGraphWidget(doc.body, "fps");
   graph.fixedWidth = 200;
--- a/browser/devtools/shared/test/browser_graphs-11a.js
+++ b/browser/devtools/shared/test/browser_graphs-11a.js
@@ -1,29 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that bar graph create a legend as expected.
 
 let {BarGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
 const CATEGORIES = [
   { color: "#46afe3", label: "Foo" },
   { color: "#eb5368", label: "Bar" },
   { color: "#70bf53", label: "Baz" }
 ];
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new BarGraphWidget(doc.body);
   yield graph.once("ready");
 
   testGraph(graph);
--- a/browser/devtools/shared/test/browser_graphs-11b.js
+++ b/browser/devtools/shared/test/browser_graphs-11b.js
@@ -1,29 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that bar graph's legend items handle mouseover/mouseout.
 
 let {BarGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
 const CATEGORIES = [
   { color: "#46afe3", label: "Foo" },
   { color: "#eb5368", label: "Bar" },
   { color: "#70bf53", label: "Baz" }
 ];
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
 
   let graph = new BarGraphWidget(doc.body, 1);
   graph.fixedWidth = 200;
--- a/browser/devtools/shared/test/browser_graphs-12.js
+++ b/browser/devtools/shared/test/browser_graphs-12.js
@@ -1,23 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that canvas graphs can have their selection linked.
 
 let {LineGraphWidget, BarGraphWidget, CanvasGraphUtils} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
 
   let first = document.createElement("div");
   first.setAttribute("style", "display: inline-block; width: 100%; height: 50%;");
--- a/browser/devtools/shared/test/browser_graphs-13.js
+++ b/browser/devtools/shared/test/browser_graphs-13.js
@@ -1,23 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets may have a fixed width or height.
 
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
 
   let graph = new LineGraphWidget(doc.body, "fps");
   graph.fixedWidth = 200;
--- a/browser/devtools/shared/test/browser_graphs-14.js
+++ b/browser/devtools/shared/test/browser_graphs-14.js
@@ -1,24 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets correctly emit mouse input events.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
 
   yield testGraph(graph);
 
--- a/browser/devtools/shared/test/browser_inplace-editor.js
+++ b/browser/devtools/shared/test/browser_inplace-editor.js
@@ -4,119 +4,120 @@
 
 "use strict";
 
 let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 let {editableField, getInplaceEditorForSpan: inplaceEditor} = devtools.require("devtools/shared/inplace-editor");
 
 // Test the inplace-editor behavior.
 
-let test = Task.async(function*() {
+add_task(function*() {
   yield promiseTab("data:text/html;charset=utf-8,inline editor tests");
+  let [host, win, doc] = yield createHost();
 
-  yield testReturnCommit();
-  yield testBlurCommit();
-  yield testAdvanceCharCommit();
+  yield testReturnCommit(doc);
+  yield testBlurCommit(doc);
+  yield testAdvanceCharCommit(doc);
 
+  host.destroy();
   gBrowser.removeCurrentTab();
-  finish();
 });
 
-function testReturnCommit() {
+function testReturnCommit(doc) {
   info("Testing that pressing return commits the new value");
   let def = promise.defer();
 
   createInplaceEditorAndClick({
     initial: "explicit initial",
     start: function(editor) {
       is(editor.input.value, "explicit initial", "Explicit initial value should be used.");
       editor.input.value = "Test Value";
       EventUtils.sendKey("return");
     },
     done: onDone("Test Value", true, def)
-  });
+  }, doc);
 
   return def.promise;
 }
 
-function testBlurCommit() {
+function testBlurCommit(doc) {
   info("Testing that bluring the field commits the new value");
   let def = promise.defer();
 
   createInplaceEditorAndClick({
     start: function(editor) {
       is(editor.input.value, "Edit Me!", "textContent of the span used.");
       editor.input.value = "Test Value";
       editor.input.blur();
     },
     done: onDone("Test Value", true, def)
-  });
+  }, doc);
 
   return def.promise;
 }
 
-function testAdvanceCharCommit() {
+function testAdvanceCharCommit(doc) {
   info("Testing that configured advanceChars commit the new value");
   let def = promise.defer();
 
   createInplaceEditorAndClick({
     advanceChars: ":",
     start: function(editor) {
       let input = editor.input;
       for each (let ch in "Test:") {
         EventUtils.sendChar(ch);
       }
     },
     done: onDone("Test", true, def)
-  });
+  }, doc);
 
   return def.promise;
 }
 
-function testEscapeCancel() {
+function testEscapeCancel(doc) {
   info("Testing that escape cancels the new value");
   let def = promise.defer();
 
   createInplaceEditorAndClick({
     initial: "initial text",
     start: function(editor) {
       editor.input.value = "Test Value";
       EventUtils.sendKey("escape");
     },
     done: onDone("initial text", false, def)
-  });
+  }, doc);
 
   return def.promise;
 }
 
 function onDone(value, isCommit, def) {
   return function(actualValue, actualCommit) {
     info("Inplace-editor's done callback executed, checking its state");
     is(actualValue, value, "The value is correct");
     is(actualCommit, isCommit, "The commit boolean is correct");
     def.resolve();
   }
 }
 
-function createInplaceEditorAndClick(options) {
-  clearBody();
-  let span = options.element = createSpan();
+function createInplaceEditorAndClick(options, doc) {
+  clearBody(doc);
+  let span = options.element = createSpan(doc);
 
   info("Creating an inplace-editor field");
   editableField(options);
 
   info("Clicking on the inplace-editor field to turn to edit mode");
   span.click();
 }
 
-function clearBody() {
+function clearBody(doc) {
   info("Clearing the page body");
-  content.document.body.innerHTML = "";
+  doc.body.innerHTML = "";
 }
 
-function createSpan() {
+function createSpan(doc) {
   info("Creating a new span element");
-  let span = content.document.createElement("span");
+  let span = doc.createElement("span");
   span.setAttribute("tabindex", "0");
   span.textContent = "Edit Me!";
-  content.document.body.appendChild(span);
+  doc.body.appendChild(span);
   return span;
 }
--- a/browser/devtools/shared/test/browser_options-view-01.js
+++ b/browser/devtools/shared/test/browser_options-view-01.js
@@ -1,41 +1,49 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that options-view OptionsView responds to events correctly.
 
-let { OptionsView } = devtools.require("devtools/shared/options-view");
-let { Services } = devtools.require("resource://gre/modules/Services.jsm");
+const {OptionsView} = devtools.require("devtools/shared/options-view");
+const {Services} = devtools.require("resource://gre/modules/Services.jsm");
 
 const BRANCH = "devtools.debugger.";
 const BLACK_BOX_PREF = "auto-black-box";
 const PRETTY_PRINT_PREF = "auto-pretty-print";
 
 let originalBlackBox = Services.prefs.getBoolPref(BRANCH + BLACK_BOX_PREF);
 let originalPrettyPrint = Services.prefs.getBoolPref(BRANCH + PRETTY_PRINT_PREF);
 
-let test = Task.async(function*() {
+add_task(function*() {
+  info("Setting a couple of preferences");
   Services.prefs.setBoolPref(BRANCH + BLACK_BOX_PREF, false);
   Services.prefs.setBoolPref(BRANCH + PRETTY_PRINT_PREF, true);
-  let tab = yield promiseTab(OPTIONS_VIEW_URL);
+
+  info("Opening a test tab and a toolbox host to create the options view in");
+  yield promiseTab("about:blank");
+  let [host, win, doc] = yield createHost("bottom", OPTIONS_VIEW_URL);
+
+  yield testOptionsView(win);
 
-  yield testOptionsView(tab);
+  info("Closing the host and current tab");
+  host.destroy();
   gBrowser.removeCurrentTab();
-  cleanup();
-  finish();
+
+  info("Resetting the preferences");
+  Services.prefs.setBoolPref(BRANCH + BLACK_BOX_PREF, originalBlackBox);
+  Services.prefs.setBoolPref(BRANCH + PRETTY_PRINT_PREF, originalPrettyPrint);
 });
 
-function* testOptionsView(tab) {
+function* testOptionsView(win) {
   let events = [];
-  let options = createOptionsView(tab);
+  let options = createOptionsView(win);
   yield options.initialize();
 
-  let window = tab._contentWindow;
-  let $ = window.document.querySelector.bind(window.document);
+  let $ = win.document.querySelector.bind(win.document);
 
   options.on("pref-changed", (_, pref) => events.push(pref));
 
   let ppEl = $("menuitem[data-pref='auto-pretty-print']");
   let bbEl = $("menuitem[data-pref='auto-black-box']");
 
   // Test default config
   is(ppEl.getAttribute("checked"), "true", "`true` prefs are checked on start");
@@ -52,56 +60,42 @@ function* testOptionsView(tab) {
   is(bbEl.getAttribute("checked"), "true", "menuitems update when preferences change");
 
   // Tests events are fired when preferences update outside of the menu
   is(events.length, 2, "two 'pref-changed' events fired");
   is(events[0], "auto-pretty-print", "correct pref passed in 'pref-changed' event (auto-pretty-print)");
   is(events[1], "auto-black-box", "correct pref passed in 'pref-changed' event (auto-black-box)");
 
   // Test buttons update when clicked and preferences are updated
-  yield click(options, window, ppEl);
+  yield click(options, win, ppEl);
   is(ppEl.getAttribute("checked"), "true", "menuitems update when clicked");
   is(Services.prefs.getBoolPref(BRANCH + PRETTY_PRINT_PREF), true, "preference updated via click");
 
-  yield click(options, window, bbEl);
+  yield click(options, win, bbEl);
   is(bbEl.getAttribute("checked"), "", "menuitems update when clicked");
   is(Services.prefs.getBoolPref(BRANCH + BLACK_BOX_PREF), false, "preference updated via click");
 
   // Tests events are fired when preferences updated via click
   is(events.length, 4, "two 'pref-changed' events fired");
   is(events[2], "auto-pretty-print", "correct pref passed in 'pref-changed' event (auto-pretty-print)");
   is(events[3], "auto-black-box", "correct pref passed in 'pref-changed' event (auto-black-box)");
 
   yield options.destroy();
 }
 
-function wait(window) {
-  return new Promise(function (resolve, reject) {
-  window.setTimeout(() => resolve, 60000);
-  });
-}
-function createOptionsView (tab) {
+function createOptionsView(win) {
   return new OptionsView({
     branchName: BRANCH,
-    window: tab._contentWindow,
-    menupopup: tab._contentWindow.document.querySelector("#options-menupopup")
+    menupopup: win.document.querySelector("#options-menupopup")
   });
 }
 
-function cleanup () {
-  Services.prefs.setBoolPref(BRANCH + BLACK_BOX_PREF, originalBlackBox);
-  Services.prefs.setBoolPref(BRANCH + PRETTY_PRINT_PREF, originalPrettyPrint);
-}
-
-function* click (view, win, menuitem) {
+function* click(view, win, menuitem) {
   let opened = view.once("options-shown");
   let closed = view.once("options-hidden");
 
   let button = win.document.querySelector("#options-button");
   EventUtils.synthesizeMouseAtCenter(button, {}, win);
   yield opened;
 
   EventUtils.synthesizeMouseAtCenter(menuitem, {}, win);
   yield closed;
 }
-
-function* openMenu (view, win) {
-}
--- a/browser/devtools/shared/test/browser_outputparser.js
+++ b/browser/devtools/shared/test/browser_outputparser.js
@@ -1,38 +1,35 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
 let {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
 let {OutputParser} = devtools.require("devtools/output-parser");
 
-let parser;
-let doc;
-
-function test() {
-  waitForExplicitFinish();
+add_task(function*() {
+  yield promiseTab("about:blank");
+  yield performTest();
+  gBrowser.removeCurrentTab();
+});
 
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function onload() {
-    gBrowser.selectedBrowser.removeEventListener("load", onload, true);
-    waitForFocus(init, content);
-    doc = content.document;
-  }, true);
+function* performTest() {
+  let [host, win, doc] = yield createHost("bottom", "data:text/html," +
+    "<h1>browser_outputParser.js</h1><div></div>");
 
-  content.location = "data:text/html,<h1>browser_outputParser.js</h1>" +
-                     "<div></div>";
+  let parser = new OutputParser();
+  testParseCssProperty(doc, parser);
+  testParseCssVar(doc, parser);
+  testParseHTMLAttribute(doc, parser);
+  testParseNonCssHTMLAttribute(doc, parser);
+
+  host.destroy();
 }
 
-function init() {
-  parser = new OutputParser();
-  testParseCssProperty();
-}
-
-function testParseCssProperty() {
+function testParseCssProperty(doc, parser) {
   let frag = parser.parseCssProperty("border", "1px solid red", {
     colorSwatchClass: "test-colorswatch"
   });
 
   let target = doc.querySelector("div");
   ok(target, "captain, we have the div");
   target.appendChild(frag);
 
@@ -48,37 +45,33 @@ function testParseCssProperty() {
   });
   target.appendChild(frag);
   is(target.innerHTML,
      'linear-gradient(to right, <span data-color="#F60"><span style="background-color:#F60" class="test-colorswatch"></span><span class="test-color">#F60</span></span> 10%, ' +
      '<span data-color="#000"><span style="background-color:rgba(0,0,0,1)" class="test-colorswatch"></span><span class="test-color">#000</span></span>)',
      "Gradient CSS property correctly parsed");
 
   target.innerHTML = "";
-
-  testParseCssVar();
 }
 
-function testParseCssVar() {
+function testParseCssVar(doc, parser) {
   let frag = parser.parseCssProperty("color", "var(--some-kind-of-green)", {
     colorSwatchClass: "test-colorswatch"
   });
 
   let target = doc.querySelector("div");
   ok(target, "captain, we have the div");
   target.appendChild(frag);
 
   is(target.innerHTML, "var(--some-kind-of-green)", "CSS property correctly parsed");
 
   target.innerHTML = "";
-
-  testParseHTMLAttribute();
 }
 
-function testParseHTMLAttribute() {
+function testParseHTMLAttribute(doc, parser) {
   let attrib = "color:red; font-size: 12px; background-image: " +
                "url(chrome://branding/content/about-logo.png)";
   let frag = parser.parseHTMLAttribute(attrib, {
     urlClass: "theme-link",
     colorClass: "theme-color"
   });
 
   let target = doc.querySelector("div");
@@ -87,32 +80,23 @@ function testParseHTMLAttribute() {
 
   let expected = 'color:<span data-color="#F00"><span class="theme-color">#F00</span></span>; font-size: 12px; ' +
                  'background-image: url("<a href="chrome://branding/content/about-logo.png" ' +
                  'class="theme-link" ' +
                  'target="_blank">chrome://branding/content/about-logo.png</a>")';
 
   is(target.innerHTML, expected, "HTML Attribute correctly parsed");
   target.innerHTML = "";
-  testParseNonCssHTMLAttribute();
 }
 
-function testParseNonCssHTMLAttribute() {
+function testParseNonCssHTMLAttribute(doc, parser) {
   let attrib = "someclass background someotherclass red";
   let frag = parser.parseHTMLAttribute(attrib);
 
   let target = doc.querySelector("div");
   ok(target, "captain, we have the div");
   target.appendChild(frag);
 
   let expected = 'someclass background someotherclass red';
 
   is(target.innerHTML, expected, "Non-CSS HTML Attribute correctly parsed");
   target.innerHTML = "";
-  finishUp();
 }
-
-
-function finishUp() {
-  Services = Loader = OutputParser = parser = doc = null;
-  gBrowser.removeCurrentTab();
-  finish();
-}
--- a/browser/devtools/shared/test/browser_spectrum.js
+++ b/browser/devtools/shared/test/browser_spectrum.js
@@ -2,109 +2,102 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the spectrum color picker works correctly
 
 const TEST_URI = "chrome://browser/content/devtools/spectrum-frame.xhtml";
 const {Spectrum} = devtools.require("devtools/shared/widgets/Spectrum");
 
-let doc;
+add_task(function*() {
+  yield promiseTab("about:blank");
+  yield performTest();
+  gBrowser.removeCurrentTab();
+});
 
-function test() {
-  waitForExplicitFinish();
-  addTab(TEST_URI, () => {
-    doc = content.document;
-    startTests();
-  });
+function* performTest() {
+  let [host, win, doc] = yield createHost("bottom", TEST_URI);
+
+  yield testCreateAndDestroyShouldAppendAndRemoveElements(doc);
+  yield testPassingAColorAtInitShouldSetThatColor(doc);
+  yield testSettingAndGettingANewColor(doc);
+  yield testChangingColorShouldEmitEvents(doc);
+  yield testSettingColorShoudUpdateTheUI(doc);
+
+  host.destroy();
 }
 
-function endTests() {
-  doc = null;
-  gBrowser.removeCurrentTab();
-  finish();
-}
-
-function startTests() {
-  testCreateAndDestroyShouldAppendAndRemoveElements();
-}
-
-function testCreateAndDestroyShouldAppendAndRemoveElements() {
+function testCreateAndDestroyShouldAppendAndRemoveElements(doc) {
   let containerElement = doc.querySelector("#spectrum");
   ok(containerElement, "We have the root node to append spectrum to");
   is(containerElement.childElementCount, 0, "Root node is empty");
 
   let s = new Spectrum(containerElement, [255, 126, 255, 1]);
   s.show();
   ok(containerElement.childElementCount > 0, "Spectrum has appended elements");
 
   s.destroy();
   is(containerElement.childElementCount, 0, "Destroying spectrum removed all nodes");
-
-  testPassingAColorAtInitShouldSetThatColor();
 }
 
-function testPassingAColorAtInitShouldSetThatColor() {
+function testPassingAColorAtInitShouldSetThatColor(doc) {
   let initRgba = [255, 126, 255, 1];
 
   let s = new Spectrum(doc.querySelector("#spectrum"), initRgba);
   s.show();
 
   let setRgba = s.rgb;
 
   is(initRgba[0], setRgba[0], "Spectrum initialized with the right color");
   is(initRgba[1], setRgba[1], "Spectrum initialized with the right color");
   is(initRgba[2], setRgba[2], "Spectrum initialized with the right color");
   is(initRgba[3], setRgba[3], "Spectrum initialized with the right color");
 
   s.destroy();
-  testSettingAndGettingANewColor();
 }
 
-function testSettingAndGettingANewColor() {
+function testSettingAndGettingANewColor(doc) {
   let s = new Spectrum(doc.querySelector("#spectrum"), [0, 0, 0, 1]);
   s.show();
 
   let colorToSet = [255, 255, 255, 1];
   s.rgb = colorToSet;
   let newColor = s.rgb;
 
   is(colorToSet[0], newColor[0], "Spectrum set with the right color");
   is(colorToSet[1], newColor[1], "Spectrum set with the right color");
   is(colorToSet[2], newColor[2], "Spectrum set with the right color");
   is(colorToSet[3], newColor[3], "Spectrum set with the right color");
 
   s.destroy();
-  testChangingColorShouldEmitEvents();
 }
 
-function testChangingColorShouldEmitEvents() {
-  let s = new Spectrum(doc.querySelector("#spectrum"), [255, 255, 255, 1]);
-  s.show();
-
-  s.once("changed", (event, rgba, color) => {
-    EventUtils.sendMouseEvent({type: "mouseup"}, s.dragger, doc.defaultView);
+function testChangingColorShouldEmitEvents(doc) {
+  return new Promise(resolve => {
+    let s = new Spectrum(doc.querySelector("#spectrum"), [255, 255, 255, 1]);
+    s.show();
 
-    ok(true, "Changed event was emitted on color change");
-    is(rgba[0], 128, "New color is correct");
-    is(rgba[1], 64, "New color is correct");
-    is(rgba[2], 64, "New color is correct");
-    is(rgba[3], 1, "New color is correct");
-    is("rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ", " + rgba[3] + ")", color, "RGBA and css color correspond");
+    s.once("changed", (event, rgba, color) => {
+      ok(true, "Changed event was emitted on color change");
+      is(rgba[0], 128, "New color is correct");
+      is(rgba[1], 64, "New color is correct");
+      is(rgba[2], 64, "New color is correct");
+      is(rgba[3], 1, "New color is correct");
+      is("rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ", " + rgba[3] + ")", color, "RGBA and css color correspond");
 
-    s.destroy();
-    testSettingColorShoudUpdateTheUI();
-  });
+      s.destroy();
+      resolve();
+    });
 
-  executeSoon(() => {
-    EventUtils.synthesizeMouse(s.dragger, s.dragger.offsetWidth/2, s.dragger.offsetHeight/2, {}, content);
+    // Simulate a drag move event by calling the handler directly.
+    s.onDraggerMove(s.dragger.offsetWidth/2, s.dragger.offsetHeight/2);
   });
 }
 
-function testSettingColorShoudUpdateTheUI() {
+function testSettingColorShoudUpdateTheUI(doc) {
   let s = new Spectrum(doc.querySelector("#spectrum"), [255, 255, 255, 1]);
   s.show();
   let dragHelperOriginalPos = [s.dragHelper.style.top, s.dragHelper.style.left];
   let alphaHelperOriginalPos = s.alphaSliderHelper.style.left;
 
   s.rgb = [50, 240, 234, .2];
   s.updateUI();
 
@@ -113,10 +106,9 @@ function testSettingColorShoudUpdateTheU
   ok(s.dragHelper.style.left !== dragHelperOriginalPos[1], "Drag helper has moved");
 
   s.rgb = [240, 32, 124, 0];
   s.updateUI();
   is(s.alphaSliderHelper.style.left, - (s.alphaSliderHelper.offsetWidth/2) + "px",
     "Alpha range UI has been updated again");
 
   s.destroy();
-  executeSoon(endTests);
 }
--- a/browser/devtools/shared/test/browser_telemetry_button_eyedropper.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_eyedropper.js
@@ -1,110 +1,57 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_eyedropper.js</p><div>test</div>";
+const TEST_URI = "data:text/html;charset=utf-8," +
+  "<p>browser_telemetry_button_eyedropper.js</p><div>test</div>";
 
-let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
+let {EyedropperManager} = require("devtools/eyedropper/eyedropper");
 
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-let { EyedropperManager } = require("devtools/eyedropper/eyedropper");
-
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  let toolbox = yield gDevTools.showToolbox(target, "inspector");
+  info("inspector opened");
 
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
+  info("testing the eyedropper button");
+  testButton(toolbox, Telemetry);
+
+  stopRecordingTelemetryLogs(Telemetry);
+  yield gDevTools.closeToolbox(target);
+  gBrowser.removeCurrentTab();
+});
 
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
+function testButton(toolbox, Telemetry) {
+  let button = toolbox.doc.querySelector("#command-button-eyedropper");
+  ok(button, "Captain, we have the eyedropper button");
 
-  testButton("command-button-eyedropper");
+  info("clicking the button to open the eyedropper");
+  button.click();
+
+  checkResults("_EYEDROPPER_", Telemetry);
 }
 
-function testButton(id) {
-  info("Testing " + id);
-
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
-    info("inspector opened");
-
-    let button = toolbox.doc.querySelector("#" + id);
-    ok(button, "Captain, we have the button");
-
-    // open the eyedropper
-    button.click();
-
-    checkResults("_EYEDROPPER_");
-  }).then(null, console.error);
-}
-
-function clickButton(node, clicks) {
-  for (let i = 0; i < clicks; i++) {
-    info("Clicking button " + node.id);
-    node.click();
-  }
-}
-
-function checkResults(histIdFocus) {
+function checkResults(histIdFocus, Telemetry) {
   let result = Telemetry.prototype.telemetryInfo;
 
   for (let [histId, value] of Iterator(result)) {
     if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
         !histId.contains(histIdFocus)) {
       // Inspector stats are tested in
       // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
       // because we only open the inspector once for this test.
       continue;
     }
 
     if (histId.endsWith("OPENED_PER_USER_FLAG")) {
       ok(value.length === 1 && value[0] === true,
          "Per user value " + histId + " has a single value of true");
     } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length == 1, histId + " has one entry");
+      is(value.length, 1, histId + " has one entry");
 
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
+      let okay = value.every(element => element === true);
       ok(okay, "All " + histId + " entries are === true");
     }
   }
-
-  finishUp();
 }
-
-function finishUp() {
-  gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
--- a/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js
@@ -1,81 +1,64 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_paintflashing.js</p>";
+const TEST_URI = "data:text/html;charset=utf-8," +
+  "<p>browser_telemetry_button_paintflashing.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
-
-  testButton("command-button-paintflashing");
-}
-
-function testButton(id) {
-  info("Testing " + id);
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
+  let toolbox = yield gDevTools.showToolbox(target, "inspector");
+  info("inspector opened");
 
-  gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
-    info("inspector opened");
+  info("testing the paintflashing button");
+  yield testButton(toolbox, Telemetry);
 
-    let button = toolbox.doc.querySelector("#" + id);
-    ok(button, "Captain, we have the button");
+  stopRecordingTelemetryLogs(Telemetry);
+  yield gDevTools.closeToolbox(target);
+  gBrowser.removeCurrentTab();
+});
 
-    delayedClicks(button, 4).then(function() {
-      checkResults("_PAINTFLASHING_");
-    });
-  }).then(null, console.error);
+function* testButton(toolbox, Telemetry) {
+  info("Testing command-button-paintflashing");
+
+  let button = toolbox.doc.querySelector("#command-button-paintflashing");
+  ok(button, "Captain, we have the button");
+
+  yield delayedClicks(button, 4);
+  checkResults("_PAINTFLASHING_", Telemetry);
 }
 
 function delayedClicks(node, clicks) {
-  let deferred = promise.defer();
-  let clicked = 0;
-
-  // See TOOL_DELAY for why we need setTimeout here
-  setTimeout(function delayedClick() {
-    info("Clicking button " + node.id);
-    node.click();
-    clicked++;
+  return new Promise(resolve => {
+    let clicked = 0;
 
-    if (clicked >= clicks) {
-      deferred.resolve(node);
-    } else {
-      setTimeout(delayedClick, TOOL_DELAY);
-    }
-  }, TOOL_DELAY);
+    // See TOOL_DELAY for why we need setTimeout here
+    setTimeout(function delayedClick() {
+      info("Clicking button " + node.id);
+      node.click();
+      clicked++;
 
-  return deferred.promise;
+      if (clicked >= clicks) {
+        resolve(node);
+      } else {
+        setTimeout(delayedClick, TOOL_DELAY);
+      }
+    }, TOOL_DELAY);
+  });
 }
 
-function checkResults(histIdFocus) {
+function checkResults(histIdFocus, Telemetry) {
   let result = Telemetry.prototype.telemetryInfo;
 
   for (let [histId, value] of Iterator(result)) {
     if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
         !histId.contains(histIdFocus)) {
       // Inspector stats are tested in
       // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
       // because we only open the inspector once for this test.
@@ -98,34 +81,9 @@ function checkResults(histIdFocus) {
 
       let okay = value.every(function(element) {
         return element > 0;
       });
 
       ok(okay, "All " + histId + " entries have time > 0");
     }
   }
-
-  finishUp();
 }
-
-function finishUp() {
-  gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
--- a/browser/devtools/shared/test/browser_telemetry_button_responsive.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_responsive.js
@@ -1,81 +1,64 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_responsive.js</p>";
+const TEST_URI = "data:text/html;charset=utf-8," +
+  "<p>browser_telemetry_button_responsive.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
-
-  testButton("command-button-responsive");
-}
-
-function testButton(id) {
-  info("Testing " + id);
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
+  let toolbox = yield gDevTools.showToolbox(target, "inspector");
+  info("inspector opened");
 
-  gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
-    info("inspector opened");
+  info("testing the responsivedesign button");
+  yield testButton(toolbox, Telemetry);
 
-    let button = toolbox.doc.querySelector("#" + id);
-    ok(button, "Captain, we have the button");
+  stopRecordingTelemetryLogs(Telemetry);
+  yield gDevTools.closeToolbox(target);
+  gBrowser.removeCurrentTab();
+});
 
-    delayedClicks(button, 4).then(function() {
-      checkResults("_RESPONSIVE_");
-    });
-  }).then(null, console.error);
+function* testButton(toolbox, Telemetry) {
+  info("Testing command-button-responsive");
+
+  let button = toolbox.doc.querySelector("#command-button-responsive");
+  ok(button, "Captain, we have the button");
+
+  yield delayedClicks(button, 4);
+  checkResults("_RESPONSIVE_", Telemetry);
 }
 
 function delayedClicks(node, clicks) {
-  let deferred = promise.defer();
-  let clicked = 0;
-
-  // See TOOL_DELAY for why we need setTimeout here
-  setTimeout(function delayedClick() {
-    info("Clicking button " + node.id);
-    node.click();
-    clicked++;
+  return new Promise(resolve => {
+    let clicked = 0;
 
-    if (clicked >= clicks) {
-      deferred.resolve(node);
-    } else {
-      setTimeout(delayedClick, TOOL_DELAY);
-    }
-  }, TOOL_DELAY);
+    // See TOOL_DELAY for why we need setTimeout here
+    setTimeout(function delayedClick() {
+      info("Clicking button " + node.id);
+      node.click();
+      clicked++;
 
-  return deferred.promise;
+      if (clicked >= clicks) {
+        resolve(node);
+      } else {
+        setTimeout(delayedClick, TOOL_DELAY);
+      }
+    }, TOOL_DELAY);
+  });
 }
 
-function checkResults(histIdFocus) {
+function checkResults(histIdFocus, Telemetry) {
   let result = Telemetry.prototype.telemetryInfo;
 
   for (let [histId, value] of Iterator(result)) {
     if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
         !histId.contains(histIdFocus)) {
       // Inspector stats are tested in
       // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
       // because we only open the inspector once for this test.
@@ -98,34 +81,9 @@ function checkResults(histIdFocus) {
 
       let okay = value.every(function(element) {
         return element > 0;
       });
 
       ok(okay, "All " + histId + " entries have time > 0");
     }
   }
-
-  finishUp();
 }
-
-function finishUp() {
-  gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
--- a/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js
@@ -1,116 +1,102 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-///////////////////
-//
-// Whitelisting this test.
-// As part of bug 1077403, the leaking uncaught rejection should be fixed.
-//
-thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Protocol error (unknownError): Error: Got an invalid root window in DocumentWalker");
-
-const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_scratchpad.js</p>";
+const TEST_URI = "data:text/html;charset=utf-8," +
+  "<p>browser_telemetry_button_scratchpad.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-let numScratchpads = 0;
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
-
-  Services.ww.registerNotification(windowObserver);
-  testButton("command-button-scratchpad");
-}
-
-function testButton(id) {
-  info("Testing " + id);
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
+  let toolbox = yield gDevTools.showToolbox(target, "inspector");
+  info("inspector opened");
 
-  gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
-    info("inspector opened");
+  let onAllWindowsOpened = trackScratchpadWindows();
+
+  info("testing the scratchpad button");
+  yield testButton(toolbox, Telemetry);
+  yield onAllWindowsOpened;
+
+  checkResults("_SCRATCHPAD_", Telemetry);
+
+  stopRecordingTelemetryLogs(Telemetry);
+  yield gDevTools.closeToolbox(target);
+  gBrowser.removeCurrentTab();
+});
+
+function trackScratchpadWindows() {
+  info("register the window observer to track when scratchpad windows open");
+
+  let numScratchpads = 0;
 
-    let button = toolbox.doc.querySelector("#" + id);
-    ok(button, "Captain, we have the button");
+  return new Promise(resolve => {
+    Services.ww.registerNotification(function observer(subject, topic) {
+      if (topic == "domwindowopened") {
+        let win = subject.QueryInterface(Ci.nsIDOMWindow);
+        win.addEventListener("load", function onLoad() {
+          win.removeEventListener("load", onLoad, false);
+
+          if (win.Scratchpad) {
+            win.Scratchpad.addObserver({
+              onReady: function() {
+                win.Scratchpad.removeObserver(this);
+                numScratchpads++;
+                win.close();
 
-    delayedClicks(button, 4).then(null, console.error);
-  }).then(null, console.error);
+                info("another scratchpad was opened and closed, count is now " + numScratchpads);
+
+                if (numScratchpads === 4) {
+                  Services.ww.unregisterNotification(observer);
+                  info("4 scratchpads have been opened and closed, checking results");
+                  resolve();
+                }
+              },
+            });
+          }
+        }, false);
+      }
+    });
+  });
 }
 
-function windowObserver(aSubject, aTopic, aData) {
-  if (aTopic == "domwindowopened") {
-    let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
-    win.addEventListener("load", function onLoad() {
-      win.removeEventListener("load", onLoad, false);
-
-      if (win.Scratchpad) {
-        win.Scratchpad.addObserver({
-          onReady: function() {
-            win.Scratchpad.removeObserver(this);
-            numScratchpads++;
-            win.close();
+function* testButton(toolbox, Telemetry) {
+  info("Testing command-button-scratchpad");
+  let button = toolbox.doc.querySelector("#command-button-scratchpad");
+  ok(button, "Captain, we have the button");
 
-            info("another scratchpad was opened and closed, count is now " + numScratchpads);
-
-            if (numScratchpads === 4) {
-              Services.ww.unregisterNotification(windowObserver);
-              info("4 scratchpads have been opened and closed, checking results");
-              checkResults("_SCRATCHPAD_");
-            }
-          },
-        });
-      }
-    }, false);
-  }
+  yield delayedClicks(button, 4);
 }
 
 function delayedClicks(node, clicks) {
-  let deferred = promise.defer();
-  let clicked = 0;
-
-  // See TOOL_DELAY for why we need setTimeout here
-  setTimeout(function delayedClick() {
-    info("Clicking button " + node.id);
-    node.click();
-    clicked++;
+  return new Promise(resolve => {
+    let clicked = 0;
 
-    if (clicked >= clicks) {
-      deferred.resolve(node);
-    } else {
-      setTimeout(delayedClick, TOOL_DELAY);
-    }
-  }, TOOL_DELAY);
+    // See TOOL_DELAY for why we need setTimeout here
+    setTimeout(function delayedClick() {
+      info("Clicking button " + node.id);
+      node.click();
+      clicked++;
 
-  return deferred.promise;
+      if (clicked >= clicks) {
+        resolve(node);
+      } else {
+        setTimeout(delayedClick, TOOL_DELAY);
+      }
+    }, TOOL_DELAY);
+  });
 }
 
-function checkResults(histIdFocus) {
+function checkResults(histIdFocus, Telemetry) {
   let result = Telemetry.prototype.telemetryInfo;
 
   for (let [histId, value] of Iterator(result)) {
     if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
         !histId.contains(histIdFocus)) {
       // Inspector stats are tested in
       // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
       // because we only open the inspector once for this test.
@@ -133,34 +119,9 @@ function checkResults(histIdFocus) {
 
       let okay = value.every(function(element) {
         return element > 0;
       });
 
       ok(okay, "All " + histId + " entries have time > 0");
     }
   }
-
-  finishUp();
 }
-
-function finishUp() {
-  gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = numScratchpads = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
--- a/browser/devtools/shared/test/browser_telemetry_button_tilt.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_tilt.js
@@ -1,81 +1,64 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_tilt.js</p>";
+const TEST_URI = "data:text/html;charset=utf-8," +
+  "<p>browser_telemetry_button_tilt.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
-
-  testButton("command-button-tilt");
-}
-
-function testButton(id) {
-  info("Testing " + id);
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
+  let toolbox = yield gDevTools.showToolbox(target, "inspector");
+  info("inspector opened");
 
-  gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
-    info("inspector opened");
+  info("testing the tilt button");
+  yield testButton(toolbox, Telemetry);
 
-    let button = toolbox.doc.querySelector("#" + id);
-    ok(button, "Captain, we have the button");
+  stopRecordingTelemetryLogs(Telemetry);
+  yield gDevTools.closeToolbox(target);
+  gBrowser.removeCurrentTab();
+});
 
-    delayedClicks(button, 4).then(function() {
-      checkResults("_TILT_");
-    });
-  }).then(null, console.error);
+function* testButton(toolbox, Telemetry) {
+  info("Testing command-button-tilt");
+
+  let button = toolbox.doc.querySelector("#command-button-tilt");
+  ok(button, "Captain, we have the button");
+
+  yield delayedClicks(button, 4)
+  checkResults("_TILT_", Telemetry);
 }
 
 function delayedClicks(node, clicks) {
-  let deferred = promise.defer();
-  let clicked = 0;
-
-  // See TOOL_DELAY for why we need setTimeout here
-  setTimeout(function delayedClick() {
-    info("Clicking button " + node.id);
-    node.click();
-    clicked++;
+  return new Promise(resolve => {
+    let clicked = 0;
 
-    if (clicked >= clicks) {
-      deferred.resolve(node);
-    } else {
-      setTimeout(delayedClick, TOOL_DELAY);
-    }
-  }, TOOL_DELAY);
+    // See TOOL_DELAY for why we need setTimeout here
+    setTimeout(function delayedClick() {
+      info("Clicking button " + node.id);
+      node.click();
+      clicked++;
 
-  return deferred.promise;
+      if (clicked >= clicks) {
+        resolve(node);
+      } else {
+        setTimeout(delayedClick, TOOL_DELAY);
+      }
+    }, TOOL_DELAY);
+  });
 }
 
-function checkResults(histIdFocus) {
+function checkResults(histIdFocus, Telemetry) {
   let result = Telemetry.prototype.telemetryInfo;
 
   for (let [histId, value] of Iterator(result)) {
     if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
         !histId.contains(histIdFocus)) {
       // Inspector stats are tested in
       // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
       // because we only open the inspector once for this test.
@@ -98,34 +81,9 @@ function checkResults(histIdFocus) {
 
       let okay = value.every(function(element) {
         return element > 0;
       });
 
       ok(okay, "All " + histId + " entries have time > 0");
     }
   }
-
-  finishUp();
 }
-
-function finishUp() {
-  gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
--- a/browser/devtools/shared/test/browser_telemetry_sidebar.js
+++ b/browser/devtools/shared/test/browser_telemetry_sidebar.js
@@ -2,71 +2,59 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_sidebar.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  let toolbox = yield gDevTools.showToolbox(target, "inspector");
+  info("inspector opened");
 
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
+  yield testSidebar(toolbox);
+  checkResults(Telemetry);
 
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
+  stopRecordingTelemetryLogs(Telemetry);
+  yield gDevTools.closeToolbox(target);
+  gBrowser.removeCurrentTab();
+});
 
-  testSidebar();
-}
-
-function testSidebar() {
+function* testSidebar(toolbox) {
   info("Testing sidebar");
 
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  let inspector = toolbox.getCurrentPanel();
+  let sidebarTools = ["ruleview", "computedview", "fontinspector",
+                      "layoutview", "animationinspector"];
 
-  gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
-    let inspector = toolbox.getCurrentPanel();
-    let sidebarTools = ["ruleview", "computedview", "fontinspector",
-                        "layoutview", "animationinspector"];
+  // Concatenate the array with itself so that we can open each tool twice.
+  sidebarTools.push.apply(sidebarTools, sidebarTools);
 
-    // Concatenate the array with itself so that we can open each tool twice.
-    sidebarTools.push.apply(sidebarTools, sidebarTools);
-
+  return new Promise(resolve => {
     // See TOOL_DELAY for why we need setTimeout here
     setTimeout(function selectSidebarTab() {
       let tool = sidebarTools.pop();
       if (tool) {
         inspector.sidebar.select(tool);
         setTimeout(function() {
           setTimeout(selectSidebarTab, TOOL_DELAY);
         }, TOOL_DELAY);
       } else {
-        checkResults();
+        resolve();
       }
     }, TOOL_DELAY);
   });
 }
 
-function checkResults() {
+function checkResults(Telemetry) {
   let result = Telemetry.prototype.telemetryInfo;
 
   for (let [histId, value] of Iterator(result)) {
     if (histId.startsWith("DEVTOOLS_INSPECTOR_")) {
       // Inspector stats are tested in browser_telemetry_toolboxtabs.js so we
       // skip them here because we only open the inspector once for this test.
       continue;
     }
@@ -89,34 +77,9 @@ function checkResults() {
 
       let okay = value.every(function(element) {
         return element > 0;
       });
 
       ok(okay, "All " + histId + " entries have time > 0");
     }
   }
-
-  finishUp();
 }
-
-function finishUp() {
-  gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
--- a/browser/devtools/shared/test/browser_telemetry_toolbox.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolbox.js
@@ -1,103 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolbox.js</p>";
+const TEST_URI = "data:text/html;charset=utf-8," +
+  "<p>browser_telemetry_toolbox.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  };
-
-  openToolboxThreeTimes();
-}
-
-let pass = 0;
-function openToolboxThreeTimes() {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
-    info("Toolbox opened");
-
-    toolbox.once("destroyed", function() {
-      if (pass++ === 3) {
-        checkResults();
-      } else {
-        openToolboxThreeTimes();
-      }
-    });
-    // We use a timeout to check the toolbox's active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, console.error);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
+  yield openAndCloseToolbox(3, TOOL_DELAY, "inspector");
+  checkTelemetryResults(Telemetry);
 
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
+});
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js
@@ -1,117 +1,27 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_canvasdebugger.js</p>";
+const TEST_URI = "data:text/html;charset=utf-8," +
+  "<p>browser_telemetry_toolboxtabs_canvasdebugger.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-let originalPref = Services.prefs.getBoolPref("devtools.canvasdebugger.enabled");
-Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", true);
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("canvasdebugger", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
+add_task(function*() {
+  info("Activate the canvasdebugger");
+  let originalPref = Services.prefs.getBoolPref("devtools.canvasdebugger.enabled");
+  Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", true);
 
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
+  yield openAndCloseToolbox(2, TOOL_DELAY, "canvasdebugger");
+  checkTelemetryResults(Telemetry);
 
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
-
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
+  info("De-activate the canvasdebugger");
   Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", originalPref);
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
+});
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js
@@ -1,114 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_inspector.js</p>";
+const TEST_URI = "data:text/html;charset=utf-8," +
+  "<p>browser_telemetry_toolboxtabs_inspector.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("inspector", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
-
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
+  yield openAndCloseToolbox(2, TOOL_DELAY, "inspector");
+  checkTelemetryResults(Telemetry);
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
+});
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js
@@ -1,114 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_jsdebugger.js</p>";
+const TEST_URI = "data:text/html;charset=utf-8," +
+  "<p>browser_telemetry_toolboxtabs_jsdebugger.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("jsdebugger", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
-
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
+  yield openAndCloseToolbox(2, TOOL_DELAY, "jsdebugger");
+  checkTelemetryResults(Telemetry);
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
+});
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js
@@ -2,113 +2,18 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_jsprofiler.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("jsprofiler", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
-
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
+  yield openAndCloseToolbox(2, TOOL_DELAY, "jsprofiler");
+  checkTelemetryResults(Telemetry);
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
+});
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js
@@ -2,113 +2,19 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_netmonitor.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("netmonitor", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
-
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
+  yield openAndCloseToolbox(2, TOOL_DELAY, "netmonitor");
+  checkTelemetryResults(Telemetry);
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
+});
 
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js
@@ -2,113 +2,18 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_options.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("options", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
-
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
+  yield openAndCloseToolbox(2, TOOL_DELAY, "options");
+  checkTelemetryResults(Telemetry);
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
+});
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js
@@ -1,124 +1,33 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 ///////////////////
 //
 // Whitelisting this test.
-// As part of bug 1077403, the leaking uncaught rejection should be fixed. 
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Shader Editor is still waiting for a WebGL context to be created.");
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_shadereditor.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-let originalPref = Services.prefs.getBoolPref("devtools.shadereditor.enabled");
-Services.prefs.setBoolPref("devtools.shadereditor.enabled", true);
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("shadereditor", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
+add_task(function*() {
+  info("Active the sharer editor");
+  let originalPref = Services.prefs.getBoolPref("devtools.shadereditor.enabled");
+  Services.prefs.setBoolPref("devtools.shadereditor.enabled", true);
 
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
+  yield openAndCloseToolbox(2, TOOL_DELAY, "shadereditor");
+  checkTelemetryResults(Telemetry);
 
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
-
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
+  info("De-activate the sharer editor");
   Services.prefs.setBoolPref("devtools.shadereditor.enabled", originalPref);
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
+});
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js
@@ -2,118 +2,24 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_storage.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-let STORAGE_PREF = "devtools.storage.enabled";
-Services.prefs.setBoolPref(STORAGE_PREF, true);
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("storage", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
+add_task(function*() {
+  info("Activating the storage inspector");
+  Services.prefs.setBoolPref("devtools.storage.enabled", true);
 
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
+  yield openAndCloseToolbox(2, TOOL_DELAY, "storage");
+  checkTelemetryResults(Telemetry);
 
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
-
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  Services.prefs.clearUserPref(STORAGE_PREF);
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
+  info("De-activating the storage inspector");
+  Services.prefs.clearUserPref("devtools.storage.enabled");
+});
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js
@@ -2,113 +2,19 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_styleeditor.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("styleeditor", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
-
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
+  yield openAndCloseToolbox(2, TOOL_DELAY, "styleeditor");
+  checkTelemetryResults(Telemetry);
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
+});
 
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js
@@ -2,117 +2,25 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_webaudioeditor.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-let originalPref = Services.prefs.getBoolPref("devtools.webaudioeditor.enabled");
-Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", true);
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("webaudioeditor", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
+add_task(function*() {
+  info("Activating the webaudioeditor");
+  let originalPref = Services.prefs.getBoolPref("devtools.webaudioeditor.enabled");
+  Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", true);
 
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
+  yield openAndCloseToolbox(2, TOOL_DELAY, "webaudioeditor");
+  checkTelemetryResults(Telemetry);
 
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
-
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
 
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
+  info("De-activating the webaudioeditor");
   Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", originalPref);
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
+});
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js
@@ -2,113 +2,18 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_styleeditor_webconsole.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
-let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
-
-function init() {
-  Telemetry.prototype.telemetryInfo = {};
-  Telemetry.prototype._oldlog = Telemetry.prototype.log;
-  Telemetry.prototype.log = function(histogramId, value) {
-    if (!this.telemetryInfo) {
-      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
-      return;
-    }
-    if (histogramId) {
-      if (!this.telemetryInfo[histogramId]) {
-        this.telemetryInfo[histogramId] = [];
-      }
-
-      this.telemetryInfo[histogramId].push(value);
-    }
-  }
-
-  openToolboxTabTwice("webconsole", false);
-}
-
-function openToolboxTabTwice(id, secondPass) {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  gDevTools.showToolbox(target, id).then(function(toolbox) {
-    info("Toolbox tab " + id + " opened");
-
-    toolbox.once("destroyed", function() {
-      if (secondPass) {
-        checkResults();
-      } else {
-        openToolboxTabTwice(id, true);
-      }
-    });
-    // We use a timeout to check the tools active time
-    setTimeout(function() {
-      gDevTools.closeToolbox(target);
-    }, TOOL_DELAY);
-  }).then(null, reportError);
-}
-
-function checkResults() {
-  let result = Telemetry.prototype.telemetryInfo;
+add_task(function*() {
+  yield promiseTab(TEST_URI);
+  let Telemetry = loadTelemetryAndRecordLogs();
 
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_BOOLEAN")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-
-  finishUp();
-}
+  yield openAndCloseToolbox(2, TOOL_DELAY, "webconsole");
+  checkTelemetryResults(Telemetry);
 
-function reportError(error) {
-  let stack = "    " + error.stack.replace(/\n?.*?@/g, "\n    JS frame :: ");
-
-  ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
-            error.lineNumber + "\n\nStack trace:" + stack);
-  finishUp();
-}
-
-function finishUp() {
+  stopRecordingTelemetryLogs(Telemetry);
   gBrowser.removeCurrentTab();
-
-  Telemetry.prototype.log = Telemetry.prototype._oldlog;
-  delete Telemetry.prototype._oldlog;
-  delete Telemetry.prototype.telemetryInfo;
-
-  TargetFactory = Services = promise = require = null;
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(init, content);
-  }, true);
-
-  content.location = TEST_URI;
-}
+});
--- a/browser/devtools/shared/test/browser_templater_basic.js
+++ b/browser/devtools/shared/test/browser_templater_basic.js
@@ -4,33 +4,33 @@
 // Tests that the DOM Template engine works properly
 
 /*
  * These tests run both in Mozilla/Mochitest and plain browsers (as does
  * domtemplate)
  * We should endevour to keep the source in sync.
  */
 
-var promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
-var template = Cu.import("resource://gre/modules/devtools/Templater.jsm", {}).template;
+const template = Cu.import("resource://gre/modules/devtools/Templater.jsm", {}).template;
 
 const TEST_URI = TEST_URI_ROOT + "browser_templater_basic.html";
 
-function test() {
-  addTab(TEST_URI, function() {
-    info("Starting DOM Templater Tests");
-    runTest(0);
-  });
-}
+let test = Task.async(function*() {
+  yield promiseTab("about:blank");
+  let [host, win, doc] = yield createHost("bottom", TEST_URI);
 
-function runTest(index) {
+  info("Starting DOM Templater Tests");
+  runTest(0, host, doc);
+});
+
+function runTest(index, host, doc) {
   var options = tests[index] = tests[index]();
-  var holder = content.document.createElement('div');
+  var holder = doc.createElement('div');
   holder.id = options.name;
-  var body = content.document.body;
+  var body = doc.body;
   body.appendChild(holder);
   holder.innerHTML = options.template;
 
   info('Running ' + options.name);
   template(holder, options.data, options.options);
 
   if (typeof options.result == 'string') {
     is(holder.innerHTML, options.result, options.name);
@@ -42,20 +42,20 @@ function runTest(index) {
 
   if (options.also) {
     options.also(options);
   }
 
   function runNextTest() {
     index++;
     if (index < tests.length) {
-      runTest(index);
+      runTest(index, host, doc);
     }
     else {
-      finished();
+      finished(host);
     }
   }
 
   if (options.later) {
     var ais = is.bind(this);
 
     function createTester(holder, options) {
       return () => {
@@ -66,17 +66,18 @@ function runTest(index) {
 
     executeSoon(createTester(holder, options));
   }
   else {
     runNextTest();
   }
 }
 
-function finished() {
+function finished(host) {
+  host.destroy();
   gBrowser.removeCurrentTab();
   info("Finishing DOM Templater Tests");
   tests = null;
   finish();
 }
 
 /**
  * Why have an array of functions that return data rather than just an array
@@ -275,14 +276,10 @@ var tests = [
     template: '<div><p value="${nullvar}"></p><p value="${undefinedvar1}"></p><p value="${undefinedvar2}"></p></div>',
     data: { nullvar: null, undefinedvar1: undefined },
     options: { blankNullUndefined: true },
     result: '<div><p value=""></p><p value=""></p><p value=""></p></div>'
   };}
 ];
 
 function delayReply(data) {
-  var d = promise.defer();
-  executeSoon(function() {
-    d.resolve(data);
-  });
-  return d.promise;
+  return new Promise(resolve => resolve(data));
 }
--- a/browser/devtools/shared/test/browser_theme.js
+++ b/browser/devtools/shared/test/browser_theme.js
@@ -1,31 +1,21 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that theme utilities work
 
-let { Cu } = devtools.require("chrome");
-let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
-let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
-let { getColor, getTheme, setTheme } = devtools.require("devtools/shared/theme");
+let {getColor, getTheme, setTheme} = devtools.require("devtools/shared/theme");
 
 function test() {
-  waitForExplicitFinish();
   testGetTheme();
   testSetTheme();
   testGetColor();
   testColorExistence();
-  endTests();
-}
-
-function endTests() {
-  gDevTools = Services = null;
-  finish();
 }
 
 function testGetTheme () {
   let originalTheme = getTheme();
   ok(originalTheme, "has some theme to start with.");
   Services.prefs.setCharPref("devtools.theme", "light");
   is(getTheme(), "light", "getTheme() correctly returns light theme");
   Services.prefs.setCharPref("devtools.theme", "dark");
--- a/browser/devtools/shared/test/browser_treeWidget_basic.js
+++ b/browser/devtools/shared/test/browser_treeWidget_basic.js
@@ -5,46 +5,36 @@
 // Tests that the tree widget api works fine
 
 const TEST_URI = "data:text/html;charset=utf-8,<head><link rel='stylesheet' " +
   "type='text/css' href='chrome://browser/skin/devtools/common.css'><link " +
   "rel='stylesheet' type='text/css' href='chrome://browser/skin/devtools/widg" +
   "ets.css'></head><body><div></div><span></span></body>";
 const {TreeWidget} = devtools.require("devtools/shared/widgets/TreeWidget");
 
-let doc, tree;
+add_task(function*() {
+  yield promiseTab("about:blank");
+  let [host, win, doc] = yield createHost("bottom", TEST_URI);
 
-function test() {
-  waitForExplicitFinish();
-  addTab(TEST_URI, () => {
-    doc = content.document;
-    tree = new TreeWidget(doc.querySelector("div"), {
-      defaultType: "store"
-    });
-    startTests();
+  let tree = new TreeWidget(doc.querySelector("div"), {
+    defaultType: "store"
   });
-}
 
-function endTests() {
+  populateTree(tree, doc);
+  testTreeItemInsertedCorrectly(tree, doc);
+  testAPI(tree, doc);
+  populateUnsortedTree(tree, doc);
+  testUnsortedTreeItemInsertedCorrectly(tree, doc);
+
   tree.destroy();
-  doc = tree = null;
+  host.destroy();
   gBrowser.removeCurrentTab();
-  finish();
-}
+});
 
-function startTests() {
-  populateTree();
-  testTreeItemInsertedCorrectly();
-  testAPI();
-  populateUnsortedTree();
-  testUnsortedTreeItemInsertedCorrectly();
-  endTests();
-}
-
-function populateTree() {
+function populateTree(tree, doc) {
   tree.add([{
     id: "level1",
     label: "Level 1"
   }, {
     id: "level2-1",
     label: "Level 2"
   }, {
     id: "level3-1",
@@ -72,17 +62,17 @@ function populateTree() {
     type: "js"
   }]);
   tree.add(["level1.1", "level2", {id: "level3", type: "url"}]);
 }
 
 /**
  * Test if the nodes are inserted correctly in the tree.
  */
-function testTreeItemInsertedCorrectly() {
+function testTreeItemInsertedCorrectly(tree, doc) {
   is(tree.root.children.children.length, 2, "Number of top level elements match");
   is(tree.root.children.firstChild.lastChild.children.length, 3,
      "Number of first second level elements match");
   is(tree.root.children.lastChild.lastChild.children.length, 1,
      "Number of second second level elements match");
 
   ok(tree.root.items.has("level1"), "Level1 top level element exists");
   is(tree.root.children.firstChild.dataset.id, JSON.stringify(["level1"]),
@@ -119,29 +109,29 @@ function testTreeItemInsertedCorrectly()
      "Data id of last top level element matches");
   is(tree.root.children.firstChild.firstChild.firstChild, node,
      "Newly added node is inserted at the right location");
 }
 
 /**
  * Populate the unsorted tree.
  */
-function populateUnsortedTree() {
+function populateUnsortedTree(tree, doc) {
   tree.sorted = false;
 
   tree.add([{ id: "g-1", label: "g-1"}])
   tree.add(["g-1", { id: "d-2", label: "d-2.1"}]);
   tree.add(["g-1", { id: "b-2", label: "b-2.2"}]);
   tree.add(["g-1", { id: "a-2", label: "a-2.3"}]);
 }
 
 /**
  * Test if the nodes are inserted correctly in the unsorted tree.
  */
-function testUnsortedTreeItemInsertedCorrectly() {
+function testUnsortedTreeItemInsertedCorrectly(tree, doc) {
   ok(tree.root.items.has("g-1"), "g-1 top level element exists");
 
   is(tree.root.children.firstChild.lastChild.children.length, 3,
     "Number of children for g-1 matches");
   is(tree.root.children.firstChild.dataset.id, JSON.stringify(["g-1"]),
     "Data id of g-1 matches");
   is(tree.root.children.firstChild.firstChild.textContent, "g-1",
     "Text content of g-1 matches");
@@ -154,17 +144,17 @@ function testUnsortedTreeItemInsertedCor
     "b-2.2", "Text content of b-2 matches");
   is(tree.root.children.firstChild.lastChild.lastChild.textContent, "a-2.3",
     "Text content of a-2 matches");
 }
 
 /**
  * Tests if the API exposed by TreeWidget works properly
  */
-function testAPI() {
+function testAPI(tree, doc) {
   info("Testing TreeWidget API");
   // Check if selectItem and selectedItem setter works as expected
   // Nothing should be selected beforehand
   ok(!doc.querySelector(".theme-selected"), "Nothing is selected");
   tree.selectItem(["level1"]);
   let node = doc.querySelector(".theme-selected");
   ok(!!node, "Something got selected");
   is(node.parentNode.dataset.id, JSON.stringify(["level1"]),
--- a/browser/devtools/shared/test/browser_treeWidget_keyboard_interaction.js
+++ b/browser/devtools/shared/test/browser_treeWidget_keyboard_interaction.js
@@ -4,46 +4,35 @@
 
 // Tests that keyboard interaction works fine with the tree widget
 
 const TEST_URI = "data:text/html;charset=utf-8,<head><link rel='stylesheet' " +
   "type='text/css' href='chrome://browser/skin/devtools/common.css'><link " +
   "rel='stylesheet' type='text/css' href='chrome://browser/skin/devtools/widg" +
   "ets.css'></head><body><div></div><span></span></body>";
 const {TreeWidget} = devtools.require("devtools/shared/widgets/TreeWidget");
-let {Task} = devtools.require("resource://gre/modules/Task.jsm");
-let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-
-let doc, tree;
+const {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
-function test() {
-  waitForExplicitFinish();
-  addTab(TEST_URI, () => {
-    doc = content.document;
-    tree = new TreeWidget(doc.querySelector("div"), {
-      defaultType: "store"
-    });
-    startTests();
+add_task(function*() {
+  yield promiseTab("about:blank");
+  let [host, win, doc] = yield createHost("bottom", TEST_URI);
+
+  let tree = new TreeWidget(doc.querySelector("div"), {
+    defaultType: "store"
   });
-}
 
-function endTests() {
+  populateTree(tree, doc);
+  yield testKeyboardInteraction(tree, win);
+
   tree.destroy();
-  doc = tree = null;
+  host.destroy();
   gBrowser.removeCurrentTab();
-  finish();
-}
-
-let startTests = Task.async(function*() {
-  populateTree();
-  yield testKeyboardInteraction();
-  endTests();
 });
 
-function populateTree() {
+function populateTree(tree, doc) {
   tree.add([{
     id: "level1",
     label: "Level 1"
   }, {
     id: "level2-1",
     label: "Level 2"
   }, {
     id: "level3-1",
@@ -82,23 +71,24 @@ function populateTree() {
     attachment: {
       foo: "bar"
     }
   }]);
 }
 
 // Sends a click event on the passed DOM node in an async manner
 function click(node) {
-  executeSoon(() => EventUtils.synthesizeMouseAtCenter(node, {}, content));
+  let win = node.ownerDocument.defaultView;
+  executeSoon(() => EventUtils.synthesizeMouseAtCenter(node, {}, win));
 }
 
 /**
  * Tests if pressing navigation keys on the tree items does the expected behavior
  */
-let testKeyboardInteraction = Task.async(function*() {
+function* testKeyboardInteraction(tree, win) {
   info("Testing keyboard interaction with the tree");
   let event;
   let pass = (e, d, a) => event.resolve([e, d, a]);
 
   info("clicking on first top level item");
   let node = tree.root.children.firstChild.firstChild;
   event = Promise.defer();
   tree.once("select", pass);
@@ -107,132 +97,132 @@ let testKeyboardInteraction = Task.async
   node = tree.root.children.firstChild.nextSibling.firstChild;
   // node should not have selected class
   ok(!node.classList.contains("theme-selected"), "Node should not have selected class");
   ok(!node.hasAttribute("expanded"), "Node is not expanded");
 
   info("Pressing down key to select next item");
   event = Promise.defer();
   tree.once("select", pass);
-  EventUtils.sendKey("DOWN", content);
+  EventUtils.sendKey("DOWN", win);
   let [name, data, attachment] = yield event.promise;
   is(name, "select", "Select event was fired after pressing down");
   is(data[0], "level1", "Correct item was selected after pressing down");
   ok(!attachment, "null attachment was emitted");
   ok(node.classList.contains("theme-selected"), "Node has selected class");
   ok(node.hasAttribute("expanded"), "Node is expanded now");
 
   info("Pressing down key again to select next item");
   event = Promise.defer();
   tree.once("select", pass);
-  EventUtils.sendKey("DOWN", content);
+  EventUtils.sendKey("DOWN", win);
   [name, data, attachment] = yield event.promise;
   is(data.length, 2, "Correct level item was selected after second down keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2", "Correct second level");
 
   info("Pressing down key again to select next item");
   event = Promise.defer();
   tree.once("select", pass);
-  EventUtils.sendKey("DOWN", content);
+  EventUtils.sendKey("DOWN", win);
   [name, data, attachment] = yield event.promise;
   is(data.length, 3, "Correct level item was selected after third down keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2", "Correct second level");
   is(data[2], "level3", "Correct third level");
 
   info("Pressing down key again to select next item");
   event = Promise.defer();
   tree.once("select", pass);
-  EventUtils.sendKey("DOWN", content);
+  EventUtils.sendKey("DOWN", win);
   [name, data, attachment] = yield event.promise;
   is(data.length, 2, "Correct level item was selected after fourth down keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2-1", "Correct second level");
 
   // pressing left to check expand collapse feature.
   // This does not emit any event, so listening for keypress
   tree.root.children.addEventListener("keypress", function onClick() {
     tree.root.children.removeEventListener("keypress", onClick);
     // executeSoon so that other listeners on the same method are executed first
     executeSoon(() => event.resolve(null));
   });
   info("Pressing left key to collapse the item");
   event = Promise.defer();
   node = tree._selectedLabel;
   ok(node.hasAttribute("expanded"), "Item is expanded before left keypress");
-  EventUtils.sendKey("LEFT", content);
+  EventUtils.sendKey("LEFT", win);
   yield event.promise;
 
   ok(!node.hasAttribute("expanded"), "Item is not expanded after left keypress");
 
   // pressing left on collapsed item should select the previous item
 
   info("Pressing left key on collapsed item to select previous");
   tree.once("select", pass);
   event = Promise.defer();
   // parent node should have no effect of this keypress
   node = tree.root.children.firstChild.nextSibling.firstChild;
   ok(node.hasAttribute("expanded"), "Parent is expanded");
-  EventUtils.sendKey("LEFT", content);
+  EventUtils.sendKey("LEFT", win);
   [name, data] = yield event.promise;
   is(data.length, 3, "Correct level item was selected after second left keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2", "Correct second level");
   is(data[2], "level3", "Correct third level");
   ok(node.hasAttribute("expanded"), "Parent is still expanded after left keypress");
 
   // pressing down again
 
   info("Pressing down key to select next item");
   event = Promise.defer();
   tree.once("select", pass);
-  EventUtils.sendKey("DOWN", content);
+  EventUtils.sendKey("DOWN", win);
   [name, data, attachment] = yield event.promise;
   is(data.length, 2, "Correct level item was selected after fifth down keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2-1", "Correct second level");
 
   // collapsing the item to check expand feature.
 
   tree.root.children.addEventListener("keypress", function onClick() {
     tree.root.children.removeEventListener("keypress", onClick);
     executeSoon(() => event.resolve(null));
   });
   info("Pressing left key to collapse the item");
   event = Promise.defer();
   node = tree._selectedLabel;
   ok(node.hasAttribute("expanded"), "Item is expanded before left keypress");
-  EventUtils.sendKey("LEFT", content);
+  EventUtils.sendKey("LEFT", win);
   yield event.promise;
   ok(!node.hasAttribute("expanded"), "Item is collapsed after left keypress");
 
   // pressing right should expand this now.
 
   tree.root.children.addEventListener("keypress", function onClick() {
     tree.root.children.removeEventListener("keypress", onClick);
     executeSoon(() => event.resolve(null));
   });
   info("Pressing right key to expend the collapsed item");
   event = Promise.defer();
   node = tree._selectedLabel;
   ok(!node.hasAttribute("expanded"), "Item is collapsed before right keypress");
-  EventUtils.sendKey("RIGHT", content);
+  EventUtils.sendKey("RIGHT", win);
   yield event.promise;
   ok(node.hasAttribute("expanded"), "Item is expanded after right keypress");
 
   // selecting last item node to test edge navigation case
 
   tree.selectedItem = ["level1.1", "level2", "level3"];
   node = tree._selectedLabel;
   // pressing down again should not change selection
   event = Promise.defer();
   tree.root.children.addEventListener("keypress", function onClick() {
     tree.root.children.removeEventListener("keypress", onClick);
     executeSoon(() => event.resolve(null));
   });
   info("Pressing down key on last item of the tree");
-  EventUtils.sendKey("DOWN", content);
+  EventUtils.sendKey("DOWN", win);
   yield event.promise;
 
   ok(tree.isSelected(["level1.1", "level2", "level3"]),
      "Last item is still selected after pressing down on last item of the tree");
-});
+}
--- a/browser/devtools/shared/test/browser_treeWidget_mouse_interaction.js
+++ b/browser/devtools/shared/test/browser_treeWidget_mouse_interaction.js
@@ -4,46 +4,35 @@
 
 // Tests that mouse interaction works fine with tree widget
 
 const TEST_URI = "data:text/html;charset=utf-8,<head><link rel='stylesheet' " +
   "type='text/css' href='chrome://browser/skin/devtools/common.css'><link " +
   "rel='stylesheet' type='text/css' href='chrome://browser/skin/devtools/widg" +
   "ets.css'></head><body><div></div><span></span></body>";
 const {TreeWidget} = devtools.require("devtools/shared/widgets/TreeWidget");
-let {Task} = devtools.require("resource://gre/modules/Task.jsm");
-let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-
-let doc, tree;
+const {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
-function test() {
-  waitForExplicitFinish();
-  addTab(TEST_URI, () => {
-    doc = content.document;
-    tree = new TreeWidget(doc.querySelector("div"), {
-      defaultType: "store"
-    });
-    startTests();
+add_task(function*() {
+  yield promiseTab("about:blank");
+  let [host, win, doc] = yield createHost("bottom", TEST_URI);
+
+  let tree = new TreeWidget(doc.querySelector("div"), {
+    defaultType: "store"
   });
-}
 
-function endTests() {
+  populateTree(tree, doc);
+  yield testMouseInteraction(tree);
+
   tree.destroy();
-  doc = tree = null;
+  host.destroy();
   gBrowser.removeCurrentTab();
-  finish();
-}
-
-let startTests = Task.async(function*() {
-  populateTree();
-  yield testMouseInteraction();
-  endTests();
 });
 
-function populateTree() {
+function populateTree(tree, doc) {
   tree.add([{
     id: "level1",
     label: "Level 1"
   }, {
     id: "level2-1",
     label: "Level 2"
   }, {
     id: "level3-1",
@@ -82,23 +71,24 @@ function populateTree() {
     attachment: {
       foo: "bar"
     }
   }]);
 }
 
 // Sends a click event on the passed DOM node in an async manner
 function click(node) {
-  executeSoon(() => EventUtils.synthesizeMouseAtCenter(node, {}, content));
+  let win = node.ownerDocument.defaultView;
+  executeSoon(() => EventUtils.synthesizeMouseAtCenter(node, {}, win));
 }
 
 /**
  * Tests if clicking the tree items does the expected behavior
  */
-let testMouseInteraction = Task.async(function*() {
+function* testMouseInteraction(tree) {
   info("Testing mouse interaction with the tree");
   let event;
   let pass = (e, d, a) => event.resolve([e, d, a]);
 
   ok(!tree.selectedItem, "Nothing should be selected beforehand");
 
   tree.once("select", pass);
   let node = tree.root.children.firstChild.firstChild;
@@ -139,9 +129,9 @@ let testMouseInteraction = Task.async(fu
   event = Promise.defer();
   node2.addEventListener("click", function onClick() {
     node2.removeEventListener("click", onClick);
     executeSoon(() => event.resolve(null));
   });
   click(node2);
   yield event.promise;
   ok(!node2.hasAttribute("expanded"), "New node collapsed after click again");
-});
+}
--- a/browser/devtools/shared/test/head.js
+++ b/browser/devtools/shared/test/head.js
@@ -1,15 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+let {TargetFactory, require} = devtools;
 let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
-let TargetFactory = devtools.TargetFactory;
+let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
+const {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
+const {Hosts} = require("devtools/framework/toolbox-hosts");
 
 gDevTools.testing = true;
 SimpleTest.registerCleanupFunction(() => {
   gDevTools.testing = false;
 });
 
 const TEST_URI_ROOT = "http://example.com/browser/browser/devtools/shared/test/";
 const OPTIONS_VIEW_URL = TEST_URI_ROOT + "doc_options-view.xul";
@@ -129,20 +132,110 @@ function waitForValue(aOptions)
 function oneTimeObserve(name, callback) {
   var func = function() {
     Services.obs.removeObserver(func, name);
     callback();
   };
   Services.obs.addObserver(func, name, false);
 }
 
-function* createHost(type = "bottom", src = "data:text/html;charset=utf-8,") {
+let createHost = Task.async(function*(type = "bottom", src = "data:text/html;charset=utf-8,") {
   let host = new Hosts[type](gBrowser.selectedTab);
   let iframe = yield host.create();
 
   yield new Promise(resolve => {
     let domHelper = new DOMHelpers(iframe.contentWindow);
     iframe.setAttribute("src", src);
     domHelper.onceDOMReady(resolve);
   });
 
   return [host, iframe.contentWindow, iframe.contentDocument];
+});
+
+/**
+ * Load the Telemetry utils, then stub Telemetry.prototype.log in order to
+ * record everything that's logged in it.
+ * Store all recordings on Telemetry.telemetryInfo.
+ * @return {Telemetry}
+ */
+function loadTelemetryAndRecordLogs() {
+  info("Mock the Telemetry log function to record logged information");
+
+  let Telemetry = require("devtools/shared/telemetry");
+  Telemetry.prototype.telemetryInfo = {};
+  Telemetry.prototype._oldlog = Telemetry.prototype.log;
+  Telemetry.prototype.log = function(histogramId, value) {
+    if (!this.telemetryInfo) {
+      // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
+      return;
+    }
+    if (histogramId) {
+      if (!this.telemetryInfo[histogramId]) {
+        this.telemetryInfo[histogramId] = [];
+      }
+
+      this.telemetryInfo[histogramId].push(value);
+    }
+  };
+
+  return Telemetry;
 }
+
+/**
+ * Stop recording the Telemetry logs and put back the utils as it was before.
+ */
+function stopRecordingTelemetryLogs(Telemetry) {
+  Telemetry.prototype.log = Telemetry.prototype._oldlog;
+  delete Telemetry.prototype._oldlog;
+  delete Telemetry.prototype.telemetryInfo;
+}
+
+/**
+ * Check the correctness of the data recorded in Telemetry after
+ * loadTelemetryAndRecordLogs was called.
+ */
+function checkTelemetryResults(Telemetry) {
+  let result = Telemetry.prototype.telemetryInfo;
+
+  for (let [histId, value] of Iterator(result)) {
+    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
+      ok(value.length === 1 && value[0] === true,
+         "Per user value " + histId + " has a single value of true");
+    } else if (histId.endsWith("OPENED_BOOLEAN")) {
+      ok(value.length > 1, histId + " has more than one entry");
+
+      let okay = value.every(function(element) {
+        return element === true;
+      });
+
+      ok(okay, "All " + histId + " entries are === true");
+    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
+      ok(value.length > 1, histId + " has more than one entry");
+
+      let okay = value.every(function(element) {
+        return element > 0;
+      });
+
+      ok(okay, "All " + histId + " entries have time > 0");
+    }
+  }
+}
+
+/**
+ * Open and close the toolbox in the current browser tab, several times, waiting
+ * some amount of time in between.
+ * @param {Number} nbOfTimes
+ * @param {Number} usageTime in milliseconds
+ * @param {String} toolId
+ */
+function* openAndCloseToolbox(nbOfTimes, usageTime, toolId) {
+  for (let i = 0; i < nbOfTimes; i ++) {
+    info("Opening toolbox " + (i + 1));
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    yield gDevTools.showToolbox(target, toolId)
+
+    // We use a timeout to check the toolbox's active time
+    yield new Promise(resolve => setTimeout(resolve, usageTime));
+
+    info("Closing toolbox " + (i + 1));
+    yield gDevTools.closeToolbox(target);
+  }
+}
--- a/browser/devtools/webconsole/console-output.js
+++ b/browser/devtools/webconsole/console-output.js
@@ -3097,128 +3097,126 @@ Widgets.ObjectRenderers.add({
     let closeTag = this.el("span.cm-tag");
     closeTag.textContent = ">";
     this.element.appendChild(closeTag);
 
     // Register this widget in the owner message so that it gets destroyed when
     // the message is destroyed.
     this.message.widgets.add(this);
 
-    this.linkToInspector();
+    this.linkToInspector().then(null, Cu.reportError);
   },
 
   /**
    * If the DOMNode being rendered can be highlit in the page, this function
    * will attach mouseover/out event listeners to do so, and the inspector icon
    * to open the node in the inspector.
-   * @return a promise (always the same) that resolves when the node has been
-   * linked to the inspector, or rejects if it wasn't (either if no toolbox
-   * could be found to access the inspector, or if the node isn't present in the
-   * inspector, i.e. if the node is in a DocumentFragment or not part of the
-   * tree, or not of type Ci.nsIDOMNode.ELEMENT_NODE).
+   * @return a promise that resolves when the node has been linked to the
+   * inspector, or rejects if it wasn't (either if no toolbox could be found to
+   * access the inspector, or if the node isn't present in the inspector, i.e.
+   * if the node is in a DocumentFragment or not part of the tree, or not of
+   * type Ci.nsIDOMNode.ELEMENT_NODE).
    */
-  linkToInspector: function()
+  linkToInspector: Task.async(function*()
   {
     if (this._linkedToInspector) {
-      return this._linkedToInspector;
+      return;
+    }
+
+    // Checking the node type
+    if (this.objectActor.preview.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) {
+      throw new Error("The object cannot be linked to the inspector as it " +
+        "isn't an element node");
+    }
+
+    // Checking the presence of a toolbox
+    let target = this.message.output.toolboxTarget;
+    this.toolbox = gDevTools.getToolbox(target);
+    if (!this.toolbox) {
+      throw new Error("The object cannot be linked to the inspector without a " +
+        "toolbox");
     }
 
-    this._linkedToInspector = Task.spawn(function*() {
-      // Checking the node type
-      if (this.objectActor.preview.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) {
-        throw null;
-      }
-
-      // Checking the presence of a toolbox
-      let target = this.message.output.toolboxTarget;
-      this.toolbox = gDevTools.getToolbox(target);
-      if (!this.toolbox) {
-        throw null;
-      }
-
-      // Checking that the inspector supports the node
-      yield this.toolbox.initInspector();
-      this._nodeFront = yield this.toolbox.walker.getNodeActorFromObjectActor(this.objectActor.actor);
-      if (!this._nodeFront) {
-        throw null;
-      }
-
-      // At this stage, the message may have been cleared already
-      if (!this.document) {
-        throw null;
-      }
-
-      this.highlightDomNode = this.highlightDomNode.bind(this);
-      this.element.addEventListener("mouseover", this.highlightDomNode, false);
-      this.unhighlightDomNode = this.unhighlightDomNode.bind(this);
-      this.element.addEventListener("mouseout", this.unhighlightDomNode, false);
-
-      this._openInspectorNode = this._anchor("", {
-        className: "open-inspector",
-        onClick: this.openNodeInInspector.bind(this)
-      });
-      this._openInspectorNode.title = l10n.getStr("openNodeInInspector");
-    }.bind(this));
-
-    return this._linkedToInspector;
-  },
+    // Checking that the inspector supports the node
+    yield this.toolbox.initInspector();
+    this._nodeFront = yield this.toolbox.walker.getNodeActorFromObjectActor(this.objectActor.actor);
+    if (!this._nodeFront) {
+      throw new Error("The object cannot be linked to the inspector, the " +
+        "corresponding nodeFront could not be found");
+    }
+
+    // At this stage, the message may have been cleared already
+    if (!this.document) {
+      throw new Error("The object cannot be linked to the inspector, the " +
+        "message was got cleared away");
+    }
+
+    this.highlightDomNode = this.highlightDomNode.bind(this);
+    this.element.addEventListener("mouseover", this.highlightDomNode, false);
+    this.unhighlightDomNode = this.unhighlightDomNode.bind(this);
+    this.element.addEventListener("mouseout", this.unhighlightDomNode, false);
+
+    this._openInspectorNode = this._anchor("", {
+      className: "open-inspector",
+      onClick: this.openNodeInInspector.bind(this)
+    });
+    this._openInspectorNode.title = l10n.getStr("openNodeInInspector");
+
+    this._linkedToInspector = true;
+  }),
 
   /**
    * Highlight the DOMNode corresponding to the ObjectActor in the page.
    * @return a promise that resolves when the node has been highlighted, or
    * rejects if the node cannot be highlighted (detached from the DOM)
    */
-  highlightDomNode: function()
+  highlightDomNode: Task.async(function*()
   {
-    return Task.spawn(function*() {
-      yield this.linkToInspector();
-      let isAttached = yield this.toolbox.walker.isInDOMTree(this._nodeFront);
-      if (isAttached) {
-        yield this.toolbox.highlighterUtils.highlightNodeFront(this._nodeFront);
-      } else {
-        throw null;
-      }
-    }.bind(this));
-  },
+    yield this.linkToInspector();
+    let isAttached = yield this.toolbox.walker.isInDOMTree(this._nodeFront);
+    if (isAttached) {
+      yield this.toolbox.highlighterUtils.highlightNodeFront(this._nodeFront);
+    } else {
+      throw null;
+    }
+  }),
 
   /**
    * Unhighlight a previously highlit node
    * @see highlightDomNode
    * @return a promise that resolves when the highlighter has been hidden
    */
   unhighlightDomNode: function()
   {
     return this.linkToInspector().then(() => {
       return this.toolbox.highlighterUtils.unhighlight();
-    });
+    }).then(null, Cu.reportError);
   },
 
   /**
    * Open the DOMNode corresponding to the ObjectActor in the inspector panel
    * @return a promise that resolves when the inspector has been switched to
    * and the node has been selected, or rejects if the node cannot be selected
    * (detached from the DOM). Note that in any case, the inspector panel will
    * be switched to.
    */
-  openNodeInInspector: function()
+  openNodeInInspector: Task.async(function*()
   {
-    return Task.spawn(function*() {
-      yield this.linkToInspector();
-      yield this.toolbox.selectTool("inspector");
-
-      let isAttached = yield this.toolbox.walker.isInDOMTree(this._nodeFront);
-      if (isAttached) {
-        let onReady = this.toolbox.inspector.once("inspector-updated");
-        yield this.toolbox.selection.setNodeFront(this._nodeFront, "console");
-        yield onReady;
-      } else {
-        throw null;
-      }
-    }.bind(this));
-  },
+    yield this.linkToInspector();
+    yield this.toolbox.selectTool("inspector");
+
+    let isAttached = yield this.toolbox.walker.isInDOMTree(this._nodeFront);
+    if (isAttached) {
+      let onReady = this.toolbox.inspector.once("inspector-updated");
+      yield this.toolbox.selection.setNodeFront(this._nodeFront, "console");
+      yield onReady;
+    } else {
+      throw null;
+    }
+  }),
 
   destroy: function()
   {
     if (this.toolbox && this._nodeFront) {
       this.element.removeEventListener("mouseover", this.highlightDomNode, false);
       this.element.removeEventListener("mouseout", this.unhighlightDomNode, false);
       this._openInspectorNode.removeEventListener("mousedown", this.openNodeInInspector, true);
       this.toolbox = null;
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js
@@ -1,20 +1,13 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 
-///////////////////
-//
-// Whitelisting this test.
-// As part of bug 1077403, the leaking uncaught rejection should be fixed.
-//
-thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Protocol error (unknownError): TypeError: this.conn.getActor(...) is null");
-
 // Tests that the $0 console helper works as intended.
 
 let inspector, h1, outputNode;
 
 function createDocument() {
   let doc = content.document;
   let div = doc.createElement("div");
   h1 = doc.createElement("h1");
--- a/browser/devtools/webconsole/test/browser_webconsole_output_03.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_03.js
@@ -1,20 +1,13 @@
 /*
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-///////////////////
-//
-// Whitelisting this test.
-// As part of bug 1077403, the leaking uncaught rejection should be fixed. 
-//
-thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Protocol error (unknownError): TypeError: this.conn.getActor(...) is null");
-
 // Test the webconsole output for various types of objects.
 
 const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-03.html";
 
 let inputTests = [
 
   // 0
   {
--- a/browser/devtools/webide/modules/runtimes.js
+++ b/browser/devtools/webide/modules/runtimes.js
@@ -442,19 +442,18 @@ function WiFiRuntime(deviceName) {
 
 WiFiRuntime.prototype = {
   type: RuntimeTypes.WIFI,
   connect: function(connection) {
     let service = discovery.getRemoteService("devtools", this.deviceName);
     if (!service) {
       return promise.reject(new Error("Can't find device: " + this.name));
     }
-    connection.host = service.host;
-    connection.port = service.port;
-    connection.encryption = service.encryption;
+    connection.advertisement = service;
+    // TODO: Customize client authentication UX
     connection.connect();
     return promise.resolve();
   },
   get id() {
     return this.deviceName;
   },
   get name() {
     return this.deviceName;
--- a/browser/modules/BrowserUITelemetry.jsm
+++ b/browser/modules/BrowserUITelemetry.jsm
@@ -133,16 +133,17 @@ XPCOMUtils.defineLazyGetter(this, "ALL_B
     "copy-button",
     "paste-button",
     "zoom-out-button",
     "zoom-reset-button",
     "zoom-in-button",
     "BMB_bookmarksPopup",
     "BMB_unsortedBookmarksPopup",
     "BMB_bookmarksToolbarPopup",
+    "search-go-button",
   ]
   return DEFAULT_ITEMS.concat(PALETTE_ITEMS)
                       .concat(SPECIAL_CASES);
 });
 
 const OTHER_MOUSEUP_MONITORED_ITEMS = [
   "PlacesChevron",
   "PlacesToolbarItems",
@@ -453,16 +454,23 @@ this.BrowserUITelemetry = {
     // being clicked.
     if (ALL_BUILTIN_ITEMS.indexOf(item.id) != -1) {
       // Base case - we clicked directly on one of our built-in items,
       // and we can go ahead and register that click.
       this._countMouseUpEvent("click-builtin-item", item.id, aEvent.button);
       return;
     }
 
+    // If not, we need to check if the item's anonid is in our list
+    // of built-in items to check.
+    if (ALL_BUILTIN_ITEMS.indexOf(item.getAttribute("anonid")) != -1) {
+      this._countMouseUpEvent("click-builtin-item", item.getAttribute("anonid"), aEvent.button);
+      return;
+    }
+
     // If not, we need to check if one of the ancestors of the clicked
     // item is in our list of built-in items to check.
     let candidate = getIDBasedOnFirstIDedAncestor(item);
     if (ALL_BUILTIN_ITEMS.indexOf(candidate) != -1) {
       this._countMouseUpEvent("click-builtin-item", candidate, aEvent.button);
     }
   },
 
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -29,24 +29,27 @@ SEARCH_PATHS = [
     'python/mozboot',
     'python/mozbuild',
     'python/mozversioncontrol',
     'python/blessings',
     'python/configobj',
     'python/jsmin',
     'python/psutil',
     'python/which',
+    'python/pystache',
+    'python/pyyaml/lib',
     'build/pymake',
     'config',
     'dom/bindings',
     'dom/bindings/parser',
     'layout/tools/reftest',
     'other-licenses/ply',
     'xpcom/idl-parser',
     'testing',
+    'testing/taskcluster',
     'testing/xpcshell',
     'testing/web-platform',
     'testing/web-platform/harness',
     'testing/marionette/client/marionette',
     'testing/marionette/transport',
     'testing/mozbase/mozcrash',
     'testing/mozbase/mozdebug',
     'testing/mozbase/mozdevice',
@@ -74,16 +77,17 @@ MACH_MODULES = [
     'python/mach_commands.py',
     'python/mach/mach/commands/commandinfo.py',
     'python/mozboot/mozboot/mach_commands.py',
     'python/mozbuild/mozbuild/mach_commands.py',
     'python/mozbuild/mozbuild/backend/mach_commands.py',
     'python/mozbuild/mozbuild/frontend/mach_commands.py',
     'services/common/tests/mach_commands.py',
     'testing/mach_commands.py',
+    'testing/taskcluster/mach_commands.py',
     'testing/marionette/mach_commands.py',
     'testing/mochitest/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
     'testing/talos/mach_commands.py',
     'testing/web-platform/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
     'tools/docs/mach_commands.py',
     'tools/mercurial/mach_commands.py',
@@ -103,16 +107,21 @@ CATEGORIES = {
         'long': 'Common actions performed after completing a build.',
         'priority': 70,
     },
     'testing': {
         'short': 'Testing',
         'long': 'Run tests.',
         'priority': 60,
     },
+    'ci': {
+        'short': 'CI',
+        'long': 'Taskcluster commands',
+        'priority': 59
+    },
     'devenv': {
         'short': 'Development Environment',
         'long': 'Set up and configure your development environment.',
         'priority': 50,
     },
     'build-dev': {
         'short': 'Low-level Build System Interaction',
         'long': 'Interact with specific parts of the build system.',
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonA2dpInterface.cpp
@@ -0,0 +1,429 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "BluetoothDaemonA2dpInterface.h"
+#include "BluetoothDaemonSetupInterface.h"
+#include "mozilla/unused.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+//
+// A2DP module
+//
+
+BluetoothA2dpNotificationHandler*
+  BluetoothDaemonA2dpModule::sNotificationHandler;
+
+void
+BluetoothDaemonA2dpModule::SetNotificationHandler(
+  BluetoothA2dpNotificationHandler* aNotificationHandler)
+{
+  sNotificationHandler = aNotificationHandler;
+}
+
+nsresult
+BluetoothDaemonA2dpModule::Send(BluetoothDaemonPDU* aPDU,
+                                BluetoothA2dpResultHandler* aRes)
+{
+  aRes->AddRef(); // Keep reference for response
+  return Send(aPDU, static_cast<void*>(aRes));
+}
+
+void
+BluetoothDaemonA2dpModule::HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
+                                     BluetoothDaemonPDU& aPDU, void* aUserData)
+{
+  static void (BluetoothDaemonA2dpModule::* const HandleOp[])(
+    const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&, void*) = {
+    INIT_ARRAY_AT(0, &BluetoothDaemonA2dpModule::HandleRsp),
+    INIT_ARRAY_AT(1, &BluetoothDaemonA2dpModule::HandleNtf),
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  // negate twice to map bit to 0/1
+  unsigned int isNtf = !!(aHeader.mOpcode & 0x80);
+
+  (this->*(HandleOp[isNtf]))(aHeader, aPDU, aUserData);
+}
+
+// Commands
+//
+
+nsresult
+BluetoothDaemonA2dpModule::ConnectCmd(
+  const nsAString& aRemoteAddr, BluetoothA2dpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(new BluetoothDaemonPDU(SERVICE_ID,
+                                                           OPCODE_CONNECT,
+                                                           6)); // Address
+  nsresult rv = PackPDU(
+    PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonA2dpModule::DisconnectCmd(
+  const nsAString& aRemoteAddr, BluetoothA2dpResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(new BluetoothDaemonPDU(SERVICE_ID,
+                                                           OPCODE_DISCONNECT,
+                                                           6)); // Address
+  nsresult rv = PackPDU(
+    PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+// Responses
+//
+
+void
+BluetoothDaemonA2dpModule::ErrorRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothA2dpResultHandler* aRes)
+{
+  ErrorRunnable::Dispatch(
+    aRes, &BluetoothA2dpResultHandler::OnError, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonA2dpModule::ConnectRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothA2dpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothA2dpResultHandler::Connect, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonA2dpModule::DisconnectRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothA2dpResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothA2dpResultHandler::Disconnect, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonA2dpModule::HandleRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  void* aUserData)
+{
+  static void (BluetoothDaemonA2dpModule::* const HandleRsp[])(
+    const BluetoothDaemonPDUHeader&,
+    BluetoothDaemonPDU&,
+    BluetoothA2dpResultHandler*) = {
+    INIT_ARRAY_AT(OPCODE_ERROR,
+      &BluetoothDaemonA2dpModule::ErrorRsp),
+    INIT_ARRAY_AT(OPCODE_CONNECT,
+      &BluetoothDaemonA2dpModule::ConnectRsp),
+    INIT_ARRAY_AT(OPCODE_DISCONNECT,
+      &BluetoothDaemonA2dpModule::DisconnectRsp),
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
+
+  if (NS_WARN_IF(!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(HandleRsp))) ||
+      NS_WARN_IF(!HandleRsp[aHeader.mOpcode])) {
+    return;
+  }
+
+  nsRefPtr<BluetoothA2dpResultHandler> res =
+    already_AddRefed<BluetoothA2dpResultHandler>(
+      static_cast<BluetoothA2dpResultHandler*>(aUserData));
+
+  if (!res) {
+    return; // Return early if no result handler has been set for response
+  }
+
+  (this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
+}
+
+// Notifications
+//
+
+// Returns the current notification handler to a notification runnable
+class BluetoothDaemonA2dpModule::NotificationHandlerWrapper MOZ_FINAL
+{
+public:
+  typedef BluetoothA2dpNotificationHandler ObjectType;
+
+  static ObjectType* GetInstance()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    return sNotificationHandler;
+  }
+};
+
+// Init operator class for ConnectionStateNotification
+class BluetoothDaemonA2dpModule::ConnectionStateInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  ConnectionStateInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (BluetoothA2dpConnectionState& aArg1, nsString& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read state */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read address */
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonA2dpModule::ConnectionStateNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  ConnectionStateNotification::Dispatch(
+    &BluetoothA2dpNotificationHandler::ConnectionStateNotification,
+    ConnectionStateInitOp(aPDU));
+}
+
+// Init operator class for AudioStateNotification
+class BluetoothDaemonA2dpModule::AudioStateInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  AudioStateInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (BluetoothA2dpAudioState& aArg1,
+               nsString& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read state */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read address */
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonA2dpModule::AudioStateNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  AudioStateNotification::Dispatch(
+    &BluetoothA2dpNotificationHandler::AudioStateNotification,
+    AudioStateInitOp(aPDU));
+}
+
+void
+BluetoothDaemonA2dpModule::HandleNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  void* aUserData)
+{
+  static void (BluetoothDaemonA2dpModule::* const HandleNtf[])(
+    const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&) = {
+    INIT_ARRAY_AT(0, &BluetoothDaemonA2dpModule::ConnectionStateNtf),
+    INIT_ARRAY_AT(1, &BluetoothDaemonA2dpModule::AudioStateNtf),
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  uint8_t index = aHeader.mOpcode - 0x81;
+
+  if (NS_WARN_IF(!(index < MOZ_ARRAY_LENGTH(HandleNtf))) ||
+      NS_WARN_IF(!HandleNtf[index])) {
+    return;
+  }
+
+  (this->*(HandleNtf[index]))(aHeader, aPDU);
+}
+
+//
+// A2DP interface
+//
+
+BluetoothDaemonA2dpInterface::BluetoothDaemonA2dpInterface(
+  BluetoothDaemonA2dpModule* aModule)
+  : mModule(aModule)
+{ }
+
+BluetoothDaemonA2dpInterface::~BluetoothDaemonA2dpInterface()
+{ }
+
+class BluetoothDaemonA2dpInterface::InitResultHandler MOZ_FINAL
+  : public BluetoothSetupResultHandler
+{
+public:
+  InitResultHandler(BluetoothA2dpResultHandler* aRes)
+    : mRes(aRes)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    mRes->OnError(aStatus);
+  }
+
+  void RegisterModule() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    mRes->Init();
+  }
+
+private:
+  nsRefPtr<BluetoothA2dpResultHandler> mRes;
+};
+
+void
+BluetoothDaemonA2dpInterface::Init(
+  BluetoothA2dpNotificationHandler* aNotificationHandler,
+  BluetoothA2dpResultHandler* aRes)
+{
+  // Set notification handler _before_ registering the module. It could
+  // happen that we receive notifications, before the result handler runs.
+  mModule->SetNotificationHandler(aNotificationHandler);
+
+  InitResultHandler* res;
+
+  if (aRes) {
+    res = new InitResultHandler(aRes);
+  } else {
+    // We don't need a result handler if the caller is not interested.
+    res = nullptr;
+  }
+
+  nsresult rv = mModule->RegisterModule(BluetoothDaemonA2dpModule::SERVICE_ID,
+                                        0x00, res);
+  if (NS_FAILED(rv) && aRes) {
+    DispatchError(aRes, STATUS_FAIL);
+  }
+}
+
+class BluetoothDaemonA2dpInterface::CleanupResultHandler MOZ_FINAL
+  : public BluetoothSetupResultHandler
+{
+public:
+  CleanupResultHandler(BluetoothDaemonA2dpModule* aModule,
+                       BluetoothA2dpResultHandler* aRes)
+    : mModule(aModule)
+    , mRes(aRes)
+  {
+    MOZ_ASSERT(mModule);
+  }
+
+  void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (mRes) {
+      mRes->OnError(aStatus);
+    }
+  }
+
+  void UnregisterModule() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    // Clear notification handler _after_ module has been
+    // unregistered. While unregistering the module, we might
+    // still receive notifications.
+    mModule->SetNotificationHandler(nullptr);
+
+    if (mRes) {
+      mRes->Cleanup();
+    }
+  }
+
+private:
+  BluetoothDaemonA2dpModule* mModule;
+  nsRefPtr<BluetoothA2dpResultHandler> mRes;
+};
+
+void
+BluetoothDaemonA2dpInterface::Cleanup(
+  BluetoothA2dpResultHandler* aRes)
+{
+  mModule->UnregisterModule(BluetoothDaemonA2dpModule::SERVICE_ID,
+                            new CleanupResultHandler(mModule, aRes));
+}
+
+/* Connect / Disconnect */
+
+void
+BluetoothDaemonA2dpInterface::Connect(
+  const nsAString& aBdAddr, BluetoothA2dpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->ConnectCmd(aBdAddr, aRes);
+}
+
+void
+BluetoothDaemonA2dpInterface::Disconnect(
+  const nsAString& aBdAddr, BluetoothA2dpResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->DisconnectCmd(aBdAddr, aRes);
+}
+
+void
+BluetoothDaemonA2dpInterface::DispatchError(
+  BluetoothA2dpResultHandler* aRes, BluetoothStatus aStatus)
+{
+  BluetoothResultRunnable1<BluetoothA2dpResultHandler, void,
+                           BluetoothStatus, BluetoothStatus>::Dispatch(
+    aRes, &BluetoothA2dpResultHandler::OnError,
+    ConstantInitOp1<BluetoothStatus>(aStatus));
+}
+
+END_BLUETOOTH_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonA2dpInterface.h
@@ -0,0 +1,152 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothdaemona2dpinterface_h
+#define mozilla_dom_bluetooth_bluetoothdaemona2dpinterface_h
+
+#include "BluetoothDaemonHelpers.h"
+#include "BluetoothInterface.h"
+#include "BluetoothInterfaceHelpers.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothSetupResultHandler;
+
+class BluetoothDaemonA2dpModule
+{
+public:
+  enum {
+    SERVICE_ID = 0x06
+  };
+
+  enum {
+    OPCODE_ERROR = 0x00,
+    OPCODE_CONNECT = 0x01,
+    OPCODE_DISCONNECT = 0x02
+  };
+
+  virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
+
+  virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
+                                  BluetoothSetupResultHandler* aRes) = 0;
+
+  virtual nsresult UnregisterModule(uint8_t aId,
+                                    BluetoothSetupResultHandler* aRes) = 0;
+
+  void SetNotificationHandler(
+    BluetoothA2dpNotificationHandler* aNotificationHandler);
+
+  //
+  // Commands
+  //
+
+  nsresult ConnectCmd(const nsAString& aBdAddr,
+                      BluetoothA2dpResultHandler* aRes);
+  nsresult DisconnectCmd(const nsAString& aBdAddr,
+                         BluetoothA2dpResultHandler* aRes);
+
+protected:
+  nsresult Send(BluetoothDaemonPDU* aPDU,
+                BluetoothA2dpResultHandler* aRes);
+
+  void HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU, void* aUserData);
+
+  //
+  // Responses
+  //
+
+  typedef BluetoothResultRunnable0<BluetoothA2dpResultHandler, void>
+    ResultRunnable;
+
+  typedef BluetoothResultRunnable1<BluetoothA2dpResultHandler, void,
+                                   BluetoothStatus, BluetoothStatus>
+    ErrorRunnable;
+
+  void ErrorRsp(const BluetoothDaemonPDUHeader& aHeader,
+                BluetoothDaemonPDU& aPDU,
+                BluetoothA2dpResultHandler* aRes);
+
+  void ConnectRsp(const BluetoothDaemonPDUHeader& aHeader,
+                  BluetoothDaemonPDU& aPDU,
+                  BluetoothA2dpResultHandler* aRes);
+
+  void DisconnectRsp(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU,
+                     BluetoothA2dpResultHandler* aRes);
+
+  void HandleRsp(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU,
+                 void* aUserData);
+
+  //
+  // Notifications
+  //
+
+  class NotificationHandlerWrapper;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         BluetoothA2dpConnectionState,
+                                         nsString,
+                                         BluetoothA2dpConnectionState,
+                                         const nsAString&>
+    ConnectionStateNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         BluetoothA2dpAudioState,
+                                         nsString,
+                                         BluetoothA2dpAudioState,
+                                         const nsAString&>
+    AudioStateNotification;
+
+  class AudioStateInitOp;
+  class ConnectionStateInitOp;
+
+  void ConnectionStateNtf(const BluetoothDaemonPDUHeader& aHeader,
+                          BluetoothDaemonPDU& aPDU);
+
+  void AudioStateNtf(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU);
+
+  void HandleNtf(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU,
+                 void* aUserData);
+
+  static BluetoothA2dpNotificationHandler* sNotificationHandler;
+};
+
+class BluetoothDaemonA2dpInterface MOZ_FINAL
+  : public BluetoothA2dpInterface
+{
+  class CleanupResultHandler;
+  class InitResultHandler;
+
+public:
+  BluetoothDaemonA2dpInterface(BluetoothDaemonA2dpModule* aModule);
+  ~BluetoothDaemonA2dpInterface();
+
+  void Init(
+    BluetoothA2dpNotificationHandler* aNotificationHandler,
+    BluetoothA2dpResultHandler* aRes);
+  void Cleanup(BluetoothA2dpResultHandler* aRes);
+
+  /* Connect / Disconnect */
+
+  void Connect(const nsAString& aBdAddr,
+               BluetoothA2dpResultHandler* aRes);
+  void Disconnect(const nsAString& aBdAddr,
+                  BluetoothA2dpResultHandler* aRes);
+
+private:
+  void DispatchError(BluetoothA2dpResultHandler* aRes,
+                     BluetoothStatus aStatus);
+
+  BluetoothDaemonA2dpModule* mModule;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp
@@ -93,16 +93,47 @@ Convert(uint8_t aIn, char& aOut)
 nsresult
 Convert(uint8_t aIn, int& aOut)
 {
   aOut = static_cast<int>(aIn);
   return NS_OK;
 }
 
 nsresult
+Convert(uint8_t aIn, BluetoothA2dpAudioState& aOut)
+{
+  static const BluetoothA2dpAudioState sAudioState[] = {
+    CONVERT(0x00, A2DP_AUDIO_STATE_REMOTE_SUSPEND),
+    CONVERT(0x01, A2DP_AUDIO_STATE_STOPPED),
+    CONVERT(0x02, A2DP_AUDIO_STATE_STARTED)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAudioState))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAudioState[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothA2dpConnectionState& aOut)
+{
+  static const BluetoothA2dpConnectionState sConnectionState[] = {
+    CONVERT(0x00, A2DP_CONNECTION_STATE_DISCONNECTED),
+    CONVERT(0x01, A2DP_CONNECTION_STATE_CONNECTING),
+    CONVERT(0x02, A2DP_CONNECTION_STATE_CONNECTED),
+    CONVERT(0x03, A2DP_CONNECTION_STATE_DISCONNECTING)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sConnectionState))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sConnectionState[aIn];
+  return NS_OK;
+}
+
+nsresult
 Convert(uint8_t aIn, BluetoothAclState& aOut)
 {
   static const BluetoothAclState sAclState[] = {
     CONVERT(0x00, ACL_STATE_CONNECTED),
     CONVERT(0x01, ACL_STATE_DISCONNECTED),
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAclState))) {
     return NS_ERROR_ILLEGAL_VALUE;
@@ -914,16 +945,30 @@ UnpackPDU(BluetoothDaemonPDU& aPDU, bool
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, char& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, char>(aOut));
 }
 
 nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothA2dpAudioState& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothA2dpAudioState>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothA2dpConnectionState& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothA2dpConnectionState>(aOut));
+}
+
+nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAclState& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, BluetoothAclState>(aOut));
 }
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothBondState& aOut)
 {
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h
@@ -94,16 +94,22 @@ Convert(uint8_t aIn, bool& aOut);
 
 nsresult
 Convert(uint8_t aIn, char& aOut);
 
 nsresult
 Convert(uint8_t aIn, int& aOut);
 
 nsresult
+Convert(uint8_t aIn, BluetoothA2dpAudioState& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothA2dpConnectionState& aOut);
+
+nsresult
 Convert(uint8_t aIn, BluetoothAclState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothBondState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothHandsfreeAudioState& aOut);
 
@@ -527,16 +533,22 @@ UnpackPDU(BluetoothDaemonPDU& aPDU, uint
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, bool& aOut);
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, char& aOut);
 
 nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothA2dpAudioState& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothA2dpConnectionState& aOut);
+
+nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAclState& aOut);
 
 inline nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAddress& aOut)
 {
   return aPDU.Read(aOut.mAddr, sizeof(aOut.mAddr));
 }
 
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "BluetoothDaemonInterface.h"
+#include "BluetoothDaemonA2dpInterface.h"
 #include "BluetoothDaemonHandsfreeInterface.h"
 #include "BluetoothDaemonHelpers.h"
 #include "BluetoothDaemonSetupInterface.h"
 #include "BluetoothDaemonSocketInterface.h"
 #include "BluetoothInterfaceHelpers.h"
 #include "mozilla/unused.h"
 
 using namespace mozilla::ipc;
@@ -1453,16 +1454,17 @@ private:
 //
 
 class BluetoothDaemonProtocol MOZ_FINAL
   : public BluetoothDaemonPDUConsumer
   , public BluetoothDaemonSetupModule
   , public BluetoothDaemonCoreModule
   , public BluetoothDaemonSocketModule
   , public BluetoothDaemonHandsfreeModule
+  , public BluetoothDaemonA2dpModule
 {
 public:
   BluetoothDaemonProtocol(BluetoothDaemonConnection* aConnection);
 
   nsresult RegisterModule(uint8_t aId, uint8_t aMode,
                           BluetoothSetupResultHandler* aRes) MOZ_OVERRIDE;
 
   nsresult UnregisterModule(uint8_t aId,
@@ -1486,16 +1488,18 @@ private:
   void HandleSetupSvc(const BluetoothDaemonPDUHeader& aHeader,
                       BluetoothDaemonPDU& aPDU, void* aUserData);
   void HandleCoreSvc(const BluetoothDaemonPDUHeader& aHeader,
                      BluetoothDaemonPDU& aPDU, void* aUserData);
   void HandleSocketSvc(const BluetoothDaemonPDUHeader& aHeader,
                        BluetoothDaemonPDU& aPDU, void* aUserData);
   void HandleHandsfreeSvc(const BluetoothDaemonPDUHeader& aHeader,
                           BluetoothDaemonPDU& aPDU, void* aUserData);
+  void HandleA2dpSvc(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU, void* aUserData);
 
   BluetoothDaemonConnection* mConnection;
   nsTArray<void*> mUserDataQ;
 };
 
 BluetoothDaemonProtocol::BluetoothDaemonProtocol(
   BluetoothDaemonConnection* aConnection)
   : mConnection(aConnection)
@@ -1555,30 +1559,40 @@ void
 BluetoothDaemonProtocol::HandleHandsfreeSvc(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
   void* aUserData)
 {
   BluetoothDaemonHandsfreeModule::HandleSvc(aHeader, aPDU, aUserData);
 }
 
 void
+BluetoothDaemonProtocol::HandleA2dpSvc(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  void* aUserData)
+{
+  BluetoothDaemonA2dpModule::HandleSvc(aHeader, aPDU, aUserData);
+}
+
+void
 BluetoothDaemonProtocol::Handle(BluetoothDaemonPDU& aPDU)
 {
   static void (BluetoothDaemonProtocol::* const HandleSvc[])(
     const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&, void*) = {
     INIT_ARRAY_AT(BluetoothDaemonSetupModule::SERVICE_ID,
       &BluetoothDaemonProtocol::HandleSetupSvc),
     INIT_ARRAY_AT(BluetoothDaemonCoreModule::SERVICE_ID,
       &BluetoothDaemonProtocol::HandleCoreSvc),
     INIT_ARRAY_AT(BluetoothDaemonSocketModule::SERVICE_ID,
       &BluetoothDaemonProtocol::HandleSocketSvc),
     INIT_ARRAY_AT(0x03, nullptr), // HID host
     INIT_ARRAY_AT(0x04, nullptr), // PAN
     INIT_ARRAY_AT(BluetoothDaemonHandsfreeModule::SERVICE_ID,
-      &BluetoothDaemonProtocol::HandleHandsfreeSvc)
+      &BluetoothDaemonProtocol::HandleHandsfreeSvc),
+    INIT_ARRAY_AT(BluetoothDaemonA2dpModule::SERVICE_ID,
+      &BluetoothDaemonProtocol::HandleA2dpSvc)
   };
 
   BluetoothDaemonPDUHeader header;
 
   if (NS_FAILED(UnpackPDU(aPDU, header)) ||
       NS_WARN_IF(!(header.mService < MOZ_ARRAY_LENGTH(HandleSvc))) ||
       NS_WARN_IF(!(HandleSvc[header.mService]))) {
     return;
@@ -2153,17 +2167,23 @@ BluetoothDaemonInterface::GetBluetoothHa
   mHandsfreeInterface = new BluetoothDaemonHandsfreeInterface(mProtocol);
 
   return mHandsfreeInterface;
 }
 
 BluetoothA2dpInterface*
 BluetoothDaemonInterface::GetBluetoothA2dpInterface()
 {
-  return nullptr;
+  if (mA2dpInterface) {
+    return mA2dpInterface;
+  }
+
+  mA2dpInterface = new BluetoothDaemonA2dpInterface(mProtocol);
+
+  return mA2dpInterface;
 }
 
 BluetoothAvrcpInterface*
 BluetoothDaemonInterface::GetBluetoothAvrcpInterface()
 {
   return nullptr;
 }
 
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__
 #define mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__
 
 #include "BluetoothInterface.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothDaemonChannel;
+class BluetoothDaemonA2dpInterface;
 class BluetoothDaemonHandsfreeInterface;
 class BluetoothDaemonProtocol;
 class BluetoothDaemonSocketInterface;
 
 class BluetoothDaemonInterface MOZ_FINAL : public BluetoothInterface
 {
 public:
   class CleanupResultHandler;
@@ -123,13 +124,14 @@ private:
   nsAutoPtr<BluetoothDaemonChannel> mCmdChannel;
   nsAutoPtr<BluetoothDaemonChannel> mNtfChannel;
   nsAutoPtr<BluetoothDaemonProtocol> mProtocol;
 
   nsTArray<nsRefPtr<BluetoothResultHandler> > mResultHandlerQ;
 
   nsAutoPtr<BluetoothDaemonSocketInterface> mSocketInterface;
   nsAutoPtr<BluetoothDaemonHandsfreeInterface> mHandsfreeInterface;
+  nsAutoPtr<BluetoothDaemonA2dpInterface> mA2dpInterface;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth2/moz.build
+++ b/dom/bluetooth2/moz.build
@@ -46,16 +46,17 @@ if CONFIG['MOZ_B2G_BT']:
                 'bluez',
             ]
             DEFINES['MOZ_B2G_BT_BLUEZ'] = True
         elif CONFIG['MOZ_B2G_BT_BLUEDROID']:
             SOURCES += [
                 'bluedroid/BluetoothA2dpHALInterface.cpp',
                 'bluedroid/BluetoothA2dpManager.cpp',
                 'bluedroid/BluetoothAvrcpHALInterface.cpp',
+                'bluedroid/BluetoothDaemonA2dpInterface.cpp',
                 'bluedroid/BluetoothDaemonHandsfreeInterface.cpp',
                 'bluedroid/BluetoothDaemonHelpers.cpp',
                 'bluedroid/BluetoothDaemonInterface.cpp',
                 'bluedroid/BluetoothDaemonSetupInterface.cpp',
                 'bluedroid/BluetoothDaemonSocketInterface.cpp',
                 'bluedroid/BluetoothGattHALInterface.cpp',
                 'bluedroid/BluetoothGattManager.cpp',
                 'bluedroid/BluetoothHALHelpers.cpp',
deleted file mode 100644
--- a/dom/icc/tests/marionette/head.js
+++ b/dom/icc/tests/marionette/head.js
@@ -5,24 +5,96 @@ const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} =
 
 const PREF_KEY_RIL_DEBUGGING_ENABLED = "ril.debugging.enabled";
 
 // The pin code hard coded in emulator is "0000".
 const DEFAULT_PIN = "0000";
 // The puk code hard coded in emulator is "12345678".
 const DEFAULT_PUK = "12345678";
 
-// Emulate Promise.jsm semantics.
-Promise.defer = function() { return new Deferred(); }
-function Deferred() {
-  this.promise = new Promise(function(resolve, reject) {
-    this.resolve = resolve;
-    this.reject = reject;
-  }.bind(this));
-  Object.freeze(this);
+const WHT = 0xFFFFFFFF;
+const BLK = 0x000000FF;
+const RED = 0xFF0000FF;
+const GRN = 0x00FF00FF;
+const BLU = 0x0000FFFF;
+const TSP = 0;
+
+// Basic Image, see record number 1 in EFimg.
+const BASIC_ICON = {
+  width: 8,
+  height: 8,
+  codingScheme: "basic",
+  pixels: [WHT, WHT, WHT, WHT, WHT, WHT, WHT, WHT,
+           BLK, BLK, BLK, BLK, BLK, BLK, WHT, WHT,
+           WHT, BLK, WHT, BLK, BLK, WHT, BLK, WHT,
+           WHT, BLK, BLK, WHT, WHT, BLK, BLK, WHT,
+           WHT, BLK, BLK, WHT, WHT, BLK, BLK, WHT,
+           WHT, BLK, WHT, BLK, BLK, WHT, BLK, WHT,
+           WHT, WHT, BLK, BLK, BLK, BLK, WHT, WHT,
+           WHT, WHT, WHT, WHT, WHT, WHT, WHT, WHT]
+};
+// Color Image, see record number 3 in EFimg.
+const COLOR_ICON = {
+  width: 8,
+  height: 8,
+  codingScheme: "color",
+  pixels: [BLU, BLU, BLU, BLU, BLU, BLU, BLU, BLU,
+           BLU, RED, RED, RED, RED, RED, RED, BLU,
+           BLU, RED, GRN, GRN, GRN, RED, RED, BLU,
+           BLU, RED, RED, GRN, GRN, RED, RED, BLU,
+           BLU, RED, RED, GRN, GRN, RED, RED, BLU,
+           BLU, RED, RED, GRN, GRN, GRN, RED, BLU,
+           BLU, RED, RED, RED, RED, RED, RED, BLU,
+           BLU, BLU, BLU, BLU, BLU, BLU, BLU, BLU]
+};
+// Color Image with Transparency, see record number 5 in EFimg.
+const COLOR_TRANSPARENCY_ICON = {
+  width: 8,
+  height: 8,
+  codingScheme: "color-transparency",
+  pixels: [TSP, TSP, TSP, TSP, TSP, TSP, TSP, TSP,
+           TSP, RED, RED, RED, RED, RED, RED, TSP,
+           TSP, RED, GRN, GRN, GRN, RED, RED, TSP,
+           TSP, RED, RED, GRN, GRN, RED, RED, TSP,
+           TSP, RED, RED, GRN, GRN, RED, RED, TSP,
+           TSP, RED, RED, GRN, GRN, GRN, RED, TSP,
+           TSP, RED, RED, RED, RED, RED, RED, TSP,
+           TSP, TSP, TSP, TSP, TSP, TSP, TSP, TSP]
+};
+
+/**
+ * Helper function for checking stk icon.
+ */
+function isIcons(aIcons, aExpectedIcons) {
+  is(aIcons.length, aExpectedIcons.length, "icons.length");
+  for (let i = 0; i < aIcons.length; i++) {
+    let icon = aIcons[i];
+    let expectedIcon = aExpectedIcons[i];
+
+    is(icon.width, expectedIcon.width, "icon.width");
+    is(icon.height, expectedIcon.height, "icon.height");
+    is(icon.codingScheme, expectedIcon.codingScheme, "icon.codingScheme");
+
+    is(icon.pixels.length, expectedIcon.pixels.length);
+    for (let j = 0; j < icon.pixels.length; j++) {
+      is(icon.pixels[j], expectedIcon.pixels[j], "icon.pixels[" + j + "]");
+    }
+  }
+}
+
+/**
+ * Helper function for checking stk text.
+ */
+function isStkText(aStkText, aExpectedStkText) {
+  is(aStkText.text, aExpectedStkText.text, "stkText.text");
+  if (aExpectedStkText.icons) {
+    is(aStkText.iconSelfExplanatory, aExpectedStkText.iconSelfExplanatory,
+       "stkText.iconSelfExplanatory");
+    isIcons(aStkText.icons, aExpectedStkText.icons);
+  }
 }
 
 let _pendingEmulatorCmdCount = 0;
 
 /**
  * Send emulator command with safe guard.
  *
  * We should only call |finish()| after all emulator command transactions
@@ -35,32 +107,45 @@ let _pendingEmulatorCmdCount = 0;
  *   result -- an array of emulator response lines.
  *
  * @param aCommand
  *        A string command to be passed to emulator through its telnet console.
  *
  * @return A deferred promise.
  */
 function runEmulatorCmdSafe(aCommand) {
-  let deferred = Promise.defer();
-
-  ++_pendingEmulatorCmdCount;
-  runEmulatorCmd(aCommand, function(aResult) {
-    --_pendingEmulatorCmdCount;
+  return new Promise(function(aResolve, aReject) {
+    ++_pendingEmulatorCmdCount;
+    runEmulatorCmd(aCommand, function(aResult) {
+      --_pendingEmulatorCmdCount;
 
-    ok(true, "Emulator response: " + JSON.stringify(aResult));
-    if (Array.isArray(aResult) &&
-        aResult[aResult.length - 1] === "OK") {
-      deferred.resolve(aResult);
-    } else {
-      deferred.reject(aResult);
-    }
+      ok(true, "Emulator response: " + JSON.stringify(aResult));
+      if (Array.isArray(aResult) &&
+          aResult[aResult.length - 1] === "OK") {
+        aResolve(aResult);
+      } else {
+        aReject(aResult);
+      }
+    });
   });
+}
 
-  return deferred.promise;
+/**
+ * Send stk proactive pdu.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aPdu
+ *
+ * @return A deferred promise.
+ */
+function sendEmulatorStkPdu(aPdu) {
+  let cmd = "stk pdu " + aPdu;
+  return runEmulatorCmdSafe(cmd);
 }
 
 let workingFrame;
 let iccManager;
 
 /**
  * Push required permissions and test if
  * |navigator.mozIccManager| exists. Resolve if it does,
@@ -73,56 +158,54 @@ let iccManager;
  *
  * @param aAdditonalPermissions [optional]
  *        An array of permission strings other than "mobileconnection" to be
  *        pushed. Default: empty string.
  *
  * @return A deferred promise.
  */
 function ensureIccManager(aAdditionalPermissions) {
-  let deferred = Promise.defer();
-
-  aAdditionalPermissions = aAdditionalPermissions || [];
+  return new Promise(function(aResolve, aReject) {
+    aAdditionalPermissions = aAdditionalPermissions || [];
 
-  if (aAdditionalPermissions.indexOf("mobileconnection") < 0) {
-    aAdditionalPermissions.push("mobileconnection");
-  }
-  let permissions = [];
-  for (let perm of aAdditionalPermissions) {
-    permissions.push({ "type": perm, "allow": 1, "context": document });
-  }
+    if (aAdditionalPermissions.indexOf("mobileconnection") < 0) {
+      aAdditionalPermissions.push("mobileconnection");
+    }
+    let permissions = [];
+    for (let perm of aAdditionalPermissions) {
+      permissions.push({ "type": perm, "allow": 1, "context": document });
+    }
 
-  SpecialPowers.pushPermissions(permissions, function() {
-    ok(true, "permissions pushed: " + JSON.stringify(permissions));
+    SpecialPowers.pushPermissions(permissions, function() {
+      ok(true, "permissions pushed: " + JSON.stringify(permissions));
 
-    // Permission changes can't change existing Navigator.prototype
-    // objects, so grab our objects from a new Navigator.
-    workingFrame = document.createElement("iframe");
-    workingFrame.addEventListener("load", function load() {
-      workingFrame.removeEventListener("load", load);
+      // Permission changes can't change existing Navigator.prototype
+      // objects, so grab our objects from a new Navigator.
+      workingFrame = document.createElement("iframe");
+      workingFrame.addEventListener("load", function load() {
+        workingFrame.removeEventListener("load", load);
 
-      iccManager = workingFrame.contentWindow.navigator.mozIccManager;
+        iccManager = workingFrame.contentWindow.navigator.mozIccManager;
 
-      if (iccManager) {
-        ok(true, "navigator.mozIccManager is instance of " + iccManager.constructor);
-      } else {
-        ok(true, "navigator.mozIccManager is undefined");
-      }
+        if (iccManager) {
+          ok(true, "navigator.mozIccManager is instance of " + iccManager.constructor);
+        } else {
+          ok(true, "navigator.mozIccManager is undefined");
+        }
 
-      if (iccManager instanceof MozIccManager) {
-        deferred.resolve(iccManager);
-      } else {
-        deferred.reject();
-      }
+        if (iccManager instanceof MozIccManager) {
+          aResolve(iccManager);
+        } else {
+          aReject();
+        }
+      });
+
+      document.body.appendChild(workingFrame);
     });
-
-    document.body.appendChild(workingFrame);
   });
-
-  return deferred.promise;
 }
 
 /**
  * Get MozIcc by IccId
  *
  * @param aIccId [optional]
  *        Default: The first item of |aIccManager.iccIds|.
  *
@@ -188,27 +271,25 @@ function setRadioEnabled(aEnabled, aServ
  * @param aEventName
  *        A string event name.
  * @param aMatchFun [optional]
  *        A matching function returns true or false to filter the event.
  *
  * @return A deferred promise.
  */
 function waitForTargetEvent(aEventTarget, aEventName, aMatchFun) {
-  let deferred = Promise.defer();
-
-  aEventTarget.addEventListener(aEventName, function onevent(aEvent) {
-    if (!aMatchFun || aMatchFun(aEvent)) {
-      aEventTarget.removeEventListener(aEventName, onevent);
-      ok(true, "Event '" + aEventName + "' got.");
-      deferred.resolve(aEvent);
-    }
+  return new Promise(function(aResolve, aReject) {
+    aEventTarget.addEventListener(aEventName, function onevent(aEvent) {
+      if (!aMatchFun || aMatchFun(aEvent)) {
+        aEventTarget.removeEventListener(aEventName, onevent);
+        ok(true, "Event '" + aEventName + "' got.");
+        aResolve(aEvent);
+      }
+    });
   });
-
-  return deferred.promise;
 }
 
 /**
  * Set radio enabling state and wait for "radiostatechange" event.
  *
  * Resolve if radio state changed to the expected one. Never reject.
  *
  * Fulfill params: (none)
deleted file mode 100644
--- a/dom/icc/tests/marionette/icc_header.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
-
-SpecialPowers.addPermission("mobileconnection", true, document);
-
-let iccManager = navigator.mozIccManager;
-ok(iccManager instanceof MozIccManager,
-   "iccManager is instanceof " + iccManager.constructor);
-
-// TODO: Bug 932650 - B2G RIL: WebIccManager API - add marionette tests for
-//                    multi-sim
-// In single sim scenario, there is only one sim card, we can use below way to
-// check iccId and get icc object. But in multi-sim, the index of iccIds may
-// not map to sim slot directly, we should have a better way to handle this.
-let iccIds = iccManager.iccIds;
-ok(Array.isArray(iccIds), "iccIds is an array");
-ok(iccIds.length > 0, "iccIds.length is " + iccIds.length);
-
-let iccId = iccIds[0];
-is(iccId, "89014103211118510720", "iccId is " + iccId);
-
-let icc = iccManager.getIccById(iccId);
-ok(icc instanceof MozIcc, "icc is instanceof " + icc.constructor);
-
-/* Remove permission and execute finish() */
-let cleanUp = function() {
-  SpecialPowers.removePermission("mobileconnection", document);
-  finish();
-};
-
-/* Helper for tasks */
-let taskHelper = {
-  tasks: [],
-
-  push: function(task) {
-    this.tasks.push(task);
-  },
-
-  runNext: function() {
-    let task = this.tasks.shift();
-    if (!task) {
-      cleanUp();
-      return;
-    }
-
-    if (typeof task === "function") {
-      task();
-    }
-  },
-};
-
-/* Helper for emulator console command */
-let emulatorHelper = {
-  pendingCommandCount: 0,
-
-  sendCommand: function(cmd, callback) {
-    this.pendingCommandCount++;
-    runEmulatorCmd(cmd, function(result) {
-      this.pendingCommandCount--;
-      is(result[result.length - 1], "OK");
-
-      if (callback && typeof callback === "function") {
-        callback(result);
-      }
-    });
-  },
-};
--- a/dom/icc/tests/marionette/manifest.ini
+++ b/dom/icc/tests/marionette/manifest.ini
@@ -1,14 +1,13 @@
 [DEFAULT]
 b2g = true
 browser = false
 qemu = true
 
-[test_stk_proactive_command.js]
 [test_icc_contact.js]
 [test_icc_card_lock_get_retry_count.js]
 [test_icc_card_lock_change_pin.js]
 [test_icc_card_lock_enable_pin.js]
 [test_icc_card_lock_unlock_pin.js]
 [test_icc_card_lock_unlock_puk.js]
 [test_icc_card_state.js]
 [test_icc_info.js]
@@ -23,12 +22,14 @@ qemu = true
 [test_stk_launch_browser.js]
 [test_stk_display_text.js]
 [test_stk_get_inkey.js]
 [test_stk_get_input.js]
 [test_stk_select_item.js]
 [test_stk_setup_menu.js]
 [test_stk_setup_idle_mode_text.js]
 [test_stk_bip_command.js]
+[test_stk_local_info.js]
+[test_stk_timer_management.js]
 [test_icc_access_invalid_object.js]
 [test_icc_detected_undetected_event.js]
 [test_icc_match_mvno.js]
 [test_icc_service_state.js]
deleted file mode 100644
--- a/dom/icc/tests/marionette/stk_helper.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_TIMEOUT = 30000;
-
-SpecialPowers.addPermission("mobileconnection", true, document);
-
-const WHT = 0xFFFFFFFF;
-const BLK = 0x000000FF;
-const RED = 0xFF0000FF;
-const GRN = 0x00FF00FF;
-const BLU = 0x0000FFFF;
-const TSP = 0;
-
-let iccManager = navigator.mozIccManager;
-ok(iccManager instanceof MozIccManager,
-   "iccManager is instanceof " + iccManager.constructor);
-
-// TODO: Bug 932650 - B2G RIL: WebIccManager API - add marionette tests for
-//                    multi-sim
-// In single sim scenario, there is only one sim card, we can use below way to
-// check iccId and get icc object. But in multi-sim, the index of iccIds may
-// not map to sim slot directly, we should have a better way to handle this.
-let iccIds = iccManager.iccIds;
-ok(Array.isArray(iccIds), "iccIds is an array");
-ok(iccIds.length > 0, "iccIds.length is " + iccIds.length);
-
-let iccId = iccIds[0];
-is(iccId, "89014103211118510720", "iccId is " + iccId);
-
-let icc = iccManager.getIccById(iccId);
-ok(icc instanceof MozIcc, "icc is instanceof " + icc.constructor);
-
-
-// Basic Image, see record number 1 in EFimg.
-let basicIcon = {
-  width: 8,
-  height: 8,
-  codingScheme: "basic",
-  pixels: [WHT, WHT, WHT, WHT, WHT, WHT, WHT, WHT,
-           BLK, BLK, BLK, BLK, BLK, BLK, WHT, WHT,
-           WHT, BLK, WHT, BLK, BLK, WHT, BLK, WHT,
-           WHT, BLK, BLK, WHT, WHT, BLK, BLK, WHT,
-           WHT, BLK, BLK, WHT, WHT, BLK, BLK, WHT,
-           WHT, BLK, WHT, BLK, BLK, WHT, BLK, WHT,
-           WHT, WHT, BLK, BLK, BLK, BLK, WHT, WHT,
-           WHT, WHT, WHT, WHT, WHT, WHT, WHT, WHT]
-};
-// Color Image, see record number 3 in EFimg.
-let colorIcon = {
-  width: 8,
-  height: 8,
-  codingScheme: "color",
-  pixels: [BLU, BLU, BLU, BLU, BLU, BLU, BLU, BLU,
-           BLU, RED, RED, RED, RED, RED, RED, BLU,
-           BLU, RED, GRN, GRN, GRN, RED, RED, BLU,
-           BLU, RED, RED, GRN, GRN, RED, RED, BLU,
-           BLU, RED, RED, GRN, GRN, RED, RED, BLU,
-           BLU, RED, RED, GRN, GRN, GRN, RED, BLU,
-           BLU, RED, RED, RED, RED, RED, RED, BLU,
-           BLU, BLU, BLU, BLU, BLU, BLU, BLU, BLU]
-};
-// Color Image with Transparency, see record number 5 in EFimg.
-let colorTransparencyIcon = {
-  width: 8,
-  height: 8,
-  codingScheme: "color-transparency",
-  pixels: [TSP, TSP, TSP, TSP, TSP, TSP, TSP, TSP,
-           TSP, RED, RED, RED, RED, RED, RED, TSP,
-           TSP, RED, GRN, GRN, GRN, RED, RED, TSP,
-           TSP, RED, RED, GRN, GRN, RED, RED, TSP,
-           TSP, RED, RED, GRN, GRN, RED, RED, TSP,
-           TSP, RED, RED, GRN, GRN, GRN, RED, TSP,
-           TSP, RED, RED, RED, RED, RED, RED, TSP,
-           TSP, TSP, TSP, TSP, TSP, TSP, TSP, TSP]
-};
-
-function isIcons(icons, expectedIcons, message) {
-  is(icons.length, expectedIcons.length, message);
-  for (let i = 0; i < icons.length; i++) {
-    let icon = icons[i];
-    let expectedIcon = expectedIcons[i];
-
-    is(icon.width, expectedIcon.width, message);
-    is(icon.height, expectedIcon.height, message);
-    is(icon.codingScheme, expectedIcon.codingScheme, message);
-
-    is(icon.pixels.length, expectedIcon.pixels.length);
-    for (let j = 0; j < icon.pixels.length; j++) {
-      is(icon.pixels[j], expectedIcon.pixels[j], message);
-    }
-  }
-}
-
-function isStkText(stkText, expectedStkText, message) {
-  is(stkText.text, expectedStkText.text, message);
-  if (expectedStkText.icons) {
-    is(stkText.iconSelfExplanatory, expectedStkText.iconSelfExplanatory, message);
-    isIcons(stkText.icons, expectedStkText.icons, message);
-  }
-}
-
-let pendingEmulatorCmdCount = 0;
-function sendStkPduToEmulator(command, func, expect) {
-  ++pendingEmulatorCmdCount;
-
-  runEmulatorCmd(command, function(result) {
-    --pendingEmulatorCmdCount;
-    is(result[0], "OK");
-  });
-
-  icc.onstkcommand = function(evt) {
-    if (expect) {
-      func(evt.command, expect);
-    } else {
-      func(evt.command);
-    }
-  }
-}
-
-function runNextTest() {
-  let test = tests.pop();
-  if (!test) {
-    cleanUp();
-    return;
-  }
-
-  let command = "stk pdu " + test.command;
-  sendStkPduToEmulator(command, test.func, test.expect);
-}
-
-function cleanUp() {
-  if (pendingEmulatorCmdCount) {
-    window.setTimeout(cleanUp, 100);
-    return;
-  }
-
-  SpecialPowers.removePermission("mobileconnection", document);
-  finish();
-}
--- a/dom/icc/tests/marionette/test_icc_access_invalid_object.js
+++ b/dom/icc/tests/marionette/test_icc_access_invalid_object.js
@@ -1,114 +1,101 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 30000;
-MARIONETTE_HEAD_JS = "icc_header.js";
+MARIONETTE_HEAD_JS = "head.js";
+
+function testInvalidIccObject(aIcc) {
+  // Test access iccInfo.
+  try {
+    is(aIcc.iccInfo, null, "iccInfo: expect to get null");
+  } catch(e) {
+    ok(false, "access iccInfo should not get exception");
+  }
+
+  // Test access cardState.
+  try {
+    is(aIcc.cardState, null, "cardState: expect to get null");
+  } catch(e) {
+    ok(false, "access cardState should not get exception");
+  }
 
-function setRadioEnabled(enabled) {
-  let connection = navigator.mozMobileConnections[0];
-  ok(connection);
-
-  let request  = connection.setRadioEnabled(enabled);
+  // Test STK related function.
+  try {
+    aIcc.sendStkResponse({}, {});
+    ok(false, "sendStkResponse() should get exception");
+  } catch(e) {}
+  try {
+    aIcc.sendStkMenuSelection(0, false);
+    ok(false, "sendStkMenuSelection() should get exception");
+  } catch(e) {}
+  try {
+    aIcc.sendStkTimerExpiration({});
+    ok(false, "sendStkTimerExpiration() should get exception");
+  } catch(e) {}
+  try {
+    aIcc.sendStkEventDownload({});
+    ok(false, "sendStkEventDownload() should get exception");
+  } catch(e) {}
 
-  request.onsuccess = function onsuccess() {
-    log('setRadioEnabled: ' + enabled);
-  };
+  // Test card lock related function.
+  try {
+    aIcc.getCardLock("pin");
+    ok(false, "getCardLock() should get exception");
+  } catch(e) {}
+  try {
+    aIcc.unlockCardLock({});
+    ok(false, "unlockCardLock() should get exception");
+  } catch(e) {}
+  try {
+    aIcc.setCardLock({});
+    ok(false, "setCardLock() should get exception");
+  } catch(e) {}
+  try {
+    aIcc.getCardLockRetryCount("pin");
+    ok(false, "getCardLockRetryCount() should get exception");
+  } catch(e) {}
 
-  request.onerror = function onerror() {
-    ok(false, "setRadioEnabled should be ok");
-  };
+  // Test contact related function.
+  try {
+    aIcc.readContacts("adn");
+    ok(false, "readContacts() should get exception");
+  } catch(e) {}
+  try {
+    aIcc.updateContact("adn", {});
+    ok(false, "updateContact() should get exception");
+  } catch(e) {}
+
+  // Test mvno function.
+  try {
+    aIcc.matchMvno("imsi");
+    ok(false, "matchMvno() should get exception");
+  } catch(e) {}
+
+  // Test service state function.
+  return aIcc.getServiceState("fdn").then(() => {
+    ok(false, "getServiceState() should be rejected");
+  }, () => {});
 }
 
-/* Test access invalid icc object */
-taskHelper.push(function testAccessRemovedIccObject() {
-  setRadioEnabled(false);
-  iccManager.addEventListener("iccundetected", function oniccundetected(evt) {
-    log("got icc undetected event");
-    iccManager.removeEventListener("iccundetected", oniccundetected);
-    is(evt.iccId, iccId, "icc " + evt.iccId + " becomes undetected");
-
-    // Test access iccInfo.
-    try {
-      is(icc.iccInfo, null, "iccInfo: expect to get null");
-    } catch(e) {
-      ok(false, "access iccInfo should not get exception");
-    }
-
-    // Test access cardState.
-    try {
-      is(icc.cardState, null, "cardState: expect to get null");
-    } catch(e) {
-      ok(false, "access cardState should not get exception");
-    }
-
-    // Test STK related function.
-    try {
-      icc.sendStkResponse({}, {});
-      ok(false, "sendStkResponse() should get exception");
-    } catch(e) {}
-    try {
-      icc.sendStkMenuSelection(0, false);
-      ok(false, "sendStkMenuSelection() should get exception");
-    } catch(e) {}
-    try {
-      icc.sendStkTimerExpiration({});
-      ok(false, "sendStkTimerExpiration() should get exception");
-    } catch(e) {}
-    try {
-      icc.sendStkEventDownload({});
-      ok(false, "sendStkEventDownload() should get exception");
-    } catch(e) {}
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
 
-    // Test card lock related function.
-    try {
-      icc.getCardLock("");
-      ok(false, "getCardLock() should get exception");
-    } catch(e) {}
-    try {
-      icc.unlockCardLock({});
-      ok(false, "unlockCardLock() should get exception");
-    } catch(e) {}
-    try {
-      icc.setCardLock({});
-      ok(false, "setCardLock() should get exception");
-    } catch(e) {}
-    try {
-      icc.getCardLockRetryCount("");
-      ok(false, "getCardLockRetryCount() should get exception");
-    } catch(e) {}
-
-    // Test contact related function.
-    try {
-      icc.readContacts("");
-      ok(false, "readContacts() should get exception");
-    } catch(e) {}
-    try {
-      icc.updateContact("", {});
-      ok(false, "updateContact() should get exception");
-    } catch(e) {}
-
-    // Test secure element related function.
-    try {
-      icc.iccOpenChannel("");
-      ok(false, "iccOpenChannel() should get exception");
-    } catch(e) {}
-    try {
-      icc.iccExchangeAPDU(0, {});
-      ok(false, "iccExchangeAPDU() should get exception");
-    } catch(e) {}
-    try {
-      icc.iccCloseChannel(0);
-      ok(false, "iccCloseChannel() should get exception");
-    } catch(e) {}
-
+  return Promise.resolve()
+    // Turn off radio.
+    .then(() => {
+      let promises = [];
+      promises.push(setRadioEnabled(false));
+      promises.push(waitForTargetEvent(iccManager, "iccundetected"));
+      return Promise.all(promises);
+    })
+    // Test accessing invalid icc object.
+    .then(() => testInvalidIccObject(icc))
     // We should restore the radio status.
-    setRadioEnabled(true);
-    iccManager.addEventListener("iccdetected", function oniccdetected(evt) {
-      iccManager.removeEventListener("iccdetected", oniccdetected);
-      taskHelper.runNext();
+    .then(() => {
+      let promises = [];
+      promises.push(setRadioEnabled(true));
+      promises.push(waitForTargetEvent(iccManager, "iccdetected"));
+      return Promise.all(promises);
     });
-  });
 });
-
-// Start test
-taskHelper.runNext();
--- a/dom/icc/tests/marionette/test_icc_card_state.js
+++ b/dom/icc/tests/marionette/test_icc_card_state.js
@@ -1,49 +1,32 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 30000;
-MARIONETTE_HEAD_JS = "icc_header.js";
-
-function setRadioEnabled(enabled) {
-  let connection = navigator.mozMobileConnections[0];
-  ok(connection);
-
-  let request  = connection.setRadioEnabled(enabled);
+MARIONETTE_HEAD_JS = "head.js";
 
-  request.onsuccess = function onsuccess() {
-    log('setRadioEnabled: ' + enabled);
-  };
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
 
-  request.onerror = function onerror() {
-    ok(false, "setRadioEnabled should be ok");
-  };
-}
-
-/* Basic test */
-taskHelper.push(function basicTest() {
+  // Basic test.
   is(icc.cardState, "ready", "card state is " + icc.cardState);
-  taskHelper.runNext();
-});
 
-/* Test cardstatechange event by switching radio off */
-taskHelper.push(function testCardStateChange() {
-  // Turn off radio.
-  setRadioEnabled(false);
-  icc.addEventListener("cardstatechange", function oncardstatechange() {
-    log("card state changes to " + icc.cardState);
-    // Expect to get card state changing to null.
-    if (icc.cardState === null) {
-      icc.removeEventListener("cardstatechange", oncardstatechange);
-      // We should restore radio status and expect to get iccdetected event.
-      setRadioEnabled(true);
-      iccManager.addEventListener("iccdetected", function oniccdetected(evt) {
-        log("icc iccdetected: " + evt.iccId);
-        iccManager.removeEventListener("iccdetected", oniccdetected);
-        taskHelper.runNext();
-      });
-    }
-  });
+  // Test cardstatechange event by switching radio off.
+  return Promise.resolve()
+    // Turn off radio and expect to get card state changing to null.
+    .then(() => {
+      let promises = [];
+      promises.push(setRadioEnabled(false));
+      promises.push(waitForTargetEvent(icc, "cardstatechange", function() {
+        return icc.cardState === null;
+      }));
+      return Promise.all(promises);
+    })
+    // Restore radio status and expect to get iccdetected event.
+    .then(() => {
+      let promises = [];
+      promises.push(setRadioEnabled(true));
+      promises.push(waitForTargetEvent(iccManager, "iccdetected"));
+      return Promise.all(promises);
+    });
 });
-
-// Start test
-taskHelper.runNext();
--- a/dom/icc/tests/marionette/test_icc_contact.js
+++ b/dom/icc/tests/marionette/test_icc_contact.js
@@ -1,120 +1,81 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 60000;
-MARIONETTE_HEAD_JS = "icc_header.js";
-
-const EMULATOR_ICCID = "89014103211118510720";
+MARIONETTE_HEAD_JS = "head.js";
 
-function testReadContacts(type) {
-  let request = icc.readContacts(type);
-  request.onsuccess = function onsuccess() {
-    let contacts = request.result;
+function testReadContacts(aIcc, aType) {
+  log("testReadContacts: type=" + aType);
+  let iccId = aIcc.iccInfo.iccid;
+  return aIcc.readContacts(aType)
+    .then((aResult) => {
+      is(Array.isArray(aResult), true);
 
-    is(Array.isArray(contacts), true);
-
-    is(contacts[0].name[0], "Mozilla");
-    is(contacts[0].tel[0].value, "15555218201");
-    is(contacts[0].id, EMULATOR_ICCID + "1");
+      is(aResult[0].name[0], "Mozilla");
+      is(aResult[0].tel[0].value, "15555218201");
+      is(aResult[0].id, iccId + "1");
 
-    is(contacts[1].name[0], "Saßê黃");
-    is(contacts[1].tel[0].value, "15555218202");
-    is(contacts[1].id, EMULATOR_ICCID + "2");
-
-    is(contacts[2].name[0], "Fire 火");
-    is(contacts[2].tel[0].value, "15555218203");
-    is(contacts[2].id, EMULATOR_ICCID + "3");
+      is(aResult[1].name[0], "Saßê黃");
+      is(aResult[1].tel[0].value, "15555218202");
+      is(aResult[1].id, iccId + "2");
 
-    is(contacts[3].name[0], "Huang 黃");
-    is(contacts[3].tel[0].value, "15555218204");
-    is(contacts[3].id, EMULATOR_ICCID + "4");
+      is(aResult[2].name[0], "Fire 火");
+      is(aResult[2].tel[0].value, "15555218203");
+      is(aResult[2].id, iccId + "3");
 
-    taskHelper.runNext();
-  };
-
-  request.onerror = function onerror() {
-    ok(false, "Cannot get " + type + " contacts");
-    taskHelper.runNext();
-  };
+      is(aResult[3].name[0], "Huang 黃");
+      is(aResult[3].tel[0].value, "15555218204");
+      is(aResult[3].id, iccId + "4");
+    }, (aError) => {
+      ok(false, "Cannot get " + aType + " contacts");
+    });
 }
 
-function testAddContact(type, pin2) {
+function testAddContact(aIcc, aType, aPin2) {
+  log("testAddContact: type=" + aType + ", pin2=" + aPin2);
   let contact = new mozContact({
     name: ["add"],
     tel: [{value: "0912345678"}],
     email:[]
   });
 
-  let updateRequest = icc.updateContact(type, contact, pin2);
-
-  updateRequest.onsuccess = function onsuccess() {
-    let updatedContact = updateRequest.result;
-    ok(updatedContact, "updateContact should have retuend a mozContact.");
-    ok(updatedContact.id.startsWith(EMULATOR_ICCID),
-       "The returned mozContact has wrong id.");
-
-    // Get ICC contact for checking new contact
-
-    let getRequest = icc.readContacts(type);
-
-    getRequest.onsuccess = function onsuccess() {
-      let contacts = getRequest.result;
-
-      // There are 4 SIM contacts which are harded in emulator
-      is(contacts.length, 5);
+  return aIcc.updateContact(aType, contact, aPin2)
+    .then((aResult) => {
+      // Get ICC contact for checking new contact
+      return aIcc.readContacts(aType)
+        .then((aResult) => {
+          // There are 4 SIM contacts which are harded in emulator
+          is(aResult.length, 5);
 
-      is(contacts[4].name[0], "add");
-      is(contacts[4].tel[0].value, "0912345678");
-
-      taskHelper.runNext();
-    };
-
-    getRequest.onerror = function onerror() {
-      ok(false, "Cannot get " + type + " contacts: " + getRequest.error.name);
-      taskHelper.runNext();
-    };
-  };
-
-  updateRequest.onerror = function onerror() {
-    if (type === "fdn" && pin2 === undefined) {
-      ok(updateRequest.error.name === "SimPin2",
-         "expected error when pin2 is not provided");
-    } else {
-      ok(false, "Cannot add " + type + " contact: " + updateRequest.error.name);
-    }
-    taskHelper.runNext();
-  };
+          is(aResult[4].name[0], "add");
+          is(aResult[4].tel[0].value, "0912345678");
+        }, (aError) => {
+          ok(false, "Cannot get " + aType + " contacts: " + aError.name);
+        })
+    }, (aError) => {
+      if (aType === "fdn" && aPin2 === undefined) {
+        ok(aError.name === "SimPin2",
+           "expected error when pin2 is not provided");
+      } else {
+        ok(false, "Cannot add " + aType + " contact: " + aError.name);
+      }
+    });
 }
 
-/* Test read adn contacts */
-taskHelper.push(function testReadAdnContacts() {
-  testReadContacts("adn");
-});
-
-/* Test add adn contacts */
-taskHelper.push(function testAddAdnContact() {
-  testAddContact("adn");
-});
-
-/* Test read fdn contacts */
-taskHelper.push(function testReadAdnContacts() {
-  testReadContacts("fdn");
-});
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
 
-/* Test add fdn contacts */
-taskHelper.push(function testReadAdnContacts() {
-  testAddContact("fdn", "0000");
-});
-
-/* Test add fdn contacts without passing pin2 */
-taskHelper.push(function testReadAdnContacts() {
-  testAddContact("fdn");
+  // Test read adn contacts
+  return testReadContacts(icc, "adn")
+    // Test add adn contacts
+    .then(() => testAddContact(icc, "adn"))
+    // Test read fdn contact
+    .then(() => testReadContacts(icc, "fdn"))
+    // Test add fdn contacts
+    .then(() => testAddContact(icc, "fdn", "0000"))
+    // Test add fdn contacts without passing pin2
+    .then(() => testAddContact(icc, "fdn"))
+    // Test read sdn contacts
+    .then(() => testReadContacts(icc, "sdn"));
 });
-
-/* Test read sdn contacts */
-taskHelper.push(function testReadSdnContacts() {
-  testReadContacts("sdn");
-});
-
-// Start test
-taskHelper.runNext();
--- a/dom/icc/tests/marionette/test_icc_detected_undetected_event.js
+++ b/dom/icc/tests/marionette/test_icc_detected_undetected_event.js
@@ -1,67 +1,51 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 30000;
-MARIONETTE_HEAD_JS = "icc_header.js";
-
-let origNumICCs = iccManager.iccIds.length;
+MARIONETTE_HEAD_JS = "head.js";
 
-function setRadioEnabled(enabled) {
-  let connection = navigator.mozMobileConnections[0];
-  ok(connection);
-
-  let request  = connection.setRadioEnabled(enabled);
-
-  request.onsuccess = function onsuccess() {
-    log('setRadioEnabled: ' + enabled);
-  };
+// Start tests
+startTestCommon(function() {
+  let origNumIccs = iccManager.iccIds.length;
+  let icc = getMozIcc();
+  let iccId = icc.iccInfo.iccid;
+  let mobileConnection = getMozMobileConnectionByServiceId();
 
-  request.onerror = function onerror() {
-    ok(false, "setRadioEnabled should be ok");
-  };
-}
+  return Promise.resolve()
+    // Test iccundetected event.
+    .then(() => {
+      let promises = [];
 
-/* Test iccundetected event */
-taskHelper.push(function testIccUndetectedEvent() {
-  setRadioEnabled(false);
-  iccManager.addEventListener("iccundetected", function oniccundetected(evt) {
-    log("got icc undetected event");
-    iccManager.removeEventListener("iccundetected", oniccundetected);
-
-    is(evt.iccId, iccId, "icc " + evt.iccId + " becomes undetected");
-    is(iccManager.iccIds.length, origNumICCs - 1,
-       "iccIds.length becomes to " + iccManager.iccIds.length);
-    is(iccManager.getIccById(evt.iccId), null,
-       "should not get a valid icc object here");
+      promises.push(setRadioEnabled(false));
+      promises.push(waitForTargetEvent(iccManager, "iccundetected").then((aEvt) => {
+        is(aEvt.iccId, iccId, "icc " + aEvt.iccId + " becomes undetected");
+        is(iccManager.iccIds.length, origNumIccs - 1,
+           "iccIds.length becomes to " + iccManager.iccIds.length);
+        is(iccManager.getIccById(aEvt.iccId), null,
+           "should not get a valid icc object here");
 
-    // The mozMobileConnection.iccId should be in sync.
-    is(navigator.mozMobileConnections[0].iccId, null,
-       "check mozMobileConnection.iccId");
+        // The mozMobileConnection.iccId should be in sync.
+        is(mobileConnection.iccId, null, "check mozMobileConnection.iccId");
+      }));
 
-    taskHelper.runNext();
-  });
-});
-
-/* Test iccdetected event */
-taskHelper.push(function testIccDetectedEvent() {
-  setRadioEnabled(true);
-  iccManager.addEventListener("iccdetected", function oniccdetected(evt) {
-    log("got icc detected event");
-    iccManager.removeEventListener("iccdetected", oniccdetected);
+      return Promise.all(promises);
+    })
+    // Test iccdetected event.
+    .then(() => {
+      let promises = [];
 
-    is(evt.iccId, iccId, "icc " + evt.iccId + " is detected");
-    is(iccManager.iccIds.length, origNumICCs,
-       "iccIds.length becomes to " + iccManager.iccIds.length);
-    ok(iccManager.getIccById(evt.iccId) instanceof MozIcc,
-       "should get a valid icc object here");
+      promises.push(setRadioEnabled(true));
+      promises.push(waitForTargetEvent(iccManager, "iccdetected").then((aEvt) => {
+        is(aEvt.iccId, iccId, "icc " + aEvt.iccId + " is detected");
+        is(iccManager.iccIds.length, origNumIccs,
+           "iccIds.length becomes to " + iccManager.iccIds.length);
+        ok(iccManager.getIccById(aEvt.iccId) instanceof MozIcc,
+           "should get a valid icc object here");
 
-    // The mozMobileConnection.iccId should be in sync.
-    is(navigator.mozMobileConnections[0].iccId, iccId,
-       "check mozMobileConnection.iccId");
+        // The mozMobileConnection.iccId should be in sync.
+        is(mobileConnection.iccId, iccId, "check mozMobileConnection.iccId");
+      }));
 
-    taskHelper.runNext();
-  });
+      return Promise.all(promises);
+    });
 });
-
-// Start test
-taskHelper.runNext();
--- a/dom/icc/tests/marionette/test_icc_info.js
+++ b/dom/icc/tests/marionette/test_icc_info.js
@@ -1,85 +1,64 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 30000;
-MARIONETTE_HEAD_JS = "icc_header.js";
-
-function setRadioEnabled(enabled) {
-  let connection = navigator.mozMobileConnections[0];
-  ok(connection);
-
-  let request  = connection.setRadioEnabled(enabled);
-
-  request.onsuccess = function onsuccess() {
-    log('setRadioEnabled: ' + enabled);
-  };
-
-  request.onerror = function onerror() {
-    ok(false, "setRadioEnabled should be ok");
-  };
-}
-
-function setEmulatorMccMnc(mcc, mnc) {
-  let cmd = "operator set 0 Android,Android," + mcc + mnc;
-  emulatorHelper.sendCommand(cmd, function(result) {
-    let re = new RegExp("" + mcc + mnc + "$");
-    ok(result[0].match(re), "MCC/MNC should be changed.");
-  });
-}
+MARIONETTE_HEAD_JS = "head.js";
 
 /* Basic test */
-taskHelper.push(function basicTest() {
-  let iccInfo = icc.iccInfo;
+function basicTest(aIcc) {
+  let iccInfo = aIcc.iccInfo;
 
   // The emulator's hard coded iccid value.
   // See it here {B2G_HOME}/external/qemu/telephony/sim_card.c#L299.
   is(iccInfo.iccid, 89014103211118510720);
 
   if (iccInfo instanceof MozGsmIccInfo) {
     log("Test Gsm IccInfo");
     is(iccInfo.iccType, "sim");
     is(iccInfo.spn, "Android");
     // The emulator's hard coded mcc and mnc codes.
     // See it here {B2G_HOME}/external/qemu/telephony/android_modem.c#L2465.
     is(iccInfo.mcc, 310);
     is(iccInfo.mnc, 260);
     // Phone number is hardcoded in MSISDN
-    // See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io()
+    // See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io().
     is(iccInfo.msisdn, "15555215554");
   } else {
     log("Test Cdma IccInfo");
     is(iccInfo.iccType, "ruim");
     // MDN is hardcoded as "8587777777".
     // See it here {B2G_HOME}/hardware/ril/reference-ril/reference-ril.c,
-    // in requestCdmaSubscription()
+    // in requestCdmaSubscription().
     is(iccInfo.mdn, "8587777777");
     // PRL version is hardcoded as 1.
     // See it here {B2G_HOME}/hardware/ril/reference-ril/reference-ril.c,
-    // in requestCdmaSubscription()
+    // in requestCdmaSubscription().
     is(iccInfo.prlVersion, 1);
   }
+}
 
-  taskHelper.runNext();
-});
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
 
-/* Test iccInfo when card becomes undetected */
-taskHelper.push(function testCardIsNotReady() {
-  // Turn off radio.
-  setRadioEnabled(false);
-  icc.addEventListener("iccinfochange", function oniccinfochange() {
-    // Expect iccInfo changes to null
-    if (icc.iccInfo === null) {
-      icc.removeEventListener("iccinfochange", oniccinfochange);
-      // We should restore radio status and expect to get iccdetected event.
-      setRadioEnabled(true);
-      iccManager.addEventListener("iccdetected", function oniccdetected(evt) {
-        log("icc detected: " + evt.iccId);
-        iccManager.removeEventListener("iccdetected", oniccdetected);
-        taskHelper.runNext();
-      });
-    }
-  });
+  return Promise.resolve()
+    // Basic test
+    .then(() => basicTest(icc))
+    // Test iccInfo when card becomes undetected
+    .then(() => {
+      let promises = [];
+      promises.push(setRadioEnabled(false));
+      promises.push(waitForTargetEvent(icc, "iccinfochange", function() {
+        // Expect iccInfo changes to null
+        return icc.iccInfo === null;
+      }));
+      return Promise.all(promises);
+    })
+    // Restore radio status and expect to get iccdetected event.
+    .then(() => {
+      let promises = [];
+      promises.push(setRadioEnabled(true));
+      promises.push(waitForTargetEvent(iccManager, "iccdetected"));
+      return Promise.all(promises);
+    });
 });
-
-// Start test
-taskHelper.runNext();
--- a/dom/icc/tests/marionette/test_icc_match_mvno.js
+++ b/dom/icc/tests/marionette/test_icc_match_mvno.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 30000;
-MARIONETTE_HEAD_JS = "icc_header.js";
+MARIONETTE_HEAD_JS = "head.js";
 
-let testCases = [
+const TEST_DATA = [
   // mvno type, mvno data, request success, expected result
   // Emulator's hard coded IMSI: 310260000000000
   ["imsi", "3102600",            true, true               ],
   // x and X means skip the comparison.
   ["imsi", "31026xx0",           true, true               ],
   ["imsi", "310260x0x",          true, true               ],
   ["imsi", "310260X00",          true, true               ],
   ["imsi", "310260XX1",          true, false              ],
@@ -26,41 +26,32 @@ let testCases = [
   ["gid",  "A1",                 true, false              ],
   ["gid",  "5A",                 true, true               ],
   ["gid",  "5a",                 true, true               ],
   ["gid",  "5a4d",               true, true               ],
   ["gid",  "5A4D",               true, true               ],
   ["gid",  "5a4d6c",             true, false              ]
 ];
 
-function matchMvno(mvnoType, mvnoData, success, expectedResult) {
-  log("matchMvno: " + mvnoType + ", " + mvnoData);
-  let request = icc.matchMvno(mvnoType, mvnoData);
-  request.onsuccess = function onsuccess() {
-    log("onsuccess: " + request.result);
-    ok(success, "onsuccess while error expected");
-    is(request.result, expectedResult);
-    testMatchMvno();
-  }
-  request.onerror = function onerror() {
-    log("onerror: " + request.error.name);
-    ok(!success, "onerror while success expected");
-    is(request.error.name, expectedResult);
-    testMatchMvno();
-  }
+function testMatchMvno(aIcc, aMvnoType, aMvnoData, aSuccess, aExpectedResult) {
+  log("matchMvno: " + aMvnoType + ", " + aMvnoData);
+  return aIcc.matchMvno(aMvnoType, aMvnoData)
+    .then((aResult) => {
+      log("onsuccess: " + aResult);
+      ok(aSuccess, "onsuccess while error expected");
+      is(aResult, aExpectedResult);
+    }, (aError) => {
+      log("onerror: " + aError.name);
+      ok(!aSuccess, "onerror while success expected");
+      is(aError.name, aExpectedResult);
+    });
 }
 
-function testMatchMvno() {
-  let testCase = testCases.shift();
-  if (!testCase) {
-    taskHelper.runNext();
-    return;
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
+  let promise = Promise.resolve();
+  for (let i = 0; i < TEST_DATA.length; i++) {
+    let data = TEST_DATA[i];
+    promise = promise.then(() => testMatchMvno.apply(null, [icc].concat(data)));
   }
-  matchMvno(testCase[0], testCase[1], testCase[2], testCase[3]);
-}
-
-taskHelper.push(
-  testMatchMvno
-);
-
-// Start test
-taskHelper.runNext();
-
+  return promise;
+});
--- a/dom/icc/tests/marionette/test_stk_bip_command.js
+++ b/dom/icc/tests/marionette/test_stk_bip_command.js
@@ -1,58 +1,65 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_HEAD_JS = "stk_helper.js";
-
-function testBipCommand(command, expect) {
-  log("STK CMD " + JSON.stringify(command));
-
-  is(command.typeOfCommand, expect.typeOfCommand, expect.name);
-  is(command.options.text, expect.text, expect.name);
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-  let icons = command.options.icons;
-  if (icons) {
-    isIcons(icons, expect.icons, expect.name);
-
-    let iconSelfExplanatory = command.options.iconSelfExplanatory;
-    is(iconSelfExplanatory, expect.iconSelfExplanatory, expect.name);
-  }
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
 
-  runNextTest();
-}
-
-let tests = [
+const TEST_DATA = [
+  // Open channel.
   {command: "d04f81030140018202818205074f70656e204944350702030403041f0239020578470a065465737447700272730d08f4557365724c6f670d08f4557365725077643c0301ad9c3e0521010101019e020007",
-   func: testBipCommand,
-   expect: {name: "open_channel_1",
-            typeOfCommand: iccManager.STK_CMD_OPEN_CHANNEL,
+   expect: {typeOfCommand: MozIccManager.STK_CMD_OPEN_CHANNEL,
             text: "Open ID",
             iconSelfExplanatory: true,
-            icons: [colorIcon, colorTransparencyIcon]}},
+            icons: [COLOR_ICON, COLOR_TRANSPARENCY_ICON]}},
   {command: "d0448103014001820281820500350702030403041f0239020578470a065465737447700272730d08f4557365724c6f670d08f4557365725077643c0301ad9c3e052101010101",
-   func: testBipCommand,
-   expect: {name: "open_channel_2",
-            typeOfCommand: iccManager.STK_CMD_OPEN_CHANNEL,
+   expect: {typeOfCommand: MozIccManager.STK_CMD_OPEN_CHANNEL,
             text: ""}},
   {command: "d05381030140018202818205094f70656e2049442031350702030403041f0239020578470a065465737447700272730d08f4557365724c6f670d08f4557365725077643c0301ad9c3e052101010101d004000900b4",
-   func: testBipCommand,
-   expect: {name: "open_channel_3",
-            typeOfCommand: iccManager.STK_CMD_OPEN_CHANNEL,
+   expect: {typeOfCommand: MozIccManager.STK_CMD_OPEN_CHANNEL,
             text: "Open ID 1"}},
+  // Close channel.
   {command: "d01b810301410082028121850a436c6f73652049442031d004000a00b4",
-   func: testBipCommand,
-   expect: {name: "close_channel_1",
-            typeOfCommand: iccManager.STK_CMD_CLOSE_CHANNEL,
+   expect: {typeOfCommand: MozIccManager.STK_CMD_CLOSE_CHANNEL,
             text: "Close ID 1"}},
+  // Recive data.
   {command: "d022810301420082028121850e5265636569766520446174612031b701c8d004000e00b4",
-   func: testBipCommand,
-   expect: {name: "receive_data_1",
-            typeOfCommand: iccManager.STK_CMD_RECEIVE_DATA,
+   expect: {typeOfCommand: MozIccManager.STK_CMD_RECEIVE_DATA,
             text: "Receive Data 1"}},
+  // Send data.
   {command: "d026810301430182028121850b53656e6420446174612031b6080001020304050607d004000b00b4",
-   func: testBipCommand,
-   expect: {name: "send_data_1",
-            typeOfCommand: iccManager.STK_CMD_SEND_DATA,
+   expect: {typeOfCommand: MozIccManager.STK_CMD_SEND_DATA,
             text: "Send Data 1"}},
 ];
 
-runNextTest();
+function testBipCommand(aCommand, aExpect) {
+  is(aCommand.typeOfCommand, aExpect.typeOfCommand, "typeOfCommand");
+  is(aCommand.options.text, aExpect.text, "options.text");
+
+  if (aExpect.icons) {
+    isIcons(aCommand.options.icons, aExpect.icons);
+    is(aCommand.options.iconSelfExplanatory, aExpect.iconSelfExplanatory,
+       "options.iconSelfExplanatory");
+  }
+}
+
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
+  let promise = Promise.resolve();
+  for (let i = 0; i < TEST_DATA.length; i++) {
+    let data = TEST_DATA[i];
+    promise = promise.then(() => {
+      log("bip_cmd: " + data.command);
+
+      let promises = [];
+      // Wait onstkcommand event.
+      promises.push(waitForTargetEvent(icc, "stkcommand")
+        .then((aEvent) => testBipCommand(aEvent.command, data.expect)));
+      // Send emulator command to generate stk unsolicited event.
+      promises.push(sendEmulatorStkPdu(data.command));
+
+      return Promise.all(promises);
+    });
+  }
+  return promise;
+});
--- a/dom/icc/tests/marionette/test_stk_display_text.js
+++ b/dom/icc/tests/marionette/test_stk_display_text.js
@@ -1,198 +1,134 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_HEAD_JS = "stk_helper.js";
-
-function testDisplayText(command, expect) {
-  log("STK CMD " + JSON.stringify(command));
-  is(command.typeOfCommand, iccManager.STK_CMD_DISPLAY_TEXT, expect.name);
-  is(command.options.text, expect.text, expect.name);
-  is(command.commandQualifier, expect.commandQualifier, expect.name);
-  is(command.options.userClear, expect.userClear, expect.name);
-  is(command.options.isHighPriority, expect.isHighPriority, expect.name);
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-  let duration = command.options.duration;
-  if (duration) {
-    is(duration.timeUnit, expect.duration.timeUnit, expect.name);
-    is(duration.timeInterval, expect.duration.timeInterval, expect.name);
-  }
-
-  let icons = command.options.icons;
-  if (icons) {
-    isIcons(icons, expect.icons, expect.name);
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
 
-    let iconSelfExplanatory = command.options.iconSelfExplanatory;
-    is(iconSelfExplanatory, expect.iconSelfExplanatory, expect.name);
-  }
-
-  runNextTest();
-}
-
-let tests = [
+const TEST_DATA = [
   {command: "d01a8103012180820281028d0f04546f6f6c6b697420546573742031",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_1",
-            commandQualifier: 0x80,
+   expect: {commandQualifier: 0x80,
             text: "Toolkit Test 1",
             userClear: true}},
   {command: "d01a8103012181820281028d0f04546f6f6c6b697420546573742032",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_2",
-            commandQualifier: 0x81,
+   expect: {commandQualifier: 0x81,
             text: "Toolkit Test 2",
             isHighPriority: true,
             userClear: true}},
   {command: "d0198103012180820281028d0e00d4f79bbd4ed341d4f29c0e9a01",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_3",
-            commandQualifier: 0x80,
+   expect: {commandQualifier: 0x80,
             text: "Toolkit Test 3",
             userClear: true}},
   {command: "d01a8103012100820281028d0f04546f6f6c6b697420546573742034",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_4",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Toolkit Test 4"}},
   {command: "d081ad8103012180820281028d81a1045468697320636f6d6d616e6420696e7374727563747320746865204d4520746f20646973706c617920612074657874206d6573736167652e20497420616c6c6f7773207468652053494d20746f20646566696e6520746865207072696f72697479206f662074686174206d6573736167652c20616e6420746865207465787420737472696e6720666f726d61742e2054776f207479706573206f66207072696f",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_5",
-            commandQualifier: 0x80,
+   expect: {commandQualifier: 0x80,
             text: "This command instructs the ME to display a text message. It allows the SIM to define the priority of that message, and the text string format. Two types of prio",
             userClear: true}},
   {command: "d01a8103012180820281028d0f043c474f2d4241434b57415244533e",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_6",
-            commandQualifier: 0x80,
+   expect: {commandQualifier: 0x80,
             text: "<GO-BACKWARDS>",
             userClear: true}},
   {command: "d0248103012180820281028d1908041704140420041004120421042204120423041904220415",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_7",
-            commandQualifier: 0x80,
+   expect: {commandQualifier: 0x80,
             text: "ЗДРАВСТВУЙТЕ",
             userClear: true}},
   {command: "d0108103012180820281028d05084f60597d",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_8",
-            commandQualifier: 0x80,
+   expect: {commandQualifier: 0x80,
             text: "你好",
             userClear: true}},
   {command: "d0128103012180820281028d07080038003030eb",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_9",
-            commandQualifier: 0x80,
+   expect: {commandQualifier: 0x80,
             text: "80ル",
             userClear: true}},
   {command: "d0288103012180820281020d1d00d3309bfc06c95c301aa8e80259c3ec34b9ac07c9602f58ed159bb940",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_10",
-            commandQualifier: 0x80,
+   expect: {commandQualifier: 0x80,
             text: "Saldo 2.04 E. Validez 20/05/13. ",
             userClear: true}},
   {command: "d0198103012180820281028D0A043130205365636F6E648402010A",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_11",
-            commandQualifier: 0x80,
+   expect: {commandQualifier: 0x80,
             text: "10 Second",
             userClear: true,
-            duration: {timeUnit: iccManager.STK_TIME_UNIT_SECOND,
+            duration: {timeUnit: MozIccManager.STK_TIME_UNIT_SECOND,
                        timeInterval: 0x0A}}},
   {command: "d01a8103012180820281028d0b0442617369632049636f6e9e020001",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_12",
-            commandQualifier: 0x80,
+   expect: {commandQualifier: 0x80,
             text: "Basic Icon",
             userClear: true,
             iconSelfExplanatory: true,
-            icons: [basicIcon]}},
+            icons: [BASIC_ICON]}},
   {command: "D026810301210082028102" +
             "8D" +
             "1B" +
             "00" + // 7BIT
             "D4F79BBD4ED341D4F29C0E3A4A9F55A8" +
             "0E8687C158A09B304905",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_13",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Toolkit Test GROUP:0x00, 7BIT"}},
   {command: "D029810301210082028102" +
             "8D" +
             "1E" +
             "04" + // 8BIT
             "546F6F6C6B697420546573742047524F" +
             "55503A307830302C2038424954",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_14",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Toolkit Test GROUP:0x00, 8BIT"}},
   {command: "D046810301210082028102" +
             "8D" +
             "3B" +
             "08" + // UCS2
             "0054006F006F006C006B006900740020" +
             "0054006500730074002000470052004F" +
             "00550050003A0030007800300030002C" +
             "00200055004300530032",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_15",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Toolkit Test GROUP:0x00, UCS2"}},
   {command: "D026810301210082028102" +
             "8D" +
             "1B" +
             "12" + // 7BIT + Class 2
             "D4F79BBD4ED341D4F29C0E3A4A9F55A8" +
             "0E868FC158A09B304905",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_16",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Toolkit Test GROUP:0x10, 7BIT"}},
   {command: "D029810301210082028102" +
             "8D" +
             "1E" +
             "16" + // 8BIT + Class 2
             "546F6F6C6B697420546573742047524F" +
             "55503A307831302C2038424954",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_17",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Toolkit Test GROUP:0x10, 8BIT"}},
   {command: "D046810301210082028102" +
             "8D" +
             "3B" +
             "1A" + // UCS2 + Class 2
             "0054006F006F006C006B006900740020" +
             "0054006500730074002000470052004F" +
             "00550050003A0030007800310030002C" +
             "00200055004300530032",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_18",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Toolkit Test GROUP:0x10, UCS2"}},
   {command: "D026810301210082028102" +
             "8D" +
             "1B" +
             "F2" + // 7BIT + Class 2
             "D4F79BBD4ED341D4F29C0E3A4A9F55A8" +
             "0E8637C258A09B304905",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_19",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Toolkit Test GROUP:0xF0, 7BIT"}},
   {command: "D029810301210082028102" +
             "8D" +
             "1E" +
             "F6" + // 8BIT + Class 2
             "546F6F6C6B697420546573742047524F" +
             "55503A307846302C2038424954",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_20",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Toolkit Test GROUP:0xF0, 8BIT"}},
   // Bug 1088573: this test case is to ensure that we provide |length| argument
   // in |integer| format to GsmPDUHelper.readSeptetsToString().
   {command: "D0" +
             "81" + // 2-byte length encoded:
             "FC" + // 252
             "810301210082028102" +
             "8D" +
@@ -209,20 +145,62 @@ let tests = [
             "F5B20B24BBCD40E5391DC42E83DCEFB6" +
             "585E06B5C3F874BBDE0691CBA071581E" +
             "1ED3CBF2F21C14369BD3637458CC2EBB" +
             "40C3329D5E0699DFEE313DFD76BBC3EC" +
             "34BD0C0A83CAF432280C87CBDF757BB9" +
             "0C8287E5207619346D1E73A0783D0D9A" +
             "9FCA733A885C96BFEBEC32280C9A6689" +
             "CE621654768382D529551A64268B2E",
-   func: testDisplayText,
-   expect: {name: "display_text_cmd_21",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Ce message se compose de 273 caracteres en mode " +
                   "compresse. Ce message est affiche sur plusieurs " +
                   "ecrans et ne doit pas etre tronque. 273 est le " +
                   "nombre maximum de caracteres affichable. Cette " +
                   "fonctionnalite a ete approuvee par le SMG9 qui s'est " +
                   "deroule a SYDNEY en AUSTRALIE."}},
 ];
 
-runNextTest();
+function testDisplayText(aCommand, aExpect) {
+  is(aCommand.typeOfCommand, MozIccManager.STK_CMD_DISPLAY_TEXT,
+     "typeOfCommand");
+  is(aCommand.commandQualifier, aExpect.commandQualifier, "commandQualifier");
+  is(aCommand.options.text, aExpect.text, "options.text");
+  is(aCommand.options.userClear, aExpect.userClear, "options.userClear");
+  is(aCommand.options.isHighPriority, aExpect.isHighPriority,
+     "options.isHighPriority");
+
+  if (aExpect.duration) {
+    let duration = aCommand.options.duration;
+    is(duration.timeUnit, aExpect.duration.timeUnit,
+       "options.duration.timeUnit");
+    is(duration.timeInterval, aExpect.duration.timeInterval,
+       "options.duration.timeInterval");
+  }
+
+  if (aExpect.icons) {
+    isIcons(aCommand.options.icons, aExpect.icons);
+    is(aCommand.options.iconSelfExplanatory, aExpect.iconSelfExplanatory,
+       "options.iconSelfExplanatory");
+  }
+}
+
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
+  let promise = Promise.resolve();
+  for (let i = 0; i < TEST_DATA.length; i++) {
+    let data = TEST_DATA[i];
+    promise = promise.then(() => {
+      log("display_text_cmd: " + data.command);
+
+      let promises = [];
+      // Wait onstkcommand event.
+      promises.push(waitForTargetEvent(icc, "stkcommand")
+        .then((aEvent) => testDisplayText(aEvent.command, data.expect)));
+      // Send emulator command to generate stk unsolicited event.
+      promises.push(sendEmulatorStkPdu(data.command));
+
+      return Promise.all(promises);
+    });
+  }
+  return promise;
+});
--- a/dom/icc/tests/marionette/test_stk_get_inkey.js
+++ b/dom/icc/tests/marionette/test_stk_get_inkey.js
@@ -1,115 +1,106 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_HEAD_JS = "stk_helper.js";
-
-function testGetInKey(command, expect) {
-  log("STK CMD " + JSON.stringify(command));
-  is(command.typeOfCommand, iccManager.STK_CMD_GET_INKEY, expect.name);
-  is(command.commandQualifier, expect.commandQualifier, expect.name);
-  is(command.options.text, expect.text, expect.name);
-  is(command.options.isAlphabet, expect.isAlphabet, expect.name);
-  is(command.options.isUCS2, expect.isUCS2, expect.name);
-  is(command.options.isYesNoRequested, expect.isYesNoRequested, expect.name);
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-  let duration = command.options.duration;
-  if (duration) {
-    is(duration.timeUnit, expect.duration.timeUnit, expect.name);
-    is(duration.timeInterval, expect.duration.timeInterval, expect.name);
-  }
-
-  let icons = command.options.icons;
-  if (icons) {
-    isIcons(icons, expect.icons, expect.name);
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
 
-    let iconSelfExplanatory = command.options.iconSelfExplanatory;
-    is(iconSelfExplanatory, expect.iconSelfExplanatory, expect.name);
-  }
-
-  runNextTest();
-}
-
-let tests = [
+const TEST_DATA = [
   {command: "d0158103012200820281828d0a04456e74657220222b22",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_1",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Enter \"+\""}},
   {command: "d0148103012200820281828d09004537bd2c07896022",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_2",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Enter \"0\""}},
   {command: "d01a8103012200820281828d0f043c474f2d4241434b57415244533e",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_3",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "<GO-BACKWARDS>"}},
   {command: "d0138103012200820281828d08043c41424f52543e",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_4",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "<ABORT>"}},
   {command: "d0158103012201820281828d0a04456e74657220227122",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_5",
-            commandQualifier: 0x01,
+   expect: {commandQualifier: 0x01,
             text: "Enter \"q\"",
             isAlphabet: true}},
   {command: "d081ad8103012201820281828d81a104456e746572202278222e205468697320636f6d6d616e6420696e7374727563747320746865204d4520746f20646973706c617920746578742c20616e6420746f2065787065637420746865207573657220746f20656e74657220612073696e676c65206368617261637465722e20416e7920726573706f6e736520656e7465726564206279207468652075736572207368616c6c206265207061737365642074",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_6",
-            commandQualifier: 0x01,
+   expect: {commandQualifier: 0x01,
             text: "Enter \"x\". This command instructs the ME to display text, and to expect the user to enter a single character. Any response entered by the user shall be passed t",
             isAlphabet: true}},
   {command: "d0168103012200820281828d0b043c54494d452d4f55543e",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_7",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "<TIME-OUT>"}},
   {command: "d0248103012200820281828d1908041704140420041004120421042204120423041904220415",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_8",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "ЗДРАВСТВУЙТЕ"}},
   {command: "d081998103012200820281828d818d080417041404200410041204210422041204230419042204150417041404200410041204210422041204230419042204150417041404200410041204210422041204230419042204150417041404200410041204210422041204230419042204150417041404200410041204210422041204230419042204150417041404200410041204210422041204230419",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_9",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "ЗДРАВСТВУЙТЕЗДРАВСТВУЙТЕЗДРАВСТВУЙТЕЗДРАВСТВУЙТЕЗДРАВСТВУЙТЕЗДРАВСТВУЙ"}},
   {command: "d0118103012203820281828d0604456e746572",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_10",
-            commandQualifier: 0x03,
+   expect: {commandQualifier: 0x03,
             text: "Enter",
             isAlphabet: true,
             isUCS2: true}},
   {command: "d0158103012204820281828d0a04456e74657220594553",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_11",
-            commandQualifier: 0x04,
+   expect: {commandQualifier: 0x04,
             text: "Enter YES",
             isYesNoRequested: true}},
   {command: "d0148103012204820281828d0904456e746572204e4f",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_12",
-            commandQualifier: 0x04,
+   expect: {commandQualifier: 0x04,
             text: "Enter NO",
             isYesNoRequested: true}},
   {command: "d0198103012200820281828d0a043c4e4f2d49434f4e3e1e020002",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_13",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             // The record number 02 in EFimg is not defined, so no icon will be
             // shown, but the text string should still be displayed.
             text: "<NO-ICON>"}},
   {command: "D0198103012200820281828D0A04456E74657220222B228402010A",
-   func: testGetInKey,
-   expect: {name: "get_inkey_cmd_14",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Enter \"+\"",
-            duration: {timeUnit: iccManager.STK_TIME_UNIT_SECOND,
+            duration: {timeUnit: MozIccManager.STK_TIME_UNIT_SECOND,
                        timeInterval: 0x0A}}},
 ];
 
-runNextTest();
+function testGetInKey(aCommand, aExpect) {
+  is(aCommand.typeOfCommand, MozIccManager.STK_CMD_GET_INKEY, "typeOfCommand");
+  is(aCommand.commandQualifier, aExpect.commandQualifier, "commandQualifier");
+  is(aCommand.options.text, aExpect.text, "options.text");
+  is(aCommand.options.isAlphabet, aExpect.isAlphabet, "options.isAlphabet");
+  is(aCommand.options.isUCS2, aExpect.isUCS2, "options.isUCS2");
+  is(aCommand.options.isYesNoRequested, aExpect.isYesNoRequested,
+     "options.isYesNoRequested");
+
+  if (aExpect.duration) {
+    let duration = aCommand.options.duration;
+    is(duration.timeUnit, aExpect.duration.timeUnit,
+       "options.duration.timeUnit");
+    is(duration.timeInterval, aExpect.duration.timeInterval,
+       "options.duration.timeInterval");
+  }
+
+  if (aExpect.icons) {
+    isIcons(aCommand.options.icons, aExpect.icons);
+    is(aCommand.options.iconSelfExplanatory, aExpect.iconSelfExplanatory,
+       "options.iconSelfExplanatory");
+  }
+}
+
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
+  let promise = Promise.resolve();
+  for (let i = 0; i < TEST_DATA.length; i++) {
+    let data = TEST_DATA[i];
+    promise = promise.then(() => {
+      log("get_inkey_cmd: " + data.command);
+
+      let promises = [];
+      // Wait onstkcommand event.
+      promises.push(waitForTargetEvent(icc, "stkcommand")
+        .then((aEvent) => testGetInKey(aEvent.command, data.expect)));
+      // Send emulator command to generate stk unsolicited event.
+      promises.push(sendEmulatorStkPdu(data.command));
+
+      return Promise.all(promises);
+    });
+  }
+  return promise;
+});
--- a/dom/icc/tests/marionette/test_stk_get_input.js
+++ b/dom/icc/tests/marionette/test_stk_get_input.js
@@ -1,183 +1,169 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_HEAD_JS = "stk_helper.js";
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-function testGetInput(command, expect) {
-  log("STK CMD " + JSON.stringify(command));
-  is(command.typeOfCommand, iccManager.STK_CMD_GET_INPUT, expect.name);
-  is(command.commandQualifier, expect.commandQualifier, expect.name);
-  is(command.options.text, expect.text, expect.name);
-  is(command.options.minLength, expect.minLength, expect.name);
-  is(command.options.maxLength, expect.maxLength, expect.name);
-  if (command.options.defaultText) {
-    is(command.options.defaultText, expect.defaultText, expect.name);
-  }
-  if (command.options.isAlphabet) {
-    is(command.options.isAlphabet, expect.isAlphabet, expect.name);
-  }
-  if (command.options.isUCS2) {
-    is(command.options.isUCS2, expect.isUCS2, expect.name);
-  }
-  if (command.options.isPacked) {
-    is(command.options.isPacked, expect.isPacked, expect.name);
-  }
-  if (command.options.hideInput) {
-    is(command.options.hideInput, expect.hideInput, expect.name);
-  }
-  let icons = command.options.icons;
-  if (icons) {
-    isIcons(icons, expect.icons, expect.name);
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
 
-    let iconSelfExplanatory = command.options.iconSelfExplanatory;
-    is(iconSelfExplanatory, expect.iconSelfExplanatory, expect.name);
-  }
-
-  runNextTest();
-}
-
-let tests = [
+const TEST_DATA = [
   {command: "d01b8103012300820281828d0c04456e74657220313233343591020505",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_1",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Enter 12345",
             minLength: 5,
             maxLength: 5}},
   {command: "d01a8103012308820281828d0b004537bd2c07d96eaad10a91020505",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_2",
-            commandQualifier: 0x08,
+   expect: {commandQualifier: 0x08,
             text: "Enter 67*#+",
             minLength: 5,
             maxLength: 5,
             isPacked: true}},
   {command: "d01b8103012301820281828d0c04456e74657220416243644591020505",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_3",
-            commandQualifier: 0x01,
+   expect: {commandQualifier: 0x01,
             text: "Enter AbCdE",
             minLength: 5,
             maxLength: 5,
             isAlphabet: true}},
   {command: "d0278103012304820281828d180450617373776f726420313c53454e443e3233343536373891020408",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_4",
-            commandQualifier: 0x04,
+   expect: {commandQualifier: 0x04,
             text: "Password 1<SEND>2345678",
             minLength: 4,
             maxLength: 8,
             hideInput: true}},
   {command: "d0248103012300820281828d1504456e74657220312e2e392c302e2e392c3028312991020114",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_5",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Enter 1..9,0..9,0(1)",
             minLength: 1,
             maxLength: 20}},
   {command: "d01e8103012300820281828d0f043c474f2d4241434b57415244533e91020008",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_6",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "<GO-BACKWARDS>",
             minLength: 0,
             maxLength: 8}},
   {command: "d0178103012300820281828d08043c41424f52543e91020008",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_7",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "<ABORT>",
             minLength: 0,
             maxLength: 8}},
   {command: "d081b18103012300820281828d81a1042a2a2a313131313131313131312323232a2a2a323232323232323232322323232a2a2a333333333333333333332323232a2a2a343434343434343434342323232a2a2a353535353535353535352323232a2a2a363636363636363636362323232a2a2a373737373737373737372323232a2a2a383838383838383838382323232a2a2a393939393939393939392323232a2a2a303030303030303030302323239102a0a0",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_8",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "***1111111111###***2222222222###***3333333333###***4444444444###***5555555555###***6666666666###***7777777777###***8888888888###***9999999999###***0000000000###",
             minLength: 160,
             maxLength: 160}},
   {command: "d0168103012300820281828d07043c53454e443e91020001",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_9",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "<SEND>",
             minLength: 0,
             maxLength: 1}},
   {command: "d01a8103012300820281828d0b043c54494d452d4f55543e9102000a",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_10",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "<TIME-OUT>",
             minLength: 0,
             maxLength: 10}},
   {command: "d0288103012301820281828d190804170414042004100412042104220412042304190422041591020505",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_11",
-            commandQualifier: 0x01,
+   expect: {commandQualifier: 0x01,
             text: "ЗДРАВСТВУЙТЕ",
             minLength: 5,
             maxLength: 5,
             isAlphabet: true}},
   {command: "d0819d8103012301820281828d818d08041704140420041004120421042204120423041904220415041704140420041004120421042204120423041904220415041704140420041004120421042204120423041904220415041704140420041004120421042204120423041904220415041704140420041004120421042204120423041904220415041704140420041004120421042204120423041991020505",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_12",
-            commandQualifier: 0x01,
+   expect: {commandQualifier: 0x01,
             text: "ЗДРАВСТВУЙТЕЗДРАВСТВУЙТЕЗДРАВСТВУЙТЕЗДРАВСТВУЙТЕЗДРАВСТВУЙТЕЗДРАВСТВУЙ",
             minLength: 5,
             maxLength: 5,
             isAlphabet: true}},
   {command: "d01b8103012303820281828d0c04456e7465722048656c6c6f91020c0c",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_13",
-            commandQualifier: 0x03,
+   expect: {commandQualifier: 0x03,
             text: "Enter Hello",
             minLength: 12,
             maxLength: 12,
             isAlphabet: true,
             isUCS2: true}},
   {command: "d01b8103012303820281828d0c04456e7465722048656c6c6f910205ff",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_14",
-            commandQualifier: 0x03,
+   expect: {commandQualifier: 0x03,
             text: "Enter Hello",
             minLength: 5,
             maxLength: 0xFF,
             isAlphabet: true,
             isUCS2: true}},
   {command: "d0238103012300820281828d0c04456e746572203132333435910205051706043132333435",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_15",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Enter 12345",
             minLength: 5,
             maxLength: 5,
             defaultText: "12345"}},
   {command: "d081ba8103012300820281828d0704456e7465723a9102a0a01781a1042a2a2a313131313131313131312323232a2a2a323232323232323232322323232a2a2a333333333333333333332323232a2a2a343434343434343434342323232a2a2a353535353535353535352323232a2a2a363636363636363636362323232a2a2a373737373737373737372323232a2a2a383838383838383838382323232a2a2a393939393939393939392323232a2a2a30303030303030303030232323",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_16",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "Enter:",
             minLength: 160,
             maxLength: 160,
             defaultText: "***1111111111###***2222222222###***3333333333###***4444444444###***5555555555###***6666666666###***7777777777###***8888888888###***9999999999###***0000000000###"}},
   {command: "d01d8103012300820281828d0a043c4e4f2d49434f4e3e9102000a1e020002",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_17",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             // The record number 02 in EFimg is not defined, so no icon will be
             // shown, but the text string should still be displayed.
             text: "<NO-ICON>",
             minLength: 0,
             maxLength: 10}},
   {command: "d0208103012300820281828d0d043c42415349432d49434f4e3e9102000a1e020101",
-   func: testGetInput,
-   expect: {name: "get_input_cmd_18",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             text: "<BASIC-ICON>",
             minLength: 0,
             maxLength: 10,
             iconSelfExplanatory: false,
-            icons: [basicIcon]}},
+            icons: [BASIC_ICON]}},
 ];
 
-runNextTest();
+function testGetInput(aCommand, aExpect) {
+  is(aCommand.typeOfCommand, MozIccManager.STK_CMD_GET_INPUT, "typeOfCommand");
+  is(aCommand.commandQualifier, aExpect.commandQualifier, "commandQualifier");
+  is(aCommand.options.text, aExpect.text, "options.text");
+  is(aCommand.options.minLength, aExpect.minLength, "options.minLength");
+  is(aCommand.options.maxLength, aExpect.maxLength, "options.maxLength");
+
+  if (aExpect.defaultText) {
+    is(aCommand.options.defaultText, aExpect.defaultText, "options.defaultText");
+  }
+
+  if (aExpect.isAlphabet) {
+    is(aCommand.options.isAlphabet, aExpect.isAlphabet, "options.isAlphabet");
+  }
+
+  if (aExpect.isUCS2) {
+    is(aCommand.options.isUCS2, aExpect.isUCS2, "options.isUCS2");
+  }
+
+  if (aExpect.isPacked) {
+    is(aCommand.options.isPacked, aExpect.isPacked, "options.isPacked");
+  }
+
+  if (aExpect.hideInput) {
+    is(aCommand.options.hideInput, aExpect.hideInput, "options.hideInput");
+  }
+
+  if (aExpect.icons) {
+    isIcons(aCommand.options.icons, aExpect.icons);
+    is(aCommand.options.iconSelfExplanatory, aExpect.iconSelfExplanatory,
+       "options.iconSelfExplanatory");
+  }
+}
+
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
+  let promise = Promise.resolve();
+  for (let i = 0; i < TEST_DATA.length; i++) {
+    let data = TEST_DATA[i];
+    promise = promise.then(() => {
+      log("get_input_cmd: " + data.command);
+
+      let promises = [];
+      // Wait onstkcommand event.
+      promises.push(waitForTargetEvent(icc, "stkcommand")
+        .then((aEvent) => testGetInput(aEvent.command, data.expect)));
+      // Send emulator command to generate stk unsolicited event.
+      promises.push(sendEmulatorStkPdu(data.command));
+
+      return Promise.all(promises);
+    });
+  }
+  return promise;
+});
--- a/dom/icc/tests/marionette/test_stk_launch_browser.js
+++ b/dom/icc/tests/marionette/test_stk_launch_browser.js
@@ -1,267 +1,208 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_HEAD_JS = "stk_helper.js";
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-function testLaunchBrowser(command, expect) {
-  log("STK CMD " + JSON.stringify(command));
-  is(command.typeOfCommand, iccManager.STK_CMD_LAUNCH_BROWSER, expect.name);
-  is(command.commandQualifier, expect.commandQualifier, expect.name);
-  is(command.options.url, expect.url, expect.name);
-  if (expect.confirmMessage) {
-    isStkText(command.options.confirmMessage, expect.confirmMessage, expect.name);
-  }
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
 
-  runNextTest();
-}
-
-let tests = [
+const TEST_DATA = [
   {command: "d0188103011500820281823100050b44656661756c742055524c",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_1",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL" }}},
   {command: "d01f8103011500820281823112687474703a2f2f7878782e7979792e7a7a7a0500",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_2",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "http://xxx.yyy.zzz",
             confirmMessage: { text: "" }}},
   {command: "d00e8103011500820281823001003100",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_3",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: ""}},
   {command: "d0208103011500820281823100320103" +
             "0d10046162632e6465662e6768692e6a6b6c", // "0D" String TLV is useless for Launch Browser.
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_4",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: ""}},
   {command: "d0188103011502820281823100050b44656661756c742055524c",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_5",
-            commandQualifier: 0x02,
+   expect: {commandQualifier: 0x02,
             url: "",
             confirmMessage: { text: "Default URL" }}},
   {command: "d0188103011503820281823100050b44656661756c742055524c",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_6",
-            commandQualifier: 0x03,
+   expect: {commandQualifier: 0x03,
             url: "",
             confirmMessage: { text: "Default URL"}}},
   {command: "d00b8103011500820281823100",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_7",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: ""}},
   {command: "d0268103011502820281823100051980041704140420041004120421042204120423041904220415",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_8",
-            commandQualifier: 0x02,
+   expect: {commandQualifier: 0x02,
             url: "",
             confirmMessage: { text: "ЗДРАВСТВУЙТЕ" }}},
   {command: "d021810301150282028182310005104e6f742073656c66206578706c616e2e1e020101",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_9",
-            commandQualifier: 0x02,
+   expect: {commandQualifier: 0x02,
             url: "",
             confirmMessage: { text: "Not self explan.",
                               iconSelfExplanatory: false,
-                              icons : [basicIcon] }
+                              icons : [BASIC_ICON] }
             }},
   {command: "d01d8103011502820281823100050c53656c66206578706c616e2e1e020001",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_10",
-            commandQualifier: 0x02,
+   expect: {commandQualifier: 0x02,
             url: "",
             confirmMessage: { text: "Self explan.",
                               iconSelfExplanatory: true,
-                              icons : [basicIcon] }
+                              icons : [BASIC_ICON] }
             }},
   {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d00b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_11",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 1" }}},
   {command: "d01a8103011500820281823100050d44656661756c742055524c2032",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_12",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 2" }}},
   {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d01b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_13",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 1" }}},
   {command: "d01a8103011500820281823100050d44656661756c742055524c2032",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_14",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 2" }}},
   {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d02b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_15",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 1" }}},
   {command: "d01a8103011500820281823100050d44656661756c742055524c2032",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_16",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 2" }}},
-   {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d04b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_17",
-            commandQualifier: 0x00,
+  {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d04b4",
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 1" }}},
   {command: "d0208103011500820281823100050d44656661756c742055524c2032d004000d00b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_18",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
+            url: "",
+            confirmMessage: { text: "Default URL 2" }}},
+  {command: "d01a8103011500820281823100050d44656661756c742055524c2033",
+   expect: {commandQualifier: 0x00,
+            url: "",
+            confirmMessage: { text: "Default URL 3" }}},
+  {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d08b4",
+   expect: {commandQualifier: 0x00,
+            url: "",
+            confirmMessage: { text: "Default URL 1" }}},
+  {command: "d0208103011500820281823100050d44656661756c742055524c2032d004000d00b4",
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 2" }}},
   {command: "d01a8103011500820281823100050d44656661756c742055524c2033",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_19",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 3" }}},
-   {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d08b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_20",
-            commandQualifier: 0x00,
+  {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d10b4",
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 1" }}},
   {command: "d0208103011500820281823100050d44656661756c742055524c2032d004000d00b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_21",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 2" }}},
   {command: "d01a8103011500820281823100050d44656661756c742055524c2033",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_22",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 3" }}},
-   {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d10b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_23",
-            commandQualifier: 0x00,
+  {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d20b4",
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 1" }}},
   {command: "d0208103011500820281823100050d44656661756c742055524c2032d004000d00b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_24",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 2" }}},
   {command: "d01a8103011500820281823100050d44656661756c742055524c2033",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_25",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 3" }}},
-   {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d20b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_26",
-            commandQualifier: 0x00,
+  {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d40b4",
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 1" }}},
   {command: "d0208103011500820281823100050d44656661756c742055524c2032d004000d00b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_27",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 2" }}},
   {command: "d01a8103011500820281823100050d44656661756c742055524c2033",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_28",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 3" }}},
-   {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d40b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_29",
-            commandQualifier: 0x00,
+  {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d80b4",
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 1" }}},
   {command: "d0208103011500820281823100050d44656661756c742055524c2032d004000d00b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_30",
-            commandQualifier: 0x00,
-            url: "",
-            confirmMessage: { text: "Default URL 2" }}},
-  {command: "d01a8103011500820281823100050d44656661756c742055524c2033",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_31",
-            commandQualifier: 0x00,
-            url: "",
-            confirmMessage: { text: "Default URL 3" }}},
-   {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d80b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_32",
-            commandQualifier: 0x00,
-            url: "",
-            confirmMessage: { text: "Default URL 1" }}},
-  {command: "d0208103011500820281823100050d44656661756c742055524c2032d004000d00b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_33",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 2" }}},
   {command: "d01a8103011500820281823100050d44656661756c742055524c2033",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_34",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 3" }}},
-   {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d00b4",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_35",
-            commandQualifier: 0x00,
+  {command: "d0208103011500820281823100050d44656661756c742055524c2031d004000d00b4",
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 1" }}},
   {command: "d01a8103011500820281823100050d44656661756c742055524c2032",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_36",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { text: "Default URL 2" }}},
-   {command: "d01281030115028202818231000505804f60597d",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_37",
-            commandQualifier: 0x02,
+  {command: "d01281030115028202818231000505804f60597d",
+   expect: {commandQualifier: 0x02,
             url: "",
             confirmMessage: { text: "你好" }}},
   {command: "d010810301150282028182310005038030eb",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_38",
-            commandQualifier: 0x02,
+   expect: {commandQualifier: 0x02,
             url: "",
             confirmMessage: { text: "ル" }}},
   {command: "d01281030115008202818230010031001e020001",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_39",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
+            url: "",
+            confirmMessage: { iconSelfExplanatory: true,
+                              icons: [BASIC_ICON] }}},
+  {command: "d01281030115008202818230010031001e020003",
+   expect: {commandQualifier: 0x00,
             url: "",
             confirmMessage: { iconSelfExplanatory: true,
-                              icons: [basicIcon] }}},
-  {command: "d01281030115008202818230010031001e020003",
-   func: testLaunchBrowser,
-   expect: {name: "launch_browser_cmd_40",
-            commandQualifier: 0x00,
-            url: "",
-            confirmMessage: { iconSelfExplanatory: true,
-                              icons: [colorIcon] }}},
+                              icons: [COLOR_ICON] }}},
 ];
 
-runNextTest();
+function testLaunchBrowser(aCommand, aExpect) {
+  is(aCommand.typeOfCommand, MozIccManager.STK_CMD_LAUNCH_BROWSER,
+     "typeOfCommand");
+  is(aCommand.commandQualifier, aExpect.commandQualifier, "commandQualifier");
+  is(aCommand.options.url, aExpect.url, "options.url");
+
+  if (aExpect.confirmMessage) {
+    isStkText(aCommand.options.confirmMessage, aExpect.confirmMessage,
+              "options.confirmMessage");
+  }
+}
+
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
+  let promise = Promise.resolve();
+  for (let i = 0; i < TEST_DATA.length; i++) {
+    let data = TEST_DATA[i];
+    promise = promise.then(() => {
+      log("launch_browser_cmd: " + data.command);
+
+      let promises = [];
+      // Wait onstkcommand event.
+      promises.push(waitForTargetEvent(icc, "stkcommand")
+        .then((aEvent) => testLaunchBrowser(aEvent.command, data.expect)));
+      // Send emulator command to generate stk unsolicited event.
+      promises.push(sendEmulatorStkPdu(data.command));
+
+      return Promise.all(promises);
+    });
+  }
+  return promise;
+});
new file mode 100644
--- /dev/null
+++ b/dom/icc/tests/marionette/test_stk_local_info.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+const TEST_DATA = [
+  // Location
+  {command: "d009810301260082028182",
+   expect: {commandNumber: 0x01,
+            commandQualifier: MozIccManager.STK_LOCAL_INFO_LOCATION_INFO,
+            localInfoType: MozIccManager.STK_LOCAL_INFO_LOCATION_INFO}},
+  // Imei
+  {command: "d009810301260182028182",
+   expect: {commandNumber: 0x01,
+            commandQualifier: MozIccManager.STK_LOCAL_INFO_IMEI,
+            localInfoType: MozIccManager.STK_LOCAL_INFO_IMEI}},
+  // Data
+  {command: "d009810301260382028182",
+   expect: {commandNumber: 0x01,
+            commandQualifier: MozIccManager.STK_LOCAL_INFO_DATE_TIME_ZONE,
+            localInfoType: MozIccManager.STK_LOCAL_INFO_DATE_TIME_ZONE}},
+  // Language
+  {command: "d009810301260482028182",
+   expect: {commandNumber: 0x01,
+            commandQualifier: MozIccManager.STK_LOCAL_INFO_LANGUAGE,
+            localInfoType: MozIccManager.STK_LOCAL_INFO_LANGUAGE}},
+];
+
+function testLocalInfo(aCommand, aExpect) {
+  is(aCommand.typeOfCommand, MozIccManager.STK_CMD_PROVIDE_LOCAL_INFO, "typeOfCommand");
+  is(aCommand.commandQualifier, aExpect.commandQualifier, "commandQualifier");
+  is(aCommand.options.localInfoType, aExpect.localInfoType, "options.localInfoType");
+}
+
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
+  let promise = Promise.resolve();
+  for (let i = 0; i < TEST_DATA.length; i++) {
+    let data = TEST_DATA[i];
+    promise = promise.then(() => {
+      log("local_info_cmd: " + data.command);
+
+      let promises = [];
+      // Wait onstkcommand event.
+      promises.push(waitForTargetEvent(icc, "stkcommand")
+        .then((aEvent) => testLocalInfo(aEvent.command, data.expect)));
+      // Send emulator command to generate stk unsolicited event.
+      promises.push(sendEmulatorStkPdu(data.command));
+
+      return Promise.all(promises);
+    });
+  }
+  return promise;
+});
--- a/dom/icc/tests/marionette/test_stk_poll_off.js
+++ b/dom/icc/tests/marionette/test_stk_poll_off.js
@@ -1,21 +1,37 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-MARIONETTE_HEAD_JS = "stk_helper.js";
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
 
-function testPollOff(command, expect) {
-  log("STK CMD " + JSON.stringify(command));
-  is(command.typeOfCommand, iccManager.STK_CMD_POLL_OFF, expect.name);
-  is(command.commandQualifier, expect.commandQualifier, expect.name);
+const TEST_DATA = [
+  {command: "d009810301040082028182",
+   expect: {commandQualifier: 0x00}}
+];
 
-  runNextTest();
+function testPollOff(aCommand, aExpect) {
+  is(aCommand.typeOfCommand, MozIccManager.STK_CMD_POLL_OFF, "typeOfCommand");
+  is(aCommand.commandQualifier, aExpect.commandQualifier, "commandQualifier");
 }
 
-let tests = [
-  {command: "d009810301040082028182",
-   func: testPollOff,
-   expect: {name: "pull_off_cmd_1",
-            commandQualifier: 0x00}}
-];
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
+  let promise = Promise.resolve();
+  for (let i = 0; i < TEST_DATA.length; i++) {
+    let data = TEST_DATA[i];
+    promise = promise.then(() => {
+      log("pull_off_cmd: " + data.command);
 
-runNextTest();
+      let promises = [];
+      // Wait onstkcommand event.
+      promises.push(waitForTargetEvent(icc, "stkcommand")
+        .then((aEvent) => testPollOff(aEvent.command, data.expect)));
+      // Send emulator command to generate stk unsolicited event.
+      promises.push(sendEmulatorStkPdu(data.command));
+
+      return Promise.all(promises);
+    });
+  }
+  return promise;
+});
deleted file mode 100644
--- a/dom/icc/tests/marionette/test_stk_proactive_command.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_HEAD_JS = "stk_helper.js";
-
-function testLocalInfoLocation(cmd) {
-  log("STK CMD " + JSON.stringify(cmd));
-  is(cmd.typeOfCommand, iccManager.STK_CMD_PROVIDE_LOCAL_INFO);
-  is(cmd.commandNumber, 0x01);
-  is(cmd.commandQualifier, iccManager.STK_LOCAL_INFO_LOCATION_INFO);
-  is(cmd.options.localInfoType, iccManager.STK_LOCAL_INFO_LOCATION_INFO);
-
-  runNextTest();
-}
-
-function testLocalInfoImei(cmd) {
-  log("STK CMD " + JSON.stringify(cmd));
-  is(cmd.typeOfCommand, iccManager.STK_CMD_PROVIDE_LOCAL_INFO);
-  is(cmd.commandNumber, 0x01);
-  is(cmd.commandQualifier, iccManager.STK_LOCAL_INFO_IMEI);
-  is(cmd.options.localInfoType, iccManager.STK_LOCAL_INFO_IMEI);
-
-  runNextTest();
-}
-
-function testLocalInfoDate(cmd) {
-  log("STK CMD " + JSON.stringify(cmd));
-  is(cmd.typeOfCommand, iccManager.STK_CMD_PROVIDE_LOCAL_INFO);
-  is(cmd.commandNumber, 0x01);
-  is(cmd.commandQualifier, iccManager.STK_LOCAL_INFO_DATE_TIME_ZONE);
-  is(cmd.options.localInfoType, iccManager.STK_LOCAL_INFO_DATE_TIME_ZONE);
-
-  runNextTest();
-}
-
-function testLocalInfoLanguage(cmd) {
-  log("STK CMD " + JSON.stringify(cmd));
-  is(cmd.typeOfCommand, iccManager.STK_CMD_PROVIDE_LOCAL_INFO);
-  is(cmd.commandNumber, 0x01);
-  is(cmd.commandQualifier, iccManager.STK_LOCAL_INFO_LANGUAGE);
-  is(cmd.options.localInfoType, iccManager.STK_LOCAL_INFO_LANGUAGE);
-
-  runNextTest();
-}
-
-function testRefresh(cmd) {
-  log("STK CMD " + JSON.stringify(cmd));
-  is(cmd.typeOfCommand, iccManager.STK_CMD_REFRESH);
-  is(cmd.commandNumber, 0x01);
-  is(cmd.commandQualifier, 0x01);
-  is(cmd.options, null);
-
-  runNextTest();
-}
-
-function testTimerManagementStart(cmd) {
-  log("STK CMD " + JSON.stringify(cmd));
-  is(cmd.typeOfCommand, iccManager.STK_CMD_TIMER_MANAGEMENT);
-  is(cmd.commandNumber, 0x01);
-  is(cmd.commandQualifier, iccManager.STK_TIMER_START);
-  is(cmd.options.timerAction, iccManager.STK_TIMER_START);
-  is(cmd.options.timerId, 0x01);
-  is(cmd.options.timerValue, (0x01 * 60 * 60) + (0x02 * 60) + 0x03);
-
-  runNextTest();
-}
-
-function testTimerManagementDeactivate(cmd) {
-  log("STK CMD " + JSON.stringify(cmd));
-  is(cmd.typeOfCommand, iccManager.STK_CMD_TIMER_MANAGEMENT);
-  is(cmd.commandNumber, 0x01);
-  is(cmd.commandQualifier, iccManager.STK_TIMER_DEACTIVATE);
-  is(cmd.options.timerAction, iccManager.STK_TIMER_DEACTIVATE);
-  is(cmd.options.timerId, 0x04);
-
-  runNextTest();
-}
-
-function testTimerManagementGetCurrentValue(cmd) {
-  log("STK CMD " + JSON.stringify(cmd));
-  is(cmd.typeOfCommand, iccManager.STK_CMD_TIMER_MANAGEMENT);
-  is(cmd.commandNumber, 0x01);
-  is(cmd.commandQualifier, iccManager.STK_TIMER_GET_CURRENT_VALUE);
-  is(cmd.options.timerAction, iccManager.STK_TIMER_GET_CURRENT_VALUE);
-  is(cmd.options.timerId, 0x08);
-
-  runNextTest();
-}
-
-let tests = [
-  {command: "d009810301260082028182",
-   func: testLocalInfoLocation},
-  {command: "d009810301260182028182",
-   func: testLocalInfoImei},
-  {command: "d009810301260382028182",
-   func: testLocalInfoDate},
-  {command: "d009810301260482028182",
-   func: testLocalInfoLanguage},
-  {command: "d011810301270082028182a40101a503102030",
-   func: testTimerManagementStart},
-  {command: "d00c810301270182028182a40104",
-   func: testTimerManagementDeactivate},
-  {command: "d00c810301270282028182a40108",
-   func: testTimerManagementGetCurrentValue},
- ];
-
-runNextTest();
--- a/dom/icc/tests/marionette/test_stk_refresh.js
+++ b/dom/icc/tests/marionette/test_stk_refresh.js
@@ -1,25 +1,39 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-MARIONETTE_HEAD_JS = "stk_helper.js";
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
 
-function testRefresh(command, expect) {
-  log("STK CMD " + JSON.stringify(command));
-  is(command.typeOfCommand, iccManager.STK_CMD_REFRESH, expect.name);
-  is(command.commandQualifier, expect.commandQualifier, expect.name);
+const TEST_DATA = [
+  {command: "d0108103010101820281829205013f002fe2",
+   expect: {commandQualifier: 0x01}},
+  {command: "d009810301010482028182",
+   expect: {commandQualifier: 0x04}}
+];
 
-  runNextTest();
+function testRefresh(aCommand, aExpect) {
+  is(aCommand.typeOfCommand, MozIccManager.STK_CMD_REFRESH, "typeOfCommand");
+  is(aCommand.commandQualifier, aExpect.commandQualifier, "commandQualifier");
 }
 
-let tests = [
-  {command: "d0108103010101820281829205013f002fe2",
-   func: testRefresh,
-   expect: {name: "refresh_cmd_1",
-            commandQualifier: 0x01}},
-  {command: "d009810301010482028182",
-   func: testRefresh,
-   expect: {name: "refresh_cmd_2",
-            commandQualifier: 0x04}}
-];
+// Start tests
+startTestCommon(function() {
+  let icc = getMozIcc();
+  let promise = Promise.resolve();
+  for (let i = 0; i < TEST_DATA.length; i++) {
+    let data = TEST_DATA[i];
+    promise = promise.then(() => {
+      log("refresh_cmd: " + data.command);
 
-runNextTest();
+      let promises = [];
+      // Wait onstkcommand event.
+      promises.push(waitForTargetEvent(icc, "stkcommand")
+        .then((aEvent) => testRefresh(aEvent.command, data.expect)));
+      // Send emulator command to generate stk unsolicited event.
+      promises.push(sendEmulatorStkPdu(data.command));
+
+      return Promise.all(promises);
+    });
+  }
+  return promise;
+});
--- a/dom/icc/tests/marionette/test_stk_select_item.js
+++ b/dom/icc/tests/marionette/test_stk_select_item.js
@@ -1,347 +1,270 @@
 /* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_HEAD_JS = "stk_helper.js";
-
-function testSelectItem(command, expect) {
-  log("STK CMD " + JSON.stringify(command));
-  is(command.typeOfCommand, iccManager.STK_CMD_SELECT_ITEM, expect.name);
-  is(command.commandQualifier, expect.commandQualifier, expect.name);
-  is(command.options.title, expect.title, expect.name);
-  for (let index in command.options.items) {
-    is(command.options.items[index].identifier, expect.items[index].identifier, expect.name);
-    is(command.options.items[index].text, expect.items[index].text, expect.name);
-
-    let itemIcons = command.options.items[index].icons;
-    if (itemIcons) {
-      isIcons(itemIcons, expect.items[index].icons, expect.name);
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-      let iconSelfExplanatory = command.options.items[index].iconSelfExplanatory;
-      is(iconSelfExplanatory, expect.items[index].iconSelfExplanatory, expect.name);
-    }
-  }
-
-  let icons = command.options.icons;
-  if (icons) {
-    isIcons(icons, expect.icons, expect.name);
-
-    let iconSelfExplanatory = command.options.iconSelfExplanatory;
-    is(iconSelfExplanatory, expect.iconSelfExplanatory, expect.name);
-  }
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
 
-  let length = command.options.nextActionList ? command.options.nextActionList.length : 0;
-  for (let i = 0; i < length; i++) {
-    is(command.options.nextActionList[i], expect.nextActionList[i], expect.name);
-  }
-
-  runNextTest();
-}
-
-let tests = [
+const TEST_DATA = [
   {command: "d03d810301240082028182850e546f6f6c6b69742053656c6563748f07014974656d20318f07024974656d20328f07034974656d20338f07044974656d2034",
-   func: testSelectItem,
-   expect: {name: "select_item_cmd_1",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             title: "Toolkit Select",
             items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}, {identifier: 4, text: "Item 4"}]}},
   {command: "d081fc810301240082028182850a4c617267654d656e75318f05505a65726f8f044f4f6e658f044e54776f8f064d54687265658f054c466f75728f054b466976658f044a5369788f0649536576656e8f064845696768748f05474e696e658f0646416c7068618f0645427261766f8f0844436861726c69658f064344656c74618f05424563686f8f0941466f782d74726f748f0640426c61636b8f063f42726f776e8f043e5265648f073d4f72616e67658f073c59656c6c6f778f063b477265656e8f053a426c75658f073956696f6c65748f0538477265798f063757686974658f06366d696c6c698f06356d6963726f8f05346e616e6f8f05337069636f",
-   func: testSelectItem,
-   expect: {name: "select_item_cmd_2",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             title: "LargeMenu1",
             items: [{identifier: 80, text: "Zero"}, {identifier: 79, text: "One"}, {identifier: 78, text: "Two"}, {identifier: 77, text: "Three"}, {identifier: 76, text: "Four"}, {identifier: 75, text: "Five"}, {identifier: 74, text: "Six"}, {identifier: 73, text: "Seven"}, {identifier: 72, text: "Eight"}, {identifier: 71, text: "Nine"}, {identifier: 70, text: "Alpha"}, {identifier: 69, text: "Bravo"}, {identifier: 68, text: "Charlie"}, {identifier: 67, text: "Delta"}, {identifier: 66, text: "Echo"}, {identifier: 65, text: "Fox-trot"}, {identifier: 64, text: "Black"}, {identifier: 63, text: "Brown"}, {identifier: 62, text: "Red"}, {identifier: 61, text: "Orange"}, {identifier: 60, text: "Yellow"}, {identifier: 59, text: "Green"}, {identifier: 58, text: "Blue"}, {identifier: 57, text: "Violet"}, {identifier: 56, text: "Grey"}, {identifier: 55, text: "White"}, {identifier: 54, text: "milli"}, {identifier: 53, text: "micro"}, {identifier: 52, text: "nano"}, {identifier: 51, text: "pico"}]}},
   {command: "d081fb810301240082028182850a4c617267654d656e75328f1eff43616c6c20466f7277617264696e6720556e636f6e646974696f6e616c8f1dfe43616c6c20466f7277617264696e67204f6e205573657220427573798f1cfd43616c6c20466f7277617264696e67204f6e204e6f205265706c798f26fc43616c6c20466f7277617264696e67204f6e2055736572204e6f7420526561636861626c658f1efb42617272696e67204f6620416c6c204f7574676f696e672043616c6c738f2cfa42617272696e67204f6620416c6c204f7574676f696e6720496e7465726e6174696f6e616c2043616c6c738f11f9434c492050726573656e746174696f6e",
-   func: testSelectItem,
-   expect: {name: "select_item_cmd_3",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             title: "LargeMenu2",
             items: [{identifier: 255, text: "Call Forwarding Unconditional"}, {identifier: 254, text: "Call Forwarding On User Busy"}, {identifier: 253, text: "Call Forwarding On No Reply"}, {identifier: 252, text: "Call Forwarding On User Not Reachable"}, {identifier: 251, text: "Barring Of All Outgoing Calls"}, {identifier: 250, text: "Barring Of All Outgoing International Calls"}, {identifier: 249, text: "CLI Presentation"}]}},
   {command: "d022810301240082028182850b53656c656374204974656d8f04114f6e658f041254776f",
-   func: testSelectItem,
-   expect: {name: "select_item_cmd_4",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             title: "Select Item",
             items: [{identifier: 17, text: "One"}, {identifier: 18, text: "Two"}]}},
   {command: "d081fd8103012400820281828581ed5468652053494d207368616c6c20737570706c79206120736574206f66206974656d732066726f6d207768696368207468652075736572206d61792063686f6f7365206f6e652e2045616368206974656d20636f6d70726973657320612073686f7274206964656e74696669657220287573656420746f20696e646963617465207468652073656c656374696f6e2920616e642061207465787420737472696e672e204f7074696f6e616c6c79207468652053494d206d617920696e636c75646520616e20616c706861206964656e7469666965722e2054686520616c706861206964656e74696669657220698f020159",
-   func: testSelectItem,
-   expect: {name: "select_item_cmd_5",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             title: "The SIM shall supply a set of items from which the user may choose one. Each item comprises a short identifier (used to indicate the selection) and a text string. Optionally the SIM may include an alpha identifier. The alpha identifier i",
             items: [{identifier: 1, text: "Y"}]}},
   {command: "d081f3810301240082028182850a304c617267654d656e758f1dff312043616c6c20466f727761726420556e636f6e646974696f6e616c8f1cfe322043616c6c20466f7277617264204f6e205573657220427573798f1bfd332043616c6c20466f7277617264204f6e204e6f205265706c798f25fc342043616c6c20466f7277617264204f6e2055736572204e6f7420526561636861626c658f20fb352042617272696e67204f6620416c6c204f7574676f696e672043616c6c738f24fa362042617272696e67204f6620416c6c204f7574676f696e6720496e742043616c6c738f13f93720434c492050726573656e746174696f6e",
-   func: testSelectItem,
-   expect: {name: "select_item_cmd_6",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             title: "0LargeMenu",
             items: [{identifier: 255, text: "1 Call Forward Unconditional"}, {identifier: 254, text: "2 Call Forward On User Busy"}, {identifier: 253, text: "3 Call Forward On No Reply"}, {identifier: 252, text: "4 Call Forward On User Not Reachable"}, {identifier: 251, text: "5 Barring Of All Outgoing Calls"}, {identifier: 250, text: "6 Barring Of All Outgoing Int Calls"}, {identifier: 249, text: "7 CLI Presentation"}]}},
   {command: "d039810301240082028182850e546f6f6c6b69742053656c6563748f07014974656d20318f07024974656d20328f07034974656d20331803131026",
-   func: testSelectItem,
-   expect: {name: "select_item_cmd_7",
-            commandQualifier: 0x00,
+   expect: {commandQualifier: 0x00,
             title: "Toolkit Select",
             items: [{identifier: 1, text: "Item 1"}, {identifier: 2, text: "Item 2"}, {identifier: 3, text: "Item 3"}],
-            nextActionList: [iccManager.STK_CMD_SEND_SMS, iccManager.STK_CMD_SET_UP_CALL, iccManager.STK_C