Bug 1517837 - Move web replay tests to their own directory, r=lsmyth.
☠☠ backed out by 5e5b06dcc0c0 ☠ ☠
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 15 Jan 2019 05:38:46 -1000
changeset 454011 a0b8e8c08c8d2fe95c24c26e2160ce57077355fe
parent 454010 41184f42f451ae006abb9de0033f6c870d7ab05e
child 454012 5101144bde6a5c05419f4f3b2925a15ca696b1a1
push id35383
push userdvarga@mozilla.com
push dateWed, 16 Jan 2019 04:51:20 +0000
treeherdermozilla-central@e4ac2508e8ed [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsmyth
bugs1517837
milestone66.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
Bug 1517837 - Move web replay tests to their own directory, r=lsmyth.
.eslintignore
devtools/client/debugger/new/test/mochitest/browser.ini
devtools/client/debugger/new/test/mochitest/browser_dbg-console.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-01.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-02.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-03.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-04.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-05.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_console_warp-01.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_console_warp-02.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_record.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_recovery-01.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-01.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-02.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-03.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-01.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-02.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-03.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-04.js
devtools/client/debugger/new/test/mochitest/examples/doc_rr_basic.html
devtools/client/debugger/new/test/mochitest/examples/doc_rr_continuous.html
devtools/client/debugger/new/test/mochitest/examples/doc_rr_error.html
devtools/client/debugger/new/test/mochitest/examples/doc_rr_logs.html
devtools/client/debugger/new/test/mochitest/examples/doc_rr_recovery.html
devtools/client/debugger/new/test/mochitest/head.js
devtools/client/debugger/new/test/mochitest/helpers.js
devtools/client/webreplay/mochitest/browser.ini
devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-01.js
devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-02.js
devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-03.js
devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-04.js
devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-05.js
devtools/client/webreplay/mochitest/browser_dbg_rr_console_warp-01.js
devtools/client/webreplay/mochitest/browser_dbg_rr_console_warp-02.js
devtools/client/webreplay/mochitest/browser_dbg_rr_record.js
devtools/client/webreplay/mochitest/browser_dbg_rr_recovery-01.js
devtools/client/webreplay/mochitest/browser_dbg_rr_replay-01.js
devtools/client/webreplay/mochitest/browser_dbg_rr_replay-02.js
devtools/client/webreplay/mochitest/browser_dbg_rr_replay-03.js
devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-01.js
devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-02.js
devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-03.js
devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-04.js
devtools/client/webreplay/mochitest/examples/doc_rr_basic.html
devtools/client/webreplay/mochitest/examples/doc_rr_continuous.html
devtools/client/webreplay/mochitest/examples/doc_rr_error.html
devtools/client/webreplay/mochitest/examples/doc_rr_logs.html
devtools/client/webreplay/mochitest/examples/doc_rr_recovery.html
devtools/client/webreplay/mochitest/head.js
devtools/client/webreplay/moz.build
--- a/.eslintignore
+++ b/.eslintignore
@@ -101,16 +101,17 @@ devtools/client/storage/test/*.html
 !devtools/client/storage/test/storage-unsecured-iframe-usercontextid.html
 devtools/server/tests/browser/storage-*.html
 !devtools/server/tests/browser/storage-unsecured-iframe.html
 devtools/server/tests/browser/stylesheets-nested-iframes.html
 devtools/client/shared/webpack/shims/test/test_clipboard.html
 devtools/shared/qrcode/tests/mochitest/test_decode.html
 devtools/shared/tests/mochitest/*.html
 devtools/shared/webconsole/test/test_*.html
+devtools/client/webreplay/mochitest/examples/*.html
 
 # Soon to be removed, the new/ directory is explicitly excluded below due to
 # also being an imported repository.
 devtools/client/debugger/**
 
 # Ignore devtools imported repositories
 devtools/client/debugger/new/**
 devtools/client/shared/components/reps/**
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -651,21 +651,16 @@ support-files =
   examples/script-mutate.js
   examples/script-switching-02.js
   examples/script-switching-01.js
   examples/times2.js
   examples/doc-windowless-workers.html
   examples/simple-worker.js
   examples/doc-event-handler.html
   examples/doc-eval-throw.html
-  examples/doc_rr_basic.html
-  examples/doc_rr_continuous.html
-  examples/doc_rr_logs.html
-  examples/doc_rr_recovery.html
-  examples/doc_rr_error.html
 
 [browser_dbg-asm.js]
 [browser_dbg-async-stepping.js]
 [browser_dbg-sourcemapped-breakpoint-console.js]
 skip-if = (os == "win" && ccov) # Bug 1453549
 [browser_dbg-xhr-breakpoints.js]
 [browser_dbg-xhr-run-to-completion.js]
 [browser_dbg-scroll-run-to-completion.js]
@@ -770,41 +765,8 @@ skip-if = os == "win"
 [browser_dbg-toggling-tools.js]
 [browser_dbg-react-app.js]
 skip-if = os == "win"
 [browser_dbg-wasm-sourcemaps.js]
 skip-if = true
 [browser_dbg-windowless-workers.js]
 [browser_dbg-event-handler.js]
 [browser_dbg-eval-throw.js]
-[browser_dbg_rr_breakpoints-01.js]
-skip-if = true # bug 1513057 os != "mac" || debug || !nightly_build
-[browser_dbg_rr_breakpoints-02.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_breakpoints-03.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_breakpoints-04.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_breakpoints-05.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_record.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_stepping-01.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_stepping-02.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_stepping-03.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_stepping-04.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_recovery-01.js]
-skip-if = true # See bug 1481009
-[browser_dbg_rr_replay-01.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_replay-02.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_replay-03.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_console_warp-01.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-[browser_dbg_rr_console_warp-02.js]
-skip-if = true # os != "mac" || debug || !nightly_build
-
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-console.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-console.js
@@ -1,16 +1,16 @@
 add_task(async function() {
   Services.prefs.setBoolPref("devtools.toolbox.splitconsoleEnabled", true);
   const dbg = await initDebugger("doc-script-switching.html", "switching-01");
 
   await selectSource(dbg, "switching-01");
 
   // open the console
-  await getSplitConsole(dbg);
+  await getDebuggerSplitConsole(dbg);
   ok(dbg.toolbox.splitConsole, "Split console is shown.");
 
   // close the console
   await clickElement(dbg, "codeMirror");
   // First time to focus out of text area
   pressKey(dbg, "Escape");
 
   // Second time to hide console
--- a/devtools/client/debugger/new/test/mochitest/head.js
+++ b/devtools/client/debugger/new/test/mochitest/head.js
@@ -42,221 +42,21 @@ Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/debugger/new/test/mochitest/helpers.js",
   this
 );
 
 const EXAMPLE_URL =
   "http://example.com/browser/devtools/client/debugger/new/test/mochitest/examples/";
 
 
-async function waitUntilPredicate(predicate) {
-  let result;
-  await waitUntil(() => {
-    result = predicate();
-    return result;
-  })
-
-  return result;
-}
-
 // NOTE: still experimental, the screenshots might not be exactly correct
 async function takeScreenshot(dbg) {
   let canvas = dbg.win.document.createElementNS(
     "http://www.w3.org/1999/xhtml",
     "html:canvas"
   );
   let context = canvas.getContext("2d");
   canvas.width = dbg.win.innerWidth;
   canvas.height = dbg.win.innerHeight;
   context.drawWindow(dbg.win, 0, 0, canvas.width, canvas.height, "white");
   await waitForTime(1000);
   dump(`[SCREENSHOT] ${canvas.toDataURL()}\n`);
 }
-
-// Attach a debugger to a tab, returning a promise that resolves with the
-// debugger's toolbox.
-async function attachDebugger(tab) {
-  let target = await TargetFactory.forTab(tab);
-  let toolbox = await gDevTools.showToolbox(target, "jsdebugger");
-  return toolbox;
-}
-
-async function attachRecordingDebugger(url, { waitForRecording } = { waitForRecording: false }) {
-  let tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
-  gBrowser.selectedTab = tab;
-  openTrustedLinkIn(EXAMPLE_URL + url, "current");
-  
-  if (waitForRecording) {
-    await once(Services.ppmm, "RecordingFinished");
-  }
-  const toolbox = await attachDebugger(tab);
-  const dbg = createDebuggerContext(toolbox)
-  const threadClient = dbg.toolbox.threadClient;
-
-  await threadClient.interrupt();
-  return {...dbg, tab, threadClient};
-}
-
-
-// Return a promise with a reference to jsterm, opening the split
-// console if necessary.  This cleans up the split console pref so
-// it won't pollute other tests.
-async function getSplitConsole(dbg) {
-  const { toolbox, win } = dbg;
-
-  if (!win) {
-    win = toolbox.win;
-  }
-
-  if (!toolbox.splitConsole) {
-    pressKey(dbg, "Escape");
-  }
-
-  await toolbox.openSplitConsole();
-  return toolbox.getPanel("webconsole");
-}
-
-
-// Return a promise that resolves when a breakpoint has been set.
-async function setBreakpoint(threadClient, expectedFile, lineno) {
-  let {sources} = await threadClient.getSources();
-  ok(sources.length == 1, "Got one source");
-  ok(RegExp(expectedFile).test(sources[0].url), "Source is " + expectedFile);
-  let sourceClient = threadClient.source(sources[0]);
-  await sourceClient.setBreakpoint({ line: lineno });
-}
-
-function resumeThenPauseAtLineFunctionFactory(method) {
-  return async function(threadClient, lineno) {
-    threadClient[method]();
-    await threadClient.addOneTimeListener("paused", async function(event, packet) {
-      let {frames} = await threadClient.getFrames(0, 1);
-      let frameLine = frames[0] ? frames[0].where.line : undefined;
-      ok(frameLine == lineno, "Paused at line " + frameLine + " expected " + lineno);
-    });
-  };
-}
-
-// Define various methods that resume a thread in a specific way and ensure it
-// pauses at a specified line.
-var rewindToLine = resumeThenPauseAtLineFunctionFactory("rewind");
-var resumeToLine = resumeThenPauseAtLineFunctionFactory("resume");
-var reverseStepOverToLine = resumeThenPauseAtLineFunctionFactory("reverseStepOver");
-var stepOverToLine = resumeThenPauseAtLineFunctionFactory("stepOver");
-var reverseStepInToLine = resumeThenPauseAtLineFunctionFactory("reverseStepIn");
-var stepInToLine = resumeThenPauseAtLineFunctionFactory("stepIn");
-var reverseStepOutToLine = resumeThenPauseAtLineFunctionFactory("reverseStepOut");
-var stepOutToLine = resumeThenPauseAtLineFunctionFactory("stepOut");
-
-// Return a promise that resolves with the result of a thread evaluating a
-// string in the topmost frame.
-async function evaluateInTopFrame(threadClient, text) {
-  let {frames} = await threadClient.getFrames(0, 1);
-  ok(frames.length == 1, "Got one frame");
-  let response = await threadClient.eval(frames[0].actor, text);
-  ok(response.type == "resumed", "Got resume response from eval");
-  let rval;
-  await threadClient.addOneTimeListener("paused", function(event, packet) {
-    ok(packet.type == "paused" &&
-       packet.why.type == "clientEvaluated" &&
-       "return" in packet.why.frameFinished, "Eval returned a value");
-    rval = packet.why.frameFinished["return"];
-  });
-  return (rval.type == "undefined") ? undefined : rval;
-}
-
-// Return a promise that resolves when a thread evaluates a string in the
-// topmost frame, ensuring the result matches the expected value.
-async function checkEvaluateInTopFrame(threadClient, text, expected) {
-  let rval = await evaluateInTopFrame(threadClient, text);
-  ok(rval == expected, "Eval returned " + expected);
-}
-
-// Return a promise that resolves when a thread evaluates a string in the
-// topmost frame, with the result throwing an exception.
-async function checkEvaluateInTopFrameThrows(threadClient, text) {
-  let {frames} = await threadClient.getFrames(0, 1);
-  ok(frames.length == 1, "Got one frame");
-  let response = await threadClient.eval(frames[0].actor, text);
-  ok(response.type == "resumed", "Got resume response from eval");
-  await threadClient.addOneTimeListener("paused", function(event, packet) {
-    ok(packet.type == "paused" &&
-       packet.why.type == "clientEvaluated" &&
-       "throw" in packet.why.frameFinished, "Eval threw an exception");
-  });
-}
-
-// Return a pathname that can be used for a new recording file.
-function newRecordingFile() {
-  ChromeUtils.import("resource://gre/modules/osfile.jsm", this);
-  return OS.Path.join(OS.Constants.Path.tmpDir,
-                      "MochitestRecording" + Math.round(Math.random() * 1000000000));
-}
-
-
-async function warpToMessage(hud, threadClient, text) {
-  let messages = await waitForMessages(hud, text);
-  ok(messages.length == 1, "Found one message");
-  let message = messages.pop();
-
-  let menuPopup = await openConsoleContextMenu(hud, message);
-  console.log(`.>> menu`, menuPopup);
-
-
-  let timeWarpItem = menuPopup.querySelector("#console-menu-time-warp");
-  ok(timeWarpItem, "Time warp menu item is available");
-
-  timeWarpItem.click();
-
-  await Promise.all([
-    hideConsoleContextMenu(hud),
-    once(Services.ppmm, "TimeWarpFinished"),
-    waitForThreadEvents(threadClient, 'paused')
-  ]);
-
-  messages = findMessages(hud, "", ".paused");
-  ok(messages.length == 1, "Found one paused message");
-
-  return message;
-}
-
-
-function findMessage(hud, text, selector = ".message") {
-  return findMessages(hud, text, selector)[0]
-}
-
-function findMessages(hud, text, selector = ".message") {
-  const messages = hud.ui.outputNode.querySelectorAll(selector);
-  const elements = Array.prototype.filter.call(
-    messages,
-    (el) => el.textContent.includes(text)
-  );
-
-  if (elements.length == 0) {
-    return null;
-  }
-
-  return elements;
-}
-
-function waitForMessages(hud, text, selector = ".message") {
-  return waitUntilPredicate(() => findMessages(hud, text, selector))
-}
-
-async function openConsoleContextMenu(hud, element) {
-  const onConsoleMenuOpened = hud.ui.consoleOutput.once("menu-open");
-  synthesizeContextMenuEvent(element);
-  await onConsoleMenuOpened;
-  const doc = hud.ui.consoleOutput.owner.chromeWindow.document;
-  return doc.getElementById("webconsole-menu");
-}
-
-function hideConsoleContextMenu(hud) {
-  const doc = hud.ui.consoleOutput.owner.chromeWindow.document;
-  const popup = doc.getElementById("webconsole-menu");
-  if (!popup) {
-    return Promise.resolve();
-  }
-
-  const onPopupHidden = once(popup, "popuphidden");
-  popup.hidePopup();
-  return onPopupHidden;
-}
--- a/devtools/client/debugger/new/test/mochitest/helpers.js
+++ b/devtools/client/debugger/new/test/mochitest/helpers.js
@@ -1457,8 +1457,80 @@ async function editExpression(dbg, input
   dblClickElement(dbg, "expressionNode", 1);
   // Position cursor reliably at the end of the text.
   pressKey(dbg, "End");
   type(dbg, input);
   const evaluated = waitForDispatch(dbg, "EVALUATE_EXPRESSIONS");
   pressKey(dbg, "Enter");
   await evaluated;
 }
+
+async function waitUntilPredicate(predicate) {
+  let result;
+  await waitUntil(() => {
+    result = predicate();
+    return result;
+  })
+
+  return result;
+}
+
+// Return a promise with a reference to jsterm, opening the split
+// console if necessary.  This cleans up the split console pref so
+// it won't pollute other tests.
+async function getDebuggerSplitConsole(dbg) {
+  const { toolbox, win } = dbg;
+
+  if (!win) {
+    win = toolbox.win;
+  }
+
+  if (!toolbox.splitConsole) {
+    pressKey(dbg, "Escape");
+  }
+
+  await toolbox.openSplitConsole();
+  return toolbox.getPanel("webconsole");
+}
+
+async function openConsoleContextMenu(hud, element) {
+  const onConsoleMenuOpened = hud.ui.consoleOutput.once("menu-open");
+  synthesizeContextMenuEvent(element);
+  await onConsoleMenuOpened;
+  const doc = hud.ui.consoleOutput.owner.chromeWindow.document;
+  return doc.getElementById("webconsole-menu");
+}
+
+function hideConsoleContextMenu(hud) {
+  const doc = hud.ui.consoleOutput.owner.chromeWindow.document;
+  const popup = doc.getElementById("webconsole-menu");
+  if (!popup) {
+    return Promise.resolve();
+  }
+
+  const onPopupHidden = once(popup, "popuphidden");
+  popup.hidePopup();
+  return onPopupHidden;
+}
+
+// Return a promise that resolves with the result of a thread evaluating a
+// string in the topmost frame.
+async function evaluateInTopFrame(threadClient, text) {
+  const {frames} = await threadClient.getFrames(0, 1);
+  ok(frames.length == 1, "Got one frame");
+  const response = await threadClient.eval(frames[0].actor, text);
+  ok(response.type == "resumed", "Got resume response from eval");
+  let rval;
+  await threadClient.addOneTimeListener("paused", function(event, packet) {
+    ok(packet.type == "paused" &&
+       packet.why.type == "clientEvaluated" &&
+       "return" in packet.why.frameFinished, "Eval returned a value");
+    rval = packet.why.frameFinished.return;
+  });
+  return (rval.type == "undefined") ? undefined : rval;
+}
+
+// Return a promise that resolves when a thread evaluates a string in the
+// topmost frame, ensuring the result matches the expected value.
+async function checkEvaluateInTopFrame(threadClient, text, expected) {
+  const rval = await evaluateInTopFrame(threadClient, text);
+  ok(rval == expected, "Eval returned " + expected);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/webreplay/mochitest/browser.ini
@@ -0,0 +1,38 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+
+# Feel free to set this to true if an impending change breaks Web Replay and
+# fixing it would be annoying or difficult. This will avoid running all tests
+# that use Web Replay; we don't want this experimental feature to impede
+# development in the rest of Gecko.
+#
+# Please file a bug against the 'Core > Web Replay' component if you do so,
+# so that the problem can be fixed and tests reenabled.
+skip-if = os != "mac" || debug || !nightly_build
+
+support-files =
+  head.js
+  examples/doc_rr_basic.html
+  examples/doc_rr_continuous.html
+  examples/doc_rr_logs.html
+  examples/doc_rr_recovery.html
+  examples/doc_rr_error.html
+
+[browser_dbg_rr_breakpoints-01.js]
+[browser_dbg_rr_breakpoints-02.js]
+[browser_dbg_rr_breakpoints-03.js]
+[browser_dbg_rr_breakpoints-04.js]
+[browser_dbg_rr_breakpoints-05.js]
+[browser_dbg_rr_record.js]
+[browser_dbg_rr_stepping-01.js]
+[browser_dbg_rr_stepping-02.js]
+[browser_dbg_rr_stepping-03.js]
+[browser_dbg_rr_stepping-04.js]
+[browser_dbg_rr_recovery-01.js]
+skip-if = true # See bug 1481009
+[browser_dbg_rr_replay-01.js]
+[browser_dbg_rr_replay-02.js]
+[browser_dbg_rr_replay-03.js]
+[browser_dbg_rr_console_warp-01.js]
+[browser_dbg_rr_console_warp-02.js]
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-01.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-01.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-01.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-01.js
@@ -1,17 +1,20 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test basic breakpoint functionality in web replay.
-async function test() {
-  waitForExplicitFinish();
-
+add_task(async function() {
   const dbg = await attachRecordingDebugger(
     "doc_rr_basic.html",
     { waitForRecording: true }
   );
   const {threadClient, tab, toolbox} = dbg;
 
   await setBreakpoint(threadClient, "doc_rr_basic.html", 21);
 
@@ -33,10 +36,9 @@ async function test() {
   await checkEvaluateInTopFrame(threadClient, "number", 8);
   await resumeToLine(threadClient, 21);
   await checkEvaluateInTopFrame(threadClient, "number", 9);
   await resumeToLine(threadClient, 21);
   await checkEvaluateInTopFrame(threadClient, "number", 10);
 
   await toolbox.closeToolbox();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-02.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-02.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-02.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-02.js
@@ -1,25 +1,28 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test unhandled divergence while evaluating at a breakpoint with Web Replay.
-async function test() {
-  waitForExplicitFinish();
-
-  const dbg = await attachRecordingDebugger("doc_rr_basic.html", { waitForRecording: true });
+add_task(async function() {
+  const dbg = await attachRecordingDebugger("doc_rr_basic.html",
+                                            { waitForRecording: true });
   const {threadClient, tab, toolbox} = dbg;
 
   await setBreakpoint(threadClient, "doc_rr_basic.html", 21);
   await rewindToLine(threadClient, 21);
   await checkEvaluateInTopFrame(threadClient, "number", 10);
   await checkEvaluateInTopFrameThrows(threadClient, "window.alert(3)");
   await checkEvaluateInTopFrame(threadClient, "number", 10);
   await checkEvaluateInTopFrameThrows(threadClient, "window.alert(3)");
   await checkEvaluateInTopFrame(threadClient, "number", 10);
   await checkEvaluateInTopFrame(threadClient, "testStepping2()", undefined);
 
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-03.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-03.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-03.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-03.js
@@ -1,27 +1,31 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test some issues when stepping around after hitting a breakpoint while recording.
-async function test() {
-  waitForExplicitFinish();
-
+add_task(async function() {
   const dbg = await attachRecordingDebugger("doc_rr_continuous.html");
   const {threadClient, tab, toolbox} = dbg;
 
   await threadClient.interrupt();
   await setBreakpoint(threadClient, "doc_rr_continuous.html", 19);
   await resumeToLine(threadClient, 19);
   await reverseStepOverToLine(threadClient, 18);
-  await checkEvaluateInTopFrame(threadClient, "SpecialPowers.Cu.recordReplayDirective(/* AlwaysTakeTemporarySnapshots */ 3)", undefined);
+  await checkEvaluateInTopFrame(threadClient,
+    "SpecialPowers.Cu.recordReplayDirective(/* AlwaysTakeTemporarySnapshots */ 3)",
+    undefined);
   await stepInToLine(threadClient, 22);
   await setBreakpoint(threadClient, "doc_rr_continuous.html", 24);
   await resumeToLine(threadClient, 24);
   await setBreakpoint(threadClient, "doc_rr_continuous.html", 22);
   await rewindToLine(threadClient, 22);
 
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-04.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-04.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-04.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-04.js
@@ -1,33 +1,35 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test navigating back to earlier breakpoints while recording, then resuming
 // recording.
-async function test() {
-  waitForExplicitFinish();
-
+add_task(async function() {
   const dbg = await attachRecordingDebugger("doc_rr_continuous.html");
   const {threadClient, tab, toolbox} = dbg;
 
   await setBreakpoint(threadClient, "doc_rr_continuous.html", 14);
   await resumeToLine(threadClient, 14);
-  let value = await evaluateInTopFrame(threadClient, "number");
+  const value = await evaluateInTopFrame(threadClient, "number");
   await resumeToLine(threadClient, 14);
   await checkEvaluateInTopFrame(threadClient, "number", value + 1);
   await rewindToLine(threadClient, 14);
   await checkEvaluateInTopFrame(threadClient, "number", value);
   await resumeToLine(threadClient, 14);
   await checkEvaluateInTopFrame(threadClient, "number", value + 1);
   await resumeToLine(threadClient, 14);
   await checkEvaluateInTopFrame(threadClient, "number", value + 2);
   await resumeToLine(threadClient, 14);
   await checkEvaluateInTopFrame(threadClient, "number", value + 3);
   await rewindToLine(threadClient, 14);
   await checkEvaluateInTopFrame(threadClient, "number", value + 2);
 
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-05.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-05.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-05.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-05.js
@@ -1,30 +1,32 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test hitting breakpoints when rewinding past the point where the breakpoint
 // script was created.
-async function test() {
-  waitForExplicitFinish();
-
+add_task(async function() {
   const dbg = await attachRecordingDebugger(
-    "doc_rr_basic.html", 
+    "doc_rr_basic.html",
     { waitForRecording: true }
   );
 
   const {threadClient, tab, toolbox} = dbg;
 
   // Rewind to the beginning of the recording.
   await rewindToLine(threadClient, undefined);
 
   await setBreakpoint(threadClient, "doc_rr_basic.html", 21);
   await resumeToLine(threadClient, 21);
   await checkEvaluateInTopFrame(threadClient, "number", 1);
   await resumeToLine(threadClient, 21);
   await checkEvaluateInTopFrame(threadClient, "number", 2);
 
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_console_warp-01.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_console_warp-01.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_console_warp-01.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_console_warp-01.js
@@ -1,53 +1,39 @@
 /* -*- 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/ */
-
-// This functionality was copied from devtools/client/webconsole/test/mochitest/head.js,
-// since this test straddles both the web console and the debugger. I couldn't
-// figure out how to load that script directly here.
-function waitForThreadEvents(threadClient, eventName) {
-  info(`Waiting for thread event '${eventName}' to fire.`);
+/* eslint-disable no-undef */
 
-  return new Promise(function(resolve, reject) {
-    threadClient.addListener(eventName, function onEvent(eventName, ...args) {
-      info(`Thread event '${eventName}' fired.`);
-      threadClient.removeListener(eventName, onEvent);
-      resolve.apply(resolve, args);
-    });
-  });
-}
+"use strict";
 
+// To disable all Web Replay tests, see browser.ini
 
 // Test basic console time warping functionality in web replay.
-async function test() {
-  waitForExplicitFinish();
-
+add_task(async function() {
   const dbg = await attachRecordingDebugger(
-    "doc_rr_error.html", 
+    "doc_rr_error.html",
     { waitForRecording: true }
   );
 
   const {tab, toolbox, threadClient} = dbg;
-  const console = await getSplitConsole(dbg);
+  const console = await getDebuggerSplitConsole(dbg);
   const hud = console.hud;
 
-  await warpToMessage(hud, threadClient, "Number 5");
+  await warpToMessage(hud, dbg, "Number 5");
   await threadClient.interrupt();
 
   await checkEvaluateInTopFrame(threadClient, "number", 5);
 
   // Initially we are paused inside the 'new Error()' call on line 19. The
   // first reverse step takes us to the start of that line.
   await reverseStepOverToLine(threadClient, 19);
   await reverseStepOverToLine(threadClient, 18);
   await setBreakpoint(threadClient, "doc_rr_error.html", 12);
   await rewindToLine(threadClient, 12);
   await checkEvaluateInTopFrame(threadClient, "number", 4);
   await resumeToLine(threadClient, 12);
   await checkEvaluateInTopFrame(threadClient, "number", 5);
 
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_console_warp-02.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_console_warp-02.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_console_warp-02.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_console_warp-02.js
@@ -1,48 +1,33 @@
 /* -*- 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/ */
-
-
-// This functionality was copied from devtools/client/webconsole/test/mochitest/head.js,
-// since this test straddles both the web console and the debugger. I couldn't
-// figure out how to load that script directly here.
-function waitForThreadEvents(threadClient, eventName) {
-  info(`Waiting for thread event '${eventName}' to fire.`);
+/* eslint-disable no-undef */
 
-  return new Promise(function(resolve, reject) {
-    threadClient.addListener(eventName, function onEvent(eventName, ...args) {
-      info(`Thread event '${eventName}' fired.`);
-      threadClient.removeListener(eventName, onEvent);
-      resolve.apply(resolve, args);
-    });
-  });
-}
+"use strict";
 
+// To disable all Web Replay tests, see browser.ini
 
 // Test basic console time warping functionality in web replay.
-async function test() {
-  waitForExplicitFinish();
-
+add_task(async function() {
   const dbg = await attachRecordingDebugger(
-    "doc_rr_logs.html", 
+    "doc_rr_logs.html",
     { waitForRecording: true }
   );
 
   const {tab, toolbox, threadClient} = dbg;
-  const console = await getSplitConsole(dbg);
+  const console = await getDebuggerSplitConsole(dbg);
   const hud = console.hud;
 
-  let message = await warpToMessage(hud, threadClient, "number: 1");
+  let message = await warpToMessage(hud, dbg, "number: 1");
   ok(!message.classList.contains("paused-before"), "paused before message is not shown");
 
   await stepOverToLine(threadClient, 18);
   await reverseStepOverToLine(threadClient, 17);
 
-  message = findMessage(hud, "number: 1")
+  message = findMessage(hud, "number: 1");
   ok(message.classList.contains("paused-before"), "paused before message is shown");
 
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_record.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_record.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_record.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_record.js
@@ -1,19 +1,21 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test basic recording of a tab without any debugging.
-async function test() {
-  waitForExplicitFinish();
-
-  var recordingTab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+add_task(async function() {
+  const recordingTab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
   gBrowser.selectedTab = recordingTab;
   openTrustedLinkIn(EXAMPLE_URL + "doc_rr_basic.html", "current");
   await once(Services.ppmm, "RecordingFinished");
 
   await gBrowser.removeTab(recordingTab);
 
   ok(true, "Finished");
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_recovery-01.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_recovery-01.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_recovery-01.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_recovery-01.js
@@ -1,28 +1,33 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test basic recovery of crashed child processes in web replay.
-async function test() {
-  waitForExplicitFinish();
-
-  let tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+add_task(async function() {
+  const tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
   gBrowser.selectedTab = tab;
   openTrustedLinkIn(EXAMPLE_URL + "doc_rr_recovery.html", "current");
   await once(Services.ppmm, "RecordingFinished");
 
-  let toolbox = await attachDebugger(tab), client = toolbox.threadClient;
+  const toolbox = await attachDebugger(tab), client = toolbox.threadClient;
   await client.interrupt();
   await setBreakpoint(client, "doc_rr_recovery.html", 21);
   await rewindToLine(client, 21);
-  await checkEvaluateInTopFrame(client, "SpecialPowers.Cu.recordReplayDirective(/* CrashSoon */ 1)", undefined);
+  await checkEvaluateInTopFrame(client,
+    "SpecialPowers.Cu.recordReplayDirective(/* CrashSoon */ 1)",
+    undefined);
   await stepOverToLine(client, 22);
   await stepOverToLine(client, 23);
-  await checkEvaluateInTopFrame(client, "SpecialPowers.Cu.recordReplayDirective(/* CrashSoon */ 1); " +
-                                        "SpecialPowers.Cu.recordReplayDirective(/* MaybeCrash */ 2)", undefined);
-
+  await checkEvaluateInTopFrame(client,
+    "SpecialPowers.Cu.recordReplayDirective(/* CrashSoon */ 1); " +
+    "SpecialPowers.Cu.recordReplayDirective(/* MaybeCrash */ 2)",
+    undefined);
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-01.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_replay-01.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-01.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_replay-01.js
@@ -1,39 +1,43 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Basic test for saving a recording and then replaying it in a new tab.
-async function test() {
-  waitForExplicitFinish();
-
-  let recordingFile = newRecordingFile();
-  let recordingTab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+add_task(async function() {
+  const recordingFile = newRecordingFile();
+  const recordingTab = BrowserTestUtils.addTab(gBrowser, null,
+                                               { recordExecution: "*" });
   gBrowser.selectedTab = recordingTab;
   openTrustedLinkIn(EXAMPLE_URL + "doc_rr_basic.html", "current");
   await once(Services.ppmm, "RecordingFinished");
 
-  let tabParent = recordingTab.linkedBrowser.frameLoader.tabParent;
+  const tabParent = recordingTab.linkedBrowser.frameLoader.tabParent;
   ok(tabParent, "Found recording tab parent");
   ok(tabParent.saveRecording(recordingFile), "Saved recording");
   await once(Services.ppmm, "SaveRecordingFinished");
 
-  let replayingTab = BrowserTestUtils.addTab(gBrowser, null, { replayExecution: recordingFile });
+  const replayingTab = BrowserTestUtils.addTab(gBrowser, null,
+                                               { replayExecution: recordingFile });
   gBrowser.selectedTab = replayingTab;
   await once(Services.ppmm, "HitRecordingEndpoint");
 
-  let toolbox = await attachDebugger(replayingTab), client = toolbox.threadClient;
+  const toolbox = await attachDebugger(replayingTab), client = toolbox.threadClient;
   await client.interrupt();
   await setBreakpoint(client, "doc_rr_basic.html", 21);
   await rewindToLine(client, 21);
   await checkEvaluateInTopFrame(client, "number", 10);
   await rewindToLine(client, 21);
   await checkEvaluateInTopFrame(client, "number", 9);
   await resumeToLine(client, 21);
   await checkEvaluateInTopFrame(client, "number", 10);
 
   await toolbox.destroy();
   await gBrowser.removeTab(recordingTab);
   await gBrowser.removeTab(replayingTab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-02.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_replay-02.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-02.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_replay-02.js
@@ -1,49 +1,54 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test ending a recording at a breakpoint and then separately replaying to the end.
-async function test() {
+add_task(async function() {
   waitForExplicitFinish();
 
-  let recordingFile = newRecordingFile();
-  let recordingTab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+  const recordingFile = newRecordingFile();
+  const recordingTab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
   gBrowser.selectedTab = recordingTab;
   openTrustedLinkIn(EXAMPLE_URL + "doc_rr_continuous.html", "current");
 
   let toolbox = await attachDebugger(recordingTab), client = toolbox.threadClient;
   await client.interrupt();
   await setBreakpoint(client, "doc_rr_continuous.html", 14);
   await resumeToLine(client, 14);
   await resumeToLine(client, 14);
   await reverseStepOverToLine(client, 13);
-  let lastNumberValue = await evaluateInTopFrame(client, "number");
+  const lastNumberValue = await evaluateInTopFrame(client, "number");
 
-  let tabParent = recordingTab.linkedBrowser.frameLoader.tabParent;
+  const tabParent = recordingTab.linkedBrowser.frameLoader.tabParent;
   ok(tabParent, "Found recording tab parent");
   ok(tabParent.saveRecording(recordingFile), "Saved recording");
   await once(Services.ppmm, "SaveRecordingFinished");
 
   await toolbox.destroy();
   await gBrowser.removeTab(recordingTab);
 
-  let replayingTab = BrowserTestUtils.addTab(gBrowser, null, { replayExecution: recordingFile });
+  const replayingTab = BrowserTestUtils.addTab(gBrowser, null,
+                                               { replayExecution: recordingFile });
   gBrowser.selectedTab = replayingTab;
   await once(Services.ppmm, "HitRecordingEndpoint");
 
   toolbox = await attachDebugger(replayingTab);
   client = toolbox.threadClient;
   await client.interrupt();
   await checkEvaluateInTopFrame(client, "number", lastNumberValue);
   await reverseStepOverToLine(client, 13);
   await setBreakpoint(client, "doc_rr_continuous.html", 14);
   await rewindToLine(client, 14);
   await checkEvaluateInTopFrame(client, "number", lastNumberValue - 1);
   await resumeToLine(client, 14);
   await checkEvaluateInTopFrame(client, "number", lastNumberValue);
 
   await toolbox.destroy();
   await gBrowser.removeTab(replayingTab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-03.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_replay-03.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-03.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_replay-03.js
@@ -1,32 +1,36 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
 
-// Test for saving a recording and then replaying it in a new tab, with rewinding disabled.
-async function test() {
-  waitForExplicitFinish();
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
+// Test for saving a recording and then replaying it in a new tab,
+// with rewinding disabled.
+add_task(async function() {
   await pushPref("devtools.recordreplay.enableRewinding", false);
 
-  let recordingFile = newRecordingFile();
-  let recordingTab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+  const recordingFile = newRecordingFile();
+  const recordingTab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
   gBrowser.selectedTab = recordingTab;
   openTrustedLinkIn(EXAMPLE_URL + "doc_rr_basic.html", "current");
   await once(Services.ppmm, "RecordingFinished");
 
-  let tabParent = recordingTab.linkedBrowser.frameLoader.tabParent;
+  const tabParent = recordingTab.linkedBrowser.frameLoader.tabParent;
   ok(tabParent, "Found recording tab parent");
   ok(tabParent.saveRecording(recordingFile), "Saved recording");
   await once(Services.ppmm, "SaveRecordingFinished");
 
-  let replayingTab = BrowserTestUtils.addTab(gBrowser, null, { replayExecution: recordingFile });
+  const replayingTab = BrowserTestUtils.addTab(gBrowser, null,
+                                               { replayExecution: recordingFile });
   gBrowser.selectedTab = replayingTab;
   await once(Services.ppmm, "HitRecordingEndpoint");
 
   ok(true, "Replayed to end of recording");
 
   await gBrowser.removeTab(recordingTab);
   await gBrowser.removeTab(replayingTab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-01.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-01.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-01.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-01.js
@@ -1,29 +1,31 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test basic step-over/back functionality in web replay.
-async function test() {
-  waitForExplicitFinish();
-
-  let tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+add_task(async function() {
+  const tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
   gBrowser.selectedTab = tab;
   openTrustedLinkIn(EXAMPLE_URL + "doc_rr_basic.html", "current");
   await once(Services.ppmm, "RecordingFinished");
 
-  let toolbox = await attachDebugger(tab), client = toolbox.threadClient;
+  const toolbox = await attachDebugger(tab), client = toolbox.threadClient;
   await client.interrupt();
   await setBreakpoint(client, "doc_rr_basic.html", 21);
   await rewindToLine(client, 21);
   await checkEvaluateInTopFrame(client, "number", 10);
   await reverseStepOverToLine(client, 20);
   await checkEvaluateInTopFrame(client, "number", 9);
   await checkEvaluateInTopFrameThrows(client, "window.alert(3)");
   await stepOverToLine(client, 21);
   await checkEvaluateInTopFrame(client, "number", 10);
 
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-02.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-02.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-02.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-02.js
@@ -1,30 +1,32 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test fixes for some simple stepping bugs.
-async function test() {
-  waitForExplicitFinish();
-
-  let tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+add_task(async function() {
+  const tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
   gBrowser.selectedTab = tab;
   openTrustedLinkIn(EXAMPLE_URL + "doc_rr_basic.html", "current");
   await once(Services.ppmm, "RecordingFinished");
 
-  let toolbox = await attachDebugger(tab), client = toolbox.threadClient;
+  const toolbox = await attachDebugger(tab), client = toolbox.threadClient;
   await client.interrupt();
   await setBreakpoint(client, "doc_rr_basic.html", 22);
   await rewindToLine(client, 22);
   await stepInToLine(client, 25);
   await stepOverToLine(client, 26);
   await stepOverToLine(client, 27);
   await reverseStepInToLine(client, 33);
   await reverseStepOverToLine(client, 32);
   await reverseStepOutToLine(client, 26);
   await reverseStepOverToLine(client, 25);
 
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-03.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-03.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-03.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-03.js
@@ -1,28 +1,30 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Test stepping back while recording, then resuming recording.
-async function test() {
-  waitForExplicitFinish();
-
-  let tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+add_task(async function() {
+  const tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
   gBrowser.selectedTab = tab;
   openTrustedLinkIn(EXAMPLE_URL + "doc_rr_continuous.html", "current");
 
-  let toolbox = await attachDebugger(tab), client = toolbox.threadClient;
+  const toolbox = await attachDebugger(tab), client = toolbox.threadClient;
   await client.interrupt();
   await setBreakpoint(client, "doc_rr_continuous.html", 13);
   await resumeToLine(client, 13);
-  let value = await evaluateInTopFrame(client, "number");
+  const value = await evaluateInTopFrame(client, "number");
   await reverseStepOverToLine(client, 12);
   await checkEvaluateInTopFrame(client, "number", value - 1);
   await resumeToLine(client, 13);
   await resumeToLine(client, 13);
   await checkEvaluateInTopFrame(client, "number", value + 1);
 
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-04.js
rename to devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-04.js
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-04.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_stepping-04.js
@@ -1,23 +1,26 @@
 /* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+// To disable all Web Replay tests, see browser.ini
 
 // Stepping past the beginning or end of a frame should act like a step-out.
-async function test() {
-  waitForExplicitFinish();
-
-  let tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+add_task(async function() {
+  const tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
   gBrowser.selectedTab = tab;
   openTrustedLinkIn(EXAMPLE_URL + "doc_rr_basic.html", "current");
   await once(Services.ppmm, "RecordingFinished");
 
-  let toolbox = await attachDebugger(tab), client = toolbox.threadClient;
+  const toolbox = await attachDebugger(tab), client = toolbox.threadClient;
   await client.interrupt();
   await setBreakpoint(client, "doc_rr_basic.html", 21);
   await rewindToLine(client, 21);
   await checkEvaluateInTopFrame(client, "number", 10);
   await reverseStepOverToLine(client, 20);
   await reverseStepOverToLine(client, 12);
 
   // After reverse-stepping out of the topmost frame we should rewind to the
@@ -33,10 +36,9 @@ async function test() {
 
   // After forward-stepping out of the topmost frame we should run forward to
   // the next breakpoint hit.
   await stepOverToLine(client, 21);
   await checkEvaluateInTopFrame(client, "number", 10);
 
   await toolbox.destroy();
   await gBrowser.removeTab(tab);
-  finish();
-}
+});
rename from devtools/client/debugger/new/test/mochitest/examples/doc_rr_basic.html
rename to devtools/client/webreplay/mochitest/examples/doc_rr_basic.html
rename from devtools/client/debugger/new/test/mochitest/examples/doc_rr_continuous.html
rename to devtools/client/webreplay/mochitest/examples/doc_rr_continuous.html
rename from devtools/client/debugger/new/test/mochitest/examples/doc_rr_error.html
rename to devtools/client/webreplay/mochitest/examples/doc_rr_error.html
rename from devtools/client/debugger/new/test/mochitest/examples/doc_rr_logs.html
rename to devtools/client/webreplay/mochitest/examples/doc_rr_logs.html
rename from devtools/client/debugger/new/test/mochitest/examples/doc_rr_recovery.html
rename to devtools/client/webreplay/mochitest/examples/doc_rr_recovery.html
new file mode 100644
--- /dev/null
+++ b/devtools/client/webreplay/mochitest/head.js
@@ -0,0 +1,144 @@
+/* -*- 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/ */
+/* eslint-disable no-undef */
+
+"use strict";
+
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js",
+  this
+);
+
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/debugger/new/test/mochitest/helpers.js",
+  this
+);
+
+const EXAMPLE_URL =
+  "http://example.com/browser/devtools/client/webreplay/mochitest/examples/";
+
+// Attach a debugger to a tab, returning a promise that resolves with the
+// debugger's toolbox.
+async function attachDebugger(tab) {
+  const target = await TargetFactory.forTab(tab);
+  const toolbox = await gDevTools.showToolbox(target, "jsdebugger");
+  return toolbox;
+}
+
+async function attachRecordingDebugger(url,
+    { waitForRecording } = { waitForRecording: false }) {
+  const tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+  gBrowser.selectedTab = tab;
+  openTrustedLinkIn(EXAMPLE_URL + url, "current");
+
+  if (waitForRecording) {
+    await once(Services.ppmm, "RecordingFinished");
+  }
+  const toolbox = await attachDebugger(tab);
+  const dbg = createDebuggerContext(toolbox);
+  const threadClient = dbg.toolbox.threadClient;
+
+  await threadClient.interrupt();
+  return {...dbg, tab, threadClient};
+}
+
+// Return a promise that resolves when a breakpoint has been set.
+async function setBreakpoint(threadClient, expectedFile, lineno) {
+  const {sources} = await threadClient.getSources();
+  ok(sources.length == 1, "Got one source");
+  ok(RegExp(expectedFile).test(sources[0].url), "Source is " + expectedFile);
+  const sourceClient = threadClient.source(sources[0]);
+  await sourceClient.setBreakpoint({ line: lineno });
+}
+
+function resumeThenPauseAtLineFunctionFactory(method) {
+  return async function(threadClient, lineno) {
+    threadClient[method]();
+    await threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const {frames} = await threadClient.getFrames(0, 1);
+      const frameLine = frames[0] ? frames[0].where.line : undefined;
+      ok(frameLine == lineno, "Paused at line " + frameLine + " expected " + lineno);
+    });
+  };
+}
+
+// Define various methods that resume a thread in a specific way and ensure it
+// pauses at a specified line.
+var rewindToLine = resumeThenPauseAtLineFunctionFactory("rewind");
+var resumeToLine = resumeThenPauseAtLineFunctionFactory("resume");
+var reverseStepOverToLine = resumeThenPauseAtLineFunctionFactory("reverseStepOver");
+var stepOverToLine = resumeThenPauseAtLineFunctionFactory("stepOver");
+var reverseStepInToLine = resumeThenPauseAtLineFunctionFactory("reverseStepIn");
+var stepInToLine = resumeThenPauseAtLineFunctionFactory("stepIn");
+var reverseStepOutToLine = resumeThenPauseAtLineFunctionFactory("reverseStepOut");
+var stepOutToLine = resumeThenPauseAtLineFunctionFactory("stepOut");
+
+// Return a promise that resolves when a thread evaluates a string in the
+// topmost frame, with the result throwing an exception.
+async function checkEvaluateInTopFrameThrows(threadClient, text) {
+  const {frames} = await threadClient.getFrames(0, 1);
+  ok(frames.length == 1, "Got one frame");
+  const response = await threadClient.eval(frames[0].actor, text);
+  ok(response.type == "resumed", "Got resume response from eval");
+  await threadClient.addOneTimeListener("paused", function(event, packet) {
+    ok(packet.type == "paused" &&
+       packet.why.type == "clientEvaluated" &&
+       "throw" in packet.why.frameFinished, "Eval threw an exception");
+  });
+}
+
+// Return a pathname that can be used for a new recording file.
+function newRecordingFile() {
+  ChromeUtils.import("resource://gre/modules/osfile.jsm", this);
+  return OS.Path.join(OS.Constants.Path.tmpDir,
+                      "MochitestRecording" + Math.round(Math.random() * 1000000000));
+}
+
+function findMessage(hud, text, selector = ".message") {
+  return findMessages(hud, text, selector)[0];
+}
+
+function findMessages(hud, text, selector = ".message") {
+  const messages = hud.ui.outputNode.querySelectorAll(selector);
+  const elements = Array.prototype.filter.call(
+    messages,
+    (el) => el.textContent.includes(text)
+  );
+
+  if (elements.length == 0) {
+    return null;
+  }
+
+  return elements;
+}
+
+function waitForMessages(hud, text, selector = ".message") {
+  return waitUntilPredicate(() => findMessages(hud, text, selector));
+}
+
+async function warpToMessage(hud, threadClient, text) {
+  let messages = await waitForMessages(hud, text);
+  ok(messages.length == 1, "Found one message");
+  const message = messages.pop();
+
+  const menuPopup = await openConsoleContextMenu(hud, message);
+  console.log(`.>> menu`, menuPopup);
+
+  const timeWarpItem = menuPopup.querySelector("#console-menu-time-warp");
+  ok(timeWarpItem, "Time warp menu item is available");
+
+  timeWarpItem.click();
+
+  await Promise.all([
+    hideConsoleContextMenu(hud),
+    once(Services.ppmm, "TimeWarpFinished"),
+    waitForThreadEvents(threadClient, "paused"),
+  ]);
+
+  messages = findMessages(hud, "", ".paused");
+  ok(messages.length == 1, "Found one paused message");
+
+  return message;
+}
--- a/devtools/client/webreplay/moz.build
+++ b/devtools/client/webreplay/moz.build
@@ -9,8 +9,10 @@ DIRS += [
 ]
 
 DevToolsModules(
     'menu.js',
 )
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Web Replay')
+
+BROWSER_CHROME_MANIFESTS += [ 'mochitest/browser.ini' ]