Backed out 3 changesets (bug 1231784) for breaking 10.10 opt jetpack tests
authorWes Kocher <wkocher@mozilla.com>
Wed, 03 Feb 2016 17:38:12 -0800
changeset 321230 e307f5a43dbf971e4012c889789b1151182fee47
parent 321229 e0c8fb70a09566b8985d6414ccd06f51dcfd8d4c
child 321231 b0c2f52f52f18ca1c47a07083b7ad7ef22bc2645
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1231784
milestone47.0a1
backs out653df21ca86195f23cadc2fc180bff0c6831da25
0aac20bc3619019bc7c19a929154c9b3fbc0df46
edcbd7c0aa36be0846f2e8e989fb57c9e4449cc4
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 3 changesets (bug 1231784) for breaking 10.10 opt jetpack tests Backed out changeset 653df21ca861 (bug 1231784) Backed out changeset 0aac20bc3619 (bug 1231784) Backed out changeset edcbd7c0aa36 (bug 1231784)
build/mobile/remoteautomation.py
testing/marionette/driver/marionette_driver/marionette.py
testing/mochitest/b2g_start_script.js
testing/mochitest/bootstrap.js
testing/mochitest/browser-harness.xul
testing/mochitest/browser-test-overlay.xul
testing/mochitest/browser-test.js
testing/mochitest/install.rdf
testing/mochitest/jetpack-addon-harness.js
testing/mochitest/jetpack-package-harness.js
testing/mochitest/mochitest_options.py
testing/mochitest/moz.build
testing/mochitest/runtests.py
testing/mochitest/runtestsb2g.py
testing/mochitest/runtestsremote.py
testing/mochitest/start_b2g.js
testing/mochitest/start_desktop.js
testing/profiles/prefs_general.js
toolkit/mozapps/extensions/test/browser/browser_select_confirm.js
toolkit/mozapps/update/tests/chrome/utils.js
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -2,17 +2,16 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import datetime
 import glob
 import time
 import re
 import os
-import posixpath
 import tempfile
 import shutil
 import subprocess
 import sys
 
 from automation import Automation
 from devicemanager import DMError, DeviceManager
 from mozlog import get_default_logger
@@ -210,17 +209,17 @@ class RemoteAutomation(Automation):
 
         # If crash reporting is disabled (MOZ_CRASHREPORTER!=1), we can't say
         # anything.
         if not self.CRASHREPORTER:
             return False
 
         try:
             dumpDir = tempfile.mkdtemp()
-            remoteCrashDir = posixpath.join(self._remoteProfile, 'minidumps')
+            remoteCrashDir = self._remoteProfile + '/minidumps/'
             if not self._devicemanager.dirExists(remoteCrashDir):
                 # If crash reporting is enabled (MOZ_CRASHREPORTER=1), the
                 # minidumps directory is automatically created when Fennec
                 # (first) starts, so its lack of presence is a hint that
                 # something went wrong.
                 print "Automation Error: No crash directory (%s) found on remote device" % remoteCrashDir
                 # Whilst no crash was found, the run should still display as a failure
                 return True
--- a/testing/marionette/driver/marionette_driver/marionette.py
+++ b/testing/marionette/driver/marionette_driver/marionette.py
@@ -1144,21 +1144,18 @@ class Marionette(object):
             if returncode is not None:
                 # We're managing a binary which has terminated, so restart it.
                 self.instance.restart()
 
         self.client = transport.TcpTransport(
             self.host,
             self.port,
             self.socket_timeout)
-
-        # Call wait_for_port() before attempting to connect in
-        # the event gecko hasn't started yet.
+        self.protocol, _ = self.client.connect()
         self.wait_for_port(timeout=timeout)
-        self.protocol, _ = self.client.connect()
 
         body = {"capabilities": desired_capabilities, "sessionId": session_id}
         resp = self._send_message("newSession", body)
 
         self.session_id = resp["sessionId"]
         self.session = resp["value"] if self.protocol == 1 else resp["capabilities"]
         self.b2g = "b2g" in self.session
 
rename from testing/mochitest/start_b2g.js
rename to testing/mochitest/b2g_start_script.js
deleted file mode 100644
--- a/testing/mochitest/bootstrap.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { utils: Cu, interfaces: Ci, classes: Cc } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-var WindowListener = {
-  // browser-test.js is only loaded into the first window. Setup that
-  // needs to happen in all navigator:browser windows should go here.
-  setupWindow: function(win) {
-    win.nativeConsole = win.console;
-    XPCOMUtils.defineLazyModuleGetter(win, "console",
-      "resource://gre/modules/Console.jsm");
-  },
-
-  tearDownWindow: function(win) {
-    if (win.nativeConsole) {
-      win.console = win.nativeConsole;
-      win.nativeConsole = undefined;
-    }
-  },
-
-  onOpenWindow: function (win) {
-    win = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
-
-    win.addEventListener("load", function listener() {
-      win.removeEventListener("load", listener, false);
-      if (win.document.documentElement.getAttribute("windowtype") == "navigator:browser") {
-        WindowListener.setupWindow(win);
-      }
-    }, false);
-  }
-}
-
-function loadMochitest(e) {
-  let flavor = e.detail[0];
-  let url = e.detail[1];
-
-  let win = Services.wm.getMostRecentWindow("navigator:browser");
-  win.removeEventListener('mochitest-load', loadMochitest);
-
-  // for mochitest-plain, navigating to the url is all we need
-  win.loadURI(url);
-  if (flavor == "mochitest") {
-    return;
-  }
-
-  WindowListener.setupWindow(win);
-  Services.wm.addListener(WindowListener);
-
-  let overlay;
-  if (flavor == "jetpack-addon") {
-    overlay = "chrome://mochikit/content/jetpack-addon-overlay.xul";
-  } else if (flavor == "jetpack-package") {
-    overlay = "chrome://mochikit/content/jetpack-package-overlay.xul";
-  } else {
-    overlay = "chrome://mochikit/content/browser-test-overlay.xul";
-  }
-
-  win.document.loadOverlay(overlay, null);
-}
-
-function startup(data, reason) {
-  let win = Services.wm.getMostRecentWindow("navigator:browser");
-  // wait for event fired from start_desktop.js containing the
-  // suite and url to load
-  win.addEventListener('mochitest-load', loadMochitest);
-}
-
-function shutdown(data, reason) {
-  let windows = Services.wm.getEnumerator("navigator:browser");
-  while (windows.hasMoreElements()) {
-    let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
-    WindowListener.tearDownWindow(win);
-  }
-
-  Services.wm.removeListener(WindowListener);
-}
-
-function install(data, reason) {}
-function uninstall(data, reason) {}
--- a/testing/mochitest/browser-harness.xul
+++ b/testing/mochitest/browser-harness.xul
@@ -246,17 +246,17 @@
       // It's possible that the test harness window is not yet focused when this
       // function runs (in which case testWin is already focused, and focusing it
       // will be a no-op, and then the test harness window will steal focus later,
       // which will mess up tests). So wait for the test harness window to be
       // focused before trying to focus testWin.
       waitForFocus(() => {
         // Focus the test window and start tests.
         waitForFocus(() => {
-          var Tester = new testWin.Tester(links, gDumper.structuredLogger, testsFinished);
+          var Tester = new testWin.Tester(links, gDumper, testsFinished);
           Tester.start();
         }, testWin);
       }, window);
     }
 
     function executeSoon(callback) {
       let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
       tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
--- a/testing/mochitest/browser-test-overlay.xul
+++ b/testing/mochitest/browser-test-overlay.xul
@@ -2,12 +2,12 @@
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <!-- 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/. -->
 
 <overlay id="browserTestOverlay"
          xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"/>
-  <script type="application/javascript" src="chrome://mochikit/content/mochitest-e10s-utils.js"/>
   <script type="application/javascript" src="chrome://mochikit/content/browser-test.js"/>
   <script type="application/javascript" src="chrome://mochikit/content/cc-analyzer.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/mochitest-e10s-utils.js"/>
 </overlay>
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -1,42 +1,53 @@
 /* -*- js-indent-level: 2; tab-width: 2; indent-tabs-mode: nil -*- */
 // Test timeout (seconds)
 var gTimeoutSeconds = 45;
 var gConfig;
 
+if (Cc === undefined) {
+  var Cc = Components.classes;
+}
+if (Ci === undefined) {
+  var Ci = Components.interfaces;
+}
+if (Cu === undefined) {
+  var Cu = Components.utils;
+}
+
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+  "resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
   "resource:///modules/CustomizationTabPreloader.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
   "resource:///modules/ContentSearch.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SelfSupportBackend",
   "resource:///modules/SelfSupportBackend.jsm");
 
+var nativeConsole = console;
+XPCOMUtils.defineLazyModuleGetter(this, "console",
+  "resource://gre/modules/Console.jsm");
+
 const SIMPLETEST_OVERRIDES =
   ["ok", "is", "isnot", "todo", "todo_is", "todo_isnot", "info", "expectAssertions", "requestCompleteLog"];
 
-// non-android is bootstrapped by marionette
-if (Services.appinfo.OS == 'Android') {
-  window.addEventListener("load", function testOnLoad() {
-    window.removeEventListener("load", testOnLoad);
-    window.addEventListener("MozAfterPaint", function testOnMozAfterPaint() {
-      window.removeEventListener("MozAfterPaint", testOnMozAfterPaint);
-      setTimeout(testInit, 0);
-    });
+window.addEventListener("load", function testOnLoad() {
+  window.removeEventListener("load", testOnLoad);
+  window.addEventListener("MozAfterPaint", function testOnMozAfterPaint() {
+    window.removeEventListener("MozAfterPaint", testOnMozAfterPaint);
+    setTimeout(testInit, 0);
   });
-} else {
-  setTimeout(testInit, 0);
-}
+});
 
 function b2gStart() {
   let homescreen = document.getElementById('systemapp');
   var webNav = homescreen.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                                    .getInterface(Ci.nsIWebNavigation);
   var url = "chrome://mochikit/content/harness.xul?manifestFile=tests.json";
 
   webNav.loadURI(url, null, null, null, null);
@@ -124,18 +135,18 @@ function testInit() {
     // In non-e10s, only run the ShutdownLeaksCollector in the parent process.
     Components.utils.import("chrome://mochikit/content/ShutdownLeaksCollector.jsm");
   }
 
   let gmm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
   gmm.loadFrameScript("chrome://mochikit/content/tests/SimpleTest/AsyncUtilsContent.js", true);
 }
 
-function Tester(aTests, structuredLogger, aCallback) {
-  this.structuredLogger = structuredLogger;
+function Tester(aTests, aDumper, aCallback) {
+  this.dumper = aDumper;
   this.tests = aTests;
   this.callback = aCallback;
   this.openedWindows = {};
   this.openedURLs = {};
 
   this._scriptLoader = Services.scriptloader;
   this.EventUtils = {};
   this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", this.EventUtils);
@@ -241,17 +252,17 @@ Tester.prototype = {
 
     if (gConfig.jscovDirPrefix) {
       let coveragePath = gConfig.jscovDirPrefix;
       let {CoverageCollector} = Cu.import("resource://testing-common/CoverageUtils.jsm",
                                           {});
       this._coverageCollector = new CoverageCollector(coveragePath);
     }
 
-    this.structuredLogger.info("*** Start BrowserChrome Test Results ***");
+    this.dumper.structuredLogger.info("*** Start BrowserChrome Test Results ***");
     Services.console.registerListener(this);
     Services.obs.addObserver(this, "chrome-document-global-created", false);
     Services.obs.addObserver(this, "content-document-global-created", false);
     this._globalProperties = Object.keys(window);
     this._globalPropertyWhitelist = [
       "navigator", "constructor", "top",
       "Application",
       "__SS_tabsToRestore", "__SSi",
@@ -302,17 +313,17 @@ Tester.prototype = {
     // Replace the last tab with a fresh one
     if (window.gBrowser) {
       gBrowser.addTab("about:blank", { skipAnimation: true });
       gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true });
       gBrowser.stop();
     }
 
     // Remove stale windows
-    this.structuredLogger.info("checking window state");
+    this.dumper.structuredLogger.info("checking window state");
     let windowsEnum = Services.wm.getEnumerator(null);
     let createdFakeTestForLogging = false;
     while (windowsEnum.hasMoreElements()) {
       let win = windowsEnum.getNext();
       if (win != window && !win.closed &&
           win.document.documentElement.getAttribute("id") != "browserTestHarness") {
         let type = win.document.documentElement.getAttribute("windowtype");
         switch (type) {
@@ -325,32 +336,32 @@ Tester.prototype = {
           break;
         }
         let msg = baseMsg.replace("{elt}", type);
         if (this.currentTest) {
           this.currentTest.addResult(new testResult(false, msg, "", false));
         } else {
           if (!createdFakeTestForLogging) {
             createdFakeTestForLogging = true;
-            this.structuredLogger.testStart("browser-test.js");
+            this.dumper.structuredLogger.testStart("browser-test.js");
           }
           this.failuresFromInitialWindowState++;
-          this.structuredLogger.testStatus("browser-test.js",
-                                           msg, "FAIL", false, "");
+          this.dumper.structuredLogger.testStatus("browser-test.js",
+                                                  msg, "FAIL", false, "");
         }
 
         win.close();
       }
     }
     if (createdFakeTestForLogging) {
       let time = Date.now() - startTime;
-      this.structuredLogger.testEnd("browser-test.js",
-                                    "OK",
-                                    undefined,
-                                    "finished window state check in " + time + "ms");
+      this.dumper.structuredLogger.testEnd("browser-test.js",
+                                           "OK",
+                                           undefined,
+                                           "finished window state check in " + time + "ms");
     }
 
     // Make sure the window is raised before each test.
     this.SimpleTest.waitForFocus(aCallback);
   },
 
   finish: function Tester_finish(aSkipSummary) {
     this.Promise.Debugging.flushUncaughtErrors();
@@ -374,30 +385,32 @@ Tester.prototype = {
       Services.obs.removeObserver(this, "content-document-global-created");
       this.Promise.Debugging.clearUncaughtErrorObservers();
       this._treatUncaughtRejectionsAsFailures = false;
 
       // In the main process, we print the ShutdownLeaksCollector message here.
       let pid = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).processID;
       dump("Completed ShutdownLeaks collections in process " + pid + "\n");
 
-      this.structuredLogger.info("TEST-START | Shutdown");
+      this.dumper.structuredLogger.info("TEST-START | Shutdown");
 
       if (this.tests.length) {
-        this.structuredLogger.info("Browser Chrome Test Summary");
-        this.structuredLogger.info("Passed:  " + passCount);
-        this.structuredLogger.info("Failed:  " + failCount);
-        this.structuredLogger.info("Todo:    " + todoCount);
+        this.dumper.structuredLogger.info("Browser Chrome Test Summary");
+        this.dumper.structuredLogger.info("Passed:  " + passCount);
+        this.dumper.structuredLogger.info("Failed:  " + failCount);
+        this.dumper.structuredLogger.info("Todo:    " + todoCount);
       } else {
-        this.structuredLogger.testEnd("browser-test.js",
-                                      "FAIL",
-                                      "PASS",
-                                      "No tests to run. Did you pass invalid test_paths?");
+        this.dumper.structuredLogger.testEnd("browser-test.js",
+                                             "FAIL",
+                                             "PASS",
+                                             "No tests to run. Did you pass invalid test_paths?");
       }
-      this.structuredLogger.info("*** End BrowserChrome Test Results ***");
+      this.dumper.structuredLogger.info("*** End BrowserChrome Test Results ***");
+
+      this.dumper.done();
 
       // Tests complete, notify the callback and return
       this.callback(this.tests);
       this.callback = null;
       this.tests = null;
       this.openedWindows = null;
     }
   },
@@ -436,17 +449,17 @@ Tester.prototype = {
     if (!aConsoleMessage.message)
       return;
 
     try {
       var msg = "Console message: " + aConsoleMessage.message;
       if (this.currentTest)
         this.currentTest.addResult(new testMessage(msg));
       else
-        this.structuredLogger.info("TEST-INFO | (browser-test.js) | " + msg.replace(/\n$/, "") + "\n");
+        this.dumper.dump("TEST-INFO | (browser-test.js) | " + msg.replace(/\n$/, "") + "\n");
     } catch (ex) {
       // Swallow exception so we don't lead to another error being reported,
       // throwing us into an infinite loop
     }
   },
 
   nextTest: Task.async(function*() {
     if (this.currentTest) {
@@ -563,17 +576,17 @@ Tester.prototype = {
                               this.currentTest.path,
                               gConfig.dumpOutputDirectory,
                               gConfig.dumpAboutMemoryAfterTest,
                               gConfig.dumpDMDAfterTest);
       }
 
       // Note the test run time
       let time = Date.now() - this.lastStartTime;
-      this.structuredLogger.testEnd(this.currentTest.path,
+      this.dumper.structuredLogger.testEnd(this.currentTest.path,
                                            "OK",
                                            undefined,
                                            "finished in " + time + "ms");
       this.currentTest.setDuration(time);
 
       if (this.runUntilFailure && this.currentTest.failCount > 0) {
         this.haltTests();
       }
@@ -707,17 +720,17 @@ Tester.prototype = {
       }
 
       this.currentTestIndex++;
       this.execTest();
     }).bind(this));
   }),
 
   execTest: function Tester_execTest() {
-    this.structuredLogger.testStart(this.currentTest.path);
+    this.dumper.structuredLogger.testStart(this.currentTest.path);
 
     this.SimpleTest.reset();
 
     // Load the tests into a testscope
     let currentScope = this.currentTest.scope = new testScope(this, this.currentTest, this.currentTest.expected);
     let currentTest = this.currentTest;
 
     // Import utils in the test scope.
@@ -1060,19 +1073,19 @@ function testScope(aTester, aTest, expec
           self.__waitTimer = null;
           self.__tester.nextTest();
         }
       });
     }
   };
 
   this.requestCompleteLog = function test_requestCompleteLog() {
-    self.__tester.structuredLogger.deactivateBuffering();
+    self.__tester.dumper.structuredLogger.deactivateBuffering();
     self.registerCleanupFunction(function() {
-      self.__tester.structuredLogger.activateBuffering();
+      self.__tester.dumper.structuredLogger.activateBuffering();
     })
   };
 }
 testScope.prototype = {
   __done: true,
   __tasks: null,
   __waitTimer: null,
   __cleanupFunctions: [],
--- a/testing/mochitest/install.rdf
+++ b/testing/mochitest/install.rdf
@@ -1,24 +1,20 @@
 <?xml version="1.0"?>
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
   <Description about="urn:mozilla:install-manifest">
     <em:id>mochikit@mozilla.org</em:id>
     <em:version>1.0</em:version>
-#ifdef MOCHITEST_BOOTSTRAP
-    <em:bootstrap>true</em:bootstrap>
-#endif
     <em:targetApplication>
       <Description>
         <em:id>toolkit@mozilla.org</em:id>
 #expand        <em:minVersion>__MOZILLA_VERSION_U__</em:minVersion>
-               <!-- Set to * so toolkit/mozapps/update/chrome tests pass. -->
-               <em:maxVersion>*</em:maxVersion>
+#expand        <em:maxVersion>__MOZILLA_VERSION_U__</em:maxVersion>
       </Description>
     </em:targetApplication>
     <!-- Front End MetaData -->
     <em:name>Mochitest</em:name>
     <em:description>Mochikit test harness</em:description>
     <em:creator>Joel Maher</em:creator>
   </Description>
 </RDF>
--- a/testing/mochitest/jetpack-addon-harness.js
+++ b/testing/mochitest/jetpack-addon-harness.js
@@ -11,17 +11,24 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
   "resource://gre/modules/AddonManager.jsm");
 
-setTimeout(testInit, 0);
+// Start the tests after the window has been displayed
+window.addEventListener("load", function testOnLoad() {
+  window.removeEventListener("load", testOnLoad);
+  window.addEventListener("MozAfterPaint", function testOnMozAfterPaint() {
+    window.removeEventListener("MozAfterPaint", testOnMozAfterPaint);
+    setTimeout(testInit, 0);
+  });
+});
 
 var sdkpath = null;
 
 // Strip off the chrome prefix to get the actual path of the test directory
 function realPath(chrome) {
   return chrome.substring("chrome://mochitests/content/jetpack-addon/".length)
                .replace(".xpi", "");
 }
--- a/testing/mochitest/jetpack-package-harness.js
+++ b/testing/mochitest/jetpack-package-harness.js
@@ -13,17 +13,24 @@ if (Cc === undefined) {
 }
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 
-setTimeout(testInit, 0);
+// Start the tests after the window has been displayed
+window.addEventListener("load", function testOnLoad() {
+  window.removeEventListener("load", testOnLoad);
+  window.addEventListener("MozAfterPaint", function testOnMozAfterPaint() {
+    window.removeEventListener("MozAfterPaint", testOnMozAfterPaint);
+    setTimeout(testInit, 0);
+  });
+});
 
 // Tests a single module
 function testModule(require, { url, expected }) {
   return new Promise(resolve => {
     let path = url.substring(TEST_PACKAGE.length);
 
     const { stdout } = require("sdk/system");
 
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -553,27 +553,23 @@ class MochitestArguments(ArgumentContain
                   "times in which case the test must contain at least one of the given tags.",
           }],
         [["--enable-cpow-warnings"],
          {"action": "store_true",
           "dest": "enableCPOWWarnings",
           "help": "Enable logging of unsafe CPOW usage, which is disabled by default for tests",
           "suppress": True,
           }],
-        [["--marionette"],
-         {"default": None,
-          "help": "host:port to use when connecting to Marionette",
-          }],
     ]
 
     defaults = {
         # Bug 1065098 - The geckomediaplugin process fails to produce a leak
         # log for some reason.
         'ignoreMissingLeaks': ["geckomediaplugin"],
-        'extensionsToExclude': ['specialpowers'],
+
         # Set server information on the args object
         'webServer': '127.0.0.1',
         'httpPort': DEFAULT_PORTS['http'],
         'sslPort': DEFAULT_PORTS['https'],
         'webSocketPort': '9988',
         # The default websocket port is incorrect in mozprofile; it is
         # set to the SSL proxy setting. See:
         # see https://bugzilla.mozilla.org/show_bug.cgi?id=916517
@@ -821,16 +817,20 @@ class B2GArguments(ArgumentContainer):
 
     args = [
         [["--b2gpath"],
          {"dest": "b2gPath",
           "default": None,
           "help": "Path to B2G repo or QEMU directory.",
           "suppress": True,
           }],
+        [["--marionette"],
+         {"default": None,
+          "help": "host:port to use when connecting to Marionette",
+          }],
         [["--emulator"],
          {"default": None,
           "help": "Architecture of emulator to use, x86 or arm",
           "suppress": True,
           }],
         [["--wifi"],
          {"default": False,
           "help": "Devine wifi configuration for on device mochitest",
@@ -914,18 +914,16 @@ class B2GArguments(ArgumentContainer):
           }],
     ]
 
     defaults = {
         'logFile': 'mochitest.log',
         # Specialpowers is integrated with marionette for b2g,
         # see marionette's jar.mn.
         'extensionsToExclude': ['specialpowers'],
-        # mochijar doesn't get installed via marionette on android
-        'extensionsToInstall': [os.path.join(here, 'mochijar')],
         # See dependencies of bug 1038943.
         'defaultLeakThreshold': 5536,
     }
 
     def validate(self, parser, options, context):
         """Validate b2g options."""
 
         if options.remoteWebServer is None:
@@ -1068,20 +1066,16 @@ class AndroidArguments(ArgumentContainer
           "help": "remote directory to use as test root \
                    (eg. /mnt/sdcard/tests or /data/local/tests)",
           "suppress": True,
           }],
     ]
 
     defaults = {
         'dm': None,
-        # we don't want to exclude specialpowers on android just yet
-        'extensionsToExclude': [],
-        # mochijar doesn't get installed via marionette on android
-        'extensionsToInstall': [os.path.join(here, 'mochijar')],
         'logFile': 'mochitest.log',
         'utilityPath': None,
     }
 
     def validate(self, parser, options, context):
         """Validate android options."""
 
         if build_obj:
--- a/testing/mochitest/moz.build
+++ b/testing/mochitest/moz.build
@@ -14,20 +14,16 @@ DIRS += [
 XPI_NAME = 'mochijar'
 
 JAR_MANIFESTS += ['jar.mn']
 
 USE_EXTENSION_MANIFEST = True
 
 FINAL_TARGET_PP_FILES += ['install.rdf']
 
-if CONFIG['MOZ_BUILD_APP'] != 'mobile/android' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
-    DEFINES['MOCHITEST_BOOTSTRAP'] = True
-    FINAL_TARGET_FILES += ['bootstrap.js']
-
 MOCHITEST_MANIFESTS += [
     'tests/MochiKit-1.4.2/tests/mochitest.ini',
 ]
 MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini']
 
 TEST_HARNESS_FILES.testing.mochitest += [
     '!automation.py',
     '/build/mobile/remoteautomation.py',
@@ -39,16 +35,17 @@ TEST_HARNESS_FILES.testing.mochitest += 
     '/netwerk/test/httpserver/httpd.js',
     '/testing/mozbase/mozdevice/mozdevice/devicemanager.py',
     '/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py',
     '/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py',
     '/testing/mozbase/mozdevice/mozdevice/droid.py',
     '/testing/mozbase/mozdevice/mozdevice/version_codes.py',
     '/testing/mozbase/mozdevice/mozdevice/Zeroconf.py',
     '/testing/mozbase/moznetwork/moznetwork/moznetwork.py',
+    'b2g_start_script.js',
     'bisection.py',
     'browser-harness.xul',
     'browser-test-overlay.xul',
     'browser-test.js',
     'cc-analyzer.js',
     'chrome-harness.js',
     'chunkifyTests.js',
     'gen_template.pl',
@@ -65,18 +62,16 @@ TEST_HARNESS_FILES.testing.mochitest += 
     'nested_setup.js',
     'pywebsocket_wrapper.py',
     'redirect.html',
     'runrobocop.py',
     'runtests.py',
     'runtestsb2g.py',
     'runtestsremote.py',
     'server.js',
-    'start_b2g.js',
-    'start_desktop.js',
 ]
 
 TEST_HARNESS_FILES.testing.mochitest.pywebsocket += [
     'pywebsocket/standalone.py',
 ]
 
 TEST_HARNESS_FILES.testing.mochitest.pywebsocket.mod_pywebsocket += [
     'pywebsocket/mod_pywebsocket/__init__.py',
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -39,25 +39,16 @@ from manifestparser import TestManifest
 from manifestparser.filters import (
     chunk_by_dir,
     chunk_by_runtime,
     chunk_by_slice,
     pathprefix,
     subsuite,
     tags,
 )
-
-try:
-    from marionette import Marionette
-    from marionette_driver.addons import Addons
-
-except ImportError:
-    # Marionette not needed nor supported on android
-    Marionette = None
-
 from leaks import ShutdownLeaks, LSANLeaks
 from mochitest_options import (
     MochitestArgumentParser, build_obj, get_default_valgrind_suppression_files
 )
 from mozprofile import Profile, Preferences
 from mozprofile.permissions import ServerLocations
 from urllib import quote_plus as encodeURIComponent
 from mozlog.formatters import TbplFormatter
@@ -509,51 +500,46 @@ class WebSocketServer(object):
 
 
 class MochitestBase(object):
     """
     Base mochitest class for both desktop and b2g.
     """
 
     oldcwd = os.getcwd()
-    mochijar = os.path.join(SCRIPT_DIR, 'mochijar')
+    jarDir = 'mochijar'
 
     # Path to the test script on the server
     TEST_PATH = "tests"
     NESTED_OOP_TEST_PATH = "nested_oop"
     CHROME_PATH = "redirect.html"
     urlOpts = []
     log = None
 
     def __init__(self, logger_options):
         self.update_mozinfo()
         self.server = None
         self.wsserver = None
         self.sslTunnel = None
         self._active_tests = None
         self._locations = None
 
-        self.marionette = None
-        self.start_script = None
-        self.start_script_args = []
-
         if self.log is None:
             commandline.log_formatters["tbpl"] = (
                 MochitestFormatter,
                 "Mochitest specific tbpl formatter")
             self.log = commandline.setup_logging("mochitest",
                                                  logger_options,
                                                  {
                                                      "tbpl": sys.stdout
                                                  })
             MochitestBase.log = self.log
 
         self.message_logger = MessageLogger(logger=self.log)
 
-
     def update_mozinfo(self):
         """walk up directories to find mozinfo.json update the info"""
         # TODO: This should go in a more generic place, e.g. mozinfo
 
         path = SCRIPT_DIR
         dirs = set()
         while path != os.path.expanduser('~'):
             if path in dirs:
@@ -887,16 +873,24 @@ class MochitestBase(object):
                     options.profilePath,
                     os.path.basename(abspath))
                 shutil.copytree(abspath, dest)
             else:
                 self.log.warning(
                     "runtests.py | Failed to copy %s to profile" %
                     abspath)
 
+    def installChromeJar(self, chrome, options):
+        """
+          copy mochijar directory to profile as an extension so we have chrome://mochikit for all harness code
+        """
+        # Write chrome.manifest.
+        with open(os.path.join(options.profilePath, "extensions", "staged", "mochikit@mozilla.org", "chrome.manifest"), "a") as mfile:
+            mfile.write(chrome)
+
     def getChromeTestDir(self, options):
         dir = os.path.join(os.path.abspath("."), SCRIPT_DIR) + "/"
         if mozinfo.isWin:
             dir = "file:///" + dir.replace("\\", "/")
         return dir
 
     def writeChromeManifest(self, options):
         manifest = os.path.join(options.profilePath, "tests.manifest")
@@ -938,26 +932,49 @@ toolbar#nav-bar {
   background-image: none !important;
 }
 """
         with open(os.path.join(options.profilePath, "userChrome.css"), "a") as chromeFile:
             chromeFile.write(chrome)
 
         manifest = self.writeChromeManifest(options)
 
-        if not os.path.isdir(self.mochijar):
+        # Call installChromeJar().
+        if not os.path.isdir(os.path.join(SCRIPT_DIR, self.jarDir)):
             self.log.info(
                 "TEST-UNEXPECTED-FAIL | invalid setup: missing mochikit extension")
             return None
 
+        # Support Firefox (browser), B2G (shell), SeaMonkey (navigator), and Webapp
+        # Runtime (webapp).
+        chrome = ""
+        if options.browserChrome or options.chrome or options.a11y or options.webapprtChrome:
+            chrome += """
+overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul
+overlay chrome://browser/content/shell.xhtml chrome://mochikit/content/browser-test-overlay.xul
+overlay chrome://navigator/content/navigator.xul chrome://mochikit/content/browser-test-overlay.xul
+overlay chrome://webapprt/content/webapp.xul chrome://mochikit/content/browser-test-overlay.xul
+"""
+
+        if options.jetpackPackage:
+            chrome += """
+overlay chrome://browser/content/browser.xul chrome://mochikit/content/jetpack-package-overlay.xul
+"""
+
+        if options.jetpackAddon:
+            chrome += """
+overlay chrome://browser/content/browser.xul chrome://mochikit/content/jetpack-addon-overlay.xul
+"""
+
+        self.installChromeJar(chrome, options)
         return manifest
 
     def getExtensionsToInstall(self, options):
         "Return a list of extensions to install in the profile"
-        extensions = []
+        extensions = options.extensionsToInstall or []
         appDir = options.app[
             :options.app.rfind(
                 os.sep)] if options.app else options.utilityPath
 
         extensionDirs = [
             # Extensions distributed with the test harness.
             os.path.normpath(os.path.join(SCRIPT_DIR, "extensions")),
         ]
@@ -972,17 +989,19 @@ toolbar#nav-bar {
         for extensionDir in extensionDirs:
             if os.path.isdir(extensionDir):
                 for dirEntry in os.listdir(extensionDir):
                     if dirEntry not in options.extensionsToExclude:
                         path = os.path.join(extensionDir, dirEntry)
                         if os.path.isdir(path) or (
                                 os.path.isfile(path) and path.endswith(".xpi")):
                             extensions.append(path)
-        extensions.extend(options.extensionsToInstall)
+
+        # append mochikit
+        extensions.append(os.path.join(SCRIPT_DIR, self.jarDir))
         return extensions
 
     def logPreamble(self, tests):
         """Logs a suite_start message and test_start/test_end at the beginning of a run.
         """
         self.log.suite_start([t['path'] for t in tests])
         for test in tests:
             if 'disabled' in test:
@@ -1244,30 +1263,16 @@ toolbar#nav-bar {
                 if parts[2] == pname and parts[1] == '1':
                     self.log.info("killing %s orphan with pid %d" % (pname, pid))
                     killPid(pid, self.log)
         process = mozprocess.ProcessHandler(['ps', '-o', 'pid,ppid,comm'],
                                             processOutputLine=_psKill)
         process.run()
         process.wait()
 
-    def execute_start_script(self):
-        if not self.start_script or not self.marionette:
-            return
-
-        if os.path.isfile(self.start_script):
-            with open(self.start_script, 'r') as fh:
-                script = fh.read()
-        else:
-            script = self.start_script
-
-        with self.marionette.using_context('chrome'):
-            return self.marionette.execute_script(script,
-                script_args=self.start_script_args)
-
 
 class SSLTunnel:
 
     def __init__(self, options, logger, ignoreSSLTunnelExts=False):
         self.log = logger
         self.process = None
         self.utilityPath = options.utilityPath
         self.xrePath = options.xrePath
@@ -1502,18 +1507,18 @@ class MochitestDesktop(MochitestBase):
     sslTunnel = None
     DEFAULT_TIMEOUT = 60.0
     mediaDevices = None
 
     # XXX use automation.py for test name to avoid breaking legacy
     # TODO: replace this with 'runtests.py' or 'mochitest' or the like
     test_name = 'automation.py'
 
-    def __init__(self, *args, **kwargs):
-        MochitestBase.__init__(self, *args, **kwargs)
+    def __init__(self, logger_options):
+        MochitestBase.__init__(self, logger_options)
 
         # Max time in seconds to wait for server startup before tests will fail -- if
         # this seems big, it's mostly for debug machines where cold startup
         # (particularly after a build) takes forever.
         self.SERVER_STARTUP_TIMEOUT = 180 if mozinfo.info.get('debug') else 90
 
         # metro browser sub process id
         self.browserProcessId = None
@@ -1522,18 +1527,16 @@ class MochitestDesktop(MochitestBase):
         # Create variables to count the number of passes, fails, todos.
         self.countpass = 0
         self.countfail = 0
         self.counttodo = 0
 
         self.expectedError = {}
         self.result = {}
 
-        self.start_script = os.path.join(here, 'start_desktop.js')
-
     def extraPrefs(self, extraPrefs):
         """interpolate extra preferences from option strings"""
 
         try:
             return dict(parseKeyValue(extraPrefs, context='--setpref='))
         except KeyValueParseError as e:
             print str(e)
             sys.exit(1)
@@ -1851,21 +1854,21 @@ class MochitestDesktop(MochitestBase):
                extraArgs,
                utilityPath,
                debuggerInfo=None,
                valgrindPath=None,
                valgrindArgs=None,
                valgrindSuppFiles=None,
                symbolsPath=None,
                timeout=-1,
+               onLaunch=None,
                detectShutdownLeaks=False,
                screenshotOnFail=False,
                bisectChunk=None,
-               quiet=False,
-               marionette_args=None):
+               quiet=False):
         """
         Run the app, log the duration it took to execute, return the status code.
         Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
         """
 
         # configure the message logger buffering
         self.message_logger.buffering = quiet
 
@@ -1919,26 +1922,23 @@ class MochitestDesktop(MochitestBase):
                 # If a debugger is attached, don't use timeouts, and don't
                 # capture ctrl-c.
                 timeout = None
                 signal.signal(signal.SIGINT, lambda sigid, frame: None)
 
             # build command line
             cmd = os.path.abspath(app)
             args = list(extraArgs)
-            args.append('-marionette')
             # TODO: mozrunner should use -foreground at least for mac
             # https://bugzilla.mozilla.org/show_bug.cgi?id=916512
             args.append('-foreground')
             if testUrl:
                 if debuggerInfo and debuggerInfo.requiresEscapedArgs:
                     testUrl = testUrl.replace("&", "\\&")
-                self.start_script_args.append(testUrl)
-            else:
-                self.start_script_args.append('about:blank')
+                args.append(testUrl)
 
             if detectShutdownLeaks:
                 shutdownLeaks = ShutdownLeaks(self.log)
             else:
                 shutdownLeaks = None
 
             if mozinfo.info["asan"] and (mozinfo.isLinux or mozinfo.isMac):
                 lsanLeaks = LSANLeaks(self.log)
@@ -1979,50 +1979,37 @@ class MochitestDesktop(MochitestBase):
                     'toolkit') != 'gonk':
                 runner_cls = mozrunner.Runner
             else:
                 runner_cls = mozrunner.runners.get(
                     mozinfo.info.get(
                         'appname',
                         'firefox'),
                     mozrunner.Runner)
-
             runner = runner_cls(profile=self.profile,
                                 binary=cmd,
                                 cmdargs=args,
                                 env=env,
                                 process_class=mozprocess.ProcessHandlerMixin,
                                 process_args=kp_kwargs)
 
             # start the runner
             runner.start(debug_args=debug_args,
                          interactive=interactive,
                          outputTimeout=timeout)
             proc = runner.process_handler
             self.log.info("runtests.py | Application pid: %d" % proc.pid)
             self.log.process_start("Main app process")
 
-            # start marionette and kick off the tests
-            marionette_args = marionette_args or {}
-            self.marionette = Marionette(**marionette_args)
-            self.marionette.start_session()
-
-            # install specialpowers and mochikit as temporary addons
-            addons = Addons(self.marionette)
-
-            if mozinfo.info.get('toolkit') != 'gonk':
-                addons.install(os.path.join(here, 'extensions', 'specialpowers'), temp=True)
-                addons.install(self.mochijar, temp=True)
-
-            self.execute_start_script()
-
-            # an open marionette session interacts badly with mochitest,
-            # delete it until we figure out why.
-            self.marionette.delete_session()
-            del self.marionette
+            if onLaunch is not None:
+                # Allow callers to specify an onLaunch callback to be fired after the
+                # app is launched.
+                # We call onLaunch for b2g desktop mochitests so that we can
+                # run a Marionette script after gecko has completed startup.
+                onLaunch()
 
             # wait until app is finished
             # XXX copy functionality from
             # https://github.com/mozilla/mozbase/blob/master/mozrunner/mozrunner/runner.py#L61
             # until bug 913970 is fixed regarding mozrunner `wait` not returning status
             # see https://bugzilla.mozilla.org/show_bug.cgi?id=913970
             status = proc.wait()
             self.log.process_exit("Main app process", status)
@@ -2115,34 +2102,34 @@ class MochitestDesktop(MochitestBase):
         testsToRun = []
         for test in tests:
             if 'disabled' in test:
                 continue
             testsToRun.append(test['path'])
 
         return testsToRun
 
-    def runMochitests(self, options, testsToRun):
+    def runMochitests(self, options, testsToRun, onLaunch=None):
         "This is a base method for calling other methods in this class for --bisect-chunk."
         # Making an instance of bisect class for --bisect-chunk option.
         bisect = bisection.Bisect(self)
         finished = False
         status = 0
         bisection_log = 0
         while not finished:
             if options.bisectChunk:
                 testsToRun = bisect.pre_test(options, testsToRun, status)
                 # To inform that we are in the process of bisection, and to
                 # look for bleedthrough
                 if options.bisectChunk != "default" and not bisection_log:
                     self.log.info(
                         "TEST-UNEXPECTED-FAIL | Bisection | Please ignore repeats and look for 'Bleedthrough' (if any) at the end of the failure list")
                     bisection_log = 1
 
-            result = self.doTests(options, testsToRun)
+            result = self.doTests(options, onLaunch, testsToRun)
             if options.bisectChunk:
                 status = bisect.post_test(
                     options,
                     self.expectedError,
                     self.result)
             else:
                 status = -1
 
@@ -2152,17 +2139,17 @@ class MochitestDesktop(MochitestBase):
         # We need to print the summary only if options.bisectChunk has a value.
         # Also we need to make sure that we do not print the summary in between
         # running tests via --run-by-dir.
         if options.bisectChunk and options.bisectChunk in self.result:
             bisect.print_summary()
 
         return result
 
-    def runTests(self, options):
+    def runTests(self, options, onLaunch=None):
         """ Prepare, configure, run tests and cleanup """
 
         self.setTestRoot(options)
 
         # Despite our efforts to clean up servers started by this script, in practice
         # we still see infrequent cases where a process is orphaned and interferes
         # with future tests, typically because the old server is keeping the port in use.
         # Try to avoid those failures by checking for and killing orphan servers before
@@ -2170,30 +2157,30 @@ class MochitestDesktop(MochitestBase):
         self.killNamedOrphans('ssltunnel')
         self.killNamedOrphans('xpcshell')
 
         # Until we have all green, this only runs on bc*/dt*/mochitest-chrome
         # jobs, not webapprt*, jetpack*, a11yr (for perf reasons), or plain
 
         testsToRun = self.getTestsToRun(options)
         if not options.runByDir:
-            return self.runMochitests(options, testsToRun)
+            return self.runMochitests(options, testsToRun, onLaunch)
 
         # code for --run-by-dir
         dirs = self.getDirectories(options)
 
         result = 1  # default value, if no tests are run.
         for d in dirs:
             print "dir: %s" % d
             tests_in_dir = [t for t in testsToRun if os.path.dirname(t) == d]
 
             # If we are using --run-by-dir, we should not use the profile path (if) provided
             # by the user, since we need to create a new directory for each run. We would face problems
             # if we use the directory provided by the user.
-            result = self.runMochitests(options, tests_in_dir)
+            result = self.runMochitests(options, tests_in_dir, onLaunch)
 
             # Dump the logging buffer
             self.message_logger.dump_buffered()
 
             if result == -1:
                 break
 
         # printing total number of tests
@@ -2208,17 +2195,17 @@ class MochitestDesktop(MochitestBase):
             print "0 INFO TEST-START | Shutdown"
             print "1 INFO Passed:  %s" % self.countpass
             print "2 INFO Failed:  %s" % self.countfail
             print "3 INFO Todo:    %s" % self.counttodo
             print "4 INFO SimpleTest FINISHED"
 
         return result
 
-    def doTests(self, options, testsToFilter=None):
+    def doTests(self, options, onLaunch=None, testsToFilter=None):
         # A call to initializeLooping method is required in case of --run-by-dir or --bisect-chunk
         # since we need to initialize variables for each loop.
         if options.bisectChunk or options.runByDir:
             self.initializeLooping(options)
 
         # get debugger info, a dict of:
         # {'path': path to the debugger (string),
         #  'interactive': whether the debugger is interactive or not (bool)
@@ -2346,45 +2333,35 @@ class MochitestDesktop(MochitestBase):
                 timeout = None
             else:
                 timeout = 330.0  # default JS harness timeout is 300 seconds
 
             # detect shutdown leaks for m-bc runs
             detectShutdownLeaks = mozinfo.info[
                 "debug"] and options.browserChrome and not options.webapprtChrome
 
-            self.start_script_args.append(self.getTestFlavor(options))
-            marionette_args = {
-                'symbols_path': options.symbolsPath,
-            }
-
-            if options.marionette:
-                host, port = options.marionette.split(':')
-                marionette_args['host'] = host
-                marionette_args['port'] = int(port)
-
             self.log.info("runtests.py | Running tests: start.\n")
             try:
                 status = self.runApp(testURL,
                                      self.browserEnv,
                                      options.app,
                                      profile=self.profile,
                                      extraArgs=options.browserArgs,
                                      utilityPath=options.utilityPath,
                                      debuggerInfo=debuggerInfo,
                                      valgrindPath=valgrindPath,
                                      valgrindArgs=valgrindArgs,
                                      valgrindSuppFiles=valgrindSuppFiles,
                                      symbolsPath=options.symbolsPath,
                                      timeout=timeout,
+                                     onLaunch=onLaunch,
                                      detectShutdownLeaks=detectShutdownLeaks,
                                      screenshotOnFail=options.screenshotOnFail,
                                      bisectChunk=options.bisectChunk,
-                                     quiet=options.quiet,
-                                     marionette_args=marionette_args,
+                                     quiet=options.quiet
                                      )
             except KeyboardInterrupt:
                 self.log.info("runtests.py | Received keyboard interrupt.\n")
                 status = -1
             except:
                 traceback.print_exc()
                 self.log.error(
                     "Automation Error: Received unexpected exception while running application\n")
@@ -2632,17 +2609,16 @@ class MochitestDesktop(MochitestBase):
 
         return dirlist
 
 
 def run_test_harness(options):
     logger_options = {
         key: value for key, value in vars(options).iteritems()
         if key.startswith('log') or key == 'valgrind'}
-
     runner = MochitestDesktop(logger_options)
 
     options.runByDir = False
 
     if runner.getTestFlavor(options) == 'mochitest':
         options.runByDir = True
 
     if runner.getTestFlavor(options) == 'browser-chrome':
--- a/testing/mochitest/runtestsb2g.py
+++ b/testing/mochitest/runtestsb2g.py
@@ -37,18 +37,18 @@ class MochitestB2G(MochitestBase):
                  remote_test_root=None,
                  remote_log_file=None):
         MochitestBase.__init__(self, logger_options)
         self.marionette_args = marionette_args
         self.out_of_process = out_of_process
         self.locations_file = locations
         self.preferences = []
         self.webapps = None
-        self.start_script = os.path.join(here, 'start_b2g.js')
-        self.start_script_args = [self.out_of_process]
+        self.test_script = os.path.join(here, 'b2g_start_script.js')
+        self.test_script_args = [self.out_of_process]
         self.product = 'b2g'
         self.remote_chrome_test_dir = None
         self.local_log = None
         self.local_binary_dir = local_binary_dir
 
         self.preferences = [
             os.path.join(
                 profile_data_dir,
@@ -193,19 +193,19 @@ class MochitestB2G(MochitestBase):
             # style manifest. Not so with B2G, that conversion along with updating the URL
             # option will happen later. So backup and restore options.manifestFile to
             # prevent us from trying to pass in an instance of TestManifest via url param.
             manifestFile = options.manifestFile
             options.manifestFile = None
             self.buildURLOptions(options, {'MOZ_HIDE_RESULTS_TABLE': '1'})
             options.manifestFile = manifestFile
 
-            self.start_script_args.append(not options.emulator)
-            self.start_script_args.append(options.wifi)
-            self.start_script_args.append(options.chrome)
+            self.test_script_args.append(not options.emulator)
+            self.test_script_args.append(options.wifi)
+            self.test_script_args.append(options.chrome)
 
             self.runner.start(outputTimeout=timeout)
 
             self.marionette.wait_for_port()
             self.marionette.start_session()
             self.marionette.set_context(self.marionette.CONTEXT_CHROME)
 
             # Disable offline status management (bug 777145), otherwise the network
@@ -238,17 +238,25 @@ class MochitestB2G(MochitestBase):
                 local = MochitestBase.getChromeTestDir(self, options)
                 local = os.path.join(local, "chrome")
                 remote = self.remote_chrome_test_dir
                 self.log.info(
                     "pushing %s to %s on device..." %
                     (local, remote))
                 self.app_ctx.dm.pushDir(local, remote)
 
-            self.execute_start_script()
+            if os.path.isfile(self.test_script):
+                with open(self.test_script, 'r') as script:
+                    self.marionette.execute_script(
+                        script.read(),
+                        script_args=self.test_script_args)
+            else:
+                self.marionette.execute_script(
+                    self.test_script,
+                    script_args=self.test_script_args)
             status = self.runner.wait()
 
             if status is None:
                 # the runner has timed out
                 status = 124
 
             local_leak_file = tempfile.NamedTemporaryFile()
             self.app_ctx.dm.getFile(
@@ -349,17 +357,17 @@ class MochitestB2G(MochitestBase):
         # For B2G emulators buildURLOptions has been called
         # without calling buildTestPath first and that
         # causes manifestFile not to be set
         if "manifestFile=tests.json" not in self.urlOpts:
             self.urlOpts.append("manifestFile=%s" % options.manifestFile)
 
         if len(self.urlOpts) > 0:
             test_url += "?" + "&".join(self.urlOpts)
-        self.start_script_args.append(test_url)
+        self.test_script_args.append(test_url)
 
         options.profilePath = self.app_ctx.remote_profile
         options.logFile = self.local_log
 
 
 def run_test_harness(options):
     # create our Marionette instance
     marionette_args = {
--- a/testing/mochitest/runtestsremote.py
+++ b/testing/mochitest/runtestsremote.py
@@ -191,30 +191,16 @@ class MochiRemote(MochitestDesktop):
             self.log.error(
                 "Automation Error: Unable to copy profile to device.")
             raise
 
         restoreRemotePaths()
         options.profilePath = self.remoteProfile
         return manifest
 
-    def addChromeToProfile(self, options):
-        manifest = MochitestDesktop.addChromeToProfile(self, options)
-
-        # Support Firefox (browser), B2G (shell), SeaMonkey (navigator), and Webapp
-        # Runtime (webapp).
-        if options.chrome:
-            # append overlay to chrome.manifest
-            chrome = "overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul"
-            path = os.path.join(options.profilePath, 'extensions', 'staged',
-                                'mochikit@mozilla.org', 'chrome.manifest')
-            with open(path, "a") as f:
-                f.write(chrome)
-        return manifest
-
     def buildURLOptions(self, options, env):
         self.localLog = options.logFile
         options.logFile = self.remoteLog
         options.fileLevel = 'INFO'
         options.profilePath = self.localProfile
         env["MOZ_HIDE_RESULTS_TABLE"] = "1"
         retVal = MochitestDesktop.buildURLOptions(self, options, env)
 
@@ -290,19 +276,18 @@ class MochiRemote(MochitestDesktop):
     def runApp(self, *args, **kwargs):
         """front-end automation.py's `runApp` functionality until FennecRunner is written"""
 
         # automation.py/remoteautomation `runApp` takes the profile path,
         # whereas runtest.py's `runApp` takes a mozprofile object.
         if 'profileDir' not in kwargs and 'profile' in kwargs:
             kwargs['profileDir'] = kwargs.pop('profile').profile
 
-        # remove args not supported by automation.py
-        kwargs.pop('marionette_args', None)
-        kwargs.pop('quiet', None)
+        if 'quiet' in kwargs:
+            kwargs.pop('quiet')
 
         return self._automation.runApp(*args, **kwargs)
 
 
 def run_test_harness(options):
     message_logger = MessageLogger(logger=None)
     process_args = {'messageLogger': message_logger}
     auto = RemoteAutomation(None, "fennec", processArgs=process_args)
deleted file mode 100644
--- a/testing/mochitest/start_desktop.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const flavor  = __marionetteParams[0]
-const url = __marionetteParams[1]
-
-let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
-          .getService(Ci.nsIWindowMediator);
-let win = wm.getMostRecentWindow("navigator:browser");
-
-// mochikit's bootstrap.js has set up a listener for this event. It's
-// used so bootstrap.js knows which flavor and url to load.
-let ev = new CustomEvent('mochitest-load', {'detail': [flavor, url]});
-win.dispatchEvent(ev);
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -88,18 +88,16 @@ user_pref("browser.safebrowsing.download
 user_pref("browser.safebrowsing.provider.google.gethashURL", "http://%(server)s/safebrowsing-dummy/gethash");
 user_pref("browser.safebrowsing.provider.google.updateURL", "http://%(server)s/safebrowsing-dummy/update");
 user_pref("browser.safebrowsing.provider.mozilla.gethashURL", "http://%(server)s/safebrowsing-dummy/gethash");
 user_pref("browser.safebrowsing.provider.mozilla.updateURL", "http://%(server)s/safebrowsing-dummy/update");
 user_pref("privacy.trackingprotection.introURL", "http://%(server)s/trackingprotection/tour");
 // Point update checks to the local testing server for fast failures
 user_pref("extensions.update.url", "http://%(server)s/extensions-dummy/updateURL");
 user_pref("extensions.update.background.url", "http://%(server)s/extensions-dummy/updateBackgroundURL");
-user_pref("extensions.blocklist.detailsURL", "http://%(server)s/extensions-dummy/blocklistDetailsURL");
-user_pref("extensions.blocklist.itemURL", "http://%(server)s/extensions-dummy/blocklistItemURL");
 user_pref("extensions.blocklist.url", "http://%(server)s/extensions-dummy/blocklistURL");
 user_pref("extensions.hotfix.url", "http://%(server)s/extensions-dummy/hotfixURL");
 user_pref("extensions.systemAddon.update.url", "http://%(server)s/dummy-system-addons.xml");
 // Turn off extension updates so they don't bother tests
 user_pref("extensions.update.enabled", false);
 // Bug 1235627 Turn off pocket add-on so it doesn't bother tests
 user_pref("extensions.pocket.enabled", false);
 // Make sure opening about:addons won't hit the network
@@ -340,9 +338,8 @@ user_pref("browser.urlbar.suggest.search
 
 // Turn off the location bar search suggestions opt-in.  It interferes with
 // tests that don't expect it to be there.
 user_pref("browser.urlbar.userMadeSearchSuggestionsChoice", true);
 
 user_pref("dom.audiochannel.mutedByDefault", false);
 
 user_pref("webextensions.tests", true);
-user_pref("startup.homepage_welcome_url", "about:blank");
--- a/toolkit/mozapps/extensions/test/browser/browser_select_confirm.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_select_confirm.js
@@ -106,41 +106,39 @@ function end_test() {
 // Test for disabling
 add_test(function disabling_test() {
   setupUI(false, false, function() {
     ok(gWin.document.getElementById("incompatible-list").hidden, "Incompatible list should be hidden");
     ok(gWin.document.getElementById("update-list").hidden, "Update list should be hidden");
 
     var list = gWin.document.getElementById("disable-list");
     ok(!list.hidden, "Disable list should be visible");
-    // As of bug 1231784, mochikit and special-powers are temporary addons
-    // and therefore also getting disabled.
-    is(list.childNodes.length, 4, "Should be three add-ons getting disabled (plus the header)");
-    is(list.childNodes[3].id, "test2@tests.mozilla.org", "Should be the right add-on ID");
-    is(list.childNodes[3].getAttribute("name"), "Test Add-on 2", "Should be the right add-on name");
+    is(list.childNodes.length, 2, "Should be one add-on getting disabled (plus the header)");
+    is(list.childNodes[1].id, "test2@tests.mozilla.org", "Should be the right add-on ID");
+    is(list.childNodes[1].getAttribute("name"), "Test Add-on 2", "Should be the right add-on name");
 
     var list = gWin.document.getElementById("enable-list");
     ok(!list.hidden, "Enable list should be visible");
-    is(list.childNodes.length, 2, "Should be one add-on getting enabled (plus the header)");
+    is(list.childNodes.length, 2, "Should be one add-on getting disabled (plus the header)");
     is(list.childNodes[1].id, "test3@tests.mozilla.org", "Should be the right add-on ID");
     is(list.childNodes[1].getAttribute("name"), "Test Add-on 3", "Should be the right add-on name");
 
     ok(gWin.document.getElementById("next").hidden, "Next button should be hidden");
     ok(!gWin.document.getElementById("done").hidden, "Done button should be visible");
     gWin.close();
 
     run_next_test();
   });
 });
 
 // Test for incompatible
 add_test(function incompatible_test() {
   setupUI(true, false, function() {
     ok(gWin.document.getElementById("update-list").hidden, "Update list should be hidden");
-    ok(!gWin.document.getElementById("disable-list").hidden, "Disable list should be visible");
+    ok(gWin.document.getElementById("disable-list").hidden, "Disable list should be hidden");
     ok(gWin.document.getElementById("enable-list").hidden, "Enable list should be hidden");
 
     var list = gWin.document.getElementById("incompatible-list");
     ok(!list.hidden, "Incompatible list should be visible");
     is(list.childNodes.length, 3, "Should be two add-ons waiting to be compatible (plus the header)");
     is(list.childNodes[1].id, "test1@tests.mozilla.org", "Should be the right add-on ID");
     is(list.childNodes[1].getAttribute("name"), "Test Add-on 1", "Should be the right add-on name");
     is(list.childNodes[2].id, "test3@tests.mozilla.org", "Should be the right add-on ID");
@@ -165,21 +163,19 @@ add_test(function update_test() {
     is(list.childNodes.length, 3, "Should be two add-ons waiting to be updated (plus the header)");
     is(list.childNodes[1].id, "test1@tests.mozilla.org", "Should be the right add-on ID");
     is(list.childNodes[1].getAttribute("name"), "Test Add-on 1", "Should be the right add-on name");
     is(list.childNodes[2].id, "test3@tests.mozilla.org", "Should be the right add-on ID");
     is(list.childNodes[2].getAttribute("name"), "Test Add-on 3", "Should be the right add-on name");
 
     list = gWin.document.getElementById("disable-list");
     ok(!list.hidden, "Disable list should be visible");
-    // As of bug 1231784, mochikit and special-powers are temporary addons
-    // and therefore also getting disabled.
-    is(list.childNodes.length, 4, "Should be three add-ons getting disabled (plus the header)");
-    is(list.childNodes[3].id, "test2@tests.mozilla.org", "Should be the right add-on ID");
-    is(list.childNodes[3].getAttribute("name"), "Test Add-on 2", "Should be the right add-on name");
+    is(list.childNodes.length, 2, "Should be one add-on getting disabled (plus the header)");
+    is(list.childNodes[1].id, "test2@tests.mozilla.org", "Should be the right add-on ID");
+    is(list.childNodes[1].getAttribute("name"), "Test Add-on 2", "Should be the right add-on name");
 
     ok(!gWin.document.getElementById("next").hidden, "Next button should be visible");
     ok(gWin.document.getElementById("done").hidden, "Done button should be hidden");
     gWin.close();
 
     run_next_test();
   });
 });
--- a/toolkit/mozapps/update/tests/chrome/utils.js
+++ b/toolkit/mozapps/update/tests/chrome/utils.js
@@ -1290,28 +1290,27 @@ function setupAddons(aCallback) {
     setNoUpdateAddonsDisabledState();
     return;
   }
 
   // Disable all pre-existing enabled addons so they don't interfere with the
   // tests.
   AddonManager.getAllAddons(function(aAddons) {
     let disabledAddons = [];
-    let harnessAddons = ["special-powers@mozilla.org", "mochikit@mozilla.org"];
     aAddons.forEach(function(aAddon) {
       // If an addon's type equals plugin it is skipped since
       // checking plugins compatibility information isn't supported at this
       // time (also see bug 566787). Also, SCOPE_APPLICATION add-ons are
       // excluded by app update so there is no reason to disable them.
-      // Specialpowers and mochikit are excluded as the test harness requires
-      // them to run the tests.
+      // Specialpowers is excluded as the test harness requires it to run
+      // the tests.
       if (aAddon.type != "plugin" && !aAddon.appDisabled &&
           !aAddon.userDisabled &&
           aAddon.scope != AddonManager.SCOPE_APPLICATION &&
-          harnessAddons.indexOf(aAddon.id) == -1) {
+          aAddon.id != "special-powers@mozilla.org") {
         disabledAddons.push(aAddon);
         aAddon.userDisabled = true;
       }
     });
     // If there are no pre-existing add-ons the preference value will be an
     // empty string.
     Services.prefs.setCharPref(PREF_DISABLEDADDONS, disabledAddons.join(" "));