Merge m-c to inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 26 May 2016 21:50:28 -0400
changeset 338248 d61769108d96a74b2389bc36c4c00f4686a0b794
parent 338247 69c675c22f86edad3830fcef5decabc2add794ba (current diff)
parent 338219 4d63dde701b47b8661ab7990f197b6b60e543839 (diff)
child 338249 d4a5ef2ca595a3f3fcafd16062c4f1c22ce35c79
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone49.0a1
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
Merge m-c to inbound. a=merge CLOSED TREE
devtools/client/debugger/test/mochitest/browser_dbg_reload-preferred-script-01.js
--- a/devtools/client/animationinspector/animation-controller.js
+++ b/devtools/client/animationinspector/animation-controller.js
@@ -14,17 +14,17 @@
 
 var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 var { loader, require } = Cu.import("resource://devtools/shared/Loader.jsm");
 var { Task } = require("devtools/shared/task");
 
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
-loader.lazyRequireGetter(this, "AnimationsFront", "devtools/server/actors/animation", true);
+loader.lazyRequireGetter(this, "AnimationsFront", "devtools/shared/fronts/animation", true);
 
 const { LocalizationHelper } = require("devtools/client/shared/l10n");
 
 const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties";
 const L10N = new LocalizationHelper(STRINGS_URI);
 
 // Global toolbox/inspector, set when startup is called.
 var gToolbox, gInspector;
--- a/devtools/client/debugger/test/mochitest/browser.ini
+++ b/devtools/client/debugger/test/mochitest/browser.ini
@@ -391,18 +391,16 @@ skip-if = e10s && debug
 [browser_dbg_promises-allocation-stack.js]
 skip-if = e10s && debug
 [browser_dbg_promises-chrome-allocation-stack.js]
 skip-if = true # Bug 1177730
 [browser_dbg_promises-fulfillment-stack.js]
 skip-if = e10s && debug
 [browser_dbg_promises-rejection-stack.js]
 skip-if = e10s && debug
-[browser_dbg_reload-preferred-script-01.js]
-skip-if = e10s && debug
 [browser_dbg_reload-preferred-script-02.js]
 skip-if = e10s && debug
 [browser_dbg_reload-preferred-script-03.js]
 skip-if = e10s && debug
 [browser_dbg_reload-same-script.js]
 skip-if = e10s && debug
 [browser_dbg_scripts-switching-01.js]
 skip-if = e10s && debug
--- a/devtools/client/debugger/test/mochitest/browser_dbg_aaa_run_first_leaktest.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_aaa_run_first_leaktest.js
@@ -11,17 +11,21 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
   // Wait longer for this very simple test that comes first, to make sure that
   // GC from previous tests does not interfere with the debugger suite.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     ok(aTab, "Should have a tab available.");
     ok(aPanel, "Should have a debugger pane available.");
 
     waitForSourceAndCaretAndScopes(aPanel, "-02.js", 1).then(() => {
       resumeDebuggerThenCloseAndFinish(aPanel);
     });
 
     callInTab(aTab, "firstCall");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_auto-pretty-print-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_auto-pretty-print-01.js
@@ -11,28 +11,31 @@ var gTab, gPanel, gDebugger;
 var gEditor, gSources, gPrefs, gOptions, gView;
 
 var gFirstSourceLabel = "code_ugly-5.js";
 var gSecondSourceLabel = "code_ugly-6.js";
 
 var gOriginalPref = Services.prefs.getBoolPref("devtools.debugger.auto-pretty-print");
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: gFirstSourceLabel,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gPrefs = gDebugger.Prefs;
     gOptions = gDebugger.DebuggerView.Options;
     gView = gDebugger.DebuggerView;
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, gFirstSourceLabel);
       testSourceIsUgly();
 
       enableAutoPrettyPrint();
       testAutoPrettyPrintOn();
 
       reload(gPanel);
       yield waitForSourceShown(gPanel, gFirstSourceLabel);
       testSourceIsUgly();
--- a/devtools/client/debugger/test/mochitest/browser_dbg_auto-pretty-print-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_auto-pretty-print-02.js
@@ -16,33 +16,36 @@ var gEditor, gSources, gPrefs, gOptions,
 
 var gFirstSourceLabel = "code_ugly-6.js";
 var gSecondSourceLabel = "code_ugly-7.js";
 
 var gOriginalPref = Services.prefs.getBoolPref("devtools.debugger.auto-pretty-print");
 Services.prefs.setBoolPref("devtools.debugger.auto-pretty-print", true);
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  let options = {
+    source: gFirstSourceLabel,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab, aDebuggee, aPanel]) => {
     const gTab = aTab;
     const gDebuggee = aDebuggee;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const gPrefs = gDebugger.Prefs;
     const gOptions = gDebugger.DebuggerView.Options;
     const gView = gDebugger.DebuggerView;
 
     // Should be on by default.
     testAutoPrettyPrintOn();
 
     Task.spawn(function* () {
 
-      yield waitForSourceShown(gPanel, gFirstSourceLabel);
       testSourceIsUgly();
 
       yield waitForSourceShown(gPanel, gFirstSourceLabel);
       testSourceIsPretty();
       testPrettyPrintButtonOn();
 
       // select second source
       yield selectSecondSource();
--- a/devtools/client/debugger/test/mochitest/browser_dbg_auto-pretty-print-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_auto-pretty-print-03.js
@@ -10,30 +10,32 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_auto-pretty-print-02.html";
 
 var FIRST_SOURCE = "code_ugly-6.js";
 var SECOND_SOURCE = "code_ugly-7.js";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  let options = {
+    source: FIRST_SOURCE,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab, aDebuggee, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
 
     const gController = gDebugger.DebuggerController;
     const gEditor = gDebugger.DebuggerView.editor;
     const constants = gDebugger.require("./content/constants");
     const queries = gDebugger.require("./content/queries");
     const actions = bindActionCreators(gPanel);
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, FIRST_SOURCE);
-
       const secondSource = queries.getSourceByURL(gController.getState(), EXAMPLE_URL + SECOND_SOURCE);
       actions.selectSource(secondSource);
 
       // It should be showing the loading text
       is(gEditor.getText(), gDebugger.DebuggerView._loadingText,
         "The editor loading text is shown");
 
       gController.dispatch({
--- a/devtools/client/debugger/test/mochitest/browser_dbg_bfcache.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_bfcache.js
@@ -12,17 +12,21 @@ const TAB_URL_1 = EXAMPLE_URL + "doc_scr
 const TAB_URL_2 = EXAMPLE_URL + "doc_recursion-stack.html";
 
 var gTab, gDebuggee, gPanel, gDebugger;
 var gSources;
 
 const test = Task.async(function* () {
   info("Starting browser_dbg_bfcache.js's `test`.");
 
-  ([gTab, gDebuggee, gPanel]) = yield initDebugger(TAB_URL_1);
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  ([gTab, gDebuggee, gPanel]) = yield initDebugger(TAB_URL_1, options);
   gDebugger = gPanel.panelWin;
   gSources = gDebugger.DebuggerView.Sources;
 
   yield testFirstPage();
   yield testLocationChange();
   yield testBack();
   yield testForward();
   return closeDebuggerAndFinish(gPanel);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-01.js
@@ -7,23 +7,26 @@
  * Test that if we black box a source and then refresh, it is still black boxed.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_binary_search.html";
 
 var gTab, gPanel, gDebugger;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: ".coffee",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
 
-    waitForSourceShown(gPanel, ".coffee")
-      .then(testBlackBoxSource)
+    testBlackBoxSource()
       .then(testBlackBoxReload)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 }
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-02.js
@@ -10,24 +10,27 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
 const BLACKBOXME_URL = EXAMPLE_URL + "code_blackboxing_blackboxme.js";
 
 var gTab, gPanel, gDebugger;
 var gFrames;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: BLACKBOXME_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gFrames = gDebugger.DebuggerView.StackFrames;
 
-    waitForSourceShown(gPanel, BLACKBOXME_URL)
-      .then(testBlackBoxSource)
+    testBlackBoxSource()
       .then(testBlackBoxStack)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 }
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-03.js
@@ -10,17 +10,21 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
 const BLACKBOXME_URL = EXAMPLE_URL + "code_blackboxing_blackboxme.js";
 
 var gTab, gPanel, gDebugger;
 var gFrames, gSources;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: BLACKBOXME_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gSources = gDebugger.DebuggerView.Sources;
 
     waitForSourceAndCaretAndScopes(gPanel, ".html", 21)
       .then(testBlackBoxStack)
--- a/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-04.js
@@ -10,25 +10,28 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
 const BLACKBOXME_URL = EXAMPLE_URL + "code_blackboxing_blackboxme.js";
 
 var gTab, gPanel, gDebugger;
 var gFrames, gSources;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: BLACKBOXME_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gSources = gDebugger.DebuggerView.Sources;
 
-    waitForSourceShown(gPanel, BLACKBOXME_URL)
-      .then(blackBoxSources)
+    blackBoxSources()
       .then(testBlackBoxStack)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 }
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-05.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-05.js
@@ -9,25 +9,28 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_binary_search.html";
 
 var gTab, gPanel, gDebugger;
 var gDeck;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: ".coffee",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gDeck = gDebugger.document.getElementById("editor-deck");
 
-    waitForSourceShown(gPanel, ".coffee")
-      .then(testSourceEditorShown)
-      .then(toggleBlackBoxing.bind(null, gPanel))
+    testSourceEditorShown();
+    toggleBlackBoxing(gPanel)
       .then(testBlackBoxMessageShown)
       .then(clickStopBlackBoxingButton)
       .then(testSourceEditorShownAgain)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-06.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-06.js
@@ -9,23 +9,27 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
 
 var gTab, gPanel, gDebugger;
 var gSources;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "code_blackboxing_blackboxme.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 21)
+    waitForCaretAndScopes(gPanel, 21)
       .then(testBlackBox)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
     callInTab(gTab, "runTest");
   });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-07.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-07.js
@@ -8,23 +8,25 @@
  * and then refresh, it is still unblackboxed.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_blackboxing_unblackbox.html";
 
 var gTab, gPanel, gDebugger;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: ".min.js"
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
 
-    waitForSourceShown(gPanel, ".min.js")
-      .then(testBlackBoxSource)
+    testBlackBoxSource()
       .then(testBlackBoxReload)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 }
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breadcrumbs-access.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breadcrumbs-access.js
@@ -8,17 +8,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gSources, gFrames;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gFrames = gDebugger.DebuggerView.StackFrames;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6)
       .then(checkNavigationWhileNotFocused)
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-in-anon.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-in-anon.js
@@ -6,24 +6,27 @@
 /**
  * Make sure anonymous eval scripts can still break with a `debugger`
  * statement
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  const options = {
+    source: "-eval.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
 
     return Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-eval.js");
       is(gSources.values.length, 1, "Should have 1 source");
 
       callInTab(gTab, "evalSourceWithDebugger");
       yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
 
       is(gSources.values.length, 2, "Should have 2 sources");
 
       let item = gSources.getItemForAttachment(e => e.label.indexOf("SCRIPT") === 0);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-01.js
@@ -11,17 +11,21 @@ thisTestLeaksUncaughtRejectionsAndShould
 
 /**
  * Tests that event listeners aren't fetched when the events tab isn't selected.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let gPanel = aPanel;
     let gDebugger = aPanel.panelWin;
     let gView = gDebugger.DebuggerView;
     let gEvents = gView.EventListeners;
     let gController = gDebugger.DebuggerController;
     let constants = gDebugger.require("./content/constants");
 
     gDebugger.on(gDebugger.EVENTS.EVENT_LISTENERS_FETCHED, () => {
@@ -34,17 +38,16 @@ function test() {
     gView.toggleInstrumentsPane({ visible: true, animated: false });
 
     is(gView.instrumentsPaneHidden, false,
       "The instruments pane should be visible now.");
     is(gView.instrumentsPaneTab, "variables-tab",
       "The variables tab should be selected by default.");
 
     Task.spawn(function* () {
-      yield waitForSourceShown(aPanel, ".html");
       is(gEvents.itemCount, 0, "There should be no events before reloading.");
 
       let reloaded = waitForNavigation(gPanel);
       gDebugger.DebuggerController._target.activeTab.reload();
 
       is(gEvents.itemCount, 0, "There should be no events while reloading.");
       yield reloaded;
       is(gEvents.itemCount, 0, "There should be no events after reloading.");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-02.js
@@ -6,26 +6,29 @@
 /**
  * Tests that event listeners are fetched when the events tab is selected
  * or while sources are fetched and the events tab is focused.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let gPanel = aPanel;
     let gDebugger = aPanel.panelWin;
     let gView = gDebugger.DebuggerView;
     let gEvents = gView.EventListeners;
     let gController = gDebugger.DebuggerController;
     let constants = gDebugger.require("./content/constants");
 
     Task.spawn(function* () {
-      yield waitForSourceShown(aPanel, ".html");
       yield testFetchOnFocus();
       yield testFetchOnReloadWhenFocused();
       yield testFetchOnReloadWhenNotFocused();
       yield closeDebuggerAndFinish(aPanel);
     });
 
     function testFetchOnFocus() {
       return Task.spawn(function* () {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-03.js
@@ -5,26 +5,28 @@
 
 /**
  * Tests that event listeners are properly displayed in the view.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let gDebugger = aPanel.panelWin;
     let gView = gDebugger.DebuggerView;
     let gEvents = gView.EventListeners;
     let gController = gDebugger.DebuggerController;
     let constants = gDebugger.require("./content/constants");
 
     Task.spawn(function* () {
-      yield waitForSourceShown(aPanel, ".html");
-
       let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
       gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
       yield fetched;
 
       is(gEvents.widget._parent.querySelectorAll(".side-menu-widget-group").length, 3,
         "There should be 3 groups shown in the view.");
 
       let groupCheckboxes = gEvents.widget._parent.querySelectorAll(
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-04.js
@@ -6,26 +6,28 @@
 /**
  * Tests that checking/unchecking an event listener in the view correctly
  * causes the active thread to get updated with the new event breakpoints.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let gDebugger = aPanel.panelWin;
     let gView = gDebugger.DebuggerView;
     let gController = gDebugger.DebuggerController;
     let gEvents = gView.EventListeners;
     let constants = gDebugger.require("./content/constants");
 
     Task.spawn(function* () {
-      yield waitForSourceShown(aPanel, ".html");
-
       let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
       gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
       yield fetched;
 
       testEventItem(0, false);
       testEventItem(1, false);
       testEventItem(2, false);
       testEventItem(3, false);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-05.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-05.js
@@ -7,26 +7,28 @@
  * Tests that checking/unchecking an event listener's group in the view will
  * cause the active thread to get updated with the new event breakpoints for
  * all children inside that group.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let gDebugger = aPanel.panelWin;
     let gView = gDebugger.DebuggerView;
     let gController = gDebugger.DebuggerController;
     let gEvents = gView.EventListeners;
     let constants = gDebugger.require("./content/constants");
 
     Task.spawn(function* () {
-      yield waitForSourceShown(aPanel, ".html");
-
       let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
       gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
       yield fetched;
 
       testEventItem(0, false);
       testEventItem(1, false);
       testEventItem(2, false);
       testEventItem(3, false);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-06.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-06.js
@@ -6,27 +6,29 @@
 /**
  * Tests that the event listener states are preserved in the view after the
  * target navigates.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let gDebugger = aPanel.panelWin;
     let gView = gDebugger.DebuggerView;
     let gController = gDebugger.DebuggerController;
     let gEvents = gView.EventListeners;
     let gBreakpoints = gController.Breakpoints;
     let constants = gDebugger.require("./content/constants");
 
     Task.spawn(function* () {
-      yield waitForSourceShown(aPanel, ".html");
-
       let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
       gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
       yield fetched;
 
       testEventItem(0, false);
       testEventItem(1, false);
       testEventItem(2, false);
       testEventItem(3, false);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-07.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-07.js
@@ -3,17 +3,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that system event listeners don't get duplicated in the view.
  */
 
 function test() {
-  initDebugger("about:blank").then(([aTab,, aPanel]) => {
+  initDebugger().then(([aTab,, aPanel]) => {
     let gDebugger = aPanel.panelWin;
     let gView = gDebugger.DebuggerView;
     let gEvents = gView.EventListeners;
     let gL10N = gDebugger.L10N;
 
     is(gEvents.itemCount, 0,
       "There are no events displayed in the corresponding pane yet.");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-08.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-08.js
@@ -5,26 +5,29 @@
 
 /**
  * Tests that breaking on an event selects the variables view tab.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let gTab = aTab;
     let gDebugger = aPanel.panelWin;
     let gView = gDebugger.DebuggerView;
     let gEvents = gView.EventListeners;
     let gController = gDebugger.DebuggerController;
     let constants = gDebugger.require("./content/constants");
 
     Task.spawn(function* () {
-      yield waitForSourceShown(aPanel, ".html");
       yield callInTab(gTab, "addBodyClickEventListener");
 
       let fetched = waitForDispatch(aPanel, constants.FETCH_EVENT_LISTENERS);
       gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
       yield fetched;
       yield ensureThreadClientState(aPanel, "attached");
 
       is(gView.instrumentsPaneHidden, false,
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next-console.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next-console.js
@@ -9,28 +9,31 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gSources, gBreakpoints, gTarget, gResumeButton, gResumeKey, gThreadClient;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-eval.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gTarget = gDebugger.gTarget;
     gThreadClient = gDebugger.gThreadClient;
     gResumeButton = gDebugger.document.getElementById("resume");
     gResumeKey = gDebugger.document.getElementById("resumeKey");
 
-    waitForSourceShown(gPanel, "-eval.js")
-      .then(testConsole)
+    testConsole()
       .then(() => closeDebuggerAndFinish(gPanel));
   });
 
   let testConsole = Task.async(function* () {
     info("Starting testConsole");
 
     let oncePaused = gTarget.once("thread-paused");
     EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next.js
@@ -9,28 +9,31 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gSources, gBreakpoints, gTarget, gResumeButton, gResumeKey, gThreadClient;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  const options = {
+    source: "-eval.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gTarget = gDebugger.gTarget;
     gThreadClient = gDebugger.gThreadClient;
     gResumeButton = gDebugger.document.getElementById("resume");
     gResumeKey = gDebugger.document.getElementById("resumeKey");
 
-    waitForSourceShown(gPanel, "-eval.js")
-      .then(testInterval)
+    testInterval()
       .then(testEvent)
       .then(() => closeDebuggerAndFinish(gPanel));
   });
 
   // Testing an interval instead of a timeout / rAF because
   // it's less likely to fail due to timing issues.  If the
   // first callback happens to fire before the break request
   // happens then we'll just get it next time.
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-actual-location.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-actual-location.js
@@ -6,17 +6,21 @@
 /**
  * Bug 737803: Setting a breakpoint in a line without code should move
  * the icon to the actual location.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const gController = gDebugger.DebuggerController;
     const constants = gDebugger.require("./content/constants");
     const queries = gDebugger.require("./content/queries");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-actual-location2.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-actual-location2.js
@@ -7,17 +7,21 @@
  * Bug 1008372: Setting a breakpoint in a line without code should move
  * the icon to the actual location, and if a breakpoint already exists
  * on the new location don't duplicate
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_breakpoint-move.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const gController = gDebugger.DebuggerController;
     const actions = bindActionCreators(gPanel);
     const constants = gDebugger.require("./content/constants");
@@ -35,17 +39,19 @@ function test() {
     function testBreakpoint(line) {
       let bp = gSources._selectedBreakpoint;
       ok(bp, "There should be a selected breakpoint on line " + line);
       is(bp.location.line, line,
          "The breakpoint on line " + line + " was not hit");
     }
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 1);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 16);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
 
       is(queries.getBreakpoints(gController.getState()).length, 0,
          "There are no breakpoints in the editor");
 
       yield actions.addBreakpoint({
         actor: gSources.selectedValue,
         line: 19
       });
@@ -73,12 +79,10 @@ function test() {
       yield doResume(gPanel);
 
       callInTab(gTab, "ermahgerd");
       yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES);
 
       yield resumeAndTestBreakpoint(20);
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js
@@ -12,17 +12,21 @@ const TAB_URL = EXAMPLE_URL + "doc_break
 const CODE_URL = EXAMPLE_URL + "code_breakpoints-break-on-last-line-of-script-on-reload.js";
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
   let gPanel, gDebugger, gThreadClient, gEvents, gSources;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  const options = {
+    source: CODE_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gThreadClient = gDebugger.gThreadClient;
     gEvents = gDebugger.EVENTS;
     gSources = gDebugger.DebuggerView.Sources;
     const actions = bindActionCreators(gPanel);
 
     Task.spawn(function* () {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-button-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-button-01.js
@@ -5,17 +5,21 @@
 
 /**
  * Test if the breakpoints toggle button works as advertised.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     function checkBreakpointsDisabled(isDisabled, total = 3) {
@@ -23,18 +27,16 @@ function test() {
 
       is(breakpoints.length, total,
          "Breakpoints should still be set.");
       is(breakpoints.filter(bp => bp.disabled === isDisabled).length, total,
          "Breakpoints should be " + (isDisabled ? "disabled" : "enabled") + ".");
     }
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-01.js");
-
       yield actions.addBreakpoint({ actor: gSources.values[0], line: 5 });
       yield actions.addBreakpoint({ actor: gSources.values[1], line: 6 });
       yield actions.addBreakpoint({ actor: gSources.values[1], line: 7 });
       yield ensureThreadClientState(gPanel, "resumed");
 
       gSources.toggleBreakpoints();
       yield waitForDispatch(gPanel, gDebugger.constants.REMOVE_BREAKPOINT, 3);
       checkBreakpointsDisabled(true);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-button-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-button-02.js
@@ -6,17 +6,21 @@
 /**
  * Test if the breakpoints toggle button works as advertised when there are
  * some breakpoints already disabled.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     function checkBreakpointsDisabled(isDisabled, total = 3) {
@@ -24,18 +28,16 @@ function test() {
 
       is(breakpoints.length, total,
          "Breakpoints should still be set.");
       is(breakpoints.filter(bp => bp.disabled === isDisabled).length, total,
          "Breakpoints should be " + (isDisabled ? "disabled" : "enabled") + ".");
     }
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-01.js");
-
       yield promise.all([
         actions.addBreakpoint({ actor: gSources.values[0], line: 5 }),
         actions.addBreakpoint({ actor: gSources.values[1], line: 6 }),
         actions.addBreakpoint({ actor: gSources.values[1], line: 7 })
       ]);
       if (gDebugger.gThreadClient.state !== "attached") {
         yield waitForThreadEvents(gPanel, "resumed");
       }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-condition-thrown-message.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-condition-thrown-message.js
@@ -6,17 +6,21 @@
 /**
  * Make sure that the message which breakpoint condition throws
  * could be displayed on UI correctly
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
@@ -63,17 +67,19 @@ function test() {
         );
         let attachment = gSources._getBreakpoint(bp).attachment;
         ok(!attachment.view.container.classList.contains("dbg-breakpoint-condition-thrown"),
            "Message on line " + line + " should be hidden if condition doesn't throw.");
       });
     }
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
 
       yield actions.addBreakpoint({ actor: gSources.selectedValue, line: 18 }, " 1afff");
       // Close the popup because a SET_BREAKPOINT_CONDITION action is
       // fired when it's closed, and it sets it on the currently
       // selected breakpoint and we want to make sure it uses the
       // current breakpoint. This isn't a problem outside of tests
       // because any UI interaction will close the popup before the
       // new breakpoint is added.
@@ -92,12 +98,10 @@ function test() {
       gSources._hideConditionalPopup();
       initialCheck(22);
 
       yield resumeAndTestThrownMessage(18);
       yield resumeAndTestNoThrownMessage(19);
       yield resumeAndTestThrownMessage(22);
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-contextmenu-add.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-contextmenu-add.js
@@ -5,17 +5,21 @@
 
 /**
  * Test adding breakpoints from the source editor context menu
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const gContextMenu = gDebugger.document.getElementById("sourceEditorContextMenu");
     const queries = gDebugger.require("./content/queries");
     const actions = bindActionCreators(gPanel);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-contextmenu.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-contextmenu.js
@@ -9,17 +9,21 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
   Task.spawn(function* () {
-    const [gTab,, gPanel ] = yield initDebugger(TAB_URL);
+    const options = {
+      source: "-01.js",
+      line: 1
+    };
+    const [gTab,, gPanel ] = yield initDebugger(TAB_URL, options);
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     const addBreakpoints = Task.async(function* () {
       yield actions.addBreakpoint({ actor: gSources.values[0], line: 5 });
@@ -209,18 +213,16 @@ function test() {
     }
     function enableAll() {
       gSources._onEnableAll();
     }
     function deleteAll() {
       gSources._onDeleteAll();
     }
 
-    yield waitForSourceShown(gPanel, "-01.js");
-
     yield addBreakpoints();
     yield initialChecks();
     yield checkBreakpointToggleSelf(0);
     yield checkBreakpointToggleOthers(0);
     yield checkBreakpointToggleSelf(1);
     yield checkBreakpointToggleOthers(1);
     yield checkBreakpointToggleSelf(2);
     yield checkBreakpointToggleOthers(2);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-disabled-reload.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-disabled-reload.js
@@ -5,30 +5,33 @@
 
 /**
  * Test that disabled breakpoints survive target navigation.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gPanel = aPanel;
     const gTab = aTab;
     const gDebugger = gPanel.panelWin;
     const gEvents = gDebugger.EVENTS;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
     let gBreakpointLocation;
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-01.js");
       gBreakpointLocation = { actor: getSourceActor(gSources, EXAMPLE_URL + "code_script-switching-01.js"),
                               line: 5 };
 
       yield actions.addBreakpoint(gBreakpointLocation);
 
       yield ensureThreadClientState(gPanel, "resumed");
       yield testWhenBreakpointEnabledAndFirstSourceShown();
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-editor.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-editor.js
@@ -6,17 +6,21 @@
 /**
  * Bug 723069: Test the debugger breakpoint API and connection to the
  * source editor.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-eval.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-eval.js
@@ -5,26 +5,28 @@
 
 /**
  * Test setting breakpoints on an eval script
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-eval.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const actions = bindActionCreators(gPanel);
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-eval.js");
-
       let newSource = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.NEW_SOURCE);
       callInTab(gTab, "evalSourceWithSourceURL");
       yield newSource;
       // Wait for it to be added to the UI
       yield waitForTick();
 
       const newSourceActor = getSourceActor(gSources, EXAMPLE_URL + "bar.js");
       yield actions.addBreakpoint({
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-highlight.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-highlight.js
@@ -5,17 +5,21 @@
 
 /**
  * Test if breakpoints are highlighted when they should.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
@@ -69,18 +73,16 @@ function test() {
            "The first source is correctly displayed.");
       } else {
         is(gEditor.getText().indexOf("debugger"), 166,
            "The second source is correctly displayed.");
       }
     }
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-01.js");
-
       yield addBreakpoints();
       yield clickBreakpointAndCheck(0, 0, 5);
       yield clickBreakpointAndCheck(1, 1, 6);
       yield clickBreakpointAndCheck(2, 1, 7);
       yield clickBreakpointAndCheck(3, 1, 8);
       yield clickBreakpointAndCheck(4, 1, 9);
       closeDebuggerAndFinish(gPanel);
     });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-new-script.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-new-script.js
@@ -6,17 +6,21 @@
 /**
  * Bug 771452: Make sure that setting a breakpoint in an inline source doesn't
  * add it twice.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require('./content/queries');
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
@@ -65,23 +69,24 @@ function test() {
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
                                 gDebugger.document.getElementById("resume"),
                                 gDebugger);
       return deferred.promise;
     }
 
     Task.spawn(function(){
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 16);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 16);
+      callInTab(gTab, "runDebuggerStatement");
+      yield onCaretUpdated;
+
       is(gDebugger.gThreadClient.state, "paused",
          "The debugger statement was reached.");
       ok(isCaretPos(gPanel, 16),
          "The source editor caret position is incorrect (1).");
 
       yield actions.addBreakpoint({ actor: getSourceActor(gSources, TAB_URL), line: 20 });
       yield testResume();
       yield testBreakpointHit();
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
-
-    callInTab(gTab, "runDebuggerStatement");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-other-tabs.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-other-tabs.js
@@ -6,24 +6,26 @@
 /**
  * Make sure that setting a breakpoint in one tab, doesn't cause another tab at
  * the same source to pause at that location.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_breakpoints-other-tabs.html";
 
 var test = Task.async(function* () {
-  const [tab1,, panel1] = yield initDebugger(TAB_URL);
-  const [tab2,, panel2] = yield initDebugger(TAB_URL);
+  const options = {
+    source: "code_breakpoints-other-tabs.js",
+    line: 1
+  };
+  const [tab1,, panel1] = yield initDebugger(TAB_URL, options);
+  const [tab2,, panel2] = yield initDebugger(TAB_URL, options);
   const queries = panel1.panelWin.require("./content/queries");
   const actions = bindActionCreators(panel1);
   const getState = panel1.panelWin.DebuggerController.getState;
 
-  yield ensureSourceIs(panel1, "code_breakpoints-other-tabs.js", true);
-
   const sources = panel1.panelWin.DebuggerView.Sources;
 
   yield actions.addBreakpoint({
     actor: queries.getSelectedSource(getState()).actor,
     line: 2
   });
 
   const paused = waitForThreadEvents(panel2, "paused");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-pane.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-pane.js
@@ -6,17 +6,21 @@
 /**
  * Bug 723071: Test adding a pane to display the list of breakpoints across
  * all sources in the debuggee.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-reload.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-reload.js
@@ -8,21 +8,23 @@
  * hit when we reload.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_breakpoints-reload.html";
 
 var test = Task.async(function* () {
   requestLongerTimeout(4);
 
-  const [tab,, panel] = yield initDebugger(TAB_URL);
+  const options = {
+    source: TAB_URL,
+    line: 1
+  };
+  const [tab,, panel] = yield initDebugger(TAB_URL, options);
   const actions = bindActionCreators(panel);
 
-  yield ensureSourceIs(panel, "doc_breakpoints-reload.html", true);
-
   const sources = panel.panelWin.DebuggerView.Sources;
   yield actions.addBreakpoint({
     actor: sources.selectedValue,
     line: 10 // "break on me" string
   });
 
   const paused = waitForThreadEvents(panel, "paused");
   reloadActiveTab(panel);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_bug-896139.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_bug-896139.js
@@ -2,34 +2,53 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Bug 896139 - Breakpoints not triggering when reloading script.
  */
 
-const TAB_URL = "doc_bug-896139.html";
+const TAB_URL = EXAMPLE_URL + "doc_bug-896139.html";
 const SCRIPT_URL = "code_bug-896139.js";
 
 function test() {
   Task.spawn(function* () {
     function testBreakpoint() {
       let promise = waitForDebuggerEvents(panel, win.EVENTS.FETCHED_SCOPES);
       callInTab(tab, "f");
       return promise.then(() => doResume(panel));
     }
 
-    let [tab,, panel] = yield initDebugger(EXAMPLE_URL + TAB_URL);
+    let [tab,, panel] = yield initDebugger();
     let win = panel.panelWin;
 
     let Sources = win.DebuggerView.Sources;
-    yield waitForDebuggerEvents(panel, win.EVENTS.SOURCE_SHOWN);
+
+    // Load the debugger against a blank document and load the test url only
+    // here and not via initDebugger. That, because this test load SCRIPT_URL
+    // dynamically, on load, and the debugger may be on TAB_URL or SCRIPT_URL
+    // depending on cpu speed. initDebugger expect to assert one precise
+    // source.
+    yield navigateActiveTabTo(panel,
+                              TAB_URL,
+                              win.EVENTS.SOURCE_SHOWN);
+
     if (Sources.selectedItem.attachment.source.url.indexOf(SCRIPT_URL) === -1) {
-      Sources.selectedValue = getSourceActor(win.DebuggerView.Sources, EXAMPLE_URL + SCRIPT_URL);
+      // If there is only the html file, wait for the js file to be listed.
+      if (Sources.itemCount == 1) {
+        yield waitForDebuggerEvents(panel, win.EVENTS.NEW_SOURCE);
+        // Wait for it to be added to the UI
+        yield waitForTick();
+      }
+      // Select the js file.
+      let onSource = waitForSourceAndCaret(panel, SCRIPT_URL, 1);
+      Sources.selectedValue = getSourceActor(win.DebuggerView.Sources,
+                                             EXAMPLE_URL + SCRIPT_URL);
+      yield onSource;
     }
 
     yield panel.addBreakpoint({
       actor: getSourceActor(win.DebuggerView.Sources, EXAMPLE_URL + SCRIPT_URL),
       line: 6
     });
 
     // Race condition: the setBreakpoint request sometimes leaves the
--- a/devtools/client/debugger/test/mochitest/browser_dbg_clean-exit-window.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_clean-exit-window.js
@@ -8,17 +8,17 @@
  */
 
 var gDebuggee, gPanel, gDebugger, gWindow;
 
 const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
 
 function test() {
   addWindow(TAB_URL)
-    .then(win => initDebugger(TAB_URL, win))
+    .then(win => initDebugger(TAB_URL, { window: win }))
     .then(([aTab, aDebuggee, aPanel, aWindow]) => {
       gDebuggee = aDebuggee;
       gPanel = aPanel;
       gDebugger = gPanel.panelWin;
       gWindow = aWindow;
 
       return testCleanExit();
     })
--- a/devtools/client/debugger/test/mochitest/browser_dbg_clean-exit.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_clean-exit.js
@@ -7,17 +7,21 @@
  * Test that closing a tab with the debugger in a paused state exits cleanly.
  */
 
 var gTab, gPanel, gDebugger;
 
 const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  const options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
 
     testCleanExit();
   });
 }
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_closure-inspection.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_closure-inspection.js
@@ -5,23 +5,26 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_closures.html";
 
 // Test that inspecting a closure works as expected.
 
 function test() {
   let gPanel, gTab, gDebugger;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
 
-    waitForSourceShown(gPanel, ".html")
-      .then(testClosure)
+    testClosure()
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 
   function testClosure() {
     generateMouseClickInTab(gTab, "content.document.querySelector('button')");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-01.js
@@ -8,17 +8,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
   // Linux debug test slaves are a bit slow at this test sometimes.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
@@ -166,17 +170,20 @@ function test() {
          "There should be a selected source in the sources pane.");
       ok(gSources._selectedBreakpoint,
          "There should be a selected breakpoint in the sources pane.");
       is(gSources._conditionalPopupVisible, false,
          "The breakpoint conditional expression popup should not be shown.");
     });
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
+
       yield addBreakpoints();
 
       is(gDebugger.gThreadClient.state, "paused",
          "Should only be getting stack frames while paused.");
       is(queries.getSourceCount(getState()), 1,
          "Found the expected number of sources.");
       is(gEditor.getText().indexOf("ermahgerd"), 253,
          "The correct source was loaded initially.");
@@ -202,12 +209,10 @@ function test() {
       yield sourceShown;
 
       testAfterReload();
 
       // Reset traits back to default value
       client.mainRoot.traits.conditionalBreakpoints = true;
       closeDebuggerAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-02.js
@@ -5,17 +5,21 @@
 
 /**
  * Bug 740825: Test the debugger conditional breakpoints.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
@@ -123,17 +127,19 @@ function test() {
     function waitForConditionUpdate() {
       // This will close the popup and send another request to update
       // the condition
       gSources._hideConditionalPopup();
       return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
     }
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
 
       is(gDebugger.gThreadClient.state, "paused",
          "Should only be getting stack frames while paused.");
       is(queries.getSourceCount(getState()), 1,
          "Found the expected number of sources.");
       is(gEditor.getText().indexOf("ermahgerd"), 253,
          "The correct source was loaded initially.");
       is(gSources.selectedValue, gSources.values[0],
@@ -194,12 +200,10 @@ function test() {
       is(gSources._selectedBreakpoint.location.line, 20,
          "The selected breakpoint is line 20");
       testBreakpoint(20, true, "bamboocha");
 
       // Reset traits back to default value
       client.mainRoot.traits.conditionalBreakpoints = true;
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-03.js
@@ -5,17 +5,17 @@
 
 /**
  * Tests that conditional breakpoint expressions survive disabled breakpoints.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  initDebugger().then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
@@ -28,17 +28,23 @@ function test() {
     function waitForConditionUpdate() {
       // This will close the popup and send another request to update
       // the condition
       gSources._hideConditionalPopup();
       return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
     }
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretUpdated(gPanel, 17);
+      yield navigateActiveTabTo(gPanel,
+                                TAB_URL,
+                                gDebugger.EVENTS.SOURCE_SHOWN);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
+
       const location = { actor: gSources.selectedValue, line: 18 };
 
       yield actions.addBreakpoint(location, "hello");
       yield actions.disableBreakpoint(location);
       yield actions.addBreakpoint(location);
 
       const bp = queries.getBreakpoint(getState(), location);
       is(bp.condition, "hello", "The conditional expression is correct.");
@@ -63,12 +69,10 @@ function test() {
                                 gDebugger);
       yield finished;
       is(textbox.value, "foo", "The expression is correct (3).");
 
       // Reset traits back to default value
       client.mainRoot.traits.conditionalBreakpoints = true;
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-04.js
@@ -6,42 +6,47 @@
 /**
  * Make sure that conditional breakpoints with blank expressions
  * maintain their conditions after enabling them.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     // This test forces conditional breakpoints to be evaluated on the
     // client-side
     var client = gPanel.target.client;
     client.mainRoot.traits.conditionalBreakpoints = false;
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
+
       const location = { actor: gSources.selectedValue, line: 18 };
 
       yield actions.addBreakpoint(location, "");
       yield actions.disableBreakpoint(location);
       yield actions.addBreakpoint(location);
 
       const bp = queries.getBreakpoint(getState(), location);
       is(bp.condition, "", "The conditional expression is correct.");
 
       // Reset traits back to default value
       client.mainRoot.traits.conditionalBreakpoints = true;
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-05.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_conditional-breakpoints-05.js
@@ -6,17 +6,21 @@
 /**
  * Make sure that conditional breakpoints with an exception-throwing expression
  * could pause on hit
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
@@ -95,17 +99,19 @@ function test() {
       isnot(selectedBreakpoint.condition, undefined,
             "The breakpoint on line " + line + " should have a conditional expression.");
 
       ok(isCaretPos(gPanel, line),
          "The editor caret position is not properly set.");
     }
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
 
       yield actions.addBreakpoint(
         { actor: gSources.selectedValue, line: 18 }, " 1a"
       );
       yield actions.addBreakpoint(
         { actor: gSources.selectedValue, line: 19 }, "new Error()"
       );
       yield actions.addBreakpoint(
@@ -126,12 +132,10 @@ function test() {
       yield resumeAndTestBreakpoint(20);
       yield resumeAndTestBreakpoint(23);
       yield resumeAndTestNoBreakpoint();
 
       // Reset traits back to default value
       client.mainRoot.traits.conditionalBreakpoints = true;
       closeDebuggerAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_console-eval.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_console-eval.js
@@ -6,17 +6,17 @@
 /**
  * Breaking in the middle of a script evaluated by the console should
  * work
  */
 
 function test() {
   Task.spawn(function* () {
     let TAB_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
-    let [,, panel] = yield initDebugger(TAB_URL);
+    let [,, panel] = yield initDebugger(TAB_URL, { source: null });
     let dbgWin = panel.panelWin;
     let sources = dbgWin.DebuggerView.Sources;
     let frames = dbgWin.DebuggerView.StackFrames;
     let editor = dbgWin.DebuggerView.editor;
     let toolbox = gDevTools.getToolbox(panel.target);
 
     let paused = promise.all([
       waitForEditorEvents(panel, "cursorActivity"),
--- a/devtools/client/debugger/test/mochitest/browser_dbg_console-named-eval.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_console-named-eval.js
@@ -9,17 +9,17 @@
  */
 
 function test() {
   Task.spawn(runTests);
 }
 
 function* runTests() {
   let TAB_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
-  let [,, panel] = yield initDebugger(TAB_URL);
+  let [,, panel] = yield initDebugger(TAB_URL, { source: null });
   let dbgWin = panel.panelWin;
   let sources = dbgWin.DebuggerView.Sources;
   let frames = dbgWin.DebuggerView.StackFrames;
   let editor = dbgWin.DebuggerView.editor;
   let toolbox = gDevTools.getToolbox(panel.target);
 
   let paused = waitForSourceAndCaretAndScopes(panel, "foo.js", 1);
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_controller-evaluate-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_controller-evaluate-01.js
@@ -6,17 +6,21 @@
 /**
  * Tests the public evaluation API from the debugger controller.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
   Task.spawn(function* () {
-    const [tab,, panel] = yield initDebugger(TAB_URL);
+    const options = {
+      source: "-01.js",
+      line: 1
+    };
+    const [tab,, panel] = yield initDebugger(TAB_URL, options);
     const win = panel.panelWin;
     const frames = win.DebuggerController.StackFrames;
     const framesView = win.DebuggerView.StackFrames;
     const sourcesView = win.DebuggerView.Sources;
     const editorView = win.DebuggerView.editor;
     const events = win.EVENTS;
     const queries = win.require("./content/queries");
     const constants = win.require("./content/constants");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_controller-evaluate-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_controller-evaluate-02.js
@@ -6,17 +6,21 @@
 /**
  * Tests the public evaluation API from the debugger controller.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
   Task.spawn(function* () {
-    const [tab,, panel] = yield initDebugger(TAB_URL);
+    const options = {
+      source: "-01.js",
+      line: 1
+    };
+    const [tab,, panel] = yield initDebugger(TAB_URL, options);
     const win = panel.panelWin;
     const frames = win.DebuggerController.StackFrames;
     const framesView = win.DebuggerView.StackFrames;
     const sourcesView = win.DebuggerView.Sources;
     const editorView = win.DebuggerView.editor;
     const events = win.EVENTS;
     const queries = win.require("./content/queries");
     const constants = win.require("./content/constants");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_editor-contextmenu.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_editor-contextmenu.js
@@ -8,17 +8,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gEditor, gSources, gContextMenu;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gContextMenu = gDebugger.document.getElementById("sourceEditorContextMenu");
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1).then(performTest).then(null, info);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_editor-mode.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_editor-mode.js
@@ -9,17 +9,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_editor-mode.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "code_script-switching-01.js?a=b",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
 
     waitForSourceAndCaretAndScopes(gPanel, "code_test-editor-mode", 1)
       .then(testInitialSource)
--- a/devtools/client/debugger/test/mochitest/browser_dbg_event-listeners-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_event-listeners-04.js
@@ -27,17 +27,21 @@ function test() {
     ok(sdkTab, "Add-on SDK found the loaded tab.");
 
     info("Attaching an event handler via add-on sdk content scripts.");
     let worker = sdkTab.attach({
       contentScript: "document.body.addEventListener('click', e => alert(e))",
       onError: ok.bind(this, false)
     });
 
-    let [,, panel, win] = yield initDebugger(tab);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [,, panel, win] = yield initDebugger(tab, options);
     let dbg = panel.panelWin;
     let controller = dbg.DebuggerController;
     let constants = dbg.require("./content/constants");
     let actions = dbg.require("./content/actions/event-listeners");
     let fetched = waitForDispatch(panel, constants.FETCH_EVENT_LISTENERS);
 
     info("Scheduling event listener fetch.");
     controller.dispatch(actions.fetchEventListeners());
--- a/devtools/client/debugger/test/mochitest/browser_dbg_file-reload.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_file-reload.js
@@ -6,28 +6,31 @@
 /**
  * Tests that source contents are invalidated when the target navigates.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_random-javascript.html";
 const JS_URL = EXAMPLE_URL + "sjs_random-javascript.sjs";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: JS_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gPanel = aPanel;
     const gDebugger = aPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, JS_URL);
       let source = queries.getSelectedSource(getState());
 
       is(queries.getSourceCount(getState()), 1,
         "There should be one source displayed in the view.");
       is(source.url, JS_URL,
         "The correct source is currently selected in the view.");
       ok(gEditor.getText().includes("bacon"),
         "The currently shown source contains bacon. Mmm, delicious!");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_function-display-name.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_function-display-name.js
@@ -8,40 +8,45 @@
  * their displayName property or a SpiderMonkey-inferred name.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_function-display-name.html";
 
 var gTab, gPanel, gDebugger;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
 
     testAnonCall();
   });
 }
 
 function testAnonCall() {
-  waitForSourceAndCaretAndScopes(gPanel, ".html", 15).then(() => {
+  let onCaretUpdated = waitForCaretUpdated(gPanel, 15);
+  let onScopes = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES);
+  callInTab(gTab, "evalCall");
+  promise.all([onCaretUpdated, onScopes]).then(() => {
     ok(isCaretPos(gPanel, 15),
       "The source editor caret position was incorrect.");
     is(gDebugger.gThreadClient.state, "paused",
       "Should only be getting stack frames while paused.");
     is(gDebugger.document.querySelectorAll(".dbg-stackframe").length, 3,
       "Should have three frames.");
     is(gDebugger.document.querySelector("#stackframe-0 .dbg-stackframe-title").getAttribute("value"),
       "anonFunc", "Frame name should be 'anonFunc'.");
 
     testInferredName();
   });
-
-  callInTab(gTab, "evalCall");
 }
 
 function testInferredName() {
   waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
     ok(isCaretPos(gPanel, 15),
       "The source editor caret position was incorrect.");
     is(gDebugger.gThreadClient.state, "paused",
       "Should only be getting stack frames while paused.");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_global-method-override.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_global-method-override.js
@@ -7,16 +7,20 @@
  * Tests that scripts that override properties of the global object, like
  * toString don't break the debugger. The test page used to cause the debugger
  * to throw when trying to attach to the thread actor.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_global-method-override.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let gDebugger = aPanel.panelWin;
     ok(gDebugger, "Should have a debugger available.");
     is(gDebugger.gThreadClient.state, "attached", "Debugger should be attached.");
 
     closeDebuggerAndFinish(aPanel);
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_hide-toolbar-buttons.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_hide-toolbar-buttons.js
@@ -11,17 +11,21 @@
 const TAB_URL = EXAMPLE_URL + "doc_auto-pretty-print-01.html";
 
 var { RootActor } = require("devtools/server/actors/root");
 
 function test() {
   RootActor.prototype.traits.noBlackBoxing = true;
   RootActor.prototype.traits.noPrettyPrinting = true;
 
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  let options = {
+    source: "code_ugly-5.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab, aDebuggee, aPanel]) => {
     let document = aPanel.panelWin.document;
     let ppButton = document.querySelector("#pretty-print");
     let bbButton = document.querySelector("#black-box");
     let sep = document.querySelector("#sources-toolbar .devtools-separator");
 
     is(ppButton.style.display, "none", "The pretty-print button is hidden");
     is(bbButton.style.display, "none", "The blackboxing button is hidden");
     is(sep.style.display, "none", "The separator is hidden");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_host-layout.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_host-layout.js
@@ -30,17 +30,17 @@ function test() {
 
 function testHosts(aHostTypes, aLayoutTypes) {
   let [firstHost, secondHost, thirdHost] = aHostTypes;
   let [firstLayout, secondLayout, thirdLayout] = aLayoutTypes;
 
   Services.prefs.setCharPref("devtools.toolbox.host", getHost(firstHost));
 
   return Task.spawn(function*() {
-    let [tab, debuggee, panel] = yield initDebugger("about:blank");
+    let [tab, debuggee, panel] = yield initDebugger();
     if (getHost(firstHost) === "window") {
       yield resizeToolboxWindow(panel, firstHost);
     }
 
     yield testHost(panel, getHost(firstHost), firstLayout);
     yield switchAndTestHost(tab, panel, secondHost, secondLayout);
     yield switchAndTestHost(tab, panel, thirdHost, thirdLayout);
     yield teardown(panel);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_iframes.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_iframes.js
@@ -8,29 +8,32 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_iframes.html";
 
 function test() {
   let gTab, gDebuggee, gPanel, gDebugger;
   let gIframe, gEditor, gSources, gFrames;
 
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  let options = {
+    source: "inline-debugger-statement.html",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab, aDebuggee, aPanel]) => {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gIframe = gDebuggee.frames[0];
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gFrames = gDebugger.DebuggerView.StackFrames;
 
-    waitForSourceShown(gPanel, "inline-debugger-statement.html")
-      .then(checkIframeSource)
-      .then(checkIframePause)
+    checkIframeSource();
+    checkIframePause()
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 
   function checkIframeSource() {
     is(gDebugger.gThreadClient.paused, false,
--- a/devtools/client/debugger/test/mochitest/browser_dbg_instruments-pane-collapse.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_instruments-pane-collapse.js
@@ -8,17 +8,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 var gTab, gPanel, gDebugger;
 var gPrefs, gOptions;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gPrefs = gDebugger.Prefs;
     gOptions = gDebugger.DebuggerView.Options;
 
     testPanesState();
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_interrupts.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_interrupts.js
@@ -8,30 +8,33 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gSources, gBreakpoints, gTarget, gResumeButton, gResumeKey, gThreadClient;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gBreakpoints = gDebugger.DebuggerController.Breakpoints;
     gTarget = gDebugger.gTarget;
     gThreadClient = gDebugger.gThreadClient;
     gResumeButton = gDebugger.document.getElementById("resume");
     gResumeKey = gDebugger.document.getElementById("resumeKey");
 
-    waitForSourceShown(gPanel, "-01.js")
-      .then(() => { gTarget.on("thread-paused", failOnPause); })
-      .then(addBreakpoints)
+    gTarget.on("thread-paused", failOnPause);
+    addBreakpoints()
       .then(() => { gTarget.off("thread-paused", failOnPause); })
       .then(testResumeButton)
       .then(testResumeKeyboard)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_jump-to-function-definition.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_jump-to-function-definition.js
@@ -9,24 +9,27 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_function-jump.html";
 const SCRIPT_URI = EXAMPLE_URL + "code_function-jump-01.js";
 
 
 function test() {
   let gTab, gPanel, gDebugger, gSources;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
 
-    waitForSourceShown(gPanel, "-01.js")
-      .then(jumpToFunctionDefinition)
+    jumpToFunctionDefinition()
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 
   function jumpToFunctionDefinition() {
     let callLocation = {line: 5, ch: 0};
--- a/devtools/client/debugger/test/mochitest/browser_dbg_location-changes-01-simple.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_location-changes-01-simple.js
@@ -5,27 +5,33 @@
 
 /**
  * Make sure that changing the tab location URL works.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const gFrames = gDebugger.DebuggerView.StackFrames;
     const constants = gDebugger.require("./content/constants");
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 14);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 14);
+      callInTab(gTab, "simpleCall");
+      yield onCaretUpdated;
 
       is(gDebugger.gThreadClient.state, "paused",
          "Should only be getting stack frames while paused.");
 
       is(gFrames.itemCount, 1,
          "Should have only one frame.");
 
       is(gSources.itemCount, 1,
@@ -45,12 +51,10 @@ function test() {
       is(gDebugger.document.querySelector("#sources .side-menu-widget-empty-notice > label"), null,
          "The sources widget should not display a notice at this point (3).");
 
       yield doResume(gPanel);
       navigateActiveTabTo(gPanel, "about:blank");
       yield waitForDispatch(gPanel, constants.UNLOAD);
       closeDebuggerAndFinish(gPanel);
     });
-
-    callInTab(gTab, "simpleCall");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_location-changes-02-blank.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_location-changes-02-blank.js
@@ -5,27 +5,33 @@
 
 /**
  * Make sure that changing the tab location URL to a page with no sources works.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const gFrames = gDebugger.DebuggerView.StackFrames;
     const constants = gDebugger.require("./content/constants");
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 14);
+      let onCaretUpdated = waitForCaretUpdated(gPanel, 14);
+      callInTab(gTab, "simpleCall");
+      yield onCaretUpdated;
 
       navigateActiveTabTo(gPanel, "about:blank");
       yield waitForNavigation(gPanel);
 
       isnot(gDebugger.gThreadClient.state, "paused",
             "Should not be paused after a tab navigation.");
 
       is(gFrames.itemCount, 0,
@@ -42,12 +48,10 @@ function test() {
       is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-text").length, 1,
          "The sources widget should now display a notice (1).");
       is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-text")[0].getAttribute("value"),
          gDebugger.L10N.getStr("noSourcesText"),
          "The sources widget should now display a notice (2).");
 
       closeDebuggerAndFinish(gPanel);
     });
-
-    callInTab(gTab, "simpleCall");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_location-changes-03-new.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_location-changes-03-new.js
@@ -6,28 +6,34 @@
 /**
  * Make sure that changing the tab location URL to a page with other sources works.
  */
 
 const TAB_URL_1 = EXAMPLE_URL + "doc_recursion-stack.html";
 const TAB_URL_2 = EXAMPLE_URL + "doc_iframes.html";
 
 function test() {
-  initDebugger(TAB_URL_1).then(([aTab, aDebuggee, aPanel]) => {
+  let options = {
+    source: TAB_URL_1,
+    line: 1
+  };
+  initDebugger(TAB_URL_1, options).then(([aTab, aDebuggee, aPanel]) => {
     const gTab = aTab;
     const gDebuggee = aDebuggee;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const gFrames = gDebugger.DebuggerView.StackFrames;
     const constants = gDebugger.require("./content/constants");
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 14);
+      let onCaretUpdated = waitForCaretUpdated(gPanel, 14);
+      callInTab(gTab, "simpleCall");
+      yield onCaretUpdated;
 
       const startedLoading = waitForNextDispatch(gDebugger.DebuggerController,
                                                  constants.LOAD_SOURCE_TEXT);
       navigateActiveTabTo(gPanel, TAB_URL_2);
       yield startedLoading;
 
       isnot(gDebugger.gThreadClient.state, "paused",
             "Should not be paused after a tab navigation.");
@@ -44,12 +50,10 @@ function test() {
          "The source editor text should be 'Loading...'");
 
       is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-text").length, 0,
          "The sources widget should not display any notice at this point.");
 
       yield waitForDispatch(gPanel, constants.LOAD_SOURCE_TEXT);
       closeDebuggerAndFinish(gPanel);
     });
-
-    gDebuggee.simpleCall();
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_location-changes-04-breakpoint.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_location-changes-04-breakpoint.js
@@ -7,17 +7,21 @@
  * Make sure that reloading a page with a breakpoint set does not cause it to
  * fire more than once.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_included-script.html";
 const SOURCE_URL = EXAMPLE_URL + "code_location-changes.js";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  const options = {
+    source: SOURCE_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab, aDebuggee, aPanel]) => {
     const gTab = aTab;
     const gDebuggee = aDebuggee;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const actions = bindActionCreators(gPanel);
@@ -25,17 +29,19 @@ function test() {
 
     function clickButtonAndPause() {
       const paused = waitForPause(gDebugger.gThreadClient);
       BrowserTestUtils.synthesizeMouse("button", 2, 2, {}, gBrowser.selectedBrowser);
       return paused;
     }
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretUpdated(gPanel, 17);
+      callInTab(gTab, "runDebuggerStatement");
+      yield onCaretUpdated;
 
       const location = { actor: getSourceActor(gSources, SOURCE_URL), line: 5 };
       yield actions.addBreakpoint(location);
 
       const caretUpdated = waitForSourceAndCaret(gPanel, ".js", 5);
       gSources.highlightBreakpoint(location);
       yield caretUpdated;
       ok(true, "Switched to the desired function when adding a breakpoint");
@@ -150,12 +156,10 @@ function test() {
       is(gEditor.getText().indexOf("debugger"), 148,
          "The correct source is shown in the source editor.");
       is(gEditor.getBreakpoints().length, 1,
          "One breakpoint should be shown for the first source.");
 
       yield ensureCaretAt(gPanel, 6, 1, true);
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
-
-    callInTab(gTab, "runDebuggerStatement");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_no-dangling-breakpoints.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_no-dangling-breakpoints.js
@@ -4,17 +4,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Bug 1201008 - Make sure you can't set a breakpoint in a blank
  * editor
  */
 
 function test() {
-  initDebugger("data:text/html,hi").then(([aTab,, aPanel]) => {
+  initDebugger('data:text/html,hi', { source: null }).then(([aTab,, aPanel]) => {
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
 
     Task.spawn(function* () {
       const editor = gDebugger.DebuggerView.editor;
       editor.emit("gutterClick", 0);
       is(editor.getBreakpoints().length, 0,
          "A breakpoint should not exist");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_no-page-sources.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_no-page-sources.js
@@ -8,17 +8,17 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_no-page-sources.html";
 
 var gTab, gDebuggee, gPanel, gDebugger;
 var gEditor, gSources;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL, { source: null }).then(([aTab, aDebuggee, aPanel]) => {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     const constants = gDebugger.require("./content/constants");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_on-pause-highlight.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_on-pause-highlight.js
@@ -9,24 +9,28 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 var gTab, gPanel, gDebugger;
 var gToolbox, gToolboxTab;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gToolbox = gPanel._toolbox;
     gToolboxTab = gToolbox.doc.getElementById("toolbox-tab-jsdebugger");
 
-    waitForSourceShown(gPanel, ".html").then(testPause);
+    testPause();
   });
 }
 
 function testPause() {
   is(gDebugger.gThreadClient.paused, false,
     "Should be running after starting test.");
 
   gDebugger.gThreadClient.addOneTimeListener("paused", () => {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_on-pause-raise.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_on-pause-raise.js
@@ -8,24 +8,28 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 var gTab, gPanel, gDebugger;
 var gFocusedWindow, gToolbox, gToolboxTab;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gToolbox = gPanel._toolbox;
     gToolboxTab = gToolbox.doc.getElementById("toolbox-tab-jsdebugger");
 
-    waitForSourceShown(gPanel, ".html").then(performTest);
+    performTest();
   });
 }
 
 function performTest() {
   addTab(TAB_URL).then(aTab => {
     isnot(aTab, gTab,
       "The newly added tab is different from the debugger's tab.");
     is(gBrowser.selectedTab, aTab,
--- a/devtools/client/debugger/test/mochitest/browser_dbg_optimized-out-vars.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_optimized-out-vars.js
@@ -5,21 +5,24 @@
 
 // Test that optimized out variables aren't present in the variables view.
 
 function test() {
   Task.spawn(function* () {
     const TAB_URL = EXAMPLE_URL + "doc_closure-optimized-out.html";
     let gDebugger, sources;
 
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     gDebugger = panel.panelWin;
     sources = gDebugger.DebuggerView.Sources;
 
-    yield waitForSourceShown(panel, ".html");
     yield panel.addBreakpoint({ actor: sources.values[0],
                                 line: 18 });
     yield ensureThreadClientState(panel, "resumed");
 
     // Spin the event loop before causing the debuggee to pause, to allow
     // this function to return first.
     generateMouseClickInTab(tab, "content.document.querySelector('button')");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_panel-size.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_panel-size.js
@@ -9,25 +9,29 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gPrefs, gSources, gInstruments;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gPrefs = gDebugger.Prefs;
     gSources = gDebugger.document.getElementById("workers-and-sources-pane");
     gInstruments = gDebugger.document.getElementById("instruments-pane");
 
-    waitForSourceShown(gPanel, ".html").then(performTest);
+    performTest();
   });
 
   function performTest() {
     let preferredWsw = Services.prefs.getIntPref("devtools.debugger.ui.panes-workers-and-sources-width");
     let preferredIw = Services.prefs.getIntPref("devtools.debugger.ui.panes-instruments-width");
     let someWidth1, someWidth2;
 
     do {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-01.js
@@ -9,17 +9,21 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_pause-exceptions.html";
 
 var gTab, gPanel, gDebugger;
 var gFrames, gVariables, gPrefs, gOptions;
 
 function test() {
   requestLongerTimeout(2);
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gVariables = gDebugger.DebuggerView.Variables;
     gPrefs = gDebugger.Prefs;
     gOptions = gDebugger.DebuggerView.Options;
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-02.js
@@ -8,32 +8,35 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_pause-exceptions.html";
 
 var gTab, gPanel, gDebugger;
 var gFrames, gVariables, gPrefs, gOptions;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gVariables = gDebugger.DebuggerView.Variables;
     gPrefs = gDebugger.Prefs;
     gOptions = gDebugger.DebuggerView.Options;
 
     is(gPrefs.pauseOnExceptions, false,
       "The pause-on-exceptions pref should be disabled by default.");
     isnot(gOptions._pauseOnExceptionsItem.getAttribute("checked"), "true",
       "The pause-on-exceptions menu item should not be checked.");
 
-    waitForSourceShown(aPanel, ".html")
-      .then(enablePauseOnExceptions)
+    enablePauseOnExceptions()
       .then(disableIgnoreCaughtExceptions)
       .then(() => reloadActiveTab(gPanel, gDebugger.EVENTS.SOURCE_SHOWN))
       .then(() => {
         generateMouseClickInTab(gTab, "content.document.querySelector('button')");
       })
       .then(testPauseOnExceptionsAfterReload)
       .then(disablePauseOnExceptions)
       .then(enableIgnoreCaughtExceptions)
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pause-no-step.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pause-no-step.js
@@ -10,17 +10,21 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_pause-exceptions.html";
 
 var gTab, gPanel, gDebugger;
 var gResumeButton, gStepOverButton, gStepOutButton, gStepInButton;
 var gResumeKey, gFrames;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gResumeButton = gDebugger.document.getElementById("resume");
     gStepOverButton = gDebugger.document.getElementById("step-over");
     gStepInButton = gDebugger.document.getElementById("step-in");
     gStepOutButton = gDebugger.document.getElementById("step-out");
     gResumeKey = gDebugger.document.getElementById("resumeKey");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pause-resume.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pause-resume.js
@@ -8,17 +8,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_pause-exceptions.html";
 
 var gTab, gPanel, gDebugger;
 var gResumeButton, gResumeKey, gFrames;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gResumeButton = gDebugger.document.getElementById("resume");
     gResumeKey = gDebugger.document.getElementById("resumeKey");
     gFrames = gDebugger.DebuggerView.StackFrames;
 
     testPause();
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pause-warning.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pause-warning.js
@@ -8,17 +8,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
 
 var gTab, gPanel, gDebugger;
 var gTarget, gToolbox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gTarget = gPanel.target;
     gToolbox = gPanel._toolbox;
 
     testPause();
   });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_paused-keybindings.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_paused-keybindings.js
@@ -6,32 +6,35 @@
 // Test that keybindings still work when the content window is paused and
 // the tab is selected again.
 
 function test() {
   Task.spawn(function* () {
     const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
     let gDebugger, searchBox;
 
-    let [, debuggee, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab, debuggee, panel] = yield initDebugger(TAB_URL, options);
     gDebugger = panel.panelWin;
     searchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
-    // Spin the event loop before causing the debuggee to pause, to allow
-    // this function to return first.
-    executeSoon(() => {
-      EventUtils.sendMouseEvent({ type: "click" },
-        debuggee.document.querySelector("button"),
-        debuggee);
+    let onCaretUpdated = ensureCaretAt(panel, 20, 1, true);
+    let onThreadPaused = ensureThreadClientState(panel, "paused");
+    ContentTask.spawn(tab.linkedBrowser, {}, function* () {
+      content.document.querySelector("button").click();
     });
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 20);
-    yield ensureThreadClientState(panel, "paused");
+    yield onCaretUpdated;
+    yield onThreadPaused
 
     // Now open a tab and close it.
     let tab2 = yield addTab(TAB_URL);
+    yield waitForTick();
     yield removeTab(tab2);
     yield ensureCaretAt(panel, 20);
 
     // Try to use the Cmd-L keybinding to see if it still works.
     let caretMove = ensureCaretAt(panel, 15, 1, true);
     // Wait a tick for the editor focus event to occur first.
     executeSoon(function () {
       EventUtils.synthesizeKey("l", { accelKey: true });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_post-page.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_post-page.js
@@ -9,26 +9,26 @@
 
 const TAB_URL = EXAMPLE_URL + "sjs_post-page.sjs";
 
 const FORM = "<form method=\"POST\"><input type=\"submit\"></form>";
 const GET_CONTENT = "<script>\"GET\";</script>" + FORM;
 const POST_CONTENT = "<script>\"POST\";</script>" + FORM;
 
 add_task(function* () {
-  let [tab,, panel] = yield initDebugger("about:blank");
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  let [tab,, panel] = yield initDebugger(TAB_URL, options);
   let win = panel.panelWin;
   let editor = win.DebuggerView.editor;
   let queries = win.require("./content/queries");
   let getState = win.DebuggerController.getState;
 
-  yield navigateActiveTabTo(panel,
-                            TAB_URL,
-                            win.EVENTS.SOURCE_SHOWN);
-
   let source = queries.getSelectedSource(getState());
 
   is(queries.getSourceCount(getState()), 1,
     "There should be one source displayed in the view.");
   is(source.url, TAB_URL,
     "The correct source is currently selected in the view.");
   is(editor.getText(), GET_CONTENT,
     "The currently shown source contains bacon. Mmm, delicious!");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-01.js
@@ -5,30 +5,33 @@
 
 /**
  * Make sure that clicking the pretty print button prettifies the source.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  // Wait for debugger panel to be fully set and break on debugger statement
+  let options = {
+    source: "code_ugly.js",
+    line: 2
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "code_ugly.js");
-
       ok(!gEditor.getText().includes("\n  "),
          "The source shouldn't be pretty printed yet.");
 
       const finished = waitForSourceShown(gPanel, "code_ugly.js");
       gDebugger.document.getElementById("pretty-print").click();
       const deck = gDebugger.document.getElementById("editor-deck");
       is(deck.selectedIndex, 2, "The progress bar should be shown");
       yield finished;
@@ -38,12 +41,12 @@ function test() {
       is(deck.selectedIndex, 0, "The editor should be shown");
 
       const source = queries.getSelectedSource(getState());
       const { loading, text } = queries.getSourceText(getState(), source.actor);
       ok(!loading, "Source text is not loading");
       ok(text.includes("\n  "),
          "Subsequent calls to getText return the pretty printed source.");
 
-      closeDebuggerAndFinish(gPanel);
+      resumeDebuggerThenCloseAndFinish(gPanel);
     });
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-02.js
@@ -6,33 +6,36 @@
 /**
  * Make sure that right clicking and selecting the pretty print context menu
  * item prettifies the source.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  // Wait for debugger panel to be fully set and break on debugger statement
+  let options = {
+    source: "code_ugly.js",
+    line: 2
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gContextMenu = gDebugger.document.getElementById("sourceEditorContextMenu");
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "code_ugly.js");
-
       const finished = waitForSourceShown(gPanel, "code_ugly.js");
       once(gContextMenu, "popupshown").then(() => {
         const menuItem = gDebugger.document.getElementById("se-dbg-cMenu-prettyPrint");
         menuItem.click();
       });
       gContextMenu.openPopup(gEditor.container, "overlap", 0, 0, true, false);
       yield finished;
 
       ok(gEditor.getText().includes("\n  "),
          "The source should be pretty printed.");
 
-      closeDebuggerAndFinish(gPanel);
+      resumeDebuggerThenCloseAndFinish(gPanel);
     });
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-03.js
@@ -5,23 +5,28 @@
 
 /**
  * Make sure that we have the correct line selected after pretty printing.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  // Wait for debugger panel to be fully set and break on debugger statement
+  let options = {
+    source: "code_ugly.js",
+    line: 2
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "code_ugly.js");
+      yield doResume(gPanel);
 
       const paused = waitForPause(gDebugger.gThreadClient);
       callInTab(gTab, "foo");
       yield paused;
 
       const finished = promise.all([
         waitForSourceShown(gPanel, "code_ugly.js"),
         waitForCaretUpdated(gPanel, 7)
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-04.js
@@ -5,25 +5,28 @@
 
 /**
  * Tests that the function searching works with pretty printed sources.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  // Wait for debugger panel to be fully set and break on debugger statement
+  let options = {
+    source: "code_ugly.js",
+    line: 2
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "code_ugly.js");
-
       let popupShown = promise.defer();
       once(gDebugger, "popupshown").then(() => {
         ok(isCaretPos(gPanel, 2, 10),
            "The bar function's non-pretty-printed location should be shown.");
         popupShown.resolve();
       });
       setText(gSearchBox, "@bar");
       yield popupShown.promise;
@@ -36,12 +39,12 @@ function test() {
       once(gDebugger, "popupshown").then(() => {
         ok(isCaretPos(gPanel, 6, 10),
            "The bar function's pretty printed location should be shown.");
         popupShown.resolve();
       });
       setText(gSearchBox, "@bar");
       yield popupShown.promise;
 
-      closeDebuggerAndFinish(gPanel);
+      resumeDebuggerThenCloseAndFinish(gPanel);
     });
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-05.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-05.js
@@ -3,31 +3,39 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Make sure that prettifying HTML sources doesn't do anything.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_included-script.html";
+const SCRIPT_URL = EXAMPLE_URL + "code_location-changes.js";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: SCRIPT_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, TAB_URL);
+      // Now, select the html page
+      const sourceShown = waitForSourceShown(gPanel, TAB_URL);
+      gSources.selectedValue = getSourceActor(gSources, TAB_URL);
+      yield sourceShown;
 
       // From this point onward, the source editor's text should never change.
       gEditor.once("change", () => {
         ok(false, "The source editor text shouldn't have changed.");
       });
 
       is(getSelectedSourceURL(gSources), TAB_URL,
         "The correct source is currently selected.");
@@ -51,16 +59,8 @@ function test() {
         "The displayed source hasn't changed.");
       ok(text.includes("myFunction"),
         "The cached source text wasn't altered in any way.");
 
       yield closeDebuggerAndFinish(gPanel);
     });
   });
 }
-
-function prepareDebugger(aPanel) {
-  aPanel._view.Sources.preferredSource = getSourceActor(
-    aPanel.panelWin.DebuggerView.Sources,
-    TAB_URL
-  );
-}
-
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-06.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-06.js
@@ -6,17 +6,21 @@
 /**
  * Make sure that prettifying JS sources with type errors works as expected.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_included-script.html";
 const JS_URL = EXAMPLE_URL + "code_location-changes.js";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: JS_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gClient = gDebugger.gClient;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
@@ -34,18 +38,16 @@ function test() {
           gPrettyPrinted = true;
           return promise.reject({ error: "prettyPrintError" });
         }
         return aOriginalRequestMethod(aPacket, aCallback);
       };
     }(gClient.request));
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, JS_URL);
-
       // From this point onward, the source editor's text should never change.
       gEditor.once("change", () => {
         ok(false, "The source editor text shouldn't have changed.");
       });
 
       is(getSelectedSourceURL(gSources), JS_URL,
         "The correct source is currently selected.");
       ok(gEditor.getText().includes("myFunction"),
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-07.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-07.js
@@ -6,17 +6,21 @@
 // Test basic pretty printing functionality. Would be an xpcshell test, except
 // for bug 921252.
 
 var gTab, gPanel, gClient, gThreadClient, gSource;
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print-2.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "code_ugly-2.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gClient = gPanel.panelWin.gClient;
     gThreadClient = gPanel.panelWin.DebuggerController.activeThread;
 
     findSource();
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-08.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-08.js
@@ -5,17 +5,21 @@
 
 // Test stepping through pretty printed sources.
 
 var gTab, gPanel, gClient, gThreadClient, gSource;
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print-2.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "code_ugly-2.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gClient = gPanel.panelWin.gClient;
     gThreadClient = gPanel.panelWin.DebuggerController.activeThread;
 
     findSource();
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-09.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-09.js
@@ -9,17 +9,21 @@ var gClient;
 var gThreadClient;
 var gSource;
 
 var gTab, gPanel, gClient, gThreadClient, gSource;
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print-2.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "code_ugly-2.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gClient = gPanel.panelWin.gClient;
     gThreadClient = gPanel.panelWin.DebuggerController.activeThread;
 
     findSource();
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-10.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-10.js
@@ -6,39 +6,43 @@
 /**
  * Make sure that we disable the pretty print button for black boxed sources,
  * and that clicking it doesn't do anything.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  // Wait for debugger panel to be fully set and break on debugger statement
+  let options = {
+    source: "code_ugly.js",
+    line: 2
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const getState = gDebugger.DebuggerController.getState;
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "code_ugly.js");
-
       ok(!gEditor.getText().includes("\n    "),
          "The source shouldn't be pretty printed yet.");
 
       yield toggleBlackBoxing(gPanel);
 
       // Wait a tick before clicking to make sure the frontend's blackboxchange
       // handlers have finished.
       yield waitForTick();
       gDebugger.document.getElementById("pretty-print").click();
       // Make sure the text updates
       yield waitForTick();
 
       const source = queries.getSelectedSource(getState());
       const { text } = queries.getSourceText(getState(), source.actor);
       ok(!text.includes("\n    "));
-      closeDebuggerAndFinish(gPanel);
+
+      resumeDebuggerThenCloseAndFinish(gPanel);
     });
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-11.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-11.js
@@ -8,33 +8,38 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  // Wait for debugger panel to be fully set and break on debugger statement
+  let options = {
+    source: "code_ugly.js",
+    line: 2
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
 
-    waitForSourceShown(gPanel, "code_ugly.js")
-      .then(testSourceIsUgly)
+    testSourceIsUgly();
+    const finished = waitForCaretUpdated(gPanel, 7);
+    clickPrettyPrintButton();
+    finished.then(testSourceIsPretty)
       .then(() => {
-        const finished = waitForSourceShown(gPanel, "code_ugly.js");
-        clickPrettyPrintButton();
+        const finished = waitForCaretUpdated(gPanel, 7);
+        reloadActiveTab(gPanel);
         return finished;
       })
       .then(testSourceIsPretty)
-      .then(reloadActiveTab.bind(null, gPanel, gDebugger.EVENTS.SOURCE_SHOWN))
-      .then(testSourceIsPretty)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
       });
   });
 }
 
 function testSourceIsUgly() {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-12.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-12.js
@@ -4,31 +4,35 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Make sure that we don't leave the pretty print button checked when we fail to
  * pretty print a source (because it isn't a JS file, for example).
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
+const SCRIPT_URL = EXAMPLE_URL + "code_blackboxing_blackboxme.js";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: SCRIPT_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "");
       const source = getSourceForm(gSources, TAB_URL);
       let shown = ensureSourceIs(gPanel, TAB_URL, true);
       actions.selectSource(source);
       yield shown;
 
       try {
         yield actions.togglePrettyPrint(source);
         ok(false, "An error occurred while pretty-printing");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-13.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-13.js
@@ -7,29 +7,33 @@
  * Make sure that clicking the pretty print button prettifies the source, even
  * when the source URL does not end in ".js", but the content type is
  * JavaScript.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print-3.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  // Wait for debugger panel to be fully set and break on debugger statement
+  let options = {
+    source: "code_ugly-8",
+    line: 2
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "code_ugly-8");
       ok(!gEditor.getText().includes("\n  "),
          "The source shouldn't be pretty printed yet.");
 
       const finished = waitForSourceShown(gPanel, "code_ugly-8");
       gDebugger.document.getElementById("pretty-print").click();
       const deck = gDebugger.document.getElementById("editor-deck");
       is(deck.selectedIndex, 2, "The progress bar should be shown");
       yield finished;
@@ -38,12 +42,12 @@ function test() {
          "The source should be pretty printed.");
       is(deck.selectedIndex, 0, "The editor should be shown");
 
       const source = queries.getSelectedSource(getState());
       const { text } = queries.getSourceText(getState(), source.actor);
       ok(text.includes("\n  "),
          "Subsequent calls to getText return the pretty printed source.");
 
-      closeDebuggerAndFinish(gPanel);
-    });
+      resumeDebuggerThenCloseAndFinish(gPanel);
+    })
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-on-paused.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-on-paused.js
@@ -10,27 +10,30 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print-on-paused.html";
 
 var gTab, gPanel, gDebugger, gThreadClient, gSources;
 
 const SECOND_SOURCE_VALUE = EXAMPLE_URL + "code_ugly-2.js";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  // Wait for debugger panel to be fully set and break on debugger statement
+  let options = {
+    source: "code_script-switching-02.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gThreadClient = gDebugger.gThreadClient;
     gSources = gDebugger.DebuggerView.Sources;
 
     Task.spawn(function* () {
       try {
-        yield ensureSourceIs(gPanel, "code_script-switching-02.js", true);
-
         yield doInterrupt(gPanel);
 
         let source = gThreadClient.source(getSourceForm(gSources, SECOND_SOURCE_VALUE));
         yield source.setBreakpoint({
           line: 6
         });
         yield doResume(gPanel);
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_progress-listener-bug.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_progress-listener-bug.js
@@ -11,37 +11,41 @@
 var gTab, gPanel, gDebugger;
 var gOldListener;
 
 const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
 
 function test() {
   installListener();
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
 
     is(!!gDebugger.DebuggerController._startup, true,
       "Controller should be initialized after starting the test.");
 
     testPause();
   });
 }
 
 function testPause() {
-  waitForSourceAndCaretAndScopes(gPanel, ".html", 16).then(() => {
+  let onCaretUpdated = waitForCaretUpdated(gPanel, 16);
+  callInTab(gTab, "runDebuggerStatement");
+  onCaretUpdated.then(() => {
     is(gDebugger.gThreadClient.state, "paused",
       "The debugger statement was reached.");
 
     resumeDebuggerThenCloseAndFinish(gPanel);
   });
-
-  callInTab(gTab, "runDebuggerStatement");
 }
 
 // This is taken almost verbatim from bug 771655.
 function installListener() {
   if ("_testPL" in window) {
     gOldListener = _testPL;
 
     Cc["@mozilla.org/docloaderservice;1"]
--- a/devtools/client/debugger/test/mochitest/browser_dbg_promises-allocation-stack.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_promises-allocation-stack.js
@@ -13,17 +13,21 @@ const TAB_URL = EXAMPLE_URL + "doc_promi
 const { PromisesFront } = require("devtools/server/actors/promises");
 var events = require("sdk/event/core");
 
 function test() {
   Task.spawn(function* () {
     DebuggerServer.init();
     DebuggerServer.addBrowserActors();
 
-    const [ tab,, panel ] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    const [ tab,, panel ] = yield initDebugger(TAB_URL, options);
 
     let client = new DebuggerClient(DebuggerServer.connectPipe());
     yield connect(client);
 
     let { tabs } = yield listTabs(client);
     let targetTab = findTab(tabs, TAB_URL);
     yield attachTab(client, targetTab);
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_promises-fulfillment-stack.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_promises-fulfillment-stack.js
@@ -31,17 +31,21 @@ const TEST_DATA = [
   },
 ];
 
 function test() {
   Task.spawn(function* () {
     DebuggerServer.init();
     DebuggerServer.addBrowserActors();
 
-    const [ tab,, panel ] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    const [ tab,, panel ] = yield initDebugger(TAB_URL, options);
 
     let client = new DebuggerClient(DebuggerServer.connectPipe());
     yield connect(client);
 
     let { tabs } = yield listTabs(client);
     let targetTab = findTab(tabs, TAB_URL);
     yield attachTab(client, targetTab);
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_promises-rejection-stack.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_promises-rejection-stack.js
@@ -31,17 +31,21 @@ const TEST_DATA = [
   },
 ];
 
 function test() {
   Task.spawn(function* () {
     DebuggerServer.init();
     DebuggerServer.addBrowserActors();
 
-    const [ tab,, panel ] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    const [ tab,, panel ] = yield initDebugger(TAB_URL, options);
 
     let client = new DebuggerClient(DebuggerServer.connectPipe());
     yield connect(client);
 
     let { tabs } = yield listTabs(client);
     let targetTab = findTab(tabs, TAB_URL);
     yield attachTab(client, targetTab);
 
deleted file mode 100644
--- a/devtools/client/debugger/test/mochitest/browser_dbg_reload-preferred-script-01.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests if the preferred source is shown when a page is loaded and
- * the preferred source is specified before any other source was shown.
- */
-
-const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
-const PREFERRED_URL = EXAMPLE_URL + "code_script-switching-02.js";
-
-var gTab, gDebuggee, gPanel, gDebugger;
-var gSources;
-
-function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
-    gTab = aTab;
-    gDebuggee = aDebuggee;
-    gPanel = aPanel;
-    gDebugger = gPanel.panelWin;
-    gSources = gDebugger.DebuggerView.Sources;
-
-    waitForSourceShown(gPanel, PREFERRED_URL).then(finishTest);
-  });
-}
-
-function finishTest() {
-  info("Currently preferred source: " + gSources.preferredValue);
-  info("Currently selected source: " + gSources.selectedValue);
-
-  is(getSourceURL(gSources, gSources.preferredValue), PREFERRED_URL,
-    "The preferred source url wasn't set correctly.");
-  is(getSourceURL(gSources, gSources.selectedValue), PREFERRED_URL,
-    "The selected source isn't the correct one.");
-
-  closeDebuggerAndFinish(gPanel);
-}
-
-function prepareDebugger(aPanel) {
-  let sources = aPanel._view.Sources;
-  sources.preferredSource = getSourceActor(sources, PREFERRED_URL);
-}
-
-registerCleanupFunction(function () {
-  gTab = null;
-  gDebuggee = null;
-  gPanel = null;
-  gDebugger = null;
-  gSources = null;
-});
--- a/devtools/client/debugger/test/mochitest/browser_dbg_reload-preferred-script-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_reload-preferred-script-02.js
@@ -10,17 +10,21 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 const PREFERRED_URL = EXAMPLE_URL + "code_script-switching-02.js";
 
 var gTab, gPanel, gDebugger;
 var gSources;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
 
     waitForSourceShown(gPanel, PREFERRED_URL).then(finishTest);
     gSources.preferredSource = getSourceActor(gSources, PREFERRED_URL);
   });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_reload-preferred-script-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_reload-preferred-script-03.js
@@ -11,25 +11,28 @@
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 const FIRST_URL = EXAMPLE_URL + "code_script-switching-01.js";
 const SECOND_URL = EXAMPLE_URL + "code_script-switching-02.js";
 
 var gTab, gPanel, gDebugger;
 var gSources;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: FIRST_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
 
-    waitForSourceShown(gPanel, FIRST_URL)
-      .then(() => testSource(undefined, FIRST_URL))
-      .then(() => switchToSource(SECOND_URL))
+    testSource(undefined, FIRST_URL);
+    switchToSource(SECOND_URL)
       .then(() => testSource(SECOND_URL))
       .then(() => switchToSource(FIRST_URL))
       .then(() => testSource(FIRST_URL))
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_reload-same-script.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_reload-same-script.js
@@ -10,17 +10,21 @@
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 const FIRST_URL = EXAMPLE_URL + "code_script-switching-01.js";
 const SECOND_URL = EXAMPLE_URL + "code_script-switching-02.js";
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: FIRST_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = aPanel.panelWin;
     const gTarget = gDebugger.gTarget;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
@@ -74,11 +78,11 @@ function test() {
           break;
         case 5:
           testCurrentSource(SECOND_URL);
           closeDebuggerAndFinish(gPanel);
           break;
       }
     }
 
-    waitForSourceShown(gPanel, FIRST_URL).then(performTest);
+    performTest();
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_scripts-switching-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_scripts-switching-01.js
@@ -5,17 +5,21 @@
 
 /**
  * Make sure that switching the displayed source in the UI works as advertised.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
 
     const gLabel1 = "code_script-switching-01.js";
     const gLabel2 = "code_script-switching-02.js";
@@ -142,17 +146,16 @@ function test() {
          "Editor caret location is correct. (4)");
       is(gEditor.getDebugLocation(), 5,
          "Editor debugger location is correct. (4)");
       ok(gEditor.hasLineClass(5, "debug-line"),
          "The debugged line is highlighted appropriately (3). (4)");
     }
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-01.js", 1);
       ok(gDebugger.document.title.endsWith(EXAMPLE_URL + gLabel1),
          "Title with first source is correct.");
 
       const shown = waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1);
       callInTab(gTab, "firstCall");
       yield shown;
 
       yield testSourcesDisplay();
--- a/devtools/client/debugger/test/mochitest/browser_dbg_scripts-switching-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_scripts-switching-02.js
@@ -9,17 +9,21 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-02.html";
 
 var gLabel1 = "code_script-switching-01.js";
 var gLabel2 = "code_script-switching-02.js";
 var gParams = "?foo=bar,baz|lol";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
 
     function testSourcesDisplay() {
       let deferred = promise.defer();
--- a/devtools/client/debugger/test/mochitest/browser_dbg_scripts-switching-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_scripts-switching-03.js
@@ -5,17 +5,21 @@
 
 /**
  * Make sure that the DebuggerView error loading source text is correct.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gView = gDebugger.DebuggerView;
     const gEditor = gDebugger.DebuggerView.editor;
     const gL10N = gDebugger.L10N;
     const require = gDebugger.require;
     const actions = bindActionCreators(gPanel);
@@ -46,15 +50,14 @@ function test() {
     }
 
     function testDebuggerLoadingError() {
       ok(gEditor.getText().includes(gL10N.getFormatStr("errorLoadingText2", "")),
          "The valid error loading message is displayed.");
     }
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-01.js");
       showBogusSource();
       testDebuggerLoadingError();
       closeDebuggerAndFinish(gPanel);
     });
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-autofill-identifier.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-autofill-identifier.js
@@ -7,131 +7,132 @@
  * Tests that Debugger Search uses the identifier under cursor if nothing is
  * selected or manually passed and searching using certain operators.
  */
 "use strict";
 
 function test() {
   const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
-    let Source = "code_function-search-01.js";
+  let options = {
+    source: "code_function-search-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let Debugger = aPanel.panelWin;
     let Editor = Debugger.DebuggerView.editor;
     let Filtering = Debugger.DebuggerView.Filtering;
 
     function doSearch(aOperator) {
       Editor.dropSelection();
       Filtering._doSearch(aOperator);
     }
 
-    waitForSourceShown(aPanel, Source).then(() => {
-      info("Testing with cursor at the beginning of the file...");
+    info("Testing with cursor at the beginning of the file...");
 
-      doSearch();
-      is(Filtering._searchbox.value, "",
-        "The searchbox value should not be auto-filled when searching for files.");
-      is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
-        "The searchbox contents should not be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch();
+    is(Filtering._searchbox.value, "",
+      "The searchbox value should not be auto-filled when searching for files.");
+    is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
+      "The searchbox contents should not be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      doSearch("!");
-      is(Filtering._searchbox.value, "!",
-        "The searchbox value should not be auto-filled when searching across all files.");
-      is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
-        "The searchbox contents should not be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch("!");
+    is(Filtering._searchbox.value, "!",
+      "The searchbox value should not be auto-filled when searching across all files.");
+    is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
+      "The searchbox contents should not be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      doSearch("@");
-      is(Filtering._searchbox.value, "@",
-        "The searchbox value should not be auto-filled when searching for functions.");
-      is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
-        "The searchbox contents should not be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch("@");
+    is(Filtering._searchbox.value, "@",
+      "The searchbox value should not be auto-filled when searching for functions.");
+    is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
+      "The searchbox contents should not be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      doSearch("#");
-      is(Filtering._searchbox.value, "#",
-        "The searchbox value should not be auto-filled when searching inside a file.");
-      is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
-        "The searchbox contents should not be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch("#");
+    is(Filtering._searchbox.value, "#",
+      "The searchbox value should not be auto-filled when searching inside a file.");
+    is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
+      "The searchbox contents should not be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      doSearch(":");
-      is(Filtering._searchbox.value, ":",
-        "The searchbox value should not be auto-filled when searching for a line.");
-      is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
-        "The searchbox contents should not be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch(":");
+    is(Filtering._searchbox.value, ":",
+      "The searchbox value should not be auto-filled when searching for a line.");
+    is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
+      "The searchbox contents should not be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      doSearch("*");
-      is(Filtering._searchbox.value, "*",
-        "The searchbox value should not be auto-filled when searching for variables.");
-      is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
-        "The searchbox contents should not be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch("*");
+    is(Filtering._searchbox.value, "*",
+      "The searchbox value should not be auto-filled when searching for variables.");
+    is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
+      "The searchbox contents should not be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      Editor.setCursor({ line: 7, ch: 0});
-      info("Testing with cursor at line 8 and char 1...");
+    Editor.setCursor({ line: 7, ch: 0});
+    info("Testing with cursor at line 8 and char 1...");
 
-      doSearch();
-      is(Filtering._searchbox.value, "",
-        "The searchbox value should not be auto-filled when searching for files.");
-      is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
-        "The searchbox contents should not be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch();
+    is(Filtering._searchbox.value, "",
+      "The searchbox value should not be auto-filled when searching for files.");
+    is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
+      "The searchbox contents should not be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      doSearch("!");
-      is(Filtering._searchbox.value, "!test",
-        "The searchbox value was incorrect when searching across all files.");
-      is(Filtering._searchbox.selectionStart, 1,
-        "The searchbox operator should not be selected");
-      is(Filtering._searchbox.selectionEnd, 5,
-        "The searchbox contents should be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch("!");
+    is(Filtering._searchbox.value, "!test",
+      "The searchbox value was incorrect when searching across all files.");
+    is(Filtering._searchbox.selectionStart, 1,
+      "The searchbox operator should not be selected");
+    is(Filtering._searchbox.selectionEnd, 5,
+      "The searchbox contents should be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      doSearch("@");
-      is(Filtering._searchbox.value, "@test",
-        "The searchbox value was incorrect when searching for functions.");
-      is(Filtering._searchbox.selectionStart, 1,
-        "The searchbox operator should not be selected");
-      is(Filtering._searchbox.selectionEnd, 5,
-        "The searchbox contents should be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch("@");
+    is(Filtering._searchbox.value, "@test",
+      "The searchbox value was incorrect when searching for functions.");
+    is(Filtering._searchbox.selectionStart, 1,
+      "The searchbox operator should not be selected");
+    is(Filtering._searchbox.selectionEnd, 5,
+      "The searchbox contents should be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      doSearch("#");
-      is(Filtering._searchbox.value, "#test",
-        "The searchbox value should be auto-filled when searching inside a file.");
-      is(Filtering._searchbox.selectionStart, 1,
-        "The searchbox operator should not be selected");
-      is(Filtering._searchbox.selectionEnd, 5,
-        "The searchbox contents should be selected");
-      is(Editor.getSelection(), "test",
-        "The selection in the editor should be 'test'.");
+    doSearch("#");
+    is(Filtering._searchbox.value, "#test",
+      "The searchbox value should be auto-filled when searching inside a file.");
+    is(Filtering._searchbox.selectionStart, 1,
+      "The searchbox operator should not be selected");
+    is(Filtering._searchbox.selectionEnd, 5,
+      "The searchbox contents should be selected");
+    is(Editor.getSelection(), "test",
+      "The selection in the editor should be 'test'.");
 
-      doSearch(":");
-      is(Filtering._searchbox.value, ":",
-        "The searchbox value should not be auto-filled when searching for a line.");
-      is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
-        "The searchbox contents should not be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch(":");
+    is(Filtering._searchbox.value, ":",
+      "The searchbox value should not be auto-filled when searching for a line.");
+    is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
+      "The searchbox contents should not be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      doSearch("*");
-      is(Filtering._searchbox.value, "*",
-        "The searchbox value should not be auto-filled when searching for variables.");
-      is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
-        "The searchbox contents should not be selected");
-      is(Editor.getSelection(), "",
-        "The selection in the editor should be empty.");
+    doSearch("*");
+    is(Filtering._searchbox.value, "*",
+      "The searchbox value should not be auto-filled when searching for variables.");
+    is(Filtering._searchbox.selectionStart, Filtering._searchbox.selectionEnd,
+      "The searchbox contents should not be selected");
+    is(Editor.getSelection(), "",
+      "The selection in the editor should be empty.");
 
-      closeDebuggerAndFinish(aPanel);
-    });
+    closeDebuggerAndFinish(aPanel);
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-basic-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-basic-01.js
@@ -8,26 +8,30 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gFiltering, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gFiltering = gDebugger.DebuggerView.Filtering;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
-    waitForSourceShown(gPanel, ".html").then(performTest);
+    performTest();
   });
 }
 
 function performTest() {
   // Make sure that the search box becomes focused when pressing ctrl+f - Bug 1211038
   gEditor.focus();
   synthesizeKeyFromKeyTag(gDebugger.document.getElementById("tokenSearchKey"));
   let focusedEl = Services.focus.focusedElement;
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-basic-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-basic-02.js
@@ -8,24 +8,29 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gSources, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1,
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
-    waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
+    // Calling `firstCall` is going to break into the other script
+    waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6)
       .then(performSimpleSearch)
       .then(() => verifySourceAndCaret("-01.js", 1, 1, [1, 1]))
       .then(combineWithLineSearch)
       .then(() => verifySourceAndCaret("-01.js", 2, 1, [53, 53]))
       .then(combineWithTokenSearch)
       .then(() => verifySourceAndCaret("-01.js", 2, 48, [96, 100]))
       .then(combineWithTokenColonSearch)
       .then(() => verifySourceAndCaret("-01.js", 2, 11, [56, 63]))
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-basic-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-basic-03.js
@@ -7,24 +7,29 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gSources, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1,
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
-    waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
+    // Calling `firstCall` is going to break into the other script
+    waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6)
       .then(performFileSearch)
       .then(escapeAndHide)
       .then(escapeAndClear)
       .then(() => verifySourceAndCaret("-01.js", 1, 1))
       .then(performFunctionSearch)
       .then(escapeAndHide)
       .then(escapeAndClear)
       .then(() => verifySourceAndCaret("-01.js", 4, 10))
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-basic-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-basic-04.js
@@ -9,31 +9,31 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1,
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
-    waitForSourceShown(gPanel, "-01.js")
-      .then(testLineSearch)
-      .then(testTokenSearch)
-      .then(() => closeDebuggerAndFinish(gPanel))
-      .then(null, aError => {
-        ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
-      });
+    testLineSearch();
+    testTokenSearch();
+    closeDebuggerAndFinish(gPanel);
   });
 }
 
 function testLineSearch() {
   setText(gSearchBox, ":42");
   ok(isCaretPos(gPanel, 7),
     "The editor caret position appears to be correct (1.1).");
   ok(isEditorSel(gPanel, [151, 151]),
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-global-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-global-01.js
@@ -9,17 +9,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-global-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-global-02.js
@@ -9,17 +9,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-global-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-global-03.js
@@ -9,17 +9,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-global-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-global-04.js
@@ -9,17 +9,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-global-05.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-global-05.js
@@ -10,17 +10,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-global-06.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-global-06.js
@@ -9,17 +9,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-popup-jank.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-popup-jank.js
@@ -8,27 +8,30 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_editor-mode.html";
 
 var gTab, gPanel, gDebugger;
 var gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     gDebugger.DebuggerView.Filtering.FilteredSources._autoSelectFirstItem = false;
     gDebugger.DebuggerView.Filtering.FilteredFunctions._autoSelectFirstItem = false;
 
-    waitForSourceShown(gPanel, "-01.js")
-      .then(superGenericFileSearch)
+    superGenericFileSearch()
       .then(() => ensureSourceIs(aPanel, "-01.js"))
       .then(() => ensureCaretAt(aPanel, 1))
 
       .then(superAccurateFileSearch)
       .then(() => ensureSourceIs(aPanel, "-01.js"))
       .then(() => ensureCaretAt(aPanel, 1))
       .then(() => pressKeyToHide("RETURN"))
       .then(() => ensureSourceIs(aPanel, "code_test-editor-mode", true))
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-sources-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-sources-01.js
@@ -8,29 +8,31 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(3);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const gSearchView = gDebugger.DebuggerView.Filtering.FilteredSources;
     const gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     Task.spawn(function* () {
       // move searches to yields
       // not sure what to do with the error...
-
-      yield waitForSourceShown(gPanel, "-01.js");
       yield bogusSearch();
       yield firstSearch();
       yield secondSearch();
       yield thirdSearch();
       yield fourthSearch();
       yield fifthSearch();
       yield sixthSearch();
       yield seventhSearch();
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-sources-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-sources-02.js
@@ -11,27 +11,30 @@ const TAB_URL = EXAMPLE_URL + "doc_edito
 
 var gTab, gPanel, gDebugger;
 var gSources, gSourceUtils, gSearchView, gSearchBox;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(3);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gSourceUtils = gDebugger.SourceUtils;
     gSearchView = gDebugger.DebuggerView.Filtering.FilteredSources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
-    waitForSourceShown(gPanel, "-01.js")
-      .then(firstSearch)
+    firstSearch()
       .then(secondSearch)
       .then(thirdSearch)
       .then(fourthSearch)
       .then(fifthSearch)
       .then(goDown)
       .then(goDownAndWrap)
       .then(goUpAndWrap)
       .then(goUp)
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-sources-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-sources-03.js
@@ -8,25 +8,28 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_editor-mode.html";
 
 var gTab, gPanel, gDebugger;
 var gSources, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
-    waitForSourceShown(gPanel, "-01.js")
-      .then(superGenericSearch)
+    superGenericSearch()
       .then(verifySourcesPane)
       .then(kindaInterpretableSearch)
       .then(verifySourcesPane)
       .then(incrediblySpecificSearch)
       .then(verifySourcesPane)
       .then(returnAndHide)
       .then(verifySourcesPane)
       .then(() => closeDebuggerAndFinish(gPanel))
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-symbols.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-symbols.js
@@ -8,27 +8,30 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gSearchBox, gFilteredFunctions;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
     gFilteredFunctions = gDebugger.DebuggerView.Filtering.FilteredFunctions;
 
-    waitForSourceShown(gPanel, "-01.js")
-      .then(() => showSource("doc_function-search.html"))
+   showSource("doc_function-search.html")
       .then(htmlSearch)
       .then(() => showSource("code_function-search-01.js"))
       .then(firstJsSearch)
       .then(() => showSource("code_function-search-02.js"))
       .then(secondJsSearch)
       .then(() => showSource("code_function-search-03.js"))
       .then(thirdJsSearch)
       .then(saveSearch)
--- a/devtools/client/debugger/test/mochitest/browser_dbg_searchbox-help-popup-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_searchbox-help-popup-01.js
@@ -9,17 +9,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gSearchBox, gSearchBoxPanel;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
     gSearchBoxPanel = gDebugger.DebuggerView.Filtering._searchboxHelpPanel;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
       .then(showPopup)
--- a/devtools/client/debugger/test/mochitest/browser_dbg_searchbox-help-popup-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_searchbox-help-popup-02.js
@@ -9,17 +9,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSearchBox, gSearchBoxPanel;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
     gSearchBoxPanel = gDebugger.DebuggerView.Filtering._searchboxHelpPanel;
 
     once(gSearchBoxPanel, "popupshown").then(() => {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_searchbox-parse.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_searchbox-parse.js
@@ -3,17 +3,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that text entered in the debugger's searchbox is properly parsed.
  */
 
 function test() {
-  initDebugger("about:blank").then(([aTab,, aPanel]) => {
+  initDebugger().then(([aTab,, aPanel]) => {
     let filterView = aPanel.panelWin.DebuggerView.Filtering;
     let searchbox = aPanel.panelWin.DebuggerView.Filtering._searchbox;
 
     setText(searchbox, "");
     is(filterView.searchData.toSource(), '["", [""]]',
       "The searchbox data wasn't parsed correctly (1).");
 
     setText(searchbox, "#token");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-01.js
@@ -8,17 +8,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
   // Linux debug test slaves are a bit slow at this test sometimes.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
@@ -161,17 +165,20 @@ function test() {
          "There should be a selected source in the sources pane.");
       ok(gSources._selectedBreakpoint,
          "There should be a selected breakpoint in the sources pane.");
       is(gSources._conditionalPopupVisible, false,
          "The breakpoint conditional expression popup should not be shown.");
     });
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
+
       yield addBreakpoints();
 
       is(gDebugger.gThreadClient.state, "paused",
          "Should only be getting stack frames while paused.");
       is(queries.getSourceCount(getState()), 1,
          "Found the expected number of sources.");
       is(gEditor.getText().indexOf("ermahgerd"), 253,
          "The correct source was loaded initially.");
@@ -202,12 +209,10 @@ function test() {
       // expression to the server which pauses the server. Make sure
       // we wait if there is a pending request.
       if (gDebugger.gThreadClient.state === "paused") {
         yield waitForThreadEvents(gPanel, "resumed");
       }
 
       closeDebuggerAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-02.js
@@ -5,17 +5,21 @@
 
 /**
  * Test adding and modifying conditional breakpoints (with server-side support)
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
@@ -118,17 +122,19 @@ function test() {
     function waitForConditionUpdate() {
       // This will close the popup and send another request to update
       // the condition
       gSources._hideConditionalPopup();
       return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
     }
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
 
       is(gDebugger.gThreadClient.state, "paused",
          "Should only be getting stack frames while paused.");
       is(queries.getSourceCount(getState()), 1,
          "Found the expected number of sources.");
       is(gEditor.getText().indexOf("ermahgerd"), 253,
          "The correct source was loaded initially.");
       is(gSources.selectedValue, gSources.values[0],
@@ -187,12 +193,10 @@ function test() {
 
       clickOnBreakpoint(2);
       is(gSources._selectedBreakpoint.location.line, 20,
          "The selected breakpoint is line 20");
       testBreakpoint(20, true, "bamboocha");
 
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-03.js
@@ -6,17 +6,21 @@
 /**
  * Test that conditional breakpoints survive disabled breakpoints
  * (with server-side support)
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
@@ -24,17 +28,20 @@ function test() {
     function waitForConditionUpdate() {
       // This will close the popup and send another request to update
       // the condition
       gSources._hideConditionalPopup();
       return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
     }
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
+
       const location = { actor: gSources.selectedValue, line: 18 };
 
       yield actions.addBreakpoint(location, "hello");
       yield actions.disableBreakpoint(location);
       yield actions.addBreakpoint(location);
 
       const bp = queries.getBreakpoint(getState(), location);
       is(bp.condition, "hello", "The conditional expression is correct.");
@@ -57,12 +64,10 @@ function test() {
       EventUtils.sendMouseEvent({ type: "click" },
                                 gDebugger.document.querySelector(".dbg-breakpoint"),
                                 gDebugger);
       yield finished;
       is(textbox.value, "foo", "The expression is correct (3).");
 
       yield resumeDebuggerThenCloseAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-04.js
@@ -7,35 +7,40 @@
  * Make sure that conditional breakpoints with undefined expressions
  * maintain their conditions when re-enabling them (with
  * server-side support)
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
+
       const location = { actor: gSources.selectedValue, line: 18 };
 
       yield actions.addBreakpoint(location, "");
       yield actions.disableBreakpoint(location);
       yield actions.addBreakpoint(location);
 
       const bp = queries.getBreakpoint(getState(), location);
       is(bp.condition, "", "The conditional expression is correct.");
 
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-05.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_server-conditional-bp-05.js
@@ -6,17 +6,21 @@
 /**
  * Test conditional breakpoints throwing exceptions
  * with server support
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  const options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const queries = gDebugger.require("./content/queries");
     const constants = gDebugger.require("./content/constants");
     const actions = bindActionCreators(gPanel);
@@ -90,17 +94,19 @@ function test() {
       isnot(selectedBreakpoint.condition, undefined,
             "The breakpoint on line " + line + " should have a conditional expression.");
 
       ok(isCaretPos(gPanel, line),
          "The editor caret position is not properly set.");
     }
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
+      let onCaretUpdated = waitForCaretAndScopes(gPanel, 17);
+      callInTab(gTab, "ermahgerd");
+      yield onCaretUpdated;
 
       yield actions.addBreakpoint(
         { actor: gSources.selectedValue, line: 18 }, " 1a"
       );
       yield actions.addBreakpoint(
         { actor: gSources.selectedValue, line: 19 }, "new Error()"
       );
       yield actions.addBreakpoint(
@@ -119,12 +125,10 @@ function test() {
       yield resumeAndTestBreakpoint(18);
       yield resumeAndTestBreakpoint(19);
       yield resumeAndTestBreakpoint(20);
       yield resumeAndTestBreakpoint(23);
       yield resumeAndTestNoBreakpoint();
 
       closeDebuggerAndFinish(gPanel);
     });
-
-    callInTab(gTab, "ermahgerd");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_source-maps-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_source-maps-01.js
@@ -10,28 +10,31 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_binary_search.html";
 const COFFEE_URL = EXAMPLE_URL + "code_binary_search.coffee";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: COFFEE_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
 
     checkSourceMapsEnabled();
 
-    waitForSourceShown(gPanel, ".coffee")
-      .then(checkInitialSource)
-      .then(testSetBreakpoint)
+    checkInitialSource();
+    testSetBreakpoint()
       .then(testSetBreakpointBlankLine)
       .then(testHitBreakpoint)
       .then(testStepping)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_source-maps-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_source-maps-02.js
@@ -9,28 +9,31 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_binary_search.html";
 const JS_URL = EXAMPLE_URL + "code_binary_search.js";
 
 var gTab, gPanel, gDebugger, gEditor;
 var gSources, gFrames, gPrefs, gOptions;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: ".coffee",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gPrefs = gDebugger.Prefs;
     gOptions = gDebugger.DebuggerView.Options;
 
-    waitForSourceShown(gPanel, ".coffee")
-      .then(testToggleGeneratedSource)
+    testToggleGeneratedSource()
       .then(testSetBreakpoint)
       .then(testToggleOnPause)
       .then(testResume)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_source-maps-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_source-maps-03.js
@@ -9,27 +9,30 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_minified.html";
 const JS_URL = EXAMPLE_URL + "code_math.js";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gFrames;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: JS_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gFrames = gDebugger.DebuggerView.StackFrames;
 
-    waitForSourceShown(gPanel, JS_URL)
-      .then(checkInitialSource)
-      .then(testSetBreakpoint)
+    checkInitialSource()
+    testSetBreakpoint()
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 }
 
 function checkInitialSource() {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_source-maps-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_source-maps-04.js
@@ -12,32 +12,35 @@ const JS_URL = EXAMPLE_URL + "code_math_
 
 // This test causes an error to be logged in the console, which appears in TBPL
 // logs, so we are disabling that here.
 DevToolsUtils.reportingDisabled = true;
 
 var gPanel, gDebugger, gFrames, gSources, gPrefs, gOptions;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: JS_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gSources = gDebugger.DebuggerView.Sources;
     gPrefs = gDebugger.Prefs;
     gOptions = gDebugger.DebuggerView.Options;
 
     is(gPrefs.pauseOnExceptions, false,
       "The pause-on-exceptions pref should be disabled by default.");
     isnot(gOptions._pauseOnExceptionsItem.getAttribute("checked"), "true",
       "The pause-on-exceptions menu item should not be checked.");
 
-    waitForSourceShown(gPanel, JS_URL)
-      .then(checkInitialSource)
-      .then(enablePauseOnExceptions)
+    checkInitialSource();
+    enablePauseOnExceptions()
       .then(disableIgnoreCaughtExceptions)
       .then(testSetBreakpoint)
       .then(reloadPage)
       .then(testHitBreakpoint)
       .then(enableIgnoreCaughtExceptions)
       .then(disablePauseOnExceptions)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-bookmarklet.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-bookmarklet.js
@@ -7,30 +7,32 @@
  * Make sure javascript bookmarklet scripts appear and load correctly in the source list
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-bookmarklet.html";
 
 const BOOKMARKLET_SCRIPT_CODE = "console.log('bookmarklet executed');";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const gBreakpoints = gDebugger.DebuggerController.Breakpoints;
     const getState = gDebugger.DebuggerController.getState;
     const constants = gDebugger.require("./content/constants");
     const queries = gDebugger.require("./content/queries");
     const actions = bindActionCreators(gPanel);
 
     return Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, ".html");
-
       const added = waitForNextDispatch(gDebugger.DebuggerController, constants.ADD_SOURCE);
       // NOTE: devtools debugger panel needs to be already open,
       // or the bookmarklet script will not be shown in the sources panel
       callInTab(gTab, "injectBookmarklet", BOOKMARKLET_SCRIPT_CODE);
       yield added;
 
       is(queries.getSourceCount(getState()), 2, "Should have 2 sources");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-cache.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-cache.js
@@ -6,17 +6,21 @@
 /**
  * Tests if the sources cache knows how to cache sources when prompted.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
 const TOTAL_SOURCES = 4;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab, aDebuggee, aPanel]) => {
     const gTab = aTab;
     const gDebuggee = aDebuggee;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const gPrevLabelsCache = gDebugger.SourceUtils._labelsCache;
     const gPrevGroupsCache = gDebugger.SourceUtils._groupsCache;
@@ -122,17 +126,16 @@ function test() {
          "There should be " + TOTAL_SOURCES + " sources present in the sources list.");
       is(gDebugger.SourceUtils._labelsCache.size, TOTAL_SOURCES,
          "There should be " + TOTAL_SOURCES + " labels cached after reload.");
       is(gDebugger.SourceUtils._groupsCache.size, TOTAL_SOURCES,
          "There should be " + TOTAL_SOURCES + " groups cached after reload.");
     }
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-01.js");
       yield initialChecks();
       yield testCacheIntegrity(["code_function-search-01.js"]);
       yield fetchAllSources();
       yield testCacheIntegrity([
         "code_function-search-01.js",
         "code_function-search-02.js",
         "code_function-search-03.js",
         "doc_function-search.html"
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-contextmenu-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-contextmenu-01.js
@@ -8,24 +8,27 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
 const SCRIPT_URI = EXAMPLE_URL + "code_function-search-01.js";
 
 function test() {
   let gTab, gPanel, gDebugger, gSources;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: SCRIPT_URI,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
 
-    waitForSourceShown(gPanel, "-01.js")
-      .then(openContextMenu)
+    openContextMenu()
       .then(testCopyMenuItem)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 
   function clickCopyURL() {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-contextmenu-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-contextmenu-02.js
@@ -9,24 +9,27 @@
 
 const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
 const SCRIPT_URI = EXAMPLE_URL + "code_function-search-01.js";
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gSources;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: SCRIPT_URI,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
 
-    waitForSourceShown(gPanel, "-01.js")
-      .then(openContextMenu)
+    openContextMenu()
       .then(testNewTabMenuItem)
       .then(testNewTabURI)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-eval-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-eval-01.js
@@ -8,25 +8,28 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gSources, gBreakpoints;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-eval.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gBreakpoints = gDebugger.DebuggerController.Breakpoints;
 
     return Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-eval.js");
       is(gSources.values.length, 1, "Should have 1 source");
 
       let newSource = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.NEW_SOURCE);
       callInTab(gTab, "evalSource");
       yield newSource;
 
       is(gSources.values.length, 2, "Should have 2 sources");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-eval-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-eval-02.js
@@ -9,30 +9,33 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gSources, gBreakpoints, gEditor;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-eval.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gBreakpoints = gDebugger.DebuggerController.Breakpoints;
     gEditor = gDebugger.DebuggerView.editor;
     const constants = gDebugger.require("./content/constants");
     const queries = gDebugger.require("./content/queries");
     const actions = bindActionCreators(gPanel);
     const getState = gDebugger.DebuggerController.getState;
 
     return Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-eval.js");
       is(queries.getSourceCount(getState()), 1, "Should have 1 source");
 
       const newSource = waitForDispatch(gPanel, constants.ADD_SOURCE);
       callInTab(gTab, "evalSourceWithSourceURL");
       yield newSource;
 
       is(queries.getSourceCount(getState()), 2, "Should have 2 sources");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-iframe-reload.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-iframe-reload.js
@@ -10,17 +10,17 @@
 "use strict";
 
 const IFRAME_URL = "data:text/html;charset=utf-8," +
   "<script>function fn() { console.log('hello'); }</script>" +
   "<div onclick='fn()'>hello</div>";
 const TAB_URL = `data:text/html;charset=utf-8,<iframe src="${IFRAME_URL}"/>`;
 
 add_task(function* () {
-  let [,, panel] = yield initDebugger("about:blank");
+  let [,, panel] = yield initDebugger();
   let dbg = panel.panelWin;
   let newSource;
 
   newSource = waitForDebuggerEvents(panel, dbg.EVENTS.NEW_SOURCE);
   reload(panel, TAB_URL);
   yield newSource;
   ok(true, "Source event fired on initial load");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-keybindings.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-keybindings.js
@@ -8,24 +8,27 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
 const SCRIPT_URI = EXAMPLE_URL + "code_function-search-01.js";
 
 function test() {
   let gTab, gPanel, gDebugger, gSources;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: SCRIPT_URI,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
 
-    waitForSourceShown(gPanel, "-01.js")
-      .then(testCopyURLShortcut)
+    testCopyURLShortcut()
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 
   function testCopyURLShortcut() {
     return waitForClipboardPromise(sendCopyShortcut, SCRIPT_URI);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-labels.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-labels.js
@@ -8,28 +8,30 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gSources, gUtils;
 
-  initDebugger(TAB_URL).then(Task.async(function* ([aTab,, aPanel]) {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(Task.async(function* ([aTab,, aPanel]) {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gUtils = gDebugger.SourceUtils;
 
     let ellipsis = gPanel.panelWin.L10N.ellipsis;
     let nananana = new Array(20).join(NaN);
 
-    yield waitForSourceShown(gPanel, ".html");
-
     // Test trimming url queries.
 
     let someUrl = "a/b/c.d?test=1&random=4#reference";
     let shortenedUrl = "a/b/c.d";
     is(gUtils.trimUrlQuery(someUrl), shortenedUrl,
       "Trimming the url query isn't done properly.");
 
     // Test trimming long urls with an ellipsis.
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-large.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-large.js
@@ -7,17 +7,21 @@
  * Tests that large files are treated differently in the debugger:
  *   1) No parsing to determine current symbol is attempted when
  *      starting a search
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab, aDebuggee, aPanel]) => {
     const gTab = aTab;
     const gDebuggee = aDebuggee;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
 
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const Filtering = gDebugger.DebuggerView.Filtering;
@@ -54,17 +58,16 @@ function test() {
       gEditor.focus();
       gEditor.setCursor({ line: 3, ch: 10});
       synthesizeKeyFromKeyTag(gDebugger.document.getElementById("tokenSearchKey"));
       is(Filtering._searchbox.value, "#test",
         "Search box is prefilled with current token");
     }
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, "-01.js");
       yield testLargeFile();
 
       info("Making it appear as a small file and then reselecting 01.js");
       gDebugger.DebuggerView.LARGE_FILE_SIZE = 1000;
       gSources.selectedIndex = 1;
       yield waitForSourceShown(gPanel, "-02.js");
       gSources.selectedIndex = 0;
       yield waitForSourceShown(gPanel, "-01.js");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-sorting.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-sorting.js
@@ -8,28 +8,31 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 var gTab, gPanel, gDebugger;
 var gSources, gUtils;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gUtils = gDebugger.SourceUtils;
 
-    waitForSourceShown(gPanel, ".html")
-      .then(addSourceAndCheckOrder.bind(null, 1))
-      .then(addSourceAndCheckOrder.bind(null, 2))
-      .then(addSourceAndCheckOrder.bind(null, 3))
-      .then(() => { closeDebuggerAndFinish(gPanel); });
+    addSourceAndCheckOrder(1);
+    addSourceAndCheckOrder(2);
+    addSourceAndCheckOrder(3);
+    closeDebuggerAndFinish(gPanel);
   });
 }
 
 function addSourceAndCheckOrder(aMethod) {
   gSources.empty();
   gSources.suppressSelectionEvents = true;
 
   let urls = [
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-webext-contentscript.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-webext-contentscript.js
@@ -25,26 +25,24 @@ function test() {
       // If no debugger panel was opened, call finish directly.
       finish();
     }
   };
 
   return Task.spawn(function* () {
     gAddon = yield addAddon(EXAMPLE_URL + "/addon-webext-contentscript.xpi");
 
-    [,, gPanel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: "webext-content-script.js",
+      line: 1
+    };
+    [,, gPanel] = yield initDebugger(TAB_URL, options);
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
 
-    // Wait for a SOURCE_SHOWN event for at most 4 seconds.
-    yield Promise.race([
-      waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN),
-      waitForTime(4000),
-    ]);
-
     is(gSources.values.length, 1, "Should have 1 source");
 
     let item = gSources.getItemForAttachment(attachment => {
       return attachment.source.url.includes("moz-extension");
     });
 
     ok(item, "Got the expected WebExtensions ContentScript source");
     ok(item && item.attachment.source.url.includes(item.attachment.group),
--- a/devtools/client/debugger/test/mochitest/browser_dbg_split-console-keypress.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_split-console-keypress.js
@@ -11,23 +11,27 @@ const TAB_URL = EXAMPLE_URL + "doc_step-
 
 function test() {
   // This does the same assertions over a series of sub-tests, and it
   // can timeout in linux e10s.  No sense in breaking it up into multiple
   // tests, so request extra time.
   requestLongerTimeout(2);
 
   let gDebugger, gToolbox, gThreadClient, gTab, gPanel;
-  initDebugger(TAB_URL).then(([aTab, debuggeeWin, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab, debuggeeWin, aPanel]) => {
     gPanel = aPanel;
     gDebugger = aPanel.panelWin;
     gToolbox = gDevTools.getToolbox(aPanel.target);
     gTab = aTab;
     gThreadClient = gDebugger.DebuggerController.activeThread;
-    waitForSourceShown(aPanel, TAB_URL).then(testConsole);
+    testConsole();
   });
   let testConsole = Task.async(function* () {
     // We need to open the split console (with an ESC keypress),
     // then get the script into a paused state by pressing a button in the page,
     // ensure focus is in the split console,
     // synthesize a few keys - important ones we share listener for are
     // "resumeKey", "stepOverKey", "stepInKey", "stepOutKey"
     // then check that
--- a/devtools/client/debugger/test/mochitest/browser_dbg_split-console-paused-reload.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_split-console-paused-reload.js
@@ -9,23 +9,26 @@
  */
 
 function test() {
   Task.spawn(runTests);
 }
 
 function* runTests() {
   let TAB_URL = EXAMPLE_URL + "doc_split-console-paused-reload.html";
-  let [,, panel] = yield initDebugger(TAB_URL);
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  let [,, panel] = yield initDebugger(TAB_URL, options);
   let dbgWin = panel.panelWin;
   let sources = dbgWin.DebuggerView.Sources;
   let frames = dbgWin.DebuggerView.StackFrames;
   let toolbox = gDevTools.getToolbox(panel.target);
 
-  yield waitForSourceShown(panel, ".html");
   yield panel.addBreakpoint({ actor: getSourceActor(sources, TAB_URL), line: 16 });
   info("Breakpoint was set.");
   dbgWin.DebuggerController._target.activeTab.reload();
   info("Page reloaded.");
   yield waitForSourceAndCaretAndScopes(panel, ".html", 16);
   yield ensureThreadClientState(panel, "paused");
   info("Breakpoint was hit.");
   EventUtils.sendMouseEvent({ type: "mousedown" },
--- a/devtools/client/debugger/test/mochitest/browser_dbg_stack-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_stack-01.js
@@ -8,24 +8,28 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 var gTab, gPanel, gDebugger;
 var gFrames, gClassicFrames;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 14).then(performTest);
+    waitForCaretAndScopes(gPanel, 14).then(performTest);
     callInTab(gTab, "simpleCall");
   });
 }
 
 function performTest() {
   is(gDebugger.gThreadClient.state, "paused",
     "Should only be getting stack frames while paused.");
   is(gFrames.itemCount, 1,
--- a/devtools/client/debugger/test/mochitest/browser_dbg_stack-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_stack-02.js
@@ -5,17 +5,21 @@
 
 /**
  * Test that stackframes are added when debugger is paused in eval calls.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gFrames = gDebugger.DebuggerView.StackFrames;
     const gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
 
     const performTest = Task.async(function* () {
       is(gDebugger.gThreadClient.state, "paused",
@@ -97,15 +101,15 @@ function test() {
          "Oldest frame should be selected after click inside the oldest frame.");
       is(gClassicFrames.selectedIndex, 1,
          "Oldest frame in the mirrored view should be selected.");
 
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, ".html", 1);
+      yield waitForCaretAndScopes(gPanel, 1);
       performTest();
     });
 
     callInTab(gTab, "evalCall");
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_stack-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_stack-03.js
@@ -6,17 +6,21 @@
 /**
  * Test that stackframes are scrollable.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 let framesScrollingInterval;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab, aDebuggee, aPanel]) => {
     const tab = aTab;
     const debuggee = aDebuggee;
     const panel = aPanel;
     const gDebugger = panel.panelWin;
     const frames = gDebugger.DebuggerView.StackFrames;
     const classicFrames = gDebugger.DebuggerView.StackFramesClassicList;
 
     Task.spawn(function* () {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_stack-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_stack-04.js
@@ -8,24 +8,28 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 var gTab, gPanel, gDebugger;
 var gFrames, gClassicFrames;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 1).then(performTest);
+    waitForCaretAndScopes(gPanel, 1).then(performTest);
     callInTab(gTab, "evalCall");
   });
 }
 
 function performTest() {
   is(gDebugger.gThreadClient.state, "paused",
     "Should only be getting stack frames while paused.");
   is(gFrames.itemCount, 2,
--- a/devtools/client/debugger/test/mochitest/browser_dbg_stack-05.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_stack-05.js
@@ -6,17 +6,21 @@
 /**
  * Test that switching between stack frames properly sets the current debugger
  * location in the source editor.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gEditor = gDebugger.DebuggerView.editor;
     const gSources = gDebugger.DebuggerView.Sources;
     const gFrames = gDebugger.DebuggerView.StackFrames;
     const gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
 
@@ -38,17 +42,17 @@ function test() {
          "The second source is selected in the widget.");
       ok(isCaretPos(gPanel, 6),
          "Editor caret location is correct.");
       is(gEditor.getDebugLocation(), 5,
          "Editor debug location is correct.");
     }
 
     function testOldestFrame() {
-      const shown = waitForSourceAndCaret(gPanel, "-01.js", 1).then(() => {
+      const shown = waitForSourceAndCaret(gPanel, "-01.js", 5).then(() => {
         is(gFrames.selectedIndex, 0,
            "Second frame should be selected after click.");
         is(gClassicFrames.selectedIndex, 1,
            "Second frame should be selected in the mirrored view as well.");
         is(gSources.selectedIndex, 0,
            "The first source is now selected in the widget.");
         ok(isCaretPos(gPanel, 5),
            "Editor caret location is correct (3).");
@@ -80,17 +84,17 @@ function test() {
       }, true);
 
       gDebugger.gThreadClient.resume();
 
       return deferred.promise;
     }
 
     Task.spawn(function* () {
-      yield waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1);
+      yield waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6);
       yield initialChecks();
       yield testNewestFrame();
       yield testOldestFrame();
       yield testAfterResume();
       closeDebuggerAndFinish(gPanel);
     });
 
     callInTab(gTab, "firstCall");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_stack-06.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_stack-06.js
@@ -9,17 +9,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gFrames, gClassicFrames;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_stack-07.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_stack-07.js
@@ -10,17 +10,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
 var gTab, gPanel, gDebugger;
 var gEditor, gSources, gFrames, gClassicFrames, gToolbar;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: "-01.js",
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
     gToolbar = gDebugger.DebuggerView.Toolbar;
--- a/devtools/client/debugger/test/mochitest/browser_dbg_stack-contextmenu-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_stack-contextmenu-01.js
@@ -7,17 +7,21 @@
  * Test that the copy contextmenu has been added to the stack frames view.
  */
 
  const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
  let gTab, gPanel, gDebugger;
  let gFrames, gContextMenu;
 
  function test() {
-   initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+   let options = {
+     source: TAB_URL,
+     line: 1
+   };
+   initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
      gTab = aTab;
      gPanel = aPanel;
      gDebugger = gPanel.panelWin;
      gFrames = gDebugger.DebuggerView.StackFrames;
 
      waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_REFILLED)
       .then(performTest);
      callInTab(gTab, "simpleCall");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_stack-contextmenu-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_stack-contextmenu-02.js
@@ -7,17 +7,21 @@
  * Test that the copy contextmenu copys the stack frames to the clipboard.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 const STACK_STRING = "simpleCall@" + EXAMPLE_URL + "doc_recursion-stack.html:14:8";
 
 function test() {
   let gTab, gPanel, gDebugger, gFrames;
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gFrames = gDebugger.DebuggerView.StackFrames;
 
     waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_REFILLED)
      .then(openContextMenu)
      .then(testCopyStackMenuItem)
--- a/devtools/client/debugger/test/mochitest/browser_dbg_step-out.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_step-out.js
@@ -8,28 +8,32 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_step-out.html";
 
 var gTab, gPanel, gDebugger;
 var gVars;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVars = gDebugger.DebuggerView.Variables;
 
     testNormalReturn();
   });
 }
 
 function testNormalReturn() {
-  waitForSourceAndCaretAndScopes(gPanel, ".html", 17).then(() => {
+  waitForCaretAndScopes(gPanel, 17).then(() => {
     waitForCaretAndScopes(gPanel, 20).then(() => {
       let innerScope = gVars.getScopeAtIndex(0);
       let returnVar = innerScope.get("<return>");
 
       is(returnVar.name, "<return>",
         "Should have the right property name for the returned value.");
       is(returnVar.value, 10,
         "Should have the right property value for the returned value.");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_terminate-on-tab-close.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_terminate-on-tab-close.js
@@ -9,17 +9,21 @@ thisTestLeaksUncaughtRejectionsAndShould
 
 /**
  * Tests that debuggee scripts are terminated on tab closure.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_terminate-on-tab-close.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
 
     gDebugger.gThreadClient.addOneTimeListener("paused", () => {
       resumeDebuggerThenCloseAndFinish(gPanel).then(function () {
         ok(true, "should not throw after this point");
       });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-01.js
@@ -6,17 +6,21 @@
 /**
  * Tests that creating, collpasing and expanding scopes in the
  * variables view works as expected.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let variables = aPanel.panelWin.DebuggerView.Variables;
     let testScope = variables.addScope("test");
 
     ok(testScope,
       "Should have created a scope.");
     ok(testScope.id.includes("test"),
       "The newly created scope should have the default id set.");
     is(testScope.name, "test",
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-02.js
@@ -6,17 +6,21 @@
 /**
  * Tests that creating, collapsing and expanding variables in the
  * variables view works as expected.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let variables = aPanel.panelWin.DebuggerView.Variables;
     let testScope = variables.addScope("test");
     let testVar = testScope.addItem("something");
     let duplVar = testScope.addItem("something");
 
     info("Scope id: " + testScope.id);
     info("Scope name: " + testScope.name);
     info("Variable id: " + testVar.id);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-03.js
@@ -6,17 +6,21 @@
 /**
  * Tests that recursively creating properties in the variables view works
  * as expected.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let variables = aPanel.panelWin.DebuggerView.Variables;
     let testScope = variables.addScope("test");
 
     is(testScope.target.querySelectorAll(".variables-view-element-details.enum").length, 1,
       "One enumerable container should be present in the scope.");
     is(testScope.target.querySelectorAll(".variables-view-element-details.nonenum").length, 1,
       "One non-enumerable container should be present in the scope.");
     is(testScope.target.querySelector(".variables-view-element-details.enum").childNodes.length, 0,
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-04.js
@@ -5,17 +5,21 @@
 
 /**
  * Tests that grips are correctly applied to variables.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let variables = aPanel.panelWin.DebuggerView.Variables;
     let testScope = variables.addScope("test");
     let testVar = testScope.addItem("something");
 
     testVar.setGrip(1.618);
 
     is(testVar.target.querySelector(".value").getAttribute("value"), "1.618",
       "The grip information for the variable wasn't set correctly (1).");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-05.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-05.js
@@ -5,17 +5,21 @@
 
 /**
  * Tests that grips are correctly applied to variables and properties.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     let variables = aPanel.panelWin.DebuggerView.Variables;
 
     let globalScope = variables.addScope("Test-Global");
     let localScope = variables.addScope("Test-Local");
 
     ok(globalScope, "The globalScope hasn't been created correctly.");
     ok(localScope, "The localScope hasn't been created correctly.");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-06.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-06.js
@@ -5,18 +5,21 @@
 
 /**
  * Test that Promises get their internal state added as psuedo properties.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_promise.html";
 
 var test = Task.async(function* () {
-  const [tab,, panel] = yield initDebugger(TAB_URL);
-  yield ensureSourceIs(panel, "doc_promise.html", true);
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  const [tab,, panel] = yield initDebugger(TAB_URL, options);
 
   const scopes = waitForCaretAndScopes(panel, 21);
   callInTab(tab, "doPause");
   yield scopes;
 
   const variables = panel.panelWin.DebuggerView.Variables;
   ok(variables, "Should get the variables view.");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-accessibility.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-accessibility.js
@@ -6,17 +6,17 @@
 /**
  * Make sure that the variables view is keyboard accessible.
  */
 
 var gTab, gPanel, gDebugger;
 var gVariablesView;
 
 function test() {
-  initDebugger("about:blank").then(([aTab,, aPanel]) => {
+  initDebugger().then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariablesView = gDebugger.DebuggerView.Variables;
 
     performTest().then(null, aError => {
       ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
     });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-data.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-data.js
@@ -7,17 +7,17 @@
  * Make sure that the variables view correctly populates itself
  * when given some raw data.
  */
 
 var gTab, gPanel, gDebugger;
 var gVariablesView, gScope, gVariable;
 
 function test() {
-  initDebugger("about:blank").then(([aTab,, aPanel]) => {
+  initDebugger().then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariablesView = gDebugger.DebuggerView.Variables;
 
     performTest();
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-cancel.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-cancel.js
@@ -7,17 +7,21 @@
  * Make sure that canceling a name change correctly unhides the separator and
  * value elements.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_watch-expressions.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let vars = win.DebuggerView.Variables;
 
     win.DebuggerView.WatchExpressions.addExpression("this");
 
     callInTab(tab, "ermahgerd");
     yield waitForDebuggerEvents(panel, win.EVENTS.FETCHED_WATCH_EXPRESSIONS);
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-click.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-click.js
@@ -7,17 +7,21 @@
  * Check that the editing state of a Variable is correctly tracked. Clicking on
  * the textbox while editing should not cancel editing.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_watch-expressions.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab, debuggee, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab, debuggee, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let vars = win.DebuggerView.Variables;
 
     win.DebuggerView.WatchExpressions.addExpression("this");
 
     // Allow this generator function to yield first.
     executeSoon(() => debuggee.ermahgerd());
     yield waitForDebuggerEvents(panel, win.EVENTS.FETCHED_WATCH_EXPRESSIONS);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-getset-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-getset-01.js
@@ -11,29 +11,33 @@ const TAB_URL = EXAMPLE_URL + "doc_frame
 
 var gTab, gPanel, gDebugger;
 var gL10N, gEditor, gVars, gWatch;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gL10N = gDebugger.L10N;
     gEditor = gDebugger.DebuggerView.editor;
     gVars = gDebugger.DebuggerView.Variables;
     gWatch = gDebugger.DebuggerView.WatchExpressions;
 
     gVars.switch = function () {};
     gVars.delete = function () {};
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 24)
+    waitForCaretAndScopes(gPanel, 24)
       .then(() => addWatchExpressions())
       .then(() => testEdit("set", "this._prop = value + ' BEER CAN'", {
         "myVar.prop": "xlerb BEER CAN",
         "myVar.prop + 42": "xlerb BEER CAN42",
         "myVar.prop = 'xlerb'": "xlerb"
       }))
       .then(() => testEdit("set", "{ this._prop = value + ' BEACON' }", {
         "myVar.prop": "xlerb BEACON",
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-getset-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-getset-02.js
@@ -12,29 +12,33 @@ const TAB_URL = EXAMPLE_URL + "doc_frame
 
 var gTab, gPanel, gDebugger;
 var gL10N, gEditor, gVars, gWatch;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gL10N = gDebugger.L10N;
     gEditor = gDebugger.DebuggerView.editor;
     gVars = gDebugger.DebuggerView.Variables;
     gWatch = gDebugger.DebuggerView.WatchExpressions;
 
     gVars.switch = function () {};
     gVars.delete = function () {};
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 24)
+    waitForCaretAndScopes(gPanel, 24)
       .then(() => addWatchExpression())
       .then(() => testEdit("\"xlerb\"", "xlerb"))
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
     generateMouseClickInTab(gTab, "content.document.querySelector('button')");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-value.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-value.js
@@ -8,23 +8,27 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 var gTab, gPanel, gDebugger;
 var gVars;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVars = gDebugger.DebuggerView.Variables;
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 24)
+    waitForCaretAndScopes(gPanel, 24)
       .then(() => initialChecks())
       .then(() => testModification("a", "1"))
       .then(() => testModification("{ a: 1 }", "Object"))
       .then(() => testModification("[a]", "Array[1]"))
       .then(() => testModification("b", "Object"))
       .then(() => testModification("b.a", "1"))
       .then(() => testModification("c.a", "1"))
       .then(() => testModification("Infinity", "Infinity"))
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-watch.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-watch.js
@@ -8,26 +8,32 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_watch-expressions.html";
 
 var gTab, gPanel, gDebugger;
 var gL10N, gEditor, gVars, gWatch;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gL10N = gDebugger.L10N;
     gEditor = gDebugger.DebuggerView.editor;
     gVars = gDebugger.DebuggerView.Variables;
     gWatch = gDebugger.DebuggerView.WatchExpressions;
 
-    waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS)
+    promise.all([
+      waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS),
+      waitForCaretAndScopes(gPanel, 18)])
       .then(() => testInitialVariablesInScope())
       .then(() => testInitialExpressionsInScope())
       .then(() => testModification("document.title = 42", "document.title = 43", "43", "undefined"))
       .then(() => testIntegrity1())
       .then(() => testModification("aArg", "aArg = 44", "44", "44"))
       .then(() => testIntegrity2())
       .then(() => testModification("aArg = 44", "\ \t\r\ndocument.title\ \t\r\n", "\"43\"", "44"))
       .then(() => testIntegrity3())
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-01.js
@@ -11,30 +11,33 @@ const TAB_URL = EXAMPLE_URL + "doc_with-
 
 var gTab, gPanel, gDebugger;
 var gVariables, gSearchBox;
 
 function test() {
   // Debug test slaves are quite slow at this test.
   requestLongerTimeout(4);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
 
     gVariables._enableSearch();
     gSearchBox = gVariables._searchboxNode;
 
     // The first 'with' scope should be expanded by default, but the
     // variables haven't been fetched yet. This is how 'with' scopes work.
     promise.all([
-      waitForSourceAndCaret(gPanel, ".html", 22),
-      waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
+      waitForCaretAndScopes(gPanel, 22),
       waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_VARIABLES)
     ]).then(prepareVariablesAndProperties)
       .then(testVariablesAndPropertiesFiltering)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-02.js
@@ -11,30 +11,33 @@ const TAB_URL = EXAMPLE_URL + "doc_with-
 
 var gTab, gPanel, gDebugger;
 var gVariables, gSearchBox;
 
 function test() {
   // Debug test slaves are quite slow at this test.
   requestLongerTimeout(4);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
 
     gVariables._enableSearch();
     gSearchBox = gVariables._searchboxNode;
 
     // The first 'with' scope should be expanded by default, but the
     // variables haven't been fetched yet. This is how 'with' scopes work.
     promise.all([
-      waitForSourceAndCaret(gPanel, ".html", 22),
-      waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
+      waitForCaretAndScopes(gPanel, 22),
       waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_VARIABLES)
     ]).then(prepareVariablesAndProperties)
       .then(testVariablesAndPropertiesFiltering)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-03.js
@@ -12,28 +12,31 @@ const TAB_URL = EXAMPLE_URL + "doc_with-
 
 var gTab, gPanel, gDebugger;
 var gVariables, gSearchBox;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     // The first 'with' scope should be expanded by default, but the
     // variables haven't been fetched yet. This is how 'with' scopes work.
     promise.all([
-      waitForSourceAndCaret(gPanel, ".html", 22),
-      waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
+      waitForCaretAndScopes(gPanel, 22),
       waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_VARIABLES)
     ]).then(prepareVariablesAndProperties)
       .then(testVariablesAndPropertiesFiltering)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-04.js
@@ -12,29 +12,32 @@ const TAB_URL = EXAMPLE_URL + "doc_with-
 
 var gTab, gPanel, gDebugger;
 var gEditor, gVariables, gSearchBox;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gVariables = gDebugger.DebuggerView.Variables;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     // The first 'with' scope should be expanded by default, but the
     // variables haven't been fetched yet. This is how 'with' scopes work.
     promise.all([
-      waitForSourceAndCaret(gPanel, ".html", 22),
-      waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
+      waitForCaretAndScopes(gPanel, 22),
       waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_VARIABLES)
     ]).then(prepareVariablesAndProperties)
       .then(testVariablesAndPropertiesFiltering)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-05.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-05.js
@@ -12,28 +12,31 @@ const TAB_URL = EXAMPLE_URL + "doc_with-
 
 var gTab, gPanel, gDebugger;
 var gVariables, gSearchBox;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     // The first 'with' scope should be expanded by default, but the
     // variables haven't been fetched yet. This is how 'with' scopes work.
     promise.all([
-      waitForSourceAndCaret(gPanel, ".html", 22),
-      waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
+      waitForCaretAndScopes(gPanel, 22),
       waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_VARIABLES)
     ]).then(prepareVariablesAndProperties)
       .then(testVariablesAndPropertiesFiltering)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-pref.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-pref.js
@@ -8,25 +8,29 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
 
 var gTab, gPanel, gDebugger;
 var gPrefs, gOptions, gVariables;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gPrefs = gDebugger.Prefs;
     gOptions = gDebugger.DebuggerView.Options;
     gVariables = gDebugger.DebuggerView.Variables;
 
-    waitForSourceShown(gPanel, ".html").then(performTest);
+    performTest();
   });
 }
 
 function performTest() {
   ok(!gVariables._searchboxNode,
     "There should not initially be a searchbox available in the variables view.");
   ok(!gVariables._searchboxContainer,
     "There should not initially be a searchbox container available in the variables view.");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-searchbox.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-searchbox.js
@@ -9,23 +9,27 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
 
 var gTab, gPanel, gDebugger;
 var gVariables;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
 
-    waitForSourceShown(gPanel, ".html").then(performTest);
+    performTest();
   });
 }
 
 function performTest() {
   // Step 1: the searchbox shouldn't initially be shown.
 
   ok(!gVariables._searchboxNode,
     "There should not initially be a searchbox available in the variables view.");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-01.js
@@ -12,23 +12,27 @@ const TAB_URL = EXAMPLE_URL + "doc_frame
 
 var gTab, gPanel, gDebugger;
 var gVariables;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 24)
+    waitForCaretAndScopes(gPanel, 24)
       .then(initialChecks)
       .then(testExpandVariables)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
     generateMouseClickInTab(gTab, "content.document.querySelector('button')");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-02.js
@@ -12,23 +12,27 @@ const TAB_URL = EXAMPLE_URL + "doc_frame
 
 var gTab, gPanel, gDebugger;
 var gVariables;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 24)
+    waitForCaretAndScopes(gPanel, 24)
       .then(testScopeVariables)
       .then(testArgumentsProperties)
       .then(testSimpleObject)
       .then(testComplexObject)
       .then(testArgumentObject)
       .then(testInnerArgumentObject)
       .then(testGetterSetterObject)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-03.js
@@ -12,23 +12,27 @@ const TAB_URL = EXAMPLE_URL + "doc_frame
 
 var gTab, gPanel, gDebugger;
 var gVariables;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 24)
+    waitForCaretAndScopes(gPanel, 24)
       .then(expandGlobalScope)
       .then(testGlobalScope)
       .then(expandWindowVariable)
       .then(testWindowVariable)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-with.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-with.js
@@ -8,27 +8,30 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
 
 var gTab, gPanel, gDebugger;
 var gVariables;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
 
     // The first 'with' scope should be expanded by default, but the
     // variables haven't been fetched yet. This is how 'with' scopes work.
     promise.all([
-      waitForSourceAndCaret(gPanel, ".html", 22),
-      waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
+      waitForCaretAndScopes(gPanel, 22),
       waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_VARIABLES)
     ]).then(testFirstWithScope)
       .then(expandSecondWithScope)
       .then(testSecondWithScope)
       .then(expandFunctionScope)
       .then(testFunctionScope)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frozen-sealed-nonext.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frozen-sealed-nonext.js
@@ -8,17 +8,21 @@
  * attributes on variables so that the F/S/N is shown in the variables view.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 var gTab, gPanel, gDebugger;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
 
     prepareTest();
   });
 }
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-hide-non-enums.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-hide-non-enums.js
@@ -8,22 +8,26 @@
  * in the variables view.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 var gTab, gPanel, gDebugger;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 14).then(performTest);
+    waitForCaretAndScopes(gPanel, 14).then(performTest);
     callInTab(gTab, "simpleCall");
   });
 }
 
 function performTest() {
   let testScope = gDebugger.DebuggerView.Variables.addScope("test-scope");
   let testVar = testScope.addItem("foo");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-large-array-buffer.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-large-array-buffer.js
@@ -14,24 +14,28 @@ const TAB_URL = EXAMPLE_URL + "doc_large
 
 var gTab, gPanel, gDebugger;
 var gVariables, gEllipsis;
 
 function test() {
   // this test does a lot of work on large objects, default 45s is not enough
   requestLongerTimeout(4);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
     gEllipsis = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 28)
+    waitForCaretAndScopes(gPanel, 28, 1)
       .then(() => performTests())
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, error => {
         ok(false, "Got an error: " + error.message + "\n" + error.stack);
       });
 
     generateMouseClickInTab(gTab, "content.document.querySelector('button')");
   });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-map-set.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-map-set.js
@@ -7,18 +7,21 @@
  * Test that Map and Set and their Weak friends are displayed in variables view.
  */
 
 "use strict";
 
 const TAB_URL = EXAMPLE_URL + "doc_map-set.html";
 
 var test = Task.async(function* () {
-  const [tab,, panel] = yield initDebugger(TAB_URL);
-  yield ensureSourceIs(panel, "doc_map-set.html", true);
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  const [tab,, panel] = yield initDebugger(TAB_URL, options);
 
   const scopes = waitForCaretAndScopes(panel, 37);
   callInTab(tab, "startTest");
   yield scopes;
 
   const variables = panel.panelWin.DebuggerView.Variables;
   ok(variables, "Should get the variables view.");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-01.js
@@ -5,23 +5,27 @@
  * Tests that VariablesView methods responsible for styling variables
  * as overridden work properly.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_scope-variable-2.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let events = win.EVENTS;
     let variables = win.DebuggerView.Variables;
 
     callInTab(tab, "test");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 23);
+    yield waitForCaretAndScopes(panel, 23);
 
     let firstScope = variables.getScopeAtIndex(0);
     let secondScope = variables.getScopeAtIndex(1);
     let thirdScope = variables.getScopeAtIndex(2);
     let globalLexicalScope = variables.getScopeAtIndex(3);
     let globalScope = variables.getScopeAtIndex(4);
 
     ok(firstScope, "The first scope is available.");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-02.js
@@ -6,27 +6,33 @@
 /**
  * Tests that overridden variables in the VariablesView are styled properly.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_scope-variable-2.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let events = win.EVENTS;
     let variables = win.DebuggerView.Variables;
 
     // Wait for the hierarchy to be committed by the VariablesViewController.
     let committedLocalScopeHierarchy = promise.defer();
     variables.oncommit = committedLocalScopeHierarchy.resolve;
 
+
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 23);
     callInTab(tab, "test");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 23);
+    yield onCaretAndScopes;
     yield committedLocalScopeHierarchy.promise;
 
     let firstScope = variables.getScopeAtIndex(0);
     let secondScope = variables.getScopeAtIndex(1);
     let thirdScope = variables.getScopeAtIndex(2);
 
     let someVar1 = firstScope.get("a");
     let argsVar1 = firstScope.get("arguments");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-01.js
@@ -7,17 +7,21 @@
  * Tests opening the variable inspection popup on a variable which has a
  * simple literal as the value.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
     bubble._ignoreLiterals = false;
 
     function verifyContents(textContent, className) {
       is(tooltip.querySelectorAll(".variables-view-container").length, 0,
@@ -26,18 +30,20 @@ function test() {
         "There should be a simple text node added to the tooltip instead.");
 
       is(tooltip.querySelector(".devtools-tooltip-simple-text").textContent, textContent,
         "The inspected property's value is correct.");
       ok(tooltip.querySelector(".devtools-tooltip-simple-text").className.includes(className),
         "The inspected property's value is colorized correctly.");
     }
 
+
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 24);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
+    yield onCaretAndScopes;
 
     // Inspect variables.
     yield openVarPopup(panel, { line: 15, ch: 12 });
     verifyContents("1", "token-number");
 
     yield reopenVarPopup(panel, { line: 16, ch: 21 });
     verifyContents("1", "token-number");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-02.js
@@ -7,35 +7,41 @@
  * Tests opening the variable inspection popup on a variable which has a
  * a property accessible via getters and setters.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
     function verifyContents(textContent, className) {
       is(tooltip.querySelectorAll(".variables-view-container").length, 0,
         "There should be no variables view containers added to the tooltip.");
       is(tooltip.querySelectorAll(".devtools-tooltip-simple-text").length, 1,
         "There should be a simple text node added to the tooltip instead.");
 
       is(tooltip.querySelector(".devtools-tooltip-simple-text").textContent, textContent,
         "The inspected property's value is correct.");
       ok(tooltip.querySelector(".devtools-tooltip-simple-text").className.includes(className),
         "The inspected property's value is colorized correctly.");
     }
 
+
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 24);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
+    yield onCaretAndScopes;
 
     // Inspect properties.
     yield openVarPopup(panel, { line: 19, ch: 10 });
     verifyContents("42", "token-number");
 
     yield reopenVarPopup(panel, { line: 20, ch: 14 });
     verifyContents("42", "token-number");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-03.js
@@ -6,22 +6,27 @@
 /**
  * Tests that the inspected indentifier is highlighted.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 24);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
+    yield onCaretAndScopes;
 
     // Inspect variable.
     yield openVarPopup(panel, { line: 15, ch: 12 });
 
     ok(bubble.contentsShown(),
       "The variable should register as being shown.");
     ok(!bubble._tooltip.isEmpty(),
       "The variable inspection popup isn't empty.");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-04.js
@@ -6,22 +6,27 @@
 /**
  * Tests that the variable inspection popup is hidden when the editor scrolls.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 24);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
+    yield onCaretAndScopes;
 
     // Inspect variable.
     yield openVarPopup(panel, { line: 15, ch: 12 });
     yield hideVarPopupByScrollingEditor(panel);
     ok(true, "The variable inspection popup was hidden.");
 
     ok(bubble._tooltip.isEmpty(),
       "The variable inspection popup is now empty.");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-05.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-05.js
@@ -7,17 +7,21 @@
  * Tests opening the variable inspection popup on a variable which has a
  * simple object as the value.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
     function verifyContents() {
       is(tooltip.querySelectorAll(".variables-view-container").length, 1,
         "There should be one variables view container added to the tooltip.");
 
@@ -35,18 +39,19 @@ function test() {
         "The first property's value is correct.");
 
       is(tooltip.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"), "__proto__",
         "The second property's name is correct.");
       is(tooltip.querySelectorAll(".variables-view-property .value")[1].getAttribute("value"), "Object",
         "The second property's value is correct.");
     }
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 24);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
+    yield onCaretAndScopes;
 
     // Inspect variable.
     yield openVarPopup(panel, { line: 16, ch: 12 }, true);
     verifyContents();
 
     yield resumeDebuggerThenCloseAndFinish(panel);
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-06.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-06.js
@@ -8,17 +8,21 @@
  * complext object as the value.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 function test() {
   requestLongerTimeout(2);
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
     function verifyContents() {
       is(tooltip.querySelectorAll(".variables-view-container").length, 1,
         "There should be one variables view container added to the tooltip.");
 
@@ -61,18 +65,19 @@ function test() {
         "The sixth property's value is correct.");
 
       is(tooltip.querySelectorAll(".variables-view-property .name")[6].getAttribute("value"), "__proto__",
         "The seventh property's name is correct.");
       is(tooltip.querySelectorAll(".variables-view-property .value")[6].getAttribute("value"), "Object",
         "The seventh property's value is correct.");
     }
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 24);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
+    yield onCaretAndScopes;
 
     // Inspect variable.
     yield openVarPopup(panel, { line: 17, ch: 12 }, true);
     verifyContents();
 
     yield resumeDebuggerThenCloseAndFinish(panel);
   });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-07.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-07.js
@@ -7,17 +7,21 @@
  * Tests the variable inspection popup behaves correctly when switching
  * between simple and complex objects.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
     function verifySimpleContents(textContent, className) {
       is(tooltip.querySelectorAll(".variables-view-container").length, 0,
         "There should be no variables view container added to the tooltip.");
       is(tooltip.querySelectorAll(".devtools-tooltip-simple-text").length, 1,
@@ -39,18 +43,19 @@ function test() {
         "There should be one scope with no header displayed.");
       is(tooltip.querySelectorAll(".variables-view-variable[untitled]").length, 1,
         "There should be one variable with no header displayed.");
 
       ok(tooltip.querySelectorAll(".variables-view-property").length >= propertyCount,
         "There should be some properties displayed.");
     }
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 24);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
+    yield onCaretAndScopes;
 
     // Inspect variables.
     yield openVarPopup(panel, { line: 15, ch: 12 });
     verifySimpleContents("1", "token-number");
 
     yield reopenVarPopup(panel, { line: 16, ch: 12 }, true);
     verifyComplexContents(2);
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-08.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-08.js
@@ -6,17 +6,21 @@
 /**
  * Tests opening inspecting variables works across scopes.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_scope-variable.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let events = win.EVENTS;
     let editor = win.DebuggerView.editor;
     let frames = win.DebuggerView.StackFrames;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
     function verifyContents(textContent, className) {
@@ -37,18 +41,20 @@ function test() {
       is(frames.itemCount, 2,
         "Should have two frames.");
       is(frames.selectedDepth, selectedFrame,
         "The correct frame is selected in the widget.");
       ok(isCaretPos(panel, caretLine),
         "Editor caret location is correct.");
     }
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 20);
     callInTab(tab, "test");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 20);
+    yield onCaretAndScopes;
+
     checkView(0, 20);
 
     // Inspect variable in topmost frame.
     yield openVarPopup(panel, { line: 18, ch: 12 });
     verifyContents("\"second scope\"", "token-string");
     checkView(0, 20);
 
     // Hide the popup and change the frame.
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-09.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-09.js
@@ -6,23 +6,28 @@
 /**
  * Tests opening inspecting variables works across scopes.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_scope-variable-3.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 15);
     callInTab(tab, "test");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 15);
+    yield onCaretAndScopes;
 
     yield openVarPopup(panel, { line: 12, ch: 10 });
     ok(true, "The variable inspection popup was shown for the real variable.");
 
     once(tooltip, "popupshown").then(() => {
       ok(false, "The variable inspection popup shouldn't have been opened.");
     });
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-10.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-10.js
@@ -8,27 +8,32 @@
  * a variable inspection popup is opened and a watch expression is
  * also evaluated at the same time.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let events = win.EVENTS;
     let editor = win.DebuggerView.editor;
     let editorContainer = win.document.getElementById("editor");
     let bubble = win.DebuggerView.VariableBubble;
     let expressions = win.DebuggerView.WatchExpressions;
     let tooltip = bubble._tooltip.panel;
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 24);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
+    yield onCaretAndScopes;
 
     let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     expressions.addExpression("this");
     editor.focus();
     yield expressionsEvaluated;
 
     // Scroll to the top of the editor and inspect variables.
     let breakpointScrollPosition = editor.getScrollInfo().top;
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-11.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-11.js
@@ -6,17 +6,21 @@
 /**
  * Tests that the watch expression button is added in variable view popup.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_watch-expression-button.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let events = win.EVENTS;
     let watch = win.DebuggerView.WatchExpressions;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
     let label = win.L10N.getStr("addWatchExpressionButton");
     let className = "dbg-expression-button";
@@ -34,18 +38,19 @@ function test() {
       ok(!tooltip.querySelector("button"),
         "There should be no button available in variable view popup.");
       ok(watch.getItemAtIndex(0),
         "The expression at index 0 should be available.");
       is(watch.getItemAtIndex(0).attachment.initialExpression, aExpression,
         "The expression at index 0 is correct.");
     }
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 19);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 19);
+    yield onCaretAndScopes;
 
     // Inspect primitive value variable.
     yield openVarPopup(panel, { line: 15, ch: 12 });
     let popupHiding = once(tooltip, "popuphiding");
     let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     testExpressionButton(label, className, "a");
     yield promise.all([popupHiding, expressionsEvaluated]);
     ok(true, "The new watch expressions were re-evaluated and the panel got hidden (1).");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-12.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-12.js
@@ -7,35 +7,40 @@
  * Tests that the clicking "Watch" button twice, for the same expression, only adds it
  * once.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_watch-expression-button.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let events = win.EVENTS;
     let watch = win.DebuggerView.WatchExpressions;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
     function verifyContent(aExpression, aItemCount) {
 
       ok(watch.getItemAtIndex(0),
         "The expression at index 0 should be available.");
       is(watch.getItemAtIndex(0).attachment.initialExpression, aExpression,
         "The expression at index 0 is correct.");
       is(watch.itemCount, aItemCount,
         "The expression count is correct.");
     }
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 19);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 19);
+    yield onCaretAndScopes;
 
     // Inspect primitive value variable.
     yield openVarPopup(panel, { line: 15, ch: 12 });
     let popupHiding = once(tooltip, "popuphiding");
     let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     tooltip.querySelector("button").click();
     verifyContent("a", 1);
     yield promise.all([popupHiding, expressionsEvaluated]);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-13.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-13.js
@@ -7,17 +7,21 @@
  * Tests that the variable inspection popup has inspector links for DOMNode
  * properties and that the popup closes when the link is clicked
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_domnode-variables.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
     let toolbox = gDevTools.getToolbox(panel.target);
 
     function getDomNodeInTooltip(propertyName) {
       let domNodeProperties = tooltip.querySelectorAll(".token-domnode");
       for (let prop of domNodeProperties) {
@@ -25,18 +29,19 @@ function test() {
         if (propName.getAttribute("value") === propertyName) {
           ok(true, "DOMNode " + propertyName + " was found in the tooltip");
           return prop;
         }
       }
       ok(false, "DOMNode " + propertyName + " wasn't found in the tooltip");
     }
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 19);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 19);
+    yield onCaretAndScopes;
 
     // Inspect the div DOM variable.
     yield openVarPopup(panel, { line: 17, ch: 38 }, true);
     let property = getDomNodeInTooltip("firstElementChild");
 
     // Simulate mouseover on the property value
     let highlighted = once(toolbox, "node-highlight");
     EventUtils.sendMouseEvent({ type: "mouseover" }, property,
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-14.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-14.js
@@ -7,22 +7,27 @@
  * Tests that the variable inspection popup is hidden when
  * selecting text in the editor.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 24);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
+    yield onCaretAndScopes;
 
     // Select some text.
     let cursor = win.DebuggerView.editor.getOffset({ line: 15, ch: 12 });
     let [ anchor, head ] = win.DebuggerView.editor.getPosition(
       cursor,
       cursor + 3
     );
     win.DebuggerView.editor.setSelection(anchor, head);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-15.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-15.js
@@ -6,23 +6,28 @@
 /**
  * Tests opening the variable inspection popup directly on literals.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 24);
     callInTab(tab, "start");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
+    yield onCaretAndScopes;
 
     yield openVarPopup(panel, { line: 15, ch: 12 });
     ok(true, "The variable inspection popup was shown for the real variable.");
 
     once(tooltip, "popupshown").then(() => {
       ok(false, "The variable inspection popup shouldn't have been opened.");
     });
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-16.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-16.js
@@ -9,17 +9,21 @@ requestLongerTimeout(2);
  * Tests if opening the variables inspection popup preserves the highlighting
  * associated with the currently debugged line.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 function test() {
   Task.spawn(function* () {
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let win = panel.panelWin;
     let events = win.EVENTS;
     let editor = win.DebuggerView.editor;
     let frames = win.DebuggerView.StackFrames;
     let variables = win.DebuggerView.Variables;
     let bubble = win.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
 
@@ -50,18 +54,20 @@ function test() {
       is(globalScope.expanded, false,
         "The globalScope should not be expanded yet.");
 
       let finished = waitForDebuggerEvents(panel, events.FETCHED_VARIABLES);
       globalScope.expand();
       return finished;
     }
 
+    let onCaretAndScopes = waitForCaretAndScopes(panel, 26);
     callInTab(tab, "recurse");
-    yield waitForSourceAndCaretAndScopes(panel, ".html", 26);
+    yield onCaretAndScopes;
+
     yield checkView(0, 26);
 
     yield expandGlobalScope();
     yield checkView(0, 26);
 
     // Inspect variable in topmost frame.
     yield openVarPopup(panel, { line: 26, ch: 11 });
     yield checkView(0, 26);
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-17.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-17.js
@@ -7,17 +7,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
 
 let gTab, gPanel, gDebugger;
 let actions, gSources, gVariables;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     actions = bindActionCreators(gPanel);
     gSources = gDebugger.DebuggerView.Sources;
     gVariables = gDebugger.DebuggerView.Variables;
     let bubble = gDebugger.DebuggerView.VariableBubble;
     let tooltip = bubble._tooltip.panel;
@@ -33,17 +37,17 @@ function test() {
       executeSoon(() => EventUtils.synthesizeKey("VK_F11", {}));
       // The keypress should cause one resumed event and one paused event
       yield waitForThreadEvents(gPanel, "resumed");
       yield waitForThreadEvents(gPanel, "paused");
       // Here's the state we're actually interested in checking..
       checkVariablePopupClosed(bubble);
       yield resumeDebuggerThenCloseAndFinish(gPanel);
     });
-    waitForSourceShown(gPanel, ".html").then(testPopupHiding);
+    testPopupHiding();
   });
 }
 
 function addBreakpoint() {
   return actions.addBreakpoint({ actor: gSources.selectedValue, line: 21 });
 }
 
 function pauseDebuggee() {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-01.js
@@ -8,17 +8,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(4);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const gVariables = gDebugger.DebuggerView.Variables;
     const queries = gDebugger.require("./content/queries");
     const getState = gDebugger.DebuggerController.getState;
     const actions = bindActionCreators(gPanel);
@@ -190,17 +194,16 @@ function test() {
       functionScope.expand();
       globalLexicalScope.expand();
       globalScope.expand();
 
       return deferred.promise;
     }
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, ".html");
       yield addBreakpoint();
       yield ensureThreadClientState(gPanel, "resumed");
       yield pauseDebuggee();
       yield prepareVariablesAndProperties();
       yield stepInDebuggee();
       yield testVariablesExpand();
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-02.js
@@ -9,17 +9,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(4);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const gVariables = gDebugger.DebuggerView.Variables;
     const queries = gDebugger.require("./content/queries");
     const getState = gDebugger.DebuggerController.getState;
     const actions = bindActionCreators(gPanel);
@@ -205,18 +209,16 @@ function test() {
       functionScope.expand();
       globalLexicalScope.expand();
       globalScope.expand();
 
       return deferred.promise;
     }
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, ".html");
-
       yield addBreakpoint();
       yield ensureThreadClientState(gPanel, "resumed");
       yield pauseDebuggee();
       yield prepareVariablesAndProperties();
       yield stepInDebuggee();
       yield testVariablesExpand();
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-03.js
@@ -8,17 +8,21 @@
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_scope-variable-4.html";
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(4);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     const gTab = aTab;
     const gPanel = aPanel;
     const gDebugger = gPanel.panelWin;
     const gSources = gDebugger.DebuggerView.Sources;
     const gVariables = gDebugger.DebuggerView.Variables;
     const queries = gDebugger.require("./content/queries");
     const getState = gDebugger.DebuggerController.getState;
     const actions = bindActionCreators(gPanel);
@@ -99,17 +103,16 @@ function test() {
          "The localScope should not be expanded anymore.");
       is(functionScope.expanded, true,
          "The functionScope should now be expanded.");
       is(globalScope.expanded, false,
          "The globalScope should still not be expanded.");
     }
 
     Task.spawn(function* () {
-      yield waitForSourceShown(gPanel, ".html");
       yield addBreakpoint();
       yield ensureThreadClientState(gPanel, "resumed");
       yield pauseDebuggee();
       yield prepareScopes();
       yield resumeDebuggee();
       yield testVariablesExpand();
       resumeDebuggerThenCloseAndFinish(gPanel);
     });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-webidl.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-webidl.js
@@ -12,23 +12,27 @@ const TAB_URL = EXAMPLE_URL + "doc_frame
 
 var gTab, gPanel, gDebugger;
 var gVariables;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
 
-    waitForSourceAndCaretAndScopes(gPanel, ".html", 24)
+    waitForCaretAndScopes(gPanel, 24)
       .then(expandGlobalScope)
       .then(performTest)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
     generateMouseClickInTab(gTab, "content.document.querySelector('button')");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_watch-expressions-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_watch-expressions-01.js
@@ -11,32 +11,32 @@ const TAB_URL = EXAMPLE_URL + "doc_watch
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
   let gTab, gPanel, gDebugger;
   let gEditor, gWatch, gVariables;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gWatch = gDebugger.DebuggerView.WatchExpressions;
     gVariables = gDebugger.DebuggerView.Variables;
 
     gDebugger.DebuggerView.toggleInstrumentsPane({ visible: true, animated: false });
 
-    waitForSourceShown(gPanel, ".html")
-      .then(() => performTest())
-      .then(() => closeDebuggerAndFinish(gPanel))
-      .then(null, aError => {
-        ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
-      });
+    performTest();
+    closeDebuggerAndFinish(gPanel);
   });
 
   function performTest() {
     is(gWatch.getAllStrings().length, 0,
       "There should initially be no watch expressions.");
 
     addAndCheckExpressions(1, 0, "a");
     addAndCheckExpressions(2, 0, "b");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_watch-expressions-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_watch-expressions-02.js
@@ -11,28 +11,31 @@ const TAB_URL = EXAMPLE_URL + "doc_watch
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(2);
 
   let gTab, gPanel, gDebugger;
   let gWatch, gVariables;
 
-  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gWatch = gDebugger.DebuggerView.WatchExpressions;
     gVariables = gDebugger.DebuggerView.Variables;
 
     gDebugger.DebuggerView.toggleInstrumentsPane({ visible: true, animated: false });
 
-    waitForSourceShown(gPanel, ".html", 1)
-      .then(addExpressions)
-      .then(performTest)
+    addExpressions();
+    performTest()
       .then(finishTest)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 
   function addExpressions() {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_worker-source-map.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_worker-source-map.js
@@ -17,17 +17,21 @@ function selectWorker(aPanel, aURL) {
   Workers.selectedItem = item;
   return promise;
 }
 
 function test() {
   return Task.spawn(function* () {
     yield pushPrefs(["devtools.debugger.workers", true]);
 
-    let [tab,, panel] = yield initDebugger(TAB_URL);
+    let options = {
+      source: TAB_URL,
+      line: 1
+    };
+    let [tab,, panel] = yield initDebugger(TAB_URL, options);
     let toolbox = yield selectWorker(panel, WORKER_URL);
     let workerPanel = toolbox.getCurrentPanel();
     yield waitForSourceShown(workerPanel, ".coffee");
     let panelWin = workerPanel.panelWin;
     let Sources = panelWin.DebuggerView.Sources;
     let editor = panelWin.DebuggerView.editor;
     let threadClient = panelWin.gThreadClient;
 
--- a/devtools/client/debugger/test/mochitest/head.js
+++ b/devtools/client/debugger/test/mochitest/head.js
@@ -97,16 +97,17 @@ this.removeTab = function removeTab(aTab
 
   let deferred = promise.defer();
   let targetWindow = aWindow || window;
   let targetBrowser = targetWindow.gBrowser;
   let tabContainer = targetBrowser.tabContainer;
 
   tabContainer.addEventListener("TabClose", function onClose(aEvent) {
     tabContainer.removeEventListener("TabClose", onClose, false);
+
     info("Tab removed and finished closing.");
     deferred.resolve();
   }, false);
 
   targetBrowser.removeTab(aTab);
   return deferred.promise;
 };
 
@@ -507,39 +508,87 @@ function getSources(aClient) {
 
   aClient.getSources((packet) => {
     deferred.resolve(packet.sources);
   });
 
   return deferred.promise;
 }
 
-function initDebugger(aTarget, aWindow) {
+/**
+ * Optionaly open a new tab and then open the debugger panel.
+ * The returned promise resolves only one the panel is fully set.
+
+ * @param {String|xul:tab} urlOrTab
+ *   If a string, consider it as the url of the tab to open before opening the
+ *   debugger panel.
+ *   Otherwise, if a <xul:tab>, do nothing, but open the debugger panel against
+ *   the given tab.
+ * @param {Object} options
+ *   Set of optional arguments:
+ *   - {String} source
+ *     If given, assert the default loaded source once the debugger is loaded.
+ *     This string can be partial to only match a part of the source name.
+ *     If null, do not expect any source and skip SOURCE_SHOWN wait.
+ *   - {Number} line
+ *     If given, wait for the caret to be set on a precise line
+ *
+ * @return {Promise}
+ *   Resolves once debugger panel is fully set according to the given options.
+ */
+let initDebugger = Task.async(function*(urlOrTab, options) {
+  let { window, source, line } = options || {};
   info("Initializing a debugger panel.");
 
-  return getTab(aTarget, aWindow).then(aTab => {
-    info("Debugee tab added successfully: " + aTarget);
+  let tab, url;
+  if (urlOrTab instanceof XULElement) {
+    // `urlOrTab` Is a Tab.
+    tab = urlOrTab;
+  } else {
+    // `urlOrTab` is an url. Open an empty tab first in order to load the page
+    // only once the panel is ready. That to be able to safely catch the
+    // SOURCE_SHOWN event.
+    tab = yield addTab("about:blank", window);
+    url = urlOrTab;
+  }
+  info("Debugee tab added successfully: " + urlOrTab);
 
-    let deferred = promise.defer();
-    let debuggee = aTab.linkedBrowser.contentWindow.wrappedJSObject;
-    let target = TargetFactory.forTab(aTab);
+  let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
+  let target = TargetFactory.forTab(tab);
 
-    gDevTools.showToolbox(target, "jsdebugger").then(aToolbox => {
-      info("Debugger panel shown successfully.");
+  let toolbox = yield gDevTools.showToolbox(target, "jsdebugger");
+  info("Debugger panel shown successfully.");
+
+  let debuggerPanel = toolbox.getCurrentPanel();
+  let panelWin = debuggerPanel.panelWin;
 
-      let debuggerPanel = aToolbox.getCurrentPanel();
-      let panelWin = debuggerPanel.panelWin;
+  prepareDebugger(debuggerPanel);
 
-      prepareDebugger(debuggerPanel);
-      deferred.resolve([aTab, debuggee, debuggerPanel, aWindow]);
-    });
+  if (url && url != "about:blank") {
+    let onCaretUpdated;
+    if (line) {
+      onCaretUpdated = waitForCaretUpdated(debuggerPanel, line);
+    }
+    if (source === null) {
+      // When there is no source in the document, we shouldn't wait for
+      // SOURCE_SHOWN event
+      yield reload(debuggerPanel, url);
+    } else {
+      yield navigateActiveTabTo(debuggerPanel,
+                                url,
+                                panelWin.EVENTS.SOURCE_SHOWN);
+    }
+    if (source) {
+      ensureSourceIs(debuggerPanel, source);
+    }
+    yield onCaretUpdated;
+  }
 
-    return deferred.promise;
-  });
-}
+  return [tab, debuggee, debuggerPanel, window];
+});
 
 // Creates an add-on debugger for a given add-on. The returned AddonDebugger
 // object must be destroyed before finishing the test
 function initAddonDebugger(aUrl) {
   let addonDebugger = new AddonDebugger();
   return addonDebugger.init(aUrl).then(() => addonDebugger);
 }
 
--- a/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_01.js
@@ -6,54 +6,69 @@
 
 // Tests that CSS property names are autocompleted and cycled correctly when
 // editing an existing property in the rule view.
 
 // format :
 //  [
 //    what key to press,
 //    expected input box value after keypress,
-//    selectedIndex of the popup,
-//    total items in the popup
+//    is the popup open,
+//    is a suggestion selected in the popup,
 //  ]
+
+const OPEN = true, SELECTED = true;
 var testData = [
-  ["VK_RIGHT", "font", -1, 0],
-  ["-", "font-size", 4, 17],
-  ["f", "font-family", 0, 2],
-  ["VK_BACK_SPACE", "font-f", -1, 0],
-  ["VK_BACK_SPACE", "font-", -1, 0],
-  ["VK_BACK_SPACE", "font", -1, 0],
-  ["VK_BACK_SPACE", "fon", -1, 0],
-  ["VK_BACK_SPACE", "fo", -1, 0],
-  ["VK_BACK_SPACE", "f", -1, 0],
-  ["VK_BACK_SPACE", "", -1, 0],
-  ["d", "display", 1, 3],
-  ["VK_DOWN", "dominant-baseline", 2, 3],
-  ["VK_DOWN", "direction", 0, 3],
-  ["VK_DOWN", "display", 1, 3],
-  ["VK_UP", "direction", 0, 3],
-  ["VK_UP", "dominant-baseline", 2, 3],
-  ["VK_UP", "display", 1, 3],
-  ["VK_BACK_SPACE", "d", -1, 0],
-  ["i", "display", 1, 2],
-  ["s", "display", -1, 0],
-  ["VK_BACK_SPACE", "dis", -1, 0],
-  ["VK_BACK_SPACE", "di", -1, 0],
-  ["VK_BACK_SPACE", "d", -1, 0],
-  ["VK_BACK_SPACE", "", -1, 0],
-  ["VK_HOME", "", -1, 0],
-  ["VK_END", "", -1, 0],
-  ["VK_PAGE_UP", "", -1, 0],
-  ["VK_PAGE_DOWN", "", -1, 0],
-  ["f", "font-size", 19, 32],
-  ["i", "filter", 3, 4],
-  ["VK_LEFT", "filter", -1, 0],
-  ["VK_LEFT", "filter", -1, 0],
-  ["i", "fiilter", -1, 0],
-  ["VK_ESCAPE", null, -1, 0],
+  ["VK_RIGHT", "font", !OPEN, !SELECTED],
+  ["-", "font-size", OPEN, SELECTED],
+  ["f", "font-family", OPEN, SELECTED],
+  ["VK_BACK_SPACE", "font-f", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "font-", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "font", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "fon", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "fo", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "f", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "", !OPEN, !SELECTED],
+  ["d", "display", OPEN, SELECTED],
+  ["VK_DOWN", "dominant-baseline", OPEN, SELECTED],
+  ["VK_DOWN", "direction", OPEN, SELECTED],
+  ["VK_DOWN", "display", OPEN, SELECTED],
+  ["VK_UP", "direction", OPEN, SELECTED],
+  ["VK_UP", "dominant-baseline", OPEN, SELECTED],
+  ["VK_UP", "display", OPEN, SELECTED],
+  ["VK_BACK_SPACE", "d", !OPEN, !SELECTED],
+  ["i", "display", OPEN, SELECTED],
+  ["s", "display", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "dis", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "di", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "d", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "", !OPEN, !SELECTED],
+  ["VK_HOME", "", !OPEN, !SELECTED],
+  ["VK_END", "", !OPEN, !SELECTED],
+  ["VK_PAGE_UP", "", !OPEN, !SELECTED],
+  ["VK_PAGE_DOWN", "", !OPEN, !SELECTED],
+  ["d", "display", OPEN, SELECTED],
+  ["VK_HOME", "display", !OPEN, !SELECTED],
+  ["VK_END", "display", !OPEN, !SELECTED],
+  // Press right key to ensure caret move to end of the input on Mac OS since
+  // Mac OS doesn't move caret after pressing HOME / END.
+  ["VK_RIGHT", "display", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "displa", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "displ", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "disp", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "dis", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "di", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "d", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "", !OPEN, !SELECTED],
+  ["f", "font-size", OPEN, SELECTED],
+  ["i", "filter", OPEN, SELECTED],
+  ["VK_LEFT", "filter", !OPEN, !SELECTED],
+  ["VK_LEFT", "filter", !OPEN, !SELECTED],
+  ["i", "fiilter", !OPEN, !SELECTED],
+  ["VK_ESCAPE", null, !OPEN, !SELECTED],
 ];
 
 const TEST_URI = "<h1 style='font: 24px serif'>Header</h1>";
 
 add_task(function* () {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {toolbox, inspector, view, testActor} = yield openRuleView();
 
@@ -78,20 +93,22 @@ function* runAutocompletionTest(toolbox,
   let previousPopupSize = 0;
   for (let i = 0; i < testData.length; i++) {
     let expectPopupHiddenEvent = previousPopupSize > 0 && testData[3] === 0;
     yield testCompletion(testData[i], expectPopupHiddenEvent, editor, view);
     previousPopupSize = testData[3];
   }
 }
 
-function* testCompletion([key, completion, index, total],
+function* testCompletion([key, completion, open, selected],
                          expectPopupHiddenEvent, editor, view) {
   info("Pressing key " + key);
-  info("Expecting " + completion + ", " + index + ", " + total);
+  info("Expecting " + completion);
+  info("Is popup opened: " + open);
+  info("Is item selected: " + selected);
 
   // Listening for the right event that will tell us when the key has been
   // entered and processed.
   let onSuggest;
   if (/(left|right|back_space|escape|home|end|page_up|page_down)/ig.test(key)) {
     info("Adding event listener for " +
       "left|right|back_space|escape|home|end|page_up|page_down keys");
     onSuggest = once(editor.input, "keypress");
@@ -110,17 +127,16 @@ function* testCompletion([key, completio
 
   yield onSuggest;
   yield onMaybePopupHidden;
 
   info("Checking the state");
   if (completion != null) {
     is(editor.input.value, completion, "Correct value is autocompleted");
   }
-  if (total == 0) {
+  if (!open) {
     ok(!(editor.popup && editor.popup.isOpen), "Popup is closed");
   } else {
     ok(editor.popup._panel.state == "open" ||
        editor.popup._panel.state == "showing", "Popup is open");
-    is(editor.popup.getItems().length, total, "Number of suggestions match");
-    is(editor.popup.selectedIndex, index, "Correct item is selected");
+    is(editor.popup.selectedIndex != -1, selected, "An item is selected");
   }
 }
--- a/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_02.js
@@ -7,37 +7,39 @@
 // Tests that CSS property names and values are autocompleted and cycled
 // correctly when editing existing properties in the rule view.
 
 // format :
 //  [
 //    what key to press,
 //    modifers,
 //    expected input box value after keypress,
-//    selectedIndex of the popup,
-//    total items in the popup,
-//    expect ruleview-changed
+//    is the popup open,
+//    is a suggestion selected in the popup,
+//    expect ruleview-changed,
 //  ]
+
+const OPEN = true, SELECTED = true, CHANGE = true;
 var testData = [
-  ["b", {}, "beige", 0, 8, true],
-  ["l", {}, "black", 0, 4, true],
-  ["VK_DOWN", {}, "blanchedalmond", 1, 4, true],
-  ["VK_DOWN", {}, "blue", 2, 4, true],
-  ["VK_RIGHT", {}, "blue", -1, 0, false],
-  [" ", {}, "blue aliceblue", 0, 158, true],
-  ["!", {}, "blue !important", 0, 0, true],
-  ["VK_BACK_SPACE", {}, "blue !", -1, 0, true],
-  ["VK_BACK_SPACE", {}, "blue ", -1, 0, true],
-  ["VK_BACK_SPACE", {}, "blue", -1, 0, true],
-  ["VK_TAB", {shiftKey: true}, "color", -1, 0, true],
-  ["VK_BACK_SPACE", {}, "", -1, 0, false],
-  ["d", {}, "display", 1, 3, false],
-  ["VK_TAB", {}, "blue", -1, 0, true],
-  ["n", {}, "none", -1, 0, true],
-  ["VK_RETURN", {}, null, -1, 0, true]
+  ["b", {}, "beige", OPEN, SELECTED, CHANGE],
+  ["l", {}, "black", OPEN, SELECTED, CHANGE],
+  ["VK_DOWN", {}, "blanchedalmond", OPEN, SELECTED, CHANGE],
+  ["VK_DOWN", {}, "blue", OPEN, SELECTED, CHANGE],
+  ["VK_RIGHT", {}, "blue", !OPEN, !SELECTED, !CHANGE],
+  [" ", {}, "blue aliceblue", OPEN, SELECTED, CHANGE],
+  ["!", {}, "blue !important", !OPEN, !SELECTED, CHANGE],
+  ["VK_BACK_SPACE", {}, "blue !", !OPEN, !SELECTED, CHANGE],
+  ["VK_BACK_SPACE", {}, "blue ", !OPEN, !SELECTED, CHANGE],
+  ["VK_BACK_SPACE", {}, "blue", !OPEN, !SELECTED, CHANGE],
+  ["VK_TAB", {shiftKey: true}, "color", !OPEN, !SELECTED, CHANGE],
+  ["VK_BACK_SPACE", {}, "", !OPEN, !SELECTED, !CHANGE],
+  ["d", {}, "display", OPEN, SELECTED, !CHANGE],
+  ["VK_TAB", {}, "blue", !OPEN, !SELECTED, CHANGE],
+  ["n", {}, "none", !OPEN, !SELECTED, CHANGE],
+  ["VK_RETURN", {}, null, !OPEN, !SELECTED, CHANGE]
 ];
 
 const TEST_URI = "<h1 style='color: red'>Header</h1>";
 
 add_task(function* () {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {toolbox, inspector, view, testActor} = yield openRuleView();
 
@@ -63,23 +65,25 @@ function* runAutocompletionTest(toolbox,
   for (let i = 0; i < testData.length; i++) {
     // Re-define the editor at each iteration, because the focus may have moved
     // from property to value and back
     editor = inplaceEditor(view.styleDocument.activeElement);
     yield testCompletion(testData[i], editor, view);
   }
 }
 
-function* testCompletion([key, modifiers, completion, index, total, willChange],
+function* testCompletion([key, modifiers, completion, open, selected, change],
                          editor, view) {
   info("Pressing key " + key);
-  info("Expecting " + completion + ", " + index + ", " + total);
+  info("Expecting " + completion);
+  info("Is popup opened: " + open);
+  info("Is item selected: " + selected);
 
   let onDone;
-  if (willChange) {
+  if (change) {
     // If the key triggers a ruleview-changed, wait for that event, it will
     // always be the last to be triggered and tells us when the preview has
     // been done.
     onDone = view.once("ruleview-changed");
   } else {
     // Otherwise, expect an after-suggest event (except if the popup gets
     // closed).
     onDone = key !== "VK_RIGHT" && key !== "VK_BACK_SPACE"
@@ -94,17 +98,17 @@ function* testCompletion([key, modifiers
   // The key might have been a TAB or shift-TAB, in which case the editor will
   // be a new one
   editor = inplaceEditor(view.styleDocument.activeElement);
 
   info("Checking the state");
   if (completion != null) {
     is(editor.input.value, completion, "Correct value is autocompleted");
   }
-  if (total == 0) {
+
+  if (!open) {
     ok(!(editor.popup && editor.popup.isOpen), "Popup is closed");
   } else {
     ok(editor.popup._panel.state == "open" ||
        editor.popup._panel.state == "showing", "Popup is open");
-    is(editor.popup.getItems().length, total, "Number of suggestions match");
-    is(editor.popup.selectedIndex, index, "Correct item is selected");
+    is(editor.popup.selectedIndex != -1, selected, "An item is selected");
   }
 }
--- a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_01.js
@@ -6,37 +6,38 @@
 
 // Tests that CSS property names are autocompleted and cycled correctly when
 // creating a new property in the rule view.
 
 // format :
 //  [
 //    what key to press,
 //    expected input box value after keypress,
-//    selectedIndex of the popup,
-//    total items in the popup
+//    is the popup open,
+//    is a suggestion selected in the popup,
 //  ]
+const OPEN = true, SELECTED = true;
 var testData = [
-  ["d", "display", 1, 3],
-  ["VK_DOWN", "dominant-baseline", 2, 3],
-  ["VK_DOWN", "direction", 0, 3],
-  ["VK_DOWN", "display", 1, 3],
-  ["VK_UP", "direction", 0, 3],
-  ["VK_UP", "dominant-baseline", 2, 3],
-  ["VK_UP", "display", 1, 3],
-  ["VK_BACK_SPACE", "d", -1, 0],
-  ["i", "display", 1, 2],
-  ["s", "display", -1, 0],
-  ["VK_BACK_SPACE", "dis", -1, 0],
-  ["VK_BACK_SPACE", "di", -1, 0],
-  ["VK_BACK_SPACE", "d", -1, 0],
-  ["VK_BACK_SPACE", "", -1, 0],
-  ["f", "font-size", 19, 32],
-  ["i", "filter", 3, 4],
-  ["VK_ESCAPE", null, -1, 0],
+  ["d", "display", OPEN, SELECTED],
+  ["VK_DOWN", "dominant-baseline", OPEN, SELECTED],
+  ["VK_DOWN", "direction", OPEN, SELECTED],
+  ["VK_DOWN", "display", OPEN, SELECTED],
+  ["VK_UP", "direction", OPEN, SELECTED],
+  ["VK_UP", "dominant-baseline", OPEN, SELECTED],
+  ["VK_UP", "display", OPEN, SELECTED],
+  ["VK_BACK_SPACE", "d", !OPEN, !SELECTED],
+  ["i", "display", OPEN, SELECTED],
+  ["s", "display", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "dis", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "di", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "d", !OPEN, !SELECTED],
+  ["VK_BACK_SPACE", "", !OPEN, !SELECTED],
+  ["f", "font-size", OPEN, SELECTED],
+  ["i", "filter", OPEN, SELECTED],
+  ["VK_ESCAPE", null, !OPEN, !SELECTED],
 ];
 
 const TEST_URI = "<h1 style='border: 1px solid red'>Header</h1>";
 
 add_task(function* () {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {toolbox, inspector, view, testActor} = yield openRuleView();
 
@@ -57,19 +58,21 @@ function* runAutocompletionTest(toolbox,
   let editor = yield focusNewRuleViewProperty(ruleEditor);
 
   info("Starting to test for css property completion");
   for (let i = 0; i < testData.length; i++) {
     yield testCompletion(testData[i], editor, view);
   }
 }
 
-function* testCompletion([key, completion, index, total], editor, view) {
+function* testCompletion([key, completion, isOpen, isSelected], editor, view) {
   info("Pressing key " + key);
-  info("Expecting " + completion + ", " + index + ", " + total);
+  info("Expecting " + completion);
+  info("Is popup opened: " + isOpen);
+  info("Is item selected: " + isSelected);
 
   let onSuggest;
 
   if (/(right|back_space|escape)/ig.test(key)) {
     info("Adding event listener for right|back_space|escape keys");
     onSuggest = once(editor.input, "keypress");
   } else {
     info("Waiting for after-suggest event on the editor");
@@ -81,17 +84,16 @@ function* testCompletion([key, completio
 
   yield onSuggest;
   yield waitForTick();
 
   info("Checking the state");
   if (completion != null) {
     is(editor.input.value, completion, "Correct value is autocompleted");
   }
-  if (total == 0) {
+  if (!isOpen) {
     ok(!(editor.popup && editor.popup.isOpen), "Popup is closed");
   } else {
     ok(editor.popup._panel.state == "open" ||
        editor.popup._panel.state == "showing", "Popup is open");
-    is(editor.popup.getItems().length, total, "Number of suggestions match");
-    is(editor.popup.selectedIndex, index, "Correct item is selected");
+    is(editor.popup.selectedIndex != -1, isSelected, "An item is selected");
   }
 }
--- a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js
@@ -7,41 +7,43 @@
 // Tests that CSS property names and values are autocompleted and cycled
 // correctly when editing new properties in the rule view.
 
 // format :
 //  [
 //    what key to press,
 //    modifers,
 //    expected input box value after keypress,
-//    selectedIndex of the popup,
-//    total items in the popup,
-//    expect ruleview-changed
+//    is the popup open,
+//    is a suggestion selected in the popup,
+//    expect ruleview-changed,
 //  ]
-var testData = [
-  ["d", {}, "display", 1, 3, false],
-  ["VK_TAB", {}, "", -1, 43, true],
-  ["VK_DOWN", {}, "block", 0, 43, true],
-  ["n", {}, "none", -1, 0, true],
-  ["VK_TAB", {shiftKey: true}, "display", -1, 0, true],
-  ["VK_BACK_SPACE", {}, "", -1, 0, false],
-  ["o", {}, "overflow", 13, 17, false],
-  ["u", {}, "outline", 0, 5, false],
-  ["VK_DOWN", {}, "outline-color", 1, 5, false],
-  ["VK_TAB", {}, "none", -1, 0, true],
-  ["r", {}, "rebeccapurple", 0, 6, true],
-  ["VK_DOWN", {}, "red", 1, 6, true],
-  ["VK_DOWN", {}, "rgb", 2, 6, true],
-  ["VK_DOWN", {}, "rgba", 3, 6, true],
-  ["VK_DOWN", {}, "rosybrown", 4, 6, true],
-  ["VK_DOWN", {}, "royalblue", 5, 6, true],
-  ["VK_RIGHT", {}, "royalblue", -1, 0, false],
-  [" ", {}, "royalblue aliceblue", 0, 159, true],
-  ["!", {}, "royalblue !important", 0, 0, true],
-  ["VK_ESCAPE", {}, null, -1, 0, true]
+
+const OPEN = true, SELECTED = true, CHANGE = true;
+const testData = [
+  ["d", {}, "display", OPEN, SELECTED, !CHANGE],
+  ["VK_TAB", {}, "", OPEN, !SELECTED, CHANGE],
+  ["VK_DOWN", {}, "block", OPEN, SELECTED, CHANGE],
+  ["n", {}, "none", !OPEN, !SELECTED, CHANGE],
+  ["VK_TAB", {shiftKey: true}, "display", !OPEN, !SELECTED, CHANGE],
+  ["VK_BACK_SPACE", {}, "", !OPEN, !SELECTED, !CHANGE],
+  ["o", {}, "overflow", OPEN, SELECTED, !CHANGE],
+  ["u", {}, "outline", OPEN, SELECTED, !CHANGE],
+  ["VK_DOWN", {}, "outline-color", OPEN, SELECTED, !CHANGE],
+  ["VK_TAB", {}, "none", !OPEN, !SELECTED, CHANGE],
+  ["r", {}, "rebeccapurple", OPEN, SELECTED, CHANGE],
+  ["VK_DOWN", {}, "red", OPEN, SELECTED, CHANGE],
+  ["VK_DOWN", {}, "rgb", OPEN, SELECTED, CHANGE],
+  ["VK_DOWN", {}, "rgba", OPEN, SELECTED, CHANGE],
+  ["VK_DOWN", {}, "rosybrown", OPEN, SELECTED, CHANGE],
+  ["VK_DOWN", {}, "royalblue", OPEN, SELECTED, CHANGE],
+  ["VK_RIGHT", {}, "royalblue", !OPEN, !SELECTED, !CHANGE],
+  [" ", {}, "royalblue aliceblue", OPEN, SELECTED, CHANGE],
+  ["!", {}, "royalblue !important", !OPEN, !SELECTED, CHANGE],
+  ["VK_ESCAPE", {}, null, !OPEN, !SELECTED, CHANGE]
 ];
 
 const TEST_URI = `
   <style type="text/css">
     h1 {
       border: 1px solid red;
     }
   </style>
@@ -72,23 +74,25 @@ function* runAutocompletionTest(toolbox,
   for (let i = 0; i < testData.length; i++) {
     // Re-define the editor at each iteration, because the focus may have moved
     // from property to value and back
     editor = inplaceEditor(view.styleDocument.activeElement);
     yield testCompletion(testData[i], editor, view);
   }
 }
 
-function* testCompletion([key, modifiers, completion, index, total, willChange],
+function* testCompletion([key, modifiers, completion, open, selected, change],
                          editor, view) {
   info("Pressing key " + key);
-  info("Expecting " + completion + ", " + index + ", " + total);
+  info("Expecting " + completion);
+  info("Is popup opened: " + open);
+  info("Is item selected: " + selected);
 
   let onDone;
-  if (willChange) {
+  if (change) {
     // If the key triggers a ruleview-changed, wait for that event, it will
     // always be the last to be triggered and tells us when the preview has
     // been done.
     onDone = view.once("ruleview-changed");
   } else {
     // Otherwise, expect an after-suggest event (except if the popup gets
     // closed).
     onDone = key !== "VK_RIGHT" && key !== "VK_BACK_SPACE"
@@ -102,17 +106,16 @@ function* testCompletion([key, modifiers
 
   info("Checking the state");
   if (completion != null) {
     // The key might have been a TAB or shift-TAB, in which case the editor will
     // be a new one
     editor = inplaceEditor(view.styleDocument.activeElement);
     is(editor.input.value, completion, "Correct value is autocompleted");
   }
-  if (total == 0) {
+  if (!open) {
     ok(!(editor.popup && editor.popup.isOpen), "Popup is closed");
   } else {
     ok(editor.popup._panel.state == "open" ||
        editor.popup._panel.state == "showing", "Popup is open");
-    is(editor.popup.getItems().length, total, "Number of suggestions match");
-    is(editor.popup.selectedIndex, index, "Correct item is selected");
+    is(editor.popup.selectedIndex != -1, selected, "An item is selected");
   }
 }
--- a/devtools/client/shared/inplace-editor.js
+++ b/devtools/client/shared/inplace-editor.js
@@ -295,21 +295,21 @@ function InplaceEditor(options, event) {
   this.validate = options.validate;
 
   if (this.validate) {
     this.input.addEventListener("keyup", this._onKeyup, false);
   }
 
   this._updateSize();
 
+  EventEmitter.decorate(this);
+
   if (options.start) {
     options.start(this, event);
   }
-
-  EventEmitter.decorate(this);
 }
 
 exports.InplaceEditor = InplaceEditor;
 
 InplaceEditor.CONTENT_TYPES = CONTENT_TYPES;
 
 InplaceEditor.prototype = {
 
@@ -1045,17 +1045,17 @@ InplaceEditor.prototype = {
     let isPlainText = this.contentType == CONTENT_TYPES.PLAIN_TEXT;
     let isPopupOpen = this.popup && this.popup.isOpen;
 
     let increment = 0;
     if (!isPlainText && !multilineNavigation) {
       increment = this._getIncrement(event);
     }
 
-    if (isKeyIn(key, "HOME", "END", "PAGE_UP", "PAGE_DOWN")) {
+    if (isKeyIn(key, "PAGE_UP", "PAGE_DOWN")) {
       this._preventSuggestions = true;
     }
 
     let cycling = false;
     if (increment && this._incrementValue(increment)) {
       this._updateSize();
       prevent = true;
       cycling = true;
@@ -1063,17 +1063,17 @@ InplaceEditor.prototype = {
 
     if (isPopupOpen && isKeyIn(key, "UP", "DOWN", "PAGE_UP", "PAGE_DOWN")) {
       prevent = true;
       cycling = true;
       this._cycleCSSSuggestion(isKeyIn(key, "UP", "PAGE_UP"));
       this._doValidation();
     }
 
-    if (isKeyIn(key, "BACK_SPACE", "DELETE", "LEFT", "RIGHT")) {
+    if (isKeyIn(key, "BACK_SPACE", "DELETE", "LEFT", "RIGHT", "HOME", "END")) {
       if (isPopupOpen) {
         this._hideAutocompletePopup();
       }
     } else if (!cycling && !multilineNavigation &&
       !event.metaKey && !event.altKey && !event.ctrlKey) {
       this._maybeSuggestCompletion(true);
     }
 
@@ -1303,29 +1303,29 @@ InplaceEditor.prototype = {
           input.selectionStart < input.value.length &&
           input.value.slice(input.selectionStart)[0] != " ") {
         // This emit is mainly to make the test flow simpler.
         this.emit("after-suggest", "nothing to autocomplete");
         return;
       }
       let list = [];
       if (this.contentType == CONTENT_TYPES.CSS_PROPERTY) {
-        list = CSSPropertyList;
+        list = this._getCSSPropertyList();
       } else if (this.contentType == CONTENT_TYPES.CSS_VALUE) {
         // Get the last query to be completed before the caret.
         let match = /([^\s,.\/]+$)/.exec(query);
         if (match) {
           startCheckQuery = match[0];
         } else {
           startCheckQuery = "";
         }
 
         list =
           ["!important",
-           ...domUtils.getCSSValuesForProperty(this.property.name)];
+           ...this._getCSSValuesForPropertyName(this.property.name)];
 
         if (query == "") {
           // Do not suggest '!important' without any manually typed character.
           list.splice(0, 1);
         }
       } else if (this.contentType == CONTENT_TYPES.CSS_MIXED &&
                  /^\s*style\s*=/.test(query)) {
         // Check if the style attribute is closed before the selection.
@@ -1341,30 +1341,30 @@ InplaceEditor.prototype = {
         let match = query.match(/([:;"'=]?)\s*([^"';:=]+)?$/);
         if (match && match.length >= 2) {
           if (match[1] == ":") {
             // We are in CSS value completion
             let propertyName =
               query.match(/[;"'=]\s*([^"';:= ]+)\s*:\s*[^"';:=]*$/)[1];
             list =
               ["!important;",
-               ...domUtils.getCSSValuesForProperty(propertyName)];
+               ...this._getCSSValuesForPropertyName(propertyName)];
             let matchLastQuery = /([^\s,.\/]+$)/.exec(match[2] || "");
             if (matchLastQuery) {
               startCheckQuery = matchLastQuery[0];
             } else {
               startCheckQuery = "";
             }
             if (!match[2]) {
               // Don't suggest '!important' without any manually typed character
               list.splice(0, 1);
             }
           } else if (match[1]) {
             // We are in CSS property name completion
-            list = CSSPropertyList;
+            list = this._getCSSPropertyList();
             startCheckQuery = match[2];
           }
           if (startCheckQuery == null) {
             // This emit is mainly to make the test flow simpler.
             this.emit("after-suggest", "nothing to autocomplete");
             return;
           }
         }
@@ -1450,16 +1450,38 @@ InplaceEditor.prototype = {
    * Check if the current input is displaying more than one line of text.
    *
    * @return {Boolean} true if the input has a single line of text
    */
   _isSingleLine: function () {
     let inputRect = this.input.getBoundingClientRect();
     return inputRect.height < 2 * this.inputCharDimensions.height;
   },
+
+  /**
+   * Returns the list of CSS properties to use for the autocompletion. This
+   * method is overridden by tests in order to use mocked suggestion lists.
+   *
+   * @return {Array} array of CSS property names (Strings)
+   */
+  _getCSSPropertyList: function () {
+    return CSSPropertyList;
+  },
+
+  /**
+   * Returns a list of CSS values valid for a provided property name to use for
+   * the autocompletion. This method is overridden by tests in order to use
+   * mocked suggestion lists.
+   *
+   * @param {String} propertyName
+   * @return {Array} array of CSS property values (Strings)
+   */
+  _getCSSValuesForPropertyName: function (propertyName) {
+    return domUtils.getCSSValuesForProperty(propertyName);
+  },
 };
 
 /**
  * Copy text-related styles from one element to another.
  */
 function copyTextStyles(from, to) {
   let win = from.ownerDocument.defaultView;
   let style = win.getComputedStyle(from);
--- a/devtools/client/shared/test/browser.ini
+++ b/devtools/client/shared/test/browser.ini
@@ -6,16 +6,17 @@ support-files =
   browser_layoutHelpers-getBoxQuads.html
   browser_templater_basic.html
   browser_toolbar_basic.html
   browser_toolbar_webconsole_errors_count.html
   browser_devices.json
   doc_options-view.xul
   head.js
   helper_html_tooltip.js
+  helper_inplace_editor.js
   html-mdn-css-basic-testing.html
   html-mdn-css-no-summary.html
   html-mdn-css-no-summary-or-syntax.html
   html-mdn-css-no-syntax.html
   html-mdn-css-syntax-old-style.html
   leakhunt.js
   test-actor.js
   test-actor-registry.js
@@ -116,16 +117,18 @@ skip-if = e10s # Bug 1221911, bug 122228
 [browser_html_tooltip-02.js]
 [browser_html_tooltip-03.js]
 [browser_html_tooltip-04.js]
 [browser_html_tooltip-05.js]
 [browser_html_tooltip_arrow-01.js]
 [browser_html_tooltip_arrow-02.js]
 [browser_inplace-editor-01.js]
 [browser_inplace-editor-02.js]
+[browser_inplace-editor_autocomplete_01.js]
+[browser_inplace-editor_autocomplete_02.js]
 [browser_inplace-editor_maxwidth.js]
 [browser_key_shortcuts.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_mdn-docs-01.js]
 [browser_mdn-docs-02.js]
--- a/devtools/client/shared/test/browser_inplace-editor-01.js
+++ b/devtools/client/shared/test/browser_inplace-editor-01.js
@@ -1,27 +1,29 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+/* import-globals-from helper_inplace_editor.js */
 
 "use strict";
 
-var {editableField, getInplaceEditorForSpan: inplaceEditor} = require("devtools/client/shared/inplace-editor");
+loadHelperScript("helper_inplace_editor.js");
 
 // Test the inplace-editor behavior.
 
 add_task(function* () {
   yield addTab("data:text/html;charset=utf-8,inline editor tests");
-  let [host, win, doc] = yield createHost();
+  let [host, , doc] = yield createHost();
 
   yield testMultipleInitialization(doc);
   yield testReturnCommit(doc);
   yield testBlurCommit(doc);
   yield testAdvanceCharCommit(doc);
   yield testAdvanceCharsFunction(doc);
+  yield testEscapeCancel(doc);
 
   host.destroy();
   gBrowser.removeCurrentTab();
 });
 
 function testMultipleInitialization(doc) {
   doc.body.innerHTML = "";
   let options = {};
@@ -31,28 +33,31 @@ function testMultipleInitialization(doc)
   editableField(options);
   editableField(options);
 
   info("Clicking on the inplace-editor field to turn to edit mode");
   span.click();
 
   is(span.style.display, "none", "The original <span> is hidden");
   is(doc.querySelectorAll("input").length, 1, "Only one <input>");
-  is(doc.querySelectorAll("span").length, 2, "Correct number of <span> elements");
-  is(doc.querySelectorAll("span.autosizer").length, 1, "There is an autosizer element");
+  is(doc.querySelectorAll("span").length, 2,
+    "Correct number of <span> elements");
+  is(doc.querySelectorAll("span.autosizer").length, 1,
+    "There is an autosizer element");
 }
 
 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.");
+      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;
 }
@@ -63,56 +68,55 @@ function testBlurCommit(doc) {
 
   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);
+  }, doc, "Edit Me!");
 
   return def.promise;
 }
 
 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;
       EventUtils.sendString("Test:");
     },
     done: onDone("Test", true, def)
   }, doc);
 
   return def.promise;
 }
 
 function testAdvanceCharsFunction(doc) {
   info("Testing advanceChars as a function");
   let def = promise.defer();
 
   let firstTime = true;
 
   createInplaceEditorAndClick({
     initial: "",
-    advanceChars: function (aCharCode, aText, aInsertionPoint) {
-      if (aCharCode !== Components.interfaces.nsIDOMKeyEvent.DOM_VK_COLON) {
+    advanceChars: function (charCode, text, insertionPoint) {
+      if (charCode !== Components.interfaces.nsIDOMKeyEvent.DOM_VK_COLON) {
         return false;
       }
       if (firstTime) {
         firstTime = false;
         return false;
       }
 
       // Just to make sure we check it somehow.
-      return aText.length > 0;
+      return text.length > 0;
     },
     start: function (editor) {
       for (let ch of ":Test:") {
         EventUtils.sendChar(ch);
       }
     },
     done: onDone(":Test", true, def)
   }, doc);
@@ -139,30 +143,8 @@ function testEscapeCancel(doc) {
 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, doc) {
-  doc.body.innerHTML = "";
-  let span = options.element = createSpan(doc);
-
-  info("Creating an inplace-editor field");
-  editableField(options);
-  is(span.getAttribute("role"), "button",
-    "Editable element should have button semantics");
-
-  info("Clicking on the inplace-editor field to turn to edit mode");
-  span.click();
-}
-
-function createSpan(doc) {
-  info("Creating a new span element");
-  let span = doc.createElement("span");
-  span.setAttribute("tabindex", "0");
-  span.textContent = "Edit Me!";
-  doc.body.appendChild(span);
-  return span;
-}
--- a/devtools/client/shared/test/browser_inplace-editor-02.js
+++ b/devtools/client/shared/test/browser_inplace-editor-02.js
@@ -1,21 +1,22 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+/* import-globals-from helper_inplace_editor.js */
 
 "use strict";
 
-var {editableField, getInplaceEditorForSpan: inplaceEditor} = require("devtools/client/shared/inplace-editor");
+loadHelperScript("helper_inplace_editor.js");
 
 // Test that the trimOutput option for the inplace editor works correctly.
 
 add_task(function* () {
   yield addTab("data:text/html;charset=utf-8,inline editor tests");
-  let [host, win, doc] = yield createHost();
+  let [host, , doc] = yield createHost();
 
   yield testNonTrimmed(doc);
   yield testTrimmed(doc);
 
   host.destroy();
   gBrowser.removeCurrentTab();
 });
 
@@ -63,28 +64,8 @@ function testTrimmed(doc) {
 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, doc) {
-  doc.body.innerHTML = "";
-  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 createSpan(doc) {
-  info("Creating a new span element");
-  let span = doc.createElement("span");
-  span.setAttribute("tabindex", "0");
-  span.textContent = "Edit Me!";
-  doc.body.appendChild(span);
-  return span;
-}
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/test/browser_inplace-editor_autocomplete_01.js
@@ -0,0 +1,67 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+/* import-globals-from helper_inplace_editor.js */
+
+"use strict";
+
+const { InplaceEditor } = require("devtools/client/shared/inplace-editor");
+const { AutocompletePopup } = require("devtools/client/shared/autocomplete-popup");
+loadHelperScript("helper_inplace_editor.js");
+
+// Test the inplace-editor autocomplete popup for CSS properties suggestions.
+// Using a mocked list of CSS properties to avoid test failures linked to
+// engine changes (new property, removed property, ...).
+
+const testData = [
+  ["b", "border", 1, 3],
+  ["VK_DOWN", "box-sizing", 2, 3],
+  ["VK_DOWN", "background", 0, 3],
+  ["VK_DOWN", "border", 1, 3],
+  ["VK_BACK_SPACE", "b", -1, 0],
+  ["VK_BACK_SPACE", "", -1, 0],
+  ["VK_DOWN", "background", 0, 6],
+  ["VK_LEFT", "background", -1, 0],
+];
+
+const mockGetCSSPropertyList = function () {
+  return [
+    "background",
+    "border",
+    "box-sizing",
+    "color",
+    "display",
+    "visibility",
+  ];
+};
+
+add_task(function* () {
+  yield addTab("data:text/html;charset=utf-8," +
+    "inplace editor CSS property autocomplete");
+  let [host, win, doc] = yield createHost();
+
+  let xulDocument = win.top.document;
+  let popup = new AutocompletePopup(xulDocument, { autoSelect: true });
+  yield new Promise(resolve => {
+    createInplaceEditorAndClick({
+      start: runPropertyAutocompletionTest,
+      contentType: InplaceEditor.CONTENT_TYPES.CSS_PROPERTY,
+      done: resolve,
+      popup: popup
+    }, doc);
+  });
+
+  host.destroy();
+  gBrowser.removeCurrentTab();
+});
+
+let runPropertyAutocompletionTest = Task.async(function* (editor) {
+  info("Starting to test for css property completion");
+  editor._getCSSPropertyList = mockGetCSSPropertyList;
+
+  for (let data of testData) {
+    yield testCompletion(data, editor);
+  }
+
+  EventUtils.synthesizeKey("VK_RETURN", {}, editor.input.defaultView);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/test/browser_inplace-editor_autocomplete_02.js
@@ -0,0 +1,72 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+/* import-globals-from helper_inplace_editor.js */
+
+"use strict";
+
+const { InplaceEditor } = require("devtools/client/shared/inplace-editor");
+const { AutocompletePopup } = require("devtools/client/shared/autocomplete-popup");
+loadHelperScript("helper_inplace_editor.js");
+
+// Test the inplace-editor autocomplete popup for CSS values suggestions.
+// Using a mocked list of CSS properties to avoid test failures linked to
+// engine changes (new property, removed property, ...).
+
+const testData = [
+  ["b", "block", -1, 0],
+  ["VK_BACK_SPACE", "b", -1, 0],
+  ["VK_BACK_SPACE", "", -1, 0],
+  ["i", "inline", 0, 2],
+  ["VK_DOWN", "inline-block", 1, 2],
+  ["VK_DOWN", "inline", 0, 2],
+  ["VK_LEFT", "inline", -1, 0],
+];
+
+const mockGetCSSValuesForPropertyName = function (propertyName) {
+  let values = {
+    "display": [
+      "block",
+      "flex",
+      "inline",
+      "inline-block",
+      "none",
+    ]
+  };
+  return values[propertyName] || [];
+};
+
+add_task(function* () {
+  yield addTab("data:text/html;charset=utf-8," +
+    "inplace editor CSS value autocomplete");
+  let [host, win, doc] = yield createHost();
+
+  let xulDocument = win.top.document;
+  let popup = new AutocompletePopup(xulDocument, { autoSelect: true });
+
+  yield new Promise(resolve => {
+    createInplaceEditorAndClick({
+      start: runAutocompletionTest,
+      contentType: InplaceEditor.CONTENT_TYPES.CSS_VALUE,
+      property: {
+        name: "display"
+      },
+      done: resolve,
+      popup: popup
+    }, doc);
+  });
+
+  host.destroy();
+  gBrowser.removeCurrentTab();
+});
+
+let runAutocompletionTest = Task.async(function* (editor) {
+  info("Starting to test for css property completion");
+  editor._getCSSValuesForPropertyName = mockGetCSSValuesForPropertyName;
+
+  for (let data of testData) {
+    yield testCompletion(data, editor);
+  }
+
+  EventUtils.synthesizeKey("VK_RETURN", {}, editor.input.defaultView);
+});
--- a/devtools/client/shared/test/browser_inplace-editor_maxwidth.js
+++ b/devtools/client/shared/test/browser_inplace-editor_maxwidth.js
@@ -1,15 +1,16 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+/* import-globals-from helper_inplace_editor.js */
 
 "use strict";
 
-var { editableField } = require("devtools/client/shared/inplace-editor");
+loadHelperScript("helper_inplace_editor.js");
 
 const MAX_WIDTH = 300;
 const START_TEXT = "Start text";
 const LONG_TEXT = "I am a long text and I will not fit in a 300px container. " +
   "I expect the inplace editor to wrap.";
 
 // Test the inplace-editor behavior with a maxWidth configuration option
 // defined.
@@ -20,17 +21,17 @@ add_task(function* () {
 
   info("Testing the maxWidth option in pixels, to precisely check the size");
   yield new Promise(resolve => {
     createInplaceEditorAndClick({
       multiline: true,
       maxWidth: MAX_WIDTH,
       start: testMaxWidth,
       done: resolve
-    }, doc);
+    }, doc, START_TEXT);
   });
 
   host.destroy();
   gBrowser.removeCurrentTab();
 });
 
 let testMaxWidth = Task.async(function* (editor) {
   is(editor.input.value, START_TEXT, "Span text content should be used");
@@ -106,30 +107,8 @@ function getLines(textarea) {
  * @param {DOMNode} textarea
  */
 function checkScrollbars(textarea) {
   is(textarea.scrollHeight, textarea.clientHeight,
     "Textarea should never have vertical scrollbars");
   is(textarea.scrollWidth, textarea.clientWidth,
     "Textarea should never have horizontal scrollbars");
 }
-
-function createInplaceEditorAndClick(options, doc) {
-  doc.body.innerHTML = "";
-  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 createSpan(doc) {
-  info("Creating a new span element");
-  let span = doc.createElement("span");
-  span.setAttribute("tabindex", "0");
-  span.style.fontSize = "11px";
-  span.style.fontFamily = "monospace";
-  span.textContent = START_TEXT;
-  doc.body.appendChild(span);
-  return span;
-}
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/test/helper_inplace_editor.js
@@ -0,0 +1,99 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+/* eslint no-unused-vars: [2, {"vars": "local", "args": "none"}] */
+
+"use strict";
+
+/**
+ * Helper methods for the HTMLTooltip integration tests.
+ */
+
+const { editableField } = require("devtools/client/shared/inplace-editor");
+
+/**
+ * Create an inplace editor linked to a span element and click on the span to
+ * to turn to edit mode.
+ *
+ * @param {Object} options
+ *        Options passed to the InplaceEditor/editableField constructor.
+ * @param {Document} doc
+ *        Document where the span element will be created.
+ * @param {String} textContent
+ *        (optional) String that will be used as the text content of the span.
+ */
+function createInplaceEditorAndClick(options, doc, textContent) {
+  doc.body.innerHTML = "";
+  let span = options.element = createSpan(doc);
+  if (textContent) {
+    span.textContent = textContent;
+  }
+
+  info("Creating an inplace-editor field");
+  editableField(options);
+
+  info("Clicking on the inplace-editor field to turn to edit mode");
+  span.click();
+}
+
+/**
+ * Helper to create a span in the provided document.
+ *
+ * @param {Document} doc
+ *        Document where the span element will be created.
+ * @return {Element} the created span element.
+ */
+function createSpan(doc) {
+  info("Creating a new span element");
+  let span = doc.createElement("span");
+  span.setAttribute("tabindex", "0");
+  span.style.fontSize = "11px";
+  span.style.fontFamily = "monospace";
+  doc.body.appendChild(span);
+  return span;
+}
+
+/**
+ * Test helper simulating a key event in an InplaceEditor and checking that the
+ * autocompletion works as expected.
+ *
+ * @param {Array} testData
+ *        - {String} key, the key to send
+ *        - {String} completion, the expected value of the auto-completion
+ *        - {Number} index, the index of the selected suggestion in the popup
+ *        - {Number} total, the total number of suggestions in the popup
+ * @param {InplaceEditor} editor
+ *        The InplaceEditor instance being tested
+ */
+function* testCompletion([key, completion, index, total], editor) {
+  info("Pressing key " + key);
+  info("Expecting " + completion);
+
+  let onSuggest;
+
+  if (/(left|right|back_space|escape)/ig.test(key)) {
+    info("Adding event listener for right|back_space|escape keys");
+    onSuggest = once(editor.input, "keypress");
+  } else {
+    info("Waiting for after-suggest event on the editor");
+    onSuggest = editor.once("after-suggest");
+  }
+
+  info("Synthesizing key " + key);
+  EventUtils.synthesizeKey(key, {}, editor.input.defaultView);
+
+  yield onSuggest;
+  yield waitForTick();
+
+  info("Checking the state");
+  if (completion != null) {
+    is(editor.input.value, completion, "Correct value is autocompleted");
+  }
+  if (total === 0) {
+    ok(!(editor.popup && editor.popup.isOpen), "Popup is closed");
+  } else {
+    ok(editor.popup._panel.state == "open" ||
+       editor.popup._panel.state == "showing", "Popup is open");
+    is(editor.popup.getItems().length, total, "Number of suggestions match");
+    is(editor.popup.selectedIndex, index, "Expected item is selected");
+  }
+}
--- a/devtools/client/shared/widgets/VariablesViewController.jsm
+++ b/devtools/client/shared/widgets/VariablesViewController.jsm
@@ -254,17 +254,16 @@ VariablesViewController.prototype = {
     // as well as `enumProperties` request.
     let deferred = promise.defer();
     let objectClient = this._getObjectClient(aGrip);
     let isArray = aGrip.preview && aGrip.preview.kind === "ArrayLike";
     if (isArray) {
       // First enumerate array items, e.g. properties from `0` to `array.length`.
       let options = {
         ignoreNonIndexedProperties: true,
-        ignoreSafeGetters: true,
         query: aQuery
       };
       objectClient.enumProperties(options, ({ iterator }) => {
         let sliceGrip = {
           type: "property-iterator",
           propertyIterator: iterator,
           start: 0,
           count: iterator.count
--- a/devtools/client/webconsole/new-console-output/constants.js
+++ b/devtools/client/webconsole/new-console-output/constants.js
@@ -53,16 +53,17 @@ const fragments = {
 const levels = {
   LEVELS: {
     error: severities.SEVERITY_ERROR,
     exception: severities.SEVERITY_ERROR,
     assert: severities.SEVERITY_ERROR,
     warn: severities.SEVERITY_WARNING,
     info: severities.SEVERITY_INFO,
     log: severities.SEVERITY_LOG,
+    clear: severities.SEVERITY_LOG,
     trace: severities.SEVERITY_LOG,
     table: severities.SEVERITY_LOG,
     debug: severities.SEVERITY_LOG,
     dir: severities.SEVERITY_LOG,
     dirxml: severities.SEVERITY_LOG,
     group: severities.SEVERITY_LOG,
     groupCollapsed: severities.SEVERITY_LOG,
     groupEnd: severities.SEVERITY_LOG,
--- a/devtools/client/webconsole/new-console-output/reducers/messages.js
+++ b/devtools/client/webconsole/new-console-output/reducers/messages.js
@@ -1,29 +1,35 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* 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/. */
 "use strict";
 
+const Immutable = require("devtools/client/shared/vendor/immutable");
 const constants = require("devtools/client/webconsole/new-console-output/constants");
 
-function messages(state = [], action) {
+function messages(state = Immutable.List(), action) {
   switch (action.type) {
     case constants.MESSAGE_ADD:
       let newMessage = action.message;
-      if (newMessage.allowRepeating && state.length > 0) {
-        let lastMessage = state[state.length - 1];
+
+      if (newMessage.data.level === "clear") {
+        return Immutable.List([newMessage]);
+      }
+
+      if (newMessage.allowRepeating && state.size > 0) {
+        let lastMessage = state.last();
         if (lastMessage.repeatId === newMessage.repeatId) {
           newMessage.repeat = lastMessage.repeat + 1;
-          return state.slice(0, state.length - 1).concat(newMessage);
+          return state.pop().push(newMessage);
         }
       }
-      return state.concat([ newMessage ]);
+      return state.push(newMessage);
     case constants.MESSAGES_CLEAR:
-      return [];
+      return Immutable.List();
   }
 
   return state;
 }
 
 exports.messages = messages;
--- a/devtools/client/webconsole/new-console-output/test/store/head.js
+++ b/devtools/client/webconsole/new-console-output/test/store/head.js
@@ -34,8 +34,29 @@ testPackets.set("console.log", {
     "private": false,
     "styles": [],
     "timeStamp": 1455064271115,
     "timer": null,
     "workerType": "none",
     "category": "webdev"
   }
 });
+
+testPackets.set("console.clear", {
+  "from": "server1.conn1.child1/consoleActor2",
+  "type": "consoleAPICall",
+  "message": {
+    "arguments": [],
+    "columnNumber": 1,
+    "counter": null,
+    "filename": "debugger eval code",
+    "functionName": "",
+    "groupName": "",
+    "level": "clear",
+    "lineNumber": 1,
+    "private": false,
+    "timeStamp": 1462571355142,
+    "timer": null,
+    "workerType": "none",
+    "styles": [],
+    "category": "webdev"
+  }
+});
--- a/devtools/client/webconsole/new-console-output/test/store/test_messages.js
+++ b/devtools/client/webconsole/new-console-output/test/store/test_messages.js
@@ -1,14 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
 const packet = testPackets.get("console.log");
+const clearPacket = testPackets.get("console.clear");
 const {
   getRepeatId,
   prepareMessage
 } = require("devtools/client/webconsole/new-console-output/utils/messages");
 const { getAllMessages } = require("devtools/client/webconsole/new-console-output/selectors/messages");
 
 function run_test() {
   run_next_test();
@@ -19,42 +20,65 @@ function run_test() {
  */
 add_task(function* () {
   const { getState, dispatch } = storeFactory();
 
   dispatch(actions.messageAdd(packet));
 
   const expectedMessage = prepareMessage(packet);
 
-  deepEqual(getAllMessages(getState()), [expectedMessage],
+  let messages = getAllMessages(getState());
+  deepEqual(messages.toArray(), [expectedMessage],
     "MESSAGE_ADD action adds a message");
 });
 
 /**
  * Test repeating messages in the store.
  */
 add_task(function* () {
   const { getState, dispatch } = storeFactory();
 
   dispatch(actions.messageAdd(packet));
   dispatch(actions.messageAdd(packet));
   dispatch(actions.messageAdd(packet));
 
   const expectedMessage = prepareMessage(packet);
   expectedMessage.repeat = 3;
 
-  deepEqual(getAllMessages(getState()), [expectedMessage],
-    "Adding same message to the store twice results in repeated message");
+  let messages = getAllMessages(getState());
+  deepEqual(messages.toArray(), [expectedMessage],
+    "Adding same message to the store three times results in repeated message");
 });
 
 /**
  * Test getRepeatId().
  */
 add_task(function* () {
   const message1 = prepareMessage(packet);
   const message2 = prepareMessage(packet);
   equal(getRepeatId(message1), getRepeatId(message2),
     "getRepeatId() returns same repeat id for objects with the same values");
 
   message2.data.arguments = ["new args"];
   notEqual(getRepeatId(message1), getRepeatId(message2),
     "getRepeatId() returns different repeat ids for different values");
 });
+
+/**
+ * Test adding a console.clear message to the store.
+ */
+add_task(function*() {
+  const { getState, dispatch } = storeFactory();
+
+  dispatch(actions.messageAdd(packet));
+
+  const expectedMessage = prepareMessage(packet);
+
+  let messages = getAllMessages(getState());
+  deepEqual(messages.toArray(), [expectedMessage],
+    "MESSAGE_ADD action adds a message");
+
+  dispatch(actions.messageAdd(clearPacket));
+
+  messages = getAllMessages(getState());
+  deepEqual(messages.toArray(), [prepareMessage(clearPacket)],
+    "console.clear clears existing messages and add a new one");
+});
--- a/devtools/client/webconsole/new-console-output/utils/messages.js
+++ b/devtools/client/webconsole/new-console-output/utils/messages.js
@@ -29,16 +29,21 @@ function prepareMessage(packet) {
   let messageType;
   let repeat;
   let repeatId;
   let severity;
 
   switch (packet.type) {
     case "consoleAPICall":
       data = Object.assign({}, packet.message);
+
+      if (data.level === "clear") {
+        data.arguments = [l10n.getStr("consoleCleared")];
+      }
+
       allowRepeating = true;
       category = CATEGORY_CLASS_FRAGMENTS[CATEGORY_WEBDEV];
       messageType = "ConsoleApiCall";
       repeat = 1;
       repeatId = getRepeatId(data);
       severity = SEVERITY_CLASS_FRAGMENTS[LEVELS[data.level]];
       break;
     case "pageError":
--- a/devtools/client/webconsole/test/browser_warn_user_about_replaced_api.js
+++ b/devtools/client/webconsole/test/browser_warn_user_about_replaced_api.js
@@ -15,17 +15,17 @@ add_task(function* () {
   Services.prefs.setBoolPref(PREF, true);
 
   let { browser } = yield loadTab(TEST_URI);
   let hud = yield openConsole();
 
   yield testWarningNotPresent(hud);
 
   let loaded = loadBrowser(browser);
-  content.location = TEST_REPLACED_API_URI;
+  BrowserTestUtils.loadURI(browser, TEST_REPLACED_API_URI);
   yield loaded;
 
   let hud2 = yield openConsole();
 
   yield testWarningPresent(hud2);
 
   Services.prefs.clearUserPref(PREF);
 });
@@ -33,17 +33,20 @@ add_task(function* () {
 function testWarningNotPresent(hud) {
   let deferred = promise.defer();
 
   is(hud.outputNode.textContent.indexOf("logging API"), -1,
      "no warning displayed");
 
   // Bug 862024: make sure the warning doesn't show after page reload.
   info("reload " + TEST_URI);
-  executeSoon(() => content.location.reload());
+  executeSoon(function () {
+    let browser = gBrowser.selectedBrowser;
+    ContentTask.spawn(browser, null, "() => content.location.reload()");
+  });
 
   waitForMessages({
     webconsole: hud,
     messages: [{
       text: "testscript.js",
       category: CATEGORY_NETWORK,
     }],
   }).then(() => executeSoon(() => {
@@ -69,14 +72,15 @@ function testWarningPresent(hud) {
   };
 
   waitForMessages(warning).then(() => {
     hud.jsterm.clearOutput();
 
     executeSoon(() => {
       info("reload the test page and wait for the warning to show");
       waitForMessages(warning).then(deferred.resolve);
-      content.location.reload();
+      let browser = gBrowser.selectedBrowser;
+      ContentTask.spawn(browser, null, "() => content.location.reload()");
     });
   });
 
   return deferred.promise;
 }
--- a/devtools/client/webconsole/test/browser_webconsole_bug_587617_output_copy.js
+++ b/devtools/client/webconsole/test/browser_webconsole_bug_587617_output_copy.js
@@ -1,12 +1,13 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
+/* globals goUpdateCommand goDoCommand */
 
 "use strict";
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/test-console.html";
 
 var HUD, outputNode;
 
@@ -15,31 +16,32 @@ add_task(function* () {
 
   let hud = yield openConsole();
   yield consoleOpened(hud);
   yield testContextMenuCopy();
 
   HUD = outputNode = null;
 });
 
-function consoleOpened(aHud) {
-  HUD = aHud;
+function consoleOpened(hud) {
+  HUD = hud;
 
   let deferred = promise.defer();
 
   // See bugs 574036, 586386 and 587617.
   outputNode = HUD.outputNode;
 
   HUD.jsterm.clearOutput();
 
   let controller = top.document.commandDispatcher
                                .getControllerForCommand("cmd_copy");
   is(controller.isCommandEnabled("cmd_copy"), false, "cmd_copy is disabled");
 
-  content.console.log("Hello world! bug587617");
+  ContentTask.spawn(gBrowser.selectedBrowser, null,
+    "() => content.console.log('Hello world! bug587617')");
 
   waitForMessages({
     webconsole: HUD,
     messages: [{
       text: "bug587617",
       category: CATEGORY_WEBDEV,
       severity: SEVERITY_LOG,
     }],
--- a/devtools/client/webconsole/test/browser_webconsole_bug_600183_charset.js
+++ b/devtools/client/webconsole/test/browser_webconsole_bug_600183_charset.js
@@ -42,18 +42,18 @@ function waitForRequest() {
     performTest(req, console).then(deferred.resolve);
   };
   return deferred.promise;
 }
 
 add_task(function* () {
   let { browser } = yield loadTab(INIT_URI);
 
-  let hud = yield openConsole();
+  yield openConsole();
 
   let gotLastRequest = waitForRequest();
 
   let loaded = loadBrowser(browser);
-  content.location = TEST_URI;
+  BrowserTestUtils.loadURI(browser, TEST_URI);
   yield loaded;
 
   yield gotLastRequest;
 });
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -632,17 +632,22 @@ WebConsoleFrame.prototype = {
   },
 
   /**
    * Resizes the output node to fit the output wrapped.
    * We need this because it makes the layout a lot faster than
    * using -moz-box-flex and 100% width.  See Bug 1237368.
    */
   resize: function () {
-    this.outputNode.style.width = this.outputWrapper.clientWidth + "px";
+    if (this.NEW_CONSOLE_OUTPUT_ENABLED) {
+      this.experimentalOutputNode.style.width =
+        this.outputWrapper.clientWidth + "px";
+    } else {
+      this.outputNode.style.width = this.outputWrapper.clientWidth + "px";
+    }
   },
 
   /**
    * Sets the focus to JavaScript input field when the web console tab is
    * selected or when there is a split console present.
    * @private
    */
   _onPanelSelected: function () {
--- a/devtools/server/actors/animation.js
+++ b/devtools/server/actors/animation.js
@@ -26,20 +26,17 @@
  */
 
 const {Cu} = require("chrome");
 const promise = require("promise");
 const {Task} = require("devtools/shared/task");
 const protocol = require("devtools/shared/protocol");
 const {ActorClass, Actor, FrontClass, Front,
        Arg, method, RetVal, types} = protocol;
-// Make sure the nodeActor type is know here.
-const {NodeActor} = require("devtools/server/actors/inspector");
-const {AnimationPlayerFront} = require("devtools/shared/fronts/animation");
-const {animationPlayerSpec} = require("devtools/shared/specs/animation");
+const {animationPlayerSpec, animationsSpec} = require("devtools/shared/specs/animation");
 const events = require("sdk/event/core");
 
 // Types of animations.
 const ANIMATION_TYPES = {
   CSS_ANIMATION: "cssanimation",
   CSS_TRANSITION: "csstransition",
   SCRIPT_ANIMATION: "scriptanimation",
   UNKNOWN: "unknown"
@@ -429,41 +426,21 @@ var AnimationPlayerActor = protocol.Acto
     return this.player.effect.getProperties().map(property => {
       return {name: property.property, values: property.values};
     });
   }
 });
 
 exports.AnimationPlayerActor = AnimationPlayerActor;
 
- /**
- * Sent with the 'mutations' event as part of an array of changes, used to
- * inform fronts of the type of change that occured.
- */
-types.addDictType("animationMutationChange", {
-  // The type of change ("added" or "removed").
-  type: "string",
-  // The changed AnimationPlayerActor.
-  player: "animationplayer"
-});
-
 /**
  * The Animations actor lists animation players for a given node.
  */
-var AnimationsActor = exports.AnimationsActor = ActorClass({
-  typeName: "animations",
-
-  events: {
-    "mutations": {
-      type: "mutations",
-      changes: Arg(0, "array:animationMutationChange")
-    }
-  },
-
-  initialize: function (conn, tabActor) {
+var AnimationsActor = exports.AnimationsActor = protocol.ActorClassWithSpec(animationsSpec, {
+  initialize: function(conn, tabActor) {
     Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
 
     this.onWillNavigate = this.onWillNavigate.bind(this);
     this.onNavigate = this.onNavigate.bind(this);
     this.onAnimationMutation = this.onAnimationMutation.bind(this);
 
     this.allAnimationsPaused = false;
@@ -491,36 +468,31 @@ var AnimationsActor = exports.Animations
   /**
    * Clients can optionally call this with a reference to their WalkerActor.
    * If they do, then AnimationPlayerActor's forms are going to also include
    * NodeActor IDs when the corresponding NodeActors do exist.
    * This, in turns, is helpful for clients to avoid having to go back once more
    * to the server to get a NodeActor for a particular animation.
    * @param {WalkerActor} walker
    */
-  setWalkerActor: method(function (walker) {
+  setWalkerActor: function (walker) {
     this.walker = walker;
-  }, {
-    request: {
-      walker: Arg(0, "domwalker")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Retrieve the list of AnimationPlayerActor actors for currently running
    * animations on a node and its descendants.
    * Note that calling this method a second time will destroy all previously
    * retrieved AnimationPlayerActors. Indeed, the lifecycle of these actors
    * is managed here on the server and tied to getAnimationPlayersForNode
    * being called.
    * @param {NodeActor} nodeActor The NodeActor as defined in
    * /devtools/server/actors/inspector
    */
-  getAnimationPlayersForNode: method(function (nodeActor) {
+  getAnimationPlayersForNode: function (nodeActor) {
     let animations = nodeActor.rawNode.getAnimations({subtree: true});
 
     // Destroy previously stored actors
     if (this.actors) {
       this.actors.forEach(actor => actor.destroy());
     }
     this.actors = [];
 
@@ -537,24 +509,17 @@ var AnimationsActor = exports.Animations
     let win = nodeActor.rawNode.ownerDocument.defaultView;
     this.observer = new win.MutationObserver(this.onAnimationMutation);
     this.observer.observe(nodeActor.rawNode, {
       animations: true,
       subtree: true
     });
 
     return this.actors;
-  }, {
-    request: {
-      actorID: Arg(0, "domnode")
-    },
-    response: {
-      players: RetVal("array:animationplayer")
-    }
-  }),
+  },
 
   onAnimationMutation: function (mutations) {
     let eventData = [];
     let readyPromises = [];
 
     for (let {addedAnimations, removedAnimations} of mutations) {
       for (let player of removedAnimations) {
         // Note that animations are reported as removed either when they are
@@ -624,24 +589,21 @@ var AnimationsActor = exports.Animations
     }
   },
 
   /**
    * After the client has called getAnimationPlayersForNode for a given DOM
    * node, the actor starts sending animation mutations for this node. If the
    * client doesn't want this to happen anymore, it should call this method.
    */
-  stopAnimationPlayerUpdates: method(function () {
+  stopAnimationPlayerUpdates: function () {
     if (this.observer && !Cu.isDeadWrapper(this.observer)) {
       this.observer.disconnect();
     }
-  }, {
-    request: {},
-    response: {}
-  }),
+  },
 
   /**
    * Iterates through all nodes below a given rootNode (optionally also in
    * nested frames) and finds all existing animation players.
    * @param {DOMNode} rootNode The root node to start iterating at. Animation
    * players will *not* be reported for this node.
    * @param {Boolean} traverseFrames Whether we should iterate through nested
    * frames too.
@@ -669,120 +631,81 @@ var AnimationsActor = exports.Animations
     if (isTopLevel) {
       this.allAnimationsPaused = false;
     }
   },
 
   /**
    * Pause all animations in the current tabActor's frames.
    */
-  pauseAll: method(function () {
+  pauseAll: function () {
     let readyPromises = [];
     // Until the WebAnimations API provides a way to play/pause via the document
     // timeline, we have to iterate through the whole DOM to find all players.
     for (let player of
          this.getAllAnimations(this.tabActor.window.document, true)) {
       player.pause();
       readyPromises.push(player.ready);
     }
     this.allAnimationsPaused = true;
     return promise.all(readyPromises);
-  }, {
-    request: {},
-    response: {}
-  }),
+  },
 
   /**
    * Play all animations in the current tabActor's frames.
    * This method only returns when animations have left their pending states.
    */
-  playAll: method(function () {
+  playAll: function () {
     let readyPromises = [];
     // Until the WebAnimations API provides a way to play/pause via the document
     // timeline, we have to iterate through the whole DOM to find all players.
     for (let player of
          this.getAllAnimations(this.tabActor.window.document, true)) {
       player.play();
       readyPromises.push(player.ready);
     }
     this.allAnimationsPaused = false;
     return promise.all(readyPromises);
-  }, {
-    request: {},
-    response: {}
-  }),
+  },
 
-  toggleAll: method(function () {
+  toggleAll: function () {
     if (this.allAnimationsPaused) {
       return this.playAll();
     }
     return this.pauseAll();
-  }, {
-    request: {},
-    response: {}
-  }),
+  },
 
   /**
    * Toggle (play/pause) several animations at the same time.
    * @param {Array} players A list of AnimationPlayerActor objects.
    * @param {Boolean} shouldPause If set to true, the players will be paused,
    * otherwise they will be played.
    */
-  toggleSeveral: method(function (players, shouldPause) {
+  toggleSeveral: function (players, shouldPause) {
     return promise.all(players.map(player => {
       return shouldPause ? player.pause() : player.play();
     }));
-  }, {
-    request: {
-      players: Arg(0, "array:animationplayer"),
-      shouldPause: Arg(1, "boolean")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Set the current time of several animations at the same time.
    * @param {Array} players A list of AnimationPlayerActor.
    * @param {Number} time The new currentTime.
    * @param {Boolean} shouldPause Should the players be paused too.
    */
-  setCurrentTimes: method(function (players, time, shouldPause) {
+  setCurrentTimes: function (players, time, shouldPause) {
     return promise.all(players.map(player => {
       let pause = shouldPause ? player.pause() : promise.resolve();
       return pause.then(() => player.setCurrentTime(time));
     }));
-  }, {
-    request: {
-      players: Arg(0, "array:animationplayer"),
-      time: Arg(1, "number"),
-      shouldPause: Arg(2, "boolean")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Set the playback rate of several animations at the same time.
    * @param {Array} players A list of AnimationPlayerActor.
    * @param {Number} rate The new rate.
    */
-  setPlaybackRates: method(function (players, rate) {
+  setPlaybackRates: function (players, rate) {
     for (let player of players) {
       player.setPlaybackRate(rate);
     }
-  }, {
-    request: {
-      players: Arg(0, "array:animationplayer"),
-      rate: Arg(1, "number")
-    },
-    response: {}
-  })
-});
-
-var AnimationsFront = exports.AnimationsFront = FrontClass(AnimationsActor, {
-  initialize: function (client, {animationsActor}) {
-    Front.prototype.initialize.call(this, client, {actor: animationsActor});
-    this.manage(this);
-  },
-
-  destroy: function () {
-    Front.prototype.destroy.call(this);
   }
 });
--- a/devtools/server/actors/object.js
+++ b/devtools/server/actors/object.js
@@ -274,16 +274,26 @@ ObjectActor.prototype = {
    *         An object that maps property names to safe getter descriptors as
    *         defined by the remote debugging protocol.
    */
   _findSafeGetterValues: function (ownProperties, limit = 0) {
     let safeGetterValues = Object.create(null);
     let obj = this.obj;
     let level = 0, i = 0;
 
+    // Most objects don't have any safe getters but inherit some from their
+    // prototype. Avoid calling getOwnPropertyNames on objects that may have
+    // many properties like Array, strings or js objects. That to avoid
+    // freezing firefox when doing so.
+    if (TYPED_ARRAY_CLASSES.includes(this.obj.class) ||
+        ["Array", "Object", "String"].includes(this.obj.class)) {
+      obj = obj.proto;
+      level++;
+    }
+
     while (obj) {
       let getters = this._findSafeGetters(obj);
       for (let name of getters) {
         // Avoid overwriting properties from prototypes closer to this.obj. Also
         // avoid providing safeGetterValues from prototypes if property |name|
         // is already defined as an own property.
         if (name in safeGetterValues ||
             (obj != this.obj && ownProperties.indexOf(name) !== -1)) {
@@ -699,18 +709,16 @@ ObjectActor.prototype.requestTypes = {
  *
  * @param objectActor ObjectActor
  *        The object actor.
  * @param options Object
  *        A dictionary object with various boolean attributes:
  *        - enumEntries Boolean
  *          If true, enumerates the entries of a Map or Set object
  *          instead of enumerating properties.
- *        - ignoreSafeGetters Boolean
- *          If true, do not iterate over safe getters.
  *        - ignoreIndexedProperties Boolean
  *          If true, filters out Array items.
  *          e.g. properties names between `0` and `object.length`.
  *        - ignoreNonIndexedProperties Boolean
  *          If true, filters out items that aren't array items
  *          e.g. properties names that are not a number between `0`
  *          and `object.length`.
  *        - sort Boolean
@@ -718,218 +726,197 @@ ObjectActor.prototype.requestTypes = {
  *          before dispatching them.
  *        - query String
  *          If non-empty, will filter the properties by names and values
  *          containing this query string. The match is not case-sensitive.
  *          Regarding value filtering it just compare to the stringification
  *          of the property value.
  */
 function PropertyIteratorActor(objectActor, options) {
-  this.objectActor = objectActor;
-
   if (options.enumEntries) {
-    this._initEntries();
+    let cls = objectActor.obj.class;
+    if (cls == "Map") {
+      this.iterator = enumMapEntries(objectActor);
+    } else if (cls == "WeakMap") {
+      this.iterator = enumWeakMapEntries(objectActor);
+    } else if (cls == "Set") {
+      this.iterator = enumSetEntries(objectActor);
+    } else if (cls == "WeakSet") {
+      this.iterator = enumWeakSetEntries(objectActor);
+    } else {
+      throw new Error("Unsupported class to enumerate entries from: " + cls);
+    }
+  } else if (options.ignoreNonIndexedProperties && !options.query) {
+    this.iterator = enumArrayProperties(objectActor, options);
   } else {
-    this._initProperties(options);
+    this.iterator = enumObjectProperties(objectActor, options);
   }
 }
 
 PropertyIteratorActor.prototype = {
   actorPrefix: "propertyIterator",
 
-  _initEntries: function () {
-    let names = [];
-    let ownProperties = Object.create(null);
-
-    switch (this.objectActor.obj.class) {
-      case "Map":
-      case "WeakMap": {
-        let idx = 0;
-        let enumFn = this.objectActor.obj.class === "Map" ?
-          enumMapEntries : enumWeakMapEntries;
-        for (let entry of enumFn(this.objectActor)) {
-          names.push(idx);
-          ownProperties[idx] = {
-            enumerable: true,
-            value: {
-              type: "mapEntry",
-              preview: {
-                key: entry[0],
-                value: entry[1]
-              }
-            }
-          };
-
-          idx++;
-        }
-        break;
-      }
-      case "Set":
-      case "WeakSet": {
-        let idx = 0;
-        let enumFn = this.objectActor.obj.class === "Set" ?
-          enumSetEntries : enumWeakSetEntries;
-        for (let item of enumFn(this.objectActor)) {
-          names.push(idx);
-          ownProperties[idx] = {
-            enumerable: true,
-            value: item
-          };
-
-          idx++;
-        }
-        break;
-      }
-      default:
-        // the ownProperties and names are left empty
-        break;
-    }
-
-    this.names = names;
-    this.ownProperties = ownProperties;
-  },
-
-  _initProperties: function (options) {
-    let names = [];
-    let ownProperties = Object.create(null);
-
-    try {
-      names = this.objectActor.obj.getOwnPropertyNames();
-    } catch (ex) {}
-
-    let safeGetterValues = {};
-    let safeGetterNames = [];
-    if (!options.ignoreSafeGetters) {
-      // Merge the safe getter values into the existing properties list.
-      safeGetterValues = this.objectActor._findSafeGetterValues(names);
-      safeGetterNames = Object.keys(safeGetterValues);
-      for (let name of safeGetterNames) {
-        if (names.indexOf(name) === -1) {
-          names.push(name);
-        }
-      }
-    }
-
-    if (options.ignoreIndexedProperties || options.ignoreNonIndexedProperties) {
-      let length = DevToolsUtils.getProperty(this.objectActor.obj, "length");
-      if (typeof (length) !== "number") {
-        // Pseudo arrays are flagged as ArrayLike if they have
-        // subsequent indexed properties without having any length attribute.
-        length = 0;
-        for (let key of names) {
-          if (isNaN(key) || key != length++) {
-            break;
-          }
-        }
-      }
-
-      if (options.ignoreIndexedProperties) {
-        names = names.filter(i => {
-          // Use parseFloat in order to reject floats...
-          // (parseInt converts floats to integer)
-          // (Number(str) converts spaces to 0)
-          i = parseFloat(i);
-          return !Number.isInteger(i) || i < 0 || i >= length;
-        });
-      }
-
-      if (options.ignoreNonIndexedProperties) {
-        names = names.filter(i => {
-          i = parseFloat(i);
-          return Number.isInteger(i) && i >= 0 && i < length;
-        });
-      }
-    }
-
-    if (options.query) {
-      let { query } = options;
-      query = query.toLowerCase();
-      names = names.filter(name => {
-        // Filter on attribute names
-        if (name.toLowerCase().includes(query)) {
-          return true;
-        }
-        // and then on attribute values
-        let desc;
-        try {
-          desc = this.obj.getOwnPropertyDescriptor(name);
-        } catch (e) {}
-        if (desc && desc.value &&
-            String(desc.value).includes(query)) {
-          return true;
-        }
-        return false;
-      });
-    }
-
-    if (options.sort) {
-      names.sort();
-    }
-
-    // Now build the descriptor list
-    for (let name of names) {
-      let desc = this.objectActor._propertyDescriptor(name);
-      if (!desc) {
-        desc = safeGetterValues[name];
-      }
-      else if (name in safeGetterValues) {
-        // Merge the safe getter values into the existing properties list.
-        let { getterValue, getterPrototypeLevel } = safeGetterValues[name];
-        desc.getterValue = getterValue;
-        desc.getterPrototypeLevel = getterPrototypeLevel;
-      }
-      ownProperties[name] = desc;
-    }
-
-    this.names = names;
-    this.ownProperties = ownProperties;
-  },
-
-  grip: function () {
+  grip() {
     return {
-      type: "propertyIterator",
+      type: this.actorPrefix,
       actor: this.actorID,
-      count: this.names.length
+      count: this.iterator.size
     };
   },
 
-  names: function ({ indexes }) {
+  names({ indexes }) {
     let list = [];
     for (let idx of indexes) {
-      list.push(this.names[idx]);
+      list.push(this.iterator.propertyName(idx));
     }
     return {
-      names: list
+      names: indexes
     };
   },
 
-  slice: function ({ start, count }) {
-    let names = this.names.slice(start, start + count);
-    let props = Object.create(null);
-    for (let name of names) {
-      props[name] = this.ownProperties[name];
+  slice({ start, count }) {
+    let ownProperties = Object.create(null);
+    for (let i = start, m = start + count; i < m; i++) {
+      let name = this.iterator.propertyName(i);
+      ownProperties[name] = this.iterator.propertyDescription(i);
     }
     return {
-      ownProperties: props
+      ownProperties
     };
   },
 
-  all: function () {
-    return {
-      ownProperties: this.ownProperties
-    };
+  all() {
+    return this.slice({ start: 0, count: this.length });
   }
 };
 
 PropertyIteratorActor.prototype.requestTypes = {
   "names": PropertyIteratorActor.prototype.names,
   "slice": PropertyIteratorActor.prototype.slice,
   "all": PropertyIteratorActor.prototype.all,
 };
 
+function enumArrayProperties(objectActor, options) {
+  let length = DevToolsUtils.getProperty(objectActor.obj, "length");
+  if (typeof length !== "number") {
+    // Pseudo arrays are flagged as ArrayLike if they have
+    // subsequent indexed properties without having any length attribute.
+    length = 0;
+    let names = objectActor.obj.getOwnPropertyNames();
+    for (let key of names) {
+      if (isNaN(key) || key != length++) {
+        break;
+      }
+    }
+  }
+
+  return {
+    size: length,
+    propertyName(index) {
+      return index;
+    },
+    propertyDescription(index) {
+      return objectActor._propertyDescriptor(index);
+    }
+  };
+}
+
+function enumObjectProperties(objectActor, options) {
+  let names = [];
+  try {
+    names = objectActor.obj.getOwnPropertyNames();
+  } catch (ex) {
+    // Calling getOwnPropertyNames() on some wrapped native prototypes is not
+    // allowed: "cannot modify properties of a WrappedNative". See bug 952093.
+  }
+
+  if (options.ignoreNonIndexedProperties || options.ignoreIndexedProperties) {
+    let length = DevToolsUtils.getProperty(objectActor.obj, "length");
+    if (typeof length !== "number") {
+      // Pseudo arrays are flagged as ArrayLike if they have
+      // subsequent indexed properties without having any length attribute.
+      length = 0;
+      for (let key of names) {
+        if (isNaN(key) || key != length++) {
+          break;
+        }
+      }
+    }
+
+    // It appears that getOwnPropertyNames always returns indexed properties
+    // first, so we can safely slice `names` for/against indexed properties.
+    // We do such clever operation to optimize very large array inspection,
+    // like webaudio buffers.
+    if (options.ignoreIndexedProperties) {
+      // Keep items after `length` index
+      names = names.slice(length);
+    } else if (options.ignoreNonIndexedProperties) {
+      // Remove `length` first items
+      names.splice(length);
+    }
+  }
+
+  let safeGetterValues = objectActor._findSafeGetterValues(names, 0);
+  let safeGetterNames = Object.keys(safeGetterValues);
+  // Merge the safe getter values into the existing properties list.
+  for (let name of safeGetterNames) {
+    if (!names.includes(name)) {
+      names.push(name);
+    }
+  }
+
+  if (options.query) {
+    let { query } = options;
+    query = query.toLowerCase();
+    names = names.filter(name => {
+      // Filter on attribute names
+      if (name.toLowerCase().includes(query)) {
+        return true;
+      }
+      // and then on attribute values
+      let desc;
+      try {
+        desc = objectActor.obj.getOwnPropertyDescriptor(name);
+      } catch (e) {
+        // Calling getOwnPropertyDescriptor on wrapped native prototypes is not
+        // allowed (bug 560072).
+      }
+      if (desc && desc.value &&
+          String(desc.value).includes(query)) {
+        return true;
+      }
+      return false;
+    });
+  }
+
+  if (options.sort) {
+    names.sort();
+  }
+
+  return {
+    size: names.length,
+    propertyName(index) {
+      return names[index];
+    },
+    propertyDescription(index) {
+      let name = names[index];
+      let desc = objectActor._propertyDescriptor(name);
+      if (!desc) {
+        desc = safeGetterValues[name];
+      } else if (name in safeGetterValues) {
+        // Merge the safe getter values into the existing properties list.
+        let { getterValue, getterPrototypeLevel } = safeGetterValues[name];
+        desc.getterValue = getterValue;
+        desc.getterPrototypeLevel = getterPrototypeLevel;
+      }
+      return desc;
+    }
+  };
+}
+
 /**
  * Helper function to create a grip from a Map/Set entry
  */
 function gripFromEntry({ obj, hooks }, entry) {
   return hooks.createValueGrip(
     makeDebuggeeValueIfNeeded(obj, Cu.unwaiveXrays(entry)));
 }
 
@@ -943,92 +930,153 @@ function enumMapEntries(objectActor) {
   // and the tupes, and then re-apply them on the underlying values until
   // we fix bug 1023984.
   //
   // Even then though, we might want to continue waiving Xrays here for the
   // same reason we do so for Arrays above - this filtering behavior is likely
   // to be more confusing than beneficial in the case of Object previews.
   let raw = objectActor.obj.unsafeDereference();
 
+  let keys = [...Cu.waiveXrays(Map.prototype.keys.call(raw))];
   return {
     [Symbol.iterator]: function* () {
-      for (let keyValuePair of Cu.waiveXrays(Map.prototype.entries.call(raw))) {
-        yield keyValuePair.map(val => gripFromEntry(objectActor, val));
+      for (let key of keys) {
+        let value = Map.prototype.get.call(raw, key);
+        yield [ key, value ].map(val => gripFromEntry(objectActor, val));
       }
+    },
+    size: keys.length,
+    propertyName(index) {
+      return index;
+    },
+    propertyDescription(index) {
+      let key = keys[index];
+      let val = Map.prototype.get.call(raw, key);
+      return {
+        enumerable: true,
+        value: {
+          type: "mapEntry",
+          preview: {
+            key: gripFromEntry(objectActor, key),
+            value: gripFromEntry(objectActor, val)
+          }
+        }
+      };
     }
   };
 }
 
 function enumWeakMapEntries(objectActor) {
   // We currently lack XrayWrappers for WeakMap, so when we iterate over
   // the values, the temporary iterator objects get created in the target
   // compartment. However, we _do_ have Xrays to Object now, so we end up
   // Xraying those temporary objects, and filtering access to |it.value|
   // based on whether or not it's Xrayable and/or callable, which breaks
   // the for/of iteration.
   //
   // This code is designed to handle untrusted objects, so we can safely
   // waive Xrays on the iterable, and relying on the Debugger machinery to
   // make sure we handle the resulting objects carefully.
   let raw = objectActor.obj.unsafeDereference();
-  let keys = Cu.waiveXrays(ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(raw));
+  let keys = Cu.waiveXrays(
+    ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(raw));
 
   return {
-    size: keys.length,
     [Symbol.iterator]: function* () {
       for (let key of keys) {
         let value = WeakMap.prototype.get.call(raw, key);
         yield [ key, value ].map(val => gripFromEntry(objectActor, val));
       }
+    },
+    size: keys.length,
+    propertyName(index) {
+      return index;
+    },
+    propertyDescription(index) {
+      let key = keys[index];
+      let val = WeakMap.prototype.get.call(raw, key);
+      return {
+        enumerable: true,
+        value: {
+          type: "mapEntry",
+          preview: {
+            key: gripFromEntry(objectActor, key),
+            value: gripFromEntry(objectActor, val)
+          }
+        }
+      };
     }
   };
 }
 
 function enumSetEntries(objectActor) {
   // We currently lack XrayWrappers for Set, so when we iterate over
   // the values, the temporary iterator objects get created in the target
   // compartment. However, we _do_ have Xrays to Object now, so we end up
   // Xraying those temporary objects, and filtering access to |it.value|
   // based on whether or not it's Xrayable and/or callable, which breaks
   // the for/of iteration.
   //
   // This code is designed to handle untrusted objects, so we can safely
   // waive Xrays on the iterable, and relying on the Debugger machinery to
   // make sure we handle the resulting objects carefully.
   let raw = objectActor.obj.unsafeDereference();
+  let values = [...Cu.waiveXrays(Set.prototype.values.call(raw))];
 
   return {
     [Symbol.iterator]: function* () {
-      for (let item of Cu.waiveXrays(Set.prototype.values.call(raw))) {
+      for (let item of values) {
         yield gripFromEntry(objectActor, item);
       }
+    },
+    size: values.length,
+    propertyName(index) {
+      return index;
+    },
+    propertyDescription(index) {
+      let val = values[index];
+      return {
+        enumerable: true,
+        value: gripFromEntry(objectActor, val)
+      };
     }
   };
 }
 
 function enumWeakSetEntries(objectActor) {
   // We currently lack XrayWrappers for WeakSet, so when we iterate over
   // the values, the temporary iterator objects get created in the target
   // compartment. However, we _do_ have Xrays to Object now, so we end up
   // Xraying those temporary objects, and filtering access to |it.value|
   // based on whether or not it's Xrayable and/or callable, which breaks
   // the for/of iteration.
   //
   // This code is designed to handle untrusted objects, so we can safely
   // waive Xrays on the iterable, and relying on the Debugger machinery to
   // make sure we handle the resulting objects carefully.
   let raw = objectActor.obj.unsafeDereference();
-  let keys = Cu.waiveXrays(ThreadSafeChromeUtils.nondeterministicGetWeakSetKeys(raw));
+  let keys = Cu.waiveXrays(
+    ThreadSafeChromeUtils.nondeterministicGetWeakSetKeys(raw));
 
   return {
-    size: keys.length,
     [Symbol.iterator]: function* () {
       for (let item of keys) {
         yield gripFromEntry(objectActor, item);
       }
+    },
+    size: keys.length,
+    propertyName(index) {
+      return index;
+    },
+    propertyDescription(index) {
+      let val = keys[index];
+      return {
+        enumerable: true,
+        value: gripFromEntry(objectActor, val)
+      };
     }
   };
 }
 
 /**
  * Functions for adding information to ObjectActor grips for the purpose of
  * having customized output. This object holds arrays mapped by
  * Debugger.Object.prototype.class.
--- a/devtools/server/tests/browser/head.js
+++ b/devtools/server/tests/browser/head.js
@@ -44,17 +44,17 @@ var addTab = Task.async(function* (url) 
     let isBlank = url == "about:blank";
     waitForFocus(resolve, content, isBlank);
   });
 
   return tab.linkedBrowser;
 });
 
 function* initAnimationsFrontForUrl(url) {
-  const {AnimationsFront} = require("devtools/server/actors/animation");
+  const {AnimationsFront} = require("devtools/shared/fronts/animation");
   const {InspectorFront} = require("devtools/shared/fronts/inspector");
 
   yield addTab(url);
 
   initDebuggerServer();
   let client = new DebuggerClient(DebuggerServer.connectPipe());
   let form = yield connectDebuggerClient(client);
   let inspector = InspectorFront(client, form);
--- a/devtools/server/tests/mochitest/test_animation_actor-lifetime.html
+++ b/devtools/server/tests/mochitest/test_animation_actor-lifetime.html
@@ -8,17 +8,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 1247243</title>
 
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
   <script type="application/javascript;version=1.8">
 window.onload = function() {
   const Ci = Components.interfaces;
-  const {AnimationsFront} = require("devtools/server/actors/animation");
+  const {AnimationsFront} = require("devtools/shared/fronts/animation");
   const {InspectorFront} = require("devtools/shared/fronts/inspector");
 
   SimpleTest.waitForExplicitFinish();
 
   let gWalker = null;
   let gClient = null;
   let animationsFront = null;
 
--- a/devtools/shared/client/main.js
+++ b/devtools/shared/client/main.js
@@ -2455,18 +2455,16 @@ ObjectClient.prototype = {
   }),
 
   /**
    * Request a PropertyIteratorClient instance to ease listing
    * properties for this object.
    *
    * @param options Object
    *        A dictionary object with various boolean attributes:
-   *        - ignoreSafeGetters Boolean
-   *          If true, do not iterate over safe getters.
    *        - ignoreIndexedProperties Boolean
    *          If true, filters out Array items.
    *          e.g. properties names between `0` and `object.length`.
    *        - ignoreNonIndexedProperties Boolean
    *          If true, filters out items that aren't array items
    *          e.g. properties names that are not a number between `0`
    *          and `object.length`.
    *        - sort Boolean
--- a/devtools/shared/fronts/animation.js
+++ b/devtools/shared/fronts/animation.js
@@ -4,17 +4,20 @@
 "use strict";
 
 const {
   Front,
   FrontClassWithSpec,
   custom,
   preEvent
 } = require("devtools/shared/protocol");
-const { animationPlayerSpec } = require("devtools/shared/specs/animation");
+const {
+  animationPlayerSpec,
+  animationsSpec
+} = require("devtools/shared/specs/animation");
 const { Task } = require("devtools/shared/task");
 
 const AnimationPlayerFront = FrontClassWithSpec(animationPlayerSpec, {
   initialize: function (conn, form, detail, ctx) {
     Front.prototype.initialize.call(this, conn, form, detail, ctx);
 
     this.state = {};
   },
@@ -114,8 +117,21 @@ const AnimationPlayerFront = FrontClassW
       }
     }
 
     return {state: data, hasChanged};
   }
 });
 
 exports.AnimationPlayerFront = AnimationPlayerFront;
+
+const AnimationsFront = FrontClassWithSpec(animationsSpec, {
+  initialize: function (client, {animationsActor}) {
+    Front.prototype.initialize.call(this, client, {actor: animationsActor});
+    this.manage(this);
+  },
+
+  destroy: function () {
+    Front.prototype.destroy.call(this);
+  }
+});
+
+exports.AnimationsFront = AnimationsFront;
--- a/devtools/shared/specs/animation.js
+++ b/devtools/shared/specs/animation.js
@@ -1,14 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const { Arg, RetVal, generateActorSpec } = require("devtools/shared/protocol");
+const {
+  Arg,
+  RetVal,
+  generateActorSpec,
+  types
+} = require("devtools/shared/protocol");
+require("devtools/shared/specs/inspector");
+
+/**
+ * Sent with the 'mutations' event as part of an array of changes, used to
+ * inform fronts of the type of change that occured.
+ */
+types.addDictType("animationMutationChange", {
+  // The type of change ("added" or "removed").
+  type: "string",
+  // The changed AnimationPlayerActor.
+  player: "animationplayer"
+});
 
 const animationPlayerSpec = generateActorSpec({
   typeName: "animationplayer",
 
   events: {
     "changed": {
       type: "changed",
       state: Arg(0, "json")
@@ -58,8 +75,77 @@ const animationPlayerSpec = generateActo
       response: {
         properties: RetVal("array:json")
       }
     }
   }
 });
 
 exports.animationPlayerSpec = animationPlayerSpec;
+
+const animationsSpec = generateActorSpec({
+  typeName: "animations",
+
+  events: {
+    "mutations": {
+      type: "mutations",
+      changes: Arg(0, "array:animationMutationChange")
+    }
+  },
+
+  methods: {
+    setWalkerActor: {
+      request: {
+        walker: Arg(0, "domwalker")
+      },
+      response: {}
+    },
+    getAnimationPlayersForNode: {
+      request: {
+        actorID: Arg(0, "domnode")
+      },
+      response: {
+        players: RetVal("array:animationplayer")
+      }
+    },
+    stopAnimationPlayerUpdates: {
+      request: {},
+      response: {}
+    },
+    pauseAll: {
+      request: {},
+      response: {}
+    },
+    playAll: {
+      request: {},
+      response: {}
+    },
+    toggleAll: {
+      request: {},
+      response: {}
+    },
+    toggleSeveral: {
+      request: {
+        players: Arg(0, "array:animationplayer"),
+        shouldPause: Arg(1, "boolean")
+      },
+      response: {}
+    },
+    setCurrentTimes: {
+      request: {
+        players: Arg(0, "array:animationplayer"),
+        time: Arg(1, "number"),
+        shouldPause: Arg(2, "boolean")
+      },
+      response: {}
+    },
+    setPlaybackRates: {
+      request: {
+        players: Arg(0, "array:animationplayer"),
+        rate: Arg(1, "number")
+      },
+      response: {}
+    }
+  }
+});
+
+exports.animationsSpec = animationsSpec;
+
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -29,17 +29,16 @@ DIRS += [
     'filepicker',
     'filewatcher',
     'finalizationwitness',
     'formautofill',
     'find',
     'gfx',
     'jsdownloads',
     'lz4',
-    'narrate',
     'mediasniffer',
     'microformats',
     'osfile',
     'parentalcontrols',
     'passwordmgr',
     'perf',
     'perfmonitoring',
     'places',
@@ -63,17 +62,17 @@ DIRS += [
     'utils',
     'urlformatter',
     'viewconfig',
     'workerloader',
     'xulstore'
 ]
 
 if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
-    DIRS += ['viewsource'];
+    DIRS += ['narrate', 'viewsource'];
 
     if CONFIG['NS_PRINTING']:
         DIRS += ['printing']
 
 if CONFIG['MOZ_CRASHREPORTER']:
     DIRS += ['crashes']
 
 if CONFIG['MOZ_SOCIAL']:
--- a/toolkit/components/places/nsINavHistoryService.idl
+++ b/toolkit/components/places/nsINavHistoryService.idl
@@ -162,16 +162,35 @@ interface nsINavHistoryResultNode : nsIS
   readonly attribute ACString pageGuid;
 
   /**
    * The unique ID associated with the bookmark. It returns an empty string
    * if the result node is not associated with a bookmark, a folder or a
    * separator.
    */
   readonly attribute ACString bookmarkGuid;
+
+  /**
+   * The unique ID associated with the history visit. For node types other than
+   * history visit nodes, this value is -1.
+   */
+  readonly attribute long long visitId;
+
+  /**
+   * The unique ID associated with visit node which was the referrer of this
+   * history visit. For node types other than history visit nodes, or visits
+   * without any known referrer, this value is -1.
+   */
+  readonly attribute long long fromVisitId;
+
+  /**
+   * The transition type associated with this visit. For node types other than
+   * history visit nodes, this value is 0.
+   */
+  readonly attribute unsigned long visitType;
 };
 
 
 /**
  * Base class for container results. This includes all types of groupings.
  * Bookmark folders and places queries will be QueryResultNodes which extends
  * these items.
  */
--- a/toolkit/components/places/nsNavBookmarks.cpp
+++ b/toolkit/components/places/nsNavBookmarks.cpp
@@ -17,20 +17,20 @@
 #include "prprf.h"
 #include "mozilla/storage.h"
 
 #include "GeckoProfiler.h"
 
 using namespace mozilla;
 
 // These columns sit to the right of the kGetInfoIndex_* columns.
-const int32_t nsNavBookmarks::kGetChildrenIndex_Guid = 15;
-const int32_t nsNavBookmarks::kGetChildrenIndex_Position = 16;
-const int32_t nsNavBookmarks::kGetChildrenIndex_Type = 17;
-const int32_t nsNavBookmarks::kGetChildrenIndex_PlaceID = 18;
+const int32_t nsNavBookmarks::kGetChildrenIndex_Guid = 18;
+const int32_t nsNavBookmarks::kGetChildrenIndex_Position = 19;
+const int32_t nsNavBookmarks::kGetChildrenIndex_Type = 20;
+const int32_t nsNavBookmarks::kGetChildrenIndex_PlaceID = 21;
 
 using namespace mozilla::places;
 
 PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsNavBookmarks, gBookmarksService)
 
 #define BOOKMARKS_ANNO_PREFIX "bookmarks/"
 #define BOOKMARKS_TOOLBAR_FOLDER_ANNO NS_LITERAL_CSTRING(BOOKMARKS_ANNO_PREFIX "toolbarFolder")
 #define FEED_URI_ANNO NS_LITERAL_CSTRING("livemark/feedURI")
@@ -957,18 +957,18 @@ nsNavBookmarks::GetDescendantChildren(in
     // Select all children of a given folder, sorted by position.
     // This is a LEFT JOIN because not all bookmarks types have a place.
     // We construct a result where the first columns exactly match
     // kGetInfoIndex_* order, and additionally contains columns for position,
     // item_child, and folder_child from moz_bookmarks.
     nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
       "SELECT h.id, h.url, IFNULL(b.title, h.title), h.rev_host, h.visit_count, "
              "h.last_visit_date, f.url, b.id, b.dateAdded, b.lastModified, "
-             "b.parent, null, h.frecency, h.hidden, h.guid, b.guid, "
-             "b.position, b.type, b.fk "
+             "b.parent, null, h.frecency, h.hidden, h.guid, null, null, null, "
+             "b.guid, b.position, b.type, b.fk "
       "FROM moz_bookmarks b "
       "LEFT JOIN moz_places h ON b.fk = h.id "
       "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
       "WHERE b.parent = :parent "
       "ORDER BY b.position ASC"
     );
     NS_ENSURE_STATE(stmt);
     mozStorageStatementScoper scoper(stmt);
@@ -1630,18 +1630,18 @@ nsNavBookmarks::QueryFolderChildren(
   // Select all children of a given folder, sorted by position.
   // This is a LEFT JOIN because not all bookmarks types have a place.
   // We construct a result where the first columns exactly match those returned
   // by mDBGetURLPageInfo, and additionally contains columns for position,
   // item_child, and folder_child from moz_bookmarks.
   nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
     "SELECT h.id, h.url, IFNULL(b.title, h.title), h.rev_host, h.visit_count, "
            "h.last_visit_date, f.url, b.id, b.dateAdded, b.lastModified, "
-           "b.parent, null, h.frecency, h.hidden, h.guid, b.guid, "
-           "b.position, b.type, b.fk "
+           "b.parent, null, h.frecency, h.hidden, h.guid, null, null, null, "
+           "b.guid, b.position, b.type, b.fk "
     "FROM moz_bookmarks b "
     "LEFT JOIN moz_places h ON b.fk = h.id "
     "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
     "WHERE b.parent = :parent "
     "ORDER BY b.position ASC"
   );
   NS_ENSURE_STATE(stmt);