Bug 1508287 - Refactor most debugger server test using run_test_with_server to share more code. r=yulia
authorAlexandre Poirot <poirot.alex@gmail.com>
Thu, 22 Nov 2018 15:23:22 +0000
changeset 506967 c56b523e11e6fc73804ede8264aed1045a627ab1
parent 506966 fc10fcd1506648228b059419d4df5c3e895155c6
child 506968 fc126a74993d098fb394a1204877833c458c2570
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyulia
bugs1508287
milestone65.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 1508287 - Refactor most debugger server test using run_test_with_server to share more code. r=yulia There is a lot of code being copy paste in all these tests and as I'm most likely going to change things around them in the near future regarding fission, it would be better if we start sharing more code. After this there is still a couple of copy paste code (but way less!): * breakpoints: wait a paused event and eval a custom script in a sandbox * object grips: set the security.allow_eval_with_system_principal pref, eval stopMe and wait for paused * stepping: use executeOnNextTickAndWaitForPause to eval a custom script and wait for pause while doing this only on next tick There is most likely more to share, but at least this isn't framework code, but now only code specific to the debugger. MozReview-Commit-ID: JgD389cas2j Depends on D12309 Differential Revision: https://phabricator.services.mozilla.com/D12310
devtools/server/tests/unit/head_dbg.js
devtools/server/tests/unit/test_breakpoint-01.js
devtools/server/tests/unit/test_breakpoint-02.js
devtools/server/tests/unit/test_breakpoint-03.js
devtools/server/tests/unit/test_breakpoint-04.js
devtools/server/tests/unit/test_breakpoint-05.js
devtools/server/tests/unit/test_breakpoint-06.js
devtools/server/tests/unit/test_breakpoint-07.js
devtools/server/tests/unit/test_breakpoint-08.js
devtools/server/tests/unit/test_breakpoint-09.js
devtools/server/tests/unit/test_breakpoint-10.js
devtools/server/tests/unit/test_breakpoint-11.js
devtools/server/tests/unit/test_breakpoint-12.js
devtools/server/tests/unit/test_breakpoint-13.js
devtools/server/tests/unit/test_breakpoint-14.js
devtools/server/tests/unit/test_breakpoint-16.js
devtools/server/tests/unit/test_breakpoint-17.js
devtools/server/tests/unit/test_breakpoint-18.js
devtools/server/tests/unit/test_breakpoint-19.js
devtools/server/tests/unit/test_breakpoint-21.js
devtools/server/tests/unit/test_breakpoint-22.js
devtools/server/tests/unit/test_objectgrips-01.js
devtools/server/tests/unit/test_objectgrips-02.js
devtools/server/tests/unit/test_objectgrips-03.js
devtools/server/tests/unit/test_objectgrips-04.js
devtools/server/tests/unit/test_objectgrips-05.js
devtools/server/tests/unit/test_objectgrips-06.js
devtools/server/tests/unit/test_objectgrips-07.js
devtools/server/tests/unit/test_objectgrips-08.js
devtools/server/tests/unit/test_objectgrips-09.js
devtools/server/tests/unit/test_objectgrips-16.js
devtools/server/tests/unit/test_objectgrips-18.js
devtools/server/tests/unit/test_objectgrips-19.js
devtools/server/tests/unit/test_objectgrips-20.js
devtools/server/tests/unit/test_objectgrips-22.js
devtools/server/tests/unit/test_objectgrips-array-like-object.js
devtools/server/tests/unit/test_objectgrips-fn-apply-01.js
devtools/server/tests/unit/test_objectgrips-fn-apply-02.js
devtools/server/tests/unit/test_objectgrips-fn-apply-03.js
devtools/server/tests/unit/test_objectgrips-property-value-01.js
devtools/server/tests/unit/test_objectgrips-property-value-02.js
devtools/server/tests/unit/test_stepping-02.js
devtools/server/tests/unit/test_stepping-03.js
devtools/server/tests/unit/test_stepping-04.js
devtools/server/tests/unit/test_stepping-05.js
devtools/server/tests/unit/test_stepping-07.js
devtools/server/tests/unit/test_stepping-08.js
devtools/server/tests/unit/test_stepping-09.js
devtools/server/tests/unit/test_stepping-with-pause-points.js
devtools/server/tests/unit/test_stepping-with-skip-breakpoints.js
devtools/server/tests/unit/testactors.js
--- a/devtools/server/tests/unit/head_dbg.js
+++ b/devtools/server/tests/unit/head_dbg.js
@@ -824,8 +824,65 @@ async function setupTestFromUrl(url) {
   const sourceUrl = getFileUrl(url);
   const promise = waitForNewSource(threadClient, sourceUrl);
   loadSubScript(sourceUrl, global);
   const { source } = await promise;
 
   const sourceClient = threadClient.source(source);
   return { global, debuggerClient, threadClient, sourceClient };
 }
+
+/**
+ * Run the given test function twice, one with a regular DebuggerServer,
+ * testing against a fake tab. And another one against a WorkerDebuggerServer,
+ * testing the worker codepath.
+ *
+ * @param Function test
+ *        Test function to run twice.
+ *        This test function is called with a dictionary:
+ *        - Sandbox debuggee
+ *          The custom JS debuggee created for this test. This is a Sandbox using system
+ *           principals by default.
+ *        - ThreadClient threadClient
+ *          A reference to a ThreadClient instance that is attached to the debuggee.
+ *        - DebuggerClient client
+ *          A reference to the DebuggerClient used to communicated with the RDP server.
+ */
+function threadClientTest(test) {
+  async function runThreadClientTestWithServer(server, test) {
+    // Setup a server and connect a client to it.
+    initTestDebuggerServer(server);
+
+    // Create a custom debuggee and register it to the server.
+    // We are using a custom Sandbox as debuggee.
+    const debuggee = Cu.Sandbox(systemPrincipal);
+    const scriptName = "debuggee.js";
+    debuggee.__name = scriptName;
+    server.addTestGlobal(debuggee);
+
+    const client = new DebuggerClient(server.connectPipe());
+    await client.connect();
+
+    // Attach to the fake tab target and retrieve the ThreadClient instance.
+    // Automatically resume as the thread is paused by default after attach.
+    const [, , threadClient] =
+      await attachTestTabAndResume(client, scriptName);
+
+    // Run the test function
+    await test({ threadClient, debuggee, client });
+
+    // Cleanup the client after the test ran
+    await client.close();
+
+    server.removeTestGlobal(debuggee);
+
+    // Also cleanup the created server
+    server.destroy();
+  }
+
+  return async () => {
+    dump(">>> Run thread client test against a regular DebuggerServer\n");
+    await runThreadClientTestWithServer(DebuggerServer, test);
+
+    dump(">>> Run thread client test against a worker DebuggerServer\n");
+    await runThreadClientTestWithServer(WorkerDebuggerServer, test);
+  };
+}
--- a/devtools/server/tests/unit/test_breakpoint-01.js
+++ b/devtools/server/tests/unit/test_breakpoint-01.js
@@ -2,76 +2,51 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 /**
  * Check basic breakpoint functionality.
  */
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = {
+        line: debuggee.line0 + 3,
+      };
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_simple_breakpoint();
-                           });
-  });
-}
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        threadClient.addOneTimeListener("paused", function(event, packet) {
+          // Check the return value.
+          Assert.equal(packet.type, "paused");
+          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.line, location.line);
+          Assert.equal(packet.why.type, "breakpoint");
+          Assert.equal(packet.why.actors[0], bpClient.actor);
+          // Check that the breakpoint worked.
+          Assert.equal(debuggee.a, 1);
+          Assert.equal(debuggee.b, undefined);
 
-function test_simple_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = {
-      line: gDebuggee.line0 + 3,
-    };
-
-    source.setBreakpoint(location).then(function([response, bpClient]) {
-      gThreadClient.addOneTimeListener("paused", function(event, packet) {
-        // Check the return value.
-        Assert.equal(packet.type, "paused");
-        Assert.equal(packet.frame.where.source.actor, source.actor);
-        Assert.equal(packet.frame.where.line, location.line);
-        Assert.equal(packet.why.type, "breakpoint");
-        Assert.equal(packet.why.actors[0], bpClient.actor);
-        // Check that the breakpoint worked.
-        Assert.equal(gDebuggee.a, 1);
-        Assert.equal(gDebuggee.b, undefined);
-
-        // Remove the breakpoint.
-        bpClient.remove(function(response) {
-          gThreadClient.resume(function() {
-            gClient.close().then(gCallback);
+          // Remove the breakpoint.
+          bpClient.remove(function(response) {
+            threadClient.resume(resolve);
           });
         });
+
+        // Continue until the breakpoint is hit.
+        threadClient.resume();
       });
-
-      // Continue until the breakpoint is hit.
-      gThreadClient.resume();
     });
-  });
 
-  /* eslint-disable */
-  Cu.evalInSandbox(
-    "var line0 = Error().lineNumber;\n" +
-    "debugger;\n" +   // line0 + 1
-    "var a = 1;\n" +  // line0 + 2
-    "var b = 2;\n",   // line0 + 3
-    gDebuggee
-  );
-  /* eslint-enable */
-}
+    /* eslint-disable */
+    Cu.evalInSandbox(
+      "var line0 = Error().lineNumber;\n" +
+      "debugger;\n" +   // line0 + 1
+      "var a = 1;\n" +  // line0 + 2
+      "var b = 2;\n",   // line0 + 3
+      debuggee
+    );
+    /* eslint-enable */
+  });
+}));
--- a/devtools/server/tests/unit/test_breakpoint-02.js
+++ b/devtools/server/tests/unit/test_breakpoint-02.js
@@ -3,72 +3,44 @@
 /* eslint-disable no-shadow */
 
 "use strict";
 
 /**
  * Check that setting breakpoints when the debuggee is running works.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const location = { line: debuggee.line0 + 3 };
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+      threadClient.resume();
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_breakpoint_running();
-                           });
-  });
-}
+      // Setting the breakpoint later should interrupt the debuggee.
+      threadClient.addOneTimeListener("paused", function(event, packet) {
+        Assert.equal(packet.type, "paused");
+        Assert.equal(packet.why.type, "interrupted");
+      });
 
-function test_breakpoint_running() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const location = { line: gDebuggee.line0 + 3 };
+      const source = threadClient.source(packet.frame.where.source);
+      source.setBreakpoint(location).then(function() {
+        executeSoon(resolve);
+      }, function(response) {
+        // Eval scripts don't stick around long enough for the breakpoint to be set,
+        // so just make sure we got the expected response from the actor.
+        Assert.notEqual(response.error, "noScript");
 
-    gThreadClient.resume();
-
-    // Setting the breakpoint later should interrupt the debuggee.
-    gThreadClient.addOneTimeListener("paused", function(event, packet) {
-      Assert.equal(packet.type, "paused");
-      Assert.equal(packet.why.type, "interrupted");
+        executeSoon(resolve);
+      });
     });
 
-    const source = gThreadClient.source(packet.frame.where.source);
-    source.setBreakpoint(location).then(function() {
-      executeSoon(function() {
-        gClient.close().then(gCallback);
-      });
-    }, function(response) {
-      // Eval scripts don't stick around long enough for the breakpoint to be set,
-      // so just make sure we got the expected response from the actor.
-      Assert.notEqual(response.error, "noScript");
-
-      executeSoon(function() {
-        gClient.close().then(gCallback);
-      });
-    });
+    /* eslint-disable */
+    Cu.evalInSandbox(
+      "var line0 = Error().lineNumber;\n" +
+      "debugger;\n" +
+      "var a = 1;\n" +  // line0 + 2
+      "var b = 2;\n",  // line0 + 3
+      debuggee
+    );
+    /* eslint-enable */
   });
-
-  /* eslint-disable */
-  Cu.evalInSandbox(
-    "var line0 = Error().lineNumber;\n" +
-    "debugger;\n" +
-    "var a = 1;\n" +  // line0 + 2
-    "var b = 2;\n",  // line0 + 3
-    gDebuggee
-  );
-  /* eslint-enable */
-}
+}));
--- a/devtools/server/tests/unit/test_breakpoint-03.js
+++ b/devtools/server/tests/unit/test_breakpoint-03.js
@@ -5,95 +5,68 @@
 "use strict";
 
 /**
  * Check that setting a breakpoint on a line without code will skip
  * forward when we know the script isn't GCed (the debugger is connected,
  * so it's kept alive).
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient,
-                           "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_skip_breakpoint();
-                           });
-  });
-}
-
-var test_no_skip_breakpoint = async function(source, location) {
+var test_no_skip_breakpoint = async function(source, location, debuggee) {
   const [response, bpClient] = await source.setBreakpoint(
     Object.assign({}, location, { noSliding: true })
   );
 
   Assert.ok(!response.actualLocation);
-  Assert.equal(bpClient.location.line, gDebuggee.line0 + 3);
+  Assert.equal(bpClient.location.line, debuggee.line0 + 3);
   await bpClient.remove();
 };
 
-var test_skip_breakpoint = function() {
-  gThreadClient.addOneTimeListener("paused", async function(event, packet) {
-    const location = { line: gDebuggee.line0 + 3 };
-    const source = gThreadClient.source(packet.frame.where.source);
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const location = { line: debuggee.line0 + 3 };
+      const source = threadClient.source(packet.frame.where.source);
 
-    // First, make sure that we can disable sliding with the
-    // `noSliding` option.
-    await test_no_skip_breakpoint(source, location);
-
-    // Now make sure that the breakpoint properly slides forward one line.
-    const [response, bpClient] = await source.setBreakpoint(location);
-    Assert.ok(!!response.actualLocation);
-    Assert.equal(response.actualLocation.source.actor, source.actor);
-    Assert.equal(response.actualLocation.line, location.line + 1);
+      // First, make sure that we can disable sliding with the
+      // `noSliding` option.
+      await test_no_skip_breakpoint(source, location, debuggee);
 
-    gThreadClient.addOneTimeListener("paused", function(event, packet) {
-      // Check the return value.
-      Assert.equal(packet.type, "paused");
-      Assert.equal(packet.frame.where.source.actor, source.actor);
-      Assert.equal(packet.frame.where.line, location.line + 1);
-      Assert.equal(packet.why.type, "breakpoint");
-      Assert.equal(packet.why.actors[0], bpClient.actor);
-      // Check that the breakpoint worked.
-      Assert.equal(gDebuggee.a, 1);
-      Assert.equal(gDebuggee.b, undefined);
+      // Now make sure that the breakpoint properly slides forward one line.
+      const [response, bpClient] = await source.setBreakpoint(location);
+      Assert.ok(!!response.actualLocation);
+      Assert.equal(response.actualLocation.source.actor, source.actor);
+      Assert.equal(response.actualLocation.line, location.line + 1);
 
-      // Remove the breakpoint.
-      bpClient.remove(function(response) {
-        gThreadClient.resume(function() {
-          gClient.close().then(gCallback);
+      threadClient.addOneTimeListener("paused", function(event, packet) {
+        // Check the return value.
+        Assert.equal(packet.type, "paused");
+        Assert.equal(packet.frame.where.source.actor, source.actor);
+        Assert.equal(packet.frame.where.line, location.line + 1);
+        Assert.equal(packet.why.type, "breakpoint");
+        Assert.equal(packet.why.actors[0], bpClient.actor);
+        // Check that the breakpoint worked.
+        Assert.equal(debuggee.a, 1);
+        Assert.equal(debuggee.b, undefined);
+
+        // Remove the breakpoint.
+        bpClient.remove(function(response) {
+          threadClient.resume(resolve);
         });
       });
+
+      threadClient.resume();
     });
 
-    gThreadClient.resume();
+    // Use `evalInSandbox` to make the debugger treat it as normal
+    // globally-scoped code, where breakpoint sliding rules apply.
+    /* eslint-disable */
+    Cu.evalInSandbox(
+      "var line0 = Error().lineNumber;\n" +
+      "debugger;\n" +      // line0 + 1
+      "var a = 1;\n" +     // line0 + 2
+      "// A comment.\n" +  // line0 + 3
+      "var b = 2;",        // line0 + 4
+      debuggee
+    );
+    /* eslint-enable */
   });
-
-  // Use `evalInSandbox` to make the debugger treat it as normal
-  // globally-scoped code, where breakpoint sliding rules apply.
-  /* eslint-disable */
-  Cu.evalInSandbox(
-    "var line0 = Error().lineNumber;\n" +
-    "debugger;\n" +      // line0 + 1
-    "var a = 1;\n" +     // line0 + 2
-    "// A comment.\n" +  // line0 + 3
-    "var b = 2;",        // line0 + 4
-    gDebuggee
-  );
-  /* eslint-enable */
-};
+}));
--- a/devtools/server/tests/unit/test_breakpoint-04.js
+++ b/devtools/server/tests/unit/test_breakpoint-04.js
@@ -3,80 +3,54 @@
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 /**
  * Check that setting a breakpoint in a line in a child script works.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = { line: debuggee.line0 + 3 };
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        // actualLocation is not returned when breakpoints don't skip forward.
+        Assert.equal(response.actualLocation, undefined);
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_child_breakpoint();
-                           });
-  });
-}
-
-function test_child_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = { line: gDebuggee.line0 + 3 };
+        threadClient.addOneTimeListener("paused", function(event, packet) {
+          // Check the return value.
+          Assert.equal(packet.type, "paused");
+          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.line, location.line);
+          Assert.equal(packet.why.type, "breakpoint");
+          Assert.equal(packet.why.actors[0], bpClient.actor);
+          // Check that the breakpoint worked.
+          Assert.equal(debuggee.a, 1);
+          Assert.equal(debuggee.b, undefined);
 
-    source.setBreakpoint(location).then(function([response, bpClient]) {
-      // actualLocation is not returned when breakpoints don't skip forward.
-      Assert.equal(response.actualLocation, undefined);
-
-      gThreadClient.addOneTimeListener("paused", function(event, packet) {
-        // Check the return value.
-        Assert.equal(packet.type, "paused");
-        Assert.equal(packet.frame.where.source.actor, source.actor);
-        Assert.equal(packet.frame.where.line, location.line);
-        Assert.equal(packet.why.type, "breakpoint");
-        Assert.equal(packet.why.actors[0], bpClient.actor);
-        // Check that the breakpoint worked.
-        Assert.equal(gDebuggee.a, 1);
-        Assert.equal(gDebuggee.b, undefined);
-
-        // Remove the breakpoint.
-        bpClient.remove(function(response) {
-          gThreadClient.resume(function() {
-            gClient.close().then(gCallback);
+          // Remove the breakpoint.
+          bpClient.remove(function(response) {
+            threadClient.resume(resolve);
           });
         });
+
+        // Continue until the breakpoint is hit.
+        threadClient.resume();
       });
-
-      // Continue until the breakpoint is hit.
-      gThreadClient.resume();
     });
-  });
 
-  /* eslint-disable */
-  Cu.evalInSandbox(
-    "var line0 = Error().lineNumber;\n" +
-    "function foo() {\n" + // line0 + 1
-    "  this.a = 1;\n" +    // line0 + 2
-    "  this.b = 2;\n" +    // line0 + 3
-    "}\n" +                // line0 + 4
-    "debugger;\n" +        // line0 + 5
-    "foo();\n",            // line0 + 6
-    gDebuggee
-  );
-  /* eslint-enable */
-}
+    /* eslint-disable */
+    Cu.evalInSandbox(
+      "var line0 = Error().lineNumber;\n" +
+      "function foo() {\n" + // line0 + 1
+      "  this.a = 1;\n" +    // line0 + 2
+      "  this.b = 2;\n" +    // line0 + 3
+      "}\n" +                // line0 + 4
+      "debugger;\n" +        // line0 + 5
+      "foo();\n",            // line0 + 6
+      debuggee
+    );
+    /* eslint-enable */
+  });
+}));
--- a/devtools/server/tests/unit/test_breakpoint-05.js
+++ b/devtools/server/tests/unit/test_breakpoint-05.js
@@ -4,82 +4,56 @@
 
 "use strict";
 
 /**
  * Check that setting a breakpoint in a line without code in a child script
  * will skip forward.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = { line: debuggee.line0 + 3 };
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_child_skip_breakpoint();
-                           });
-  });
-}
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        // Check that the breakpoint has properly skipped forward one line.
+        Assert.equal(response.actualLocation.source.actor, source.actor);
+        Assert.equal(response.actualLocation.line, location.line + 1);
 
-function test_child_skip_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = { line: gDebuggee.line0 + 3 };
-
-    source.setBreakpoint(location).then(function([response, bpClient]) {
-      // Check that the breakpoint has properly skipped forward one line.
-      Assert.equal(response.actualLocation.source.actor, source.actor);
-      Assert.equal(response.actualLocation.line, location.line + 1);
+        threadClient.addOneTimeListener("paused", function(event, packet) {
+          // Check the return value.
+          Assert.equal(packet.type, "paused");
+          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.line, location.line + 1);
+          Assert.equal(packet.why.type, "breakpoint");
+          Assert.equal(packet.why.actors[0], bpClient.actor);
+          // Check that the breakpoint worked.
+          Assert.equal(debuggee.a, 1);
+          Assert.equal(debuggee.b, undefined);
 
-      gThreadClient.addOneTimeListener("paused", function(event, packet) {
-        // Check the return value.
-        Assert.equal(packet.type, "paused");
-        Assert.equal(packet.frame.where.source.actor, source.actor);
-        Assert.equal(packet.frame.where.line, location.line + 1);
-        Assert.equal(packet.why.type, "breakpoint");
-        Assert.equal(packet.why.actors[0], bpClient.actor);
-        // Check that the breakpoint worked.
-        Assert.equal(gDebuggee.a, 1);
-        Assert.equal(gDebuggee.b, undefined);
-
-        // Remove the breakpoint.
-        bpClient.remove(function(response) {
-          gThreadClient.resume(function() {
-            gClient.close().then(gCallback);
+          // Remove the breakpoint.
+          bpClient.remove(function(response) {
+            threadClient.resume(resolve);
           });
         });
+
+        // Continue until the breakpoint is hit.
+        threadClient.resume();
       });
-
-      // Continue until the breakpoint is hit.
-      gThreadClient.resume();
     });
-  });
 
-  /* eslint-disable */
-  Cu.evalInSandbox(
-    "var line0 = Error().lineNumber;\n" +
-    "function foo() {\n" + // line0 + 1
-    "  this.a = 1;\n" +    // line0 + 2
-    "  // A comment.\n" +  // line0 + 3
-    "  this.b = 2;\n" +    // line0 + 4
-    "}\n" +                // line0 + 5
-    "debugger;\n" +        // line0 + 6
-    "foo();\n",            // line0 + 7
-    gDebuggee
-  );
-  /* eslint-enable */
-}
+    /* eslint-disable */
+    Cu.evalInSandbox(
+      "var line0 = Error().lineNumber;\n" +
+      "function foo() {\n" + // line0 + 1
+      "  this.a = 1;\n" +    // line0 + 2
+      "  // A comment.\n" +  // line0 + 3
+      "  this.b = 2;\n" +    // line0 + 4
+      "}\n" +                // line0 + 5
+      "debugger;\n" +        // line0 + 6
+      "foo();\n",            // line0 + 7
+      debuggee
+    );
+    /* eslint-enable */
+  });
+}));
--- a/devtools/server/tests/unit/test_breakpoint-06.js
+++ b/devtools/server/tests/unit/test_breakpoint-06.js
@@ -4,88 +4,62 @@
 
 "use strict";
 
 /**
  * Check that setting a breakpoint in a line without code in a deeply-nested
  * child script will skip forward.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = { line: debuggee.line0 + 5 };
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_nested_breakpoint();
-                           });
-  });
-}
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        // Check that the breakpoint has properly skipped forward one line.
+        Assert.equal(response.actualLocation.source.actor, source.actor);
+        Assert.equal(response.actualLocation.line, location.line + 1);
 
-function test_nested_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = { line: gDebuggee.line0 + 5 };
-
-    source.setBreakpoint(location).then(function([response, bpClient]) {
-      // Check that the breakpoint has properly skipped forward one line.
-      Assert.equal(response.actualLocation.source.actor, source.actor);
-      Assert.equal(response.actualLocation.line, location.line + 1);
+        threadClient.addOneTimeListener("paused", function(event, packet) {
+          // Check the return value.
+          Assert.equal(packet.type, "paused");
+          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.line, location.line + 1);
+          Assert.equal(packet.why.type, "breakpoint");
+          Assert.equal(packet.why.actors[0], bpClient.actor);
+          // Check that the breakpoint worked.
+          Assert.equal(debuggee.a, 1);
+          Assert.equal(debuggee.b, undefined);
 
-      gThreadClient.addOneTimeListener("paused", function(event, packet) {
-        // Check the return value.
-        Assert.equal(packet.type, "paused");
-        Assert.equal(packet.frame.where.source.actor, source.actor);
-        Assert.equal(packet.frame.where.line, location.line + 1);
-        Assert.equal(packet.why.type, "breakpoint");
-        Assert.equal(packet.why.actors[0], bpClient.actor);
-        // Check that the breakpoint worked.
-        Assert.equal(gDebuggee.a, 1);
-        Assert.equal(gDebuggee.b, undefined);
-
-        // Remove the breakpoint.
-        bpClient.remove(function(response) {
-          gThreadClient.resume(function() {
-            gClient.close().then(gCallback);
+          // Remove the breakpoint.
+          bpClient.remove(function(response) {
+            threadClient.resume(resolve);
           });
         });
+
+        // Continue until the breakpoint is hit.
+        threadClient.resume();
       });
-
-      // Continue until the breakpoint is hit.
-      gThreadClient.resume();
     });
-  });
 
-  /* eslint-disable */
-  Cu.evalInSandbox(
-    "var line0 = Error().lineNumber;\n" +
-    "function foo() {\n" +     // line0 + 1
-    "  function bar() {\n" +   // line0 + 2
-    "    function baz() {\n" + // line0 + 3
-    "      this.a = 1;\n" +    // line0 + 4
-    "      // A comment.\n" +  // line0 + 5
-    "      this.b = 2;\n" +    // line0 + 6
-    "    }\n" +                // line0 + 7
-    "    baz();\n" +           // line0 + 8
-    "  }\n" +                  // line0 + 9
-    "  bar();\n" +             // line0 + 10
-    "}\n" +                    // line0 + 11
-    "debugger;\n" +            // line0 + 12
-    "foo();\n",               // line0 + 13
-    gDebuggee
-  );
-  /* eslint-enable */
-}
+    /* eslint-disable */
+    Cu.evalInSandbox(
+      "var line0 = Error().lineNumber;\n" +
+      "function foo() {\n" +     // line0 + 1
+      "  function bar() {\n" +   // line0 + 2
+      "    function baz() {\n" + // line0 + 3
+      "      this.a = 1;\n" +    // line0 + 4
+      "      // A comment.\n" +  // line0 + 5
+      "      this.b = 2;\n" +    // line0 + 6
+      "    }\n" +                // line0 + 7
+      "    baz();\n" +           // line0 + 8
+      "  }\n" +                  // line0 + 9
+      "  bar();\n" +             // line0 + 10
+      "}\n" +                    // line0 + 11
+      "debugger;\n" +            // line0 + 12
+      "foo();\n",               // line0 + 13
+      debuggee
+    );
+    /* eslint-enable */
+  });
+}));
--- a/devtools/server/tests/unit/test_breakpoint-07.js
+++ b/devtools/server/tests/unit/test_breakpoint-07.js
@@ -4,85 +4,59 @@
 
 "use strict";
 
 /**
  * Check that setting a breakpoint in a line without code in the second child
  * script will skip forward.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = { line: debuggee.line0 + 6 };
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_second_child_skip_breakpoint();
-                           });
-  });
-}
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        // Check that the breakpoint has properly skipped forward one line.
+        Assert.equal(response.actualLocation.source.actor, source.actor);
+        Assert.equal(response.actualLocation.line, location.line + 1);
 
-function test_second_child_skip_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = { line: gDebuggee.line0 + 6 };
-
-    source.setBreakpoint(location).then(function([response, bpClient]) {
-      // Check that the breakpoint has properly skipped forward one line.
-      Assert.equal(response.actualLocation.source.actor, source.actor);
-      Assert.equal(response.actualLocation.line, location.line + 1);
+        threadClient.addOneTimeListener("paused", function(event, packet) {
+          // Check the return value.
+          Assert.equal(packet.type, "paused");
+          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.line, location.line + 1);
+          Assert.equal(packet.why.type, "breakpoint");
+          Assert.equal(packet.why.actors[0], bpClient.actor);
+          // Check that the breakpoint worked.
+          Assert.equal(debuggee.a, 1);
+          Assert.equal(debuggee.b, undefined);
 
-      gThreadClient.addOneTimeListener("paused", function(event, packet) {
-        // Check the return value.
-        Assert.equal(packet.type, "paused");
-        Assert.equal(packet.frame.where.source.actor, source.actor);
-        Assert.equal(packet.frame.where.line, location.line + 1);
-        Assert.equal(packet.why.type, "breakpoint");
-        Assert.equal(packet.why.actors[0], bpClient.actor);
-        // Check that the breakpoint worked.
-        Assert.equal(gDebuggee.a, 1);
-        Assert.equal(gDebuggee.b, undefined);
-
-        // Remove the breakpoint.
-        bpClient.remove(function(response) {
-          gThreadClient.resume(function() {
-            gClient.close().then(gCallback);
+          // Remove the breakpoint.
+          bpClient.remove(function(response) {
+            threadClient.resume(resolve);
           });
         });
+
+        // Continue until the breakpoint is hit.
+        threadClient.resume();
       });
-
-      // Continue until the breakpoint is hit.
-      gThreadClient.resume();
     });
-  });
 
-  /* eslint-disable */
-  Cu.evalInSandbox(
-    "var line0 = Error().lineNumber;\n" +
-    "function foo() {\n" + // line0 + 1
-    "  bar();\n" +         // line0 + 2
-    "}\n" +                // line0 + 3
-    "function bar() {\n" + // line0 + 4
-    "  this.a = 1;\n" +    // line0 + 5
-    "  // A comment.\n" +  // line0 + 6
-    "  this.b = 2;\n" +    // line0 + 7
-    "}\n" +                // line0 + 8
-    "debugger;\n" +        // line0 + 9
-    "foo();\n",           // line0 + 10
-    gDebuggee
-  );
-  /* eslint-enable */
-}
+    /* eslint-disable */
+    Cu.evalInSandbox(
+      "var line0 = Error().lineNumber;\n" +
+      "function foo() {\n" + // line0 + 1
+      "  bar();\n" +         // line0 + 2
+      "}\n" +                // line0 + 3
+      "function bar() {\n" + // line0 + 4
+      "  this.a = 1;\n" +    // line0 + 5
+      "  // A comment.\n" +  // line0 + 6
+      "  this.b = 2;\n" +    // line0 + 7
+      "}\n" +                // line0 + 8
+      "debugger;\n" +        // line0 + 9
+      "foo();\n",           // line0 + 10
+      debuggee
+    );
+    /* eslint-enable */
+  });
+}));
--- a/devtools/server/tests/unit/test_breakpoint-08.js
+++ b/devtools/server/tests/unit/test_breakpoint-08.js
@@ -4,96 +4,70 @@
 
 "use strict";
 
 /**
  * Check that setting a breakpoint in a line without code in a child script
  * will skip forward, in a file with two scripts.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      threadClient.eval(packet.frame.actor, "foo", function(response) {
+        threadClient.addOneTimeListener("paused", function(event, packet) {
+          const obj = threadClient.pauseGrip(packet.why.frameFinished.return);
+          obj.getDefinitionSite(runWithBreakpoint);
+        });
+      });
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+      function runWithBreakpoint(packet) {
+        const source = threadClient.source(packet.source);
+        const location = { line: debuggee.line0 + 3 };
+
+        source.setBreakpoint(location).then(function([response, bpClient]) {
+          // Check that the breakpoint has properly skipped forward one line.
+          Assert.equal(response.actualLocation.source.actor, source.actor);
+          Assert.equal(response.actualLocation.line, location.line + 1);
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_child_skip_breakpoint();
-                           });
-  });
-}
+          threadClient.addOneTimeListener("paused", function(event, packet) {
+            // Check the return value.
+            Assert.equal(packet.type, "paused");
+            Assert.equal(packet.frame.where.source.actor, source.actor);
+            Assert.equal(packet.frame.where.line, location.line + 1);
+            Assert.equal(packet.why.type, "breakpoint");
+            Assert.equal(packet.why.actors[0], bpClient.actor);
+            // Check that the breakpoint worked.
+            Assert.equal(debuggee.a, 1);
+            Assert.equal(debuggee.b, undefined);
 
-function test_child_skip_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    gThreadClient.eval(packet.frame.actor, "foo", function(response) {
-      gThreadClient.addOneTimeListener("paused", function(event, packet) {
-        const obj = gThreadClient.pauseGrip(packet.why.frameFinished.return);
-        obj.getDefinitionSite(runWithBreakpoint);
-      });
+            // Remove the breakpoint.
+            bpClient.remove(function(response) {
+              threadClient.resume(resolve);
+            });
+          });
+
+          // Continue until the breakpoint is hit.
+          threadClient.resume();
+        });
+      }
     });
 
-    function runWithBreakpoint(packet) {
-      const source = gThreadClient.source(packet.source);
-      const location = { line: gDebuggee.line0 + 3 };
-
-      source.setBreakpoint(location).then(function([response, bpClient]) {
-        // Check that the breakpoint has properly skipped forward one line.
-        Assert.equal(response.actualLocation.source.actor, source.actor);
-        Assert.equal(response.actualLocation.line, location.line + 1);
-
-        gThreadClient.addOneTimeListener("paused", function(event, packet) {
-          // Check the return value.
-          Assert.equal(packet.type, "paused");
-          Assert.equal(packet.frame.where.source.actor, source.actor);
-          Assert.equal(packet.frame.where.line, location.line + 1);
-          Assert.equal(packet.why.type, "breakpoint");
-          Assert.equal(packet.why.actors[0], bpClient.actor);
-          // Check that the breakpoint worked.
-          Assert.equal(gDebuggee.a, 1);
-          Assert.equal(gDebuggee.b, undefined);
+    /* eslint-disable */
+    Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
+                     "function foo() {\n" + // line0 + 1
+                     "  this.a = 1;\n" +    // line0 + 2
+                     "  // A comment.\n" +  // line0 + 3
+                     "  this.b = 2;\n" +    // line0 + 4
+                     "}\n",                 // line0 + 5
+                     debuggee,
+                     "1.7",
+                     "script1.js");
 
-          // Remove the breakpoint.
-          bpClient.remove(function(response) {
-            gThreadClient.resume(function() {
-              gClient.close().then(gCallback);
-            });
-          });
-        });
-
-        // Continue until the breakpoint is hit.
-        gThreadClient.resume();
-      });
-    }
+    Cu.evalInSandbox("var line1 = Error().lineNumber;\n" +
+                     "debugger;\n" +        // line1 + 1
+                     "foo();\n",           // line1 + 2
+                     debuggee,
+                     "1.7",
+                     "script2.js");
+    /* eslint-enable */
   });
-
-  /* eslint-disable */
-  Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
-                   "function foo() {\n" + // line0 + 1
-                   "  this.a = 1;\n" +    // line0 + 2
-                   "  // A comment.\n" +  // line0 + 3
-                   "  this.b = 2;\n" +    // line0 + 4
-                   "}\n",                 // line0 + 5
-                   gDebuggee,
-                   "1.7",
-                   "script1.js");
-
-  Cu.evalInSandbox("var line1 = Error().lineNumber;\n" +
-                   "debugger;\n" +        // line1 + 1
-                   "foo();\n",           // line1 + 2
-                   gDebuggee,
-                   "1.7",
-                   "script2.js");
-  /* eslint-enable */
-}
+}));
--- a/devtools/server/tests/unit/test_breakpoint-09.js
+++ b/devtools/server/tests/unit/test_breakpoint-09.js
@@ -3,86 +3,62 @@
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 /**
  * Check that removing a breakpoint works.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    let done = false;
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = { line: debuggee.line0 + 2 };
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_remove_breakpoint();
-                           });
-  });
-}
-
-function test_remove_breakpoint() {
-  let done = false;
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = { line: gDebuggee.line0 + 2 };
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        threadClient.addOneTimeListener("paused", function(event, packet) {
+          // Check the return value.
+          Assert.equal(packet.type, "paused");
+          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.line, location.line);
+          Assert.equal(packet.why.type, "breakpoint");
+          Assert.equal(packet.why.actors[0], bpClient.actor);
+          // Check that the breakpoint worked.
+          Assert.equal(debuggee.a, undefined);
 
-    source.setBreakpoint(location).then(function([response, bpClient]) {
-      gThreadClient.addOneTimeListener("paused", function(event, packet) {
-        // Check the return value.
-        Assert.equal(packet.type, "paused");
-        Assert.equal(packet.frame.where.source.actor, source.actor);
-        Assert.equal(packet.frame.where.line, location.line);
-        Assert.equal(packet.why.type, "breakpoint");
-        Assert.equal(packet.why.actors[0], bpClient.actor);
-        // Check that the breakpoint worked.
-        Assert.equal(gDebuggee.a, undefined);
-
-        // Remove the breakpoint.
-        bpClient.remove(function(response) {
-          done = true;
-          gThreadClient.addOneTimeListener("paused",
-                                           function(event, packet) {
-            // The breakpoint should not be hit again.
-                                             gThreadClient.resume(function() {
-                                               Assert.ok(false);
+          // Remove the breakpoint.
+          bpClient.remove(function(response) {
+            done = true;
+            threadClient.addOneTimeListener("paused",
+                                             function(event, packet) {
+              // The breakpoint should not be hit again.
+                                               threadClient.resume(function() {
+                                                 Assert.ok(false);
+                                               });
                                              });
-                                           });
-          gThreadClient.resume();
+            threadClient.resume();
+          });
         });
+        // Continue until the breakpoint is hit.
+        threadClient.resume();
       });
-      // Continue until the breakpoint is hit.
-      gThreadClient.resume();
     });
-  });
 
-  /* eslint-disable */
-  Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
-                   "function foo(stop) {\n" + // line0 + 1
-                   "  this.a = 1;\n" +        // line0 + 2
-                   "  if (stop) return;\n" +  // line0 + 3
-                   "  delete this.a;\n" +     // line0 + 4
-                   "  foo(true);\n" +         // line0 + 5
-                   "}\n" +                    // line0 + 6
-                   "debugger;\n" +            // line1 + 7
-                   "foo();\n",                // line1 + 8
-                   gDebuggee);
-  /* eslint-enable */
-  if (!done) {
-    Assert.ok(false);
-  }
-  gClient.close().then(gCallback);
-}
+    /* eslint-disable */
+    Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
+                     "function foo(stop) {\n" + // line0 + 1
+                     "  this.a = 1;\n" +        // line0 + 2
+                     "  if (stop) return;\n" +  // line0 + 3
+                     "  delete this.a;\n" +     // line0 + 4
+                     "  foo(true);\n" +         // line0 + 5
+                     "}\n" +                    // line0 + 6
+                     "debugger;\n" +            // line1 + 7
+                     "foo();\n",                // line1 + 8
+                     debuggee);
+    /* eslint-enable */
+    if (!done) {
+      Assert.ok(false);
+    }
+    resolve();
+  });
+}));
--- a/devtools/server/tests/unit/test_breakpoint-10.js
+++ b/devtools/server/tests/unit/test_breakpoint-10.js
@@ -4,85 +4,59 @@
 
 "use strict";
 
 /**
  * Check that setting a breakpoint in a line with multiple entry points
  * triggers no matter which entry point we reach.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = { line: debuggee.line0 + 3 };
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_child_breakpoint();
-                           });
-  });
-}
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        // actualLocation is not returned when breakpoints don't skip forward.
+        Assert.equal(response.actualLocation, undefined);
 
-function test_child_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = { line: gDebuggee.line0 + 3 };
-
-    source.setBreakpoint(location).then(function([response, bpClient]) {
-      // actualLocation is not returned when breakpoints don't skip forward.
-      Assert.equal(response.actualLocation, undefined);
-
-      gThreadClient.addOneTimeListener("paused", function(event, packet) {
-        // Check the return value.
-        Assert.equal(packet.type, "paused");
-        Assert.equal(packet.why.type, "breakpoint");
-        Assert.equal(packet.why.actors[0], bpClient.actor);
-        // Check that the breakpoint worked.
-        Assert.equal(gDebuggee.i, 0);
-
-        gThreadClient.addOneTimeListener("paused", function(event, packet) {
+        threadClient.addOneTimeListener("paused", function(event, packet) {
           // Check the return value.
           Assert.equal(packet.type, "paused");
           Assert.equal(packet.why.type, "breakpoint");
           Assert.equal(packet.why.actors[0], bpClient.actor);
           // Check that the breakpoint worked.
-          Assert.equal(gDebuggee.i, 1);
+          Assert.equal(debuggee.i, 0);
 
-          // Remove the breakpoint.
-          bpClient.remove(function(response) {
-            gThreadClient.resume(function() {
-              gClient.close().then(gCallback);
+          threadClient.addOneTimeListener("paused", function(event, packet) {
+            // Check the return value.
+            Assert.equal(packet.type, "paused");
+            Assert.equal(packet.why.type, "breakpoint");
+            Assert.equal(packet.why.actors[0], bpClient.actor);
+            // Check that the breakpoint worked.
+            Assert.equal(debuggee.i, 1);
+
+            // Remove the breakpoint.
+            bpClient.remove(function(response) {
+              threadClient.resume(resolve);
             });
           });
+
+          // Continue until the breakpoint is hit again.
+          threadClient.resume();
         });
-
-        // Continue until the breakpoint is hit again.
-        gThreadClient.resume();
+        // Continue until the breakpoint is hit.
+        threadClient.resume();
       });
-      // Continue until the breakpoint is hit.
-      gThreadClient.resume();
     });
-  });
 
-  /* eslint-disable */
-  Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
-                   "debugger;\n" +                      // line0 + 1
-                   "var a, i = 0;\n" +                  // line0 + 2
-                   "for (i = 1; i <= 2; i++) {\n" +     // line0 + 3
-                   "  a = i;\n" +                       // line0 + 4
-                   "}\n",                               // line0 + 5
-                   gDebuggee);
-  /* eslint-enable */
-}
+    /* eslint-disable */
+    Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
+                     "debugger;\n" +                      // line0 + 1
+                     "var a, i = 0;\n" +                  // line0 + 2
+                     "for (i = 1; i <= 2; i++) {\n" +     // line0 + 3
+                     "  a = i;\n" +                       // line0 + 4
+                     "}\n",                               // line0 + 5
+                     debuggee);
+    /* eslint-enable */
+  });
+}));
--- a/devtools/server/tests/unit/test_breakpoint-11.js
+++ b/devtools/server/tests/unit/test_breakpoint-11.js
@@ -4,84 +4,58 @@
 
 "use strict";
 
 /**
  * Make sure that setting a breakpoint in a line with bytecodes in multiple
  * scripts, sets the breakpoint in all of them (bug 793214).
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = { line: debuggee.line0 + 2 };
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_child_breakpoint();
-                           });
-  });
-}
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        // actualLocation is not returned when breakpoints don't skip forward.
+        Assert.equal(response.actualLocation, undefined);
 
-function test_child_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = { line: gDebuggee.line0 + 2 };
-
-    source.setBreakpoint(location).then(function([response, bpClient]) {
-      // actualLocation is not returned when breakpoints don't skip forward.
-      Assert.equal(response.actualLocation, undefined);
-
-      gThreadClient.addOneTimeListener("paused", function(event, packet) {
-        // Check the return value.
-        Assert.equal(packet.type, "paused");
-        Assert.equal(packet.why.type, "breakpoint");
-        Assert.equal(packet.why.actors[0], bpClient.actor);
-        // Check that the breakpoint worked.
-        Assert.equal(gDebuggee.a, undefined);
-
-        gThreadClient.addOneTimeListener("paused", function(event, packet) {
+        threadClient.addOneTimeListener("paused", function(event, packet) {
           // Check the return value.
           Assert.equal(packet.type, "paused");
           Assert.equal(packet.why.type, "breakpoint");
           Assert.equal(packet.why.actors[0], bpClient.actor);
           // Check that the breakpoint worked.
-          Assert.equal(gDebuggee.a.b, 1);
-          Assert.equal(gDebuggee.res, undefined);
+          Assert.equal(debuggee.a, undefined);
 
-          // Remove the breakpoint.
-          bpClient.remove(function(response) {
-            gThreadClient.resume(function() {
-              gClient.close().then(gCallback);
+          threadClient.addOneTimeListener("paused", function(event, packet) {
+            // Check the return value.
+            Assert.equal(packet.type, "paused");
+            Assert.equal(packet.why.type, "breakpoint");
+            Assert.equal(packet.why.actors[0], bpClient.actor);
+            // Check that the breakpoint worked.
+            Assert.equal(debuggee.a.b, 1);
+            Assert.equal(debuggee.res, undefined);
+
+            // Remove the breakpoint.
+            bpClient.remove(function(response) {
+              threadClient.resume(resolve);
             });
           });
-        });
 
-        // Continue until the breakpoint is hit again.
-        gThreadClient.resume();
+          // Continue until the breakpoint is hit again.
+          threadClient.resume();
+        });
+        // Continue until the breakpoint is hit.
+        threadClient.resume();
       });
-      // Continue until the breakpoint is hit.
-      gThreadClient.resume();
     });
+
+    /* eslint-disable */
+    Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
+                     "debugger;\n" +                      // line0 + 1
+                     "var a = { b: 1, f: function() { return 2; } };\n" + // line0+2
+                     "var res = a.f();\n",               // line0 + 3
+                     debuggee);
+    /* eslint-enable */
   });
-
-  /* eslint-disable */
-  Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
-                   "debugger;\n" +                      // line0 + 1
-                   "var a = { b: 1, f: function() { return 2; } };\n" + // line0+2
-                   "var res = a.f();\n",               // line0 + 3
-                   gDebuggee);
-  /* eslint-enable */
-}
+}));
--- a/devtools/server/tests/unit/test_breakpoint-12.js
+++ b/devtools/server/tests/unit/test_breakpoint-12.js
@@ -5,109 +5,83 @@
 "use strict";
 
 /**
  * Make sure that setting a breakpoint twice in a line without bytecodes works
  * as expected.
  */
 
 const NUM_BREAKPOINTS = 10;
-var gDebuggee;
-var gClient;
-var gThreadClient;
 var gBpActor;
 var gCount;
-var gCallback;
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  gCount = 1;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_child_skip_breakpoint();
-                           });
-  });
-}
-
-function test_child_skip_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = { line: gDebuggee.line0 + 3};
-
-    source.setBreakpoint(location).then(function([response, bpClient]) {
-      // Check that the breakpoint has properly skipped forward one line.
-      Assert.equal(response.actualLocation.source.actor, source.actor);
-      Assert.equal(response.actualLocation.line, location.line + 1);
-      gBpActor = response.actor;
-
-      // Set more breakpoints at the same location.
-      set_breakpoints(source, location);
-    });
-  });
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = { line: debuggee.line0 + 3};
 
-  /* eslint-disable no-multi-spaces */
-  Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
-                   "function foo() {\n" + // line0 + 1
-                   "  this.a = 1;\n" +    // line0 + 2
-                   "  // A comment.\n" +  // line0 + 3
-                   "  this.b = 2;\n" +    // line0 + 4
-                   "}\n" +                // line0 + 5
-                   "debugger;\n" +        // line0 + 6
-                   "foo();\n",            // line0 + 7
-                   gDebuggee);
-  /* eslint-enable no-multi-spaces */
-}
-
-// Set many breakpoints at the same location.
-function set_breakpoints(source, location) {
-  Assert.notEqual(gCount, NUM_BREAKPOINTS);
-  source.setBreakpoint(location).then(function([response, bpClient]) {
-    // Check that the breakpoint has properly skipped forward one line.
-    Assert.equal(response.actualLocation.source.actor, source.actor);
-    Assert.equal(response.actualLocation.line, location.line + 1);
-    // Check that the same breakpoint actor was returned.
-    Assert.equal(response.actor, gBpActor);
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        // Check that the breakpoint has properly skipped forward one line.
+        Assert.equal(response.actualLocation.source.actor, source.actor);
+        Assert.equal(response.actualLocation.line, location.line + 1);
+        gBpActor = response.actor;
 
-    if (++gCount < NUM_BREAKPOINTS) {
-      set_breakpoints(source, location);
-      return;
-    }
-
-    // After setting all the breakpoints, check that only one has effectively
-    // remained.
-    gThreadClient.addOneTimeListener("paused", function(event, packet) {
-      // Check the return value.
-      Assert.equal(packet.type, "paused");
-      Assert.equal(packet.frame.where.source.actor, source.actor);
-      Assert.equal(packet.frame.where.line, location.line + 1);
-      Assert.equal(packet.why.type, "breakpoint");
-      Assert.equal(packet.why.actors[0], bpClient.actor);
-      // Check that the breakpoint worked.
-      Assert.equal(gDebuggee.a, 1);
-      Assert.equal(gDebuggee.b, undefined);
-
-      gThreadClient.addOneTimeListener("paused", function(event, packet) {
-        // We don't expect any more pauses after the breakpoint was hit once.
-        Assert.ok(false);
-      });
-      gThreadClient.resume(function() {
-        // Give any remaining breakpoints a chance to trigger.
-        do_timeout(1000, function() {
-          gClient.close().then(gCallback);
-        });
+        // Set more breakpoints at the same location.
+        set_breakpoints(source, location);
       });
     });
-    // Continue until the breakpoint is hit.
-    gThreadClient.resume();
+
+    /* eslint-disable no-multi-spaces */
+    Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
+                     "function foo() {\n" + // line0 + 1
+                     "  this.a = 1;\n" +    // line0 + 2
+                     "  // A comment.\n" +  // line0 + 3
+                     "  this.b = 2;\n" +    // line0 + 4
+                     "}\n" +                // line0 + 5
+                     "debugger;\n" +        // line0 + 6
+                     "foo();\n",            // line0 + 7
+                     debuggee);
+    /* eslint-enable no-multi-spaces */
+
+    // Set many breakpoints at the same location.
+    function set_breakpoints(source, location) {
+      Assert.notEqual(gCount, NUM_BREAKPOINTS);
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        // Check that the breakpoint has properly skipped forward one line.
+        Assert.equal(response.actualLocation.source.actor, source.actor);
+        Assert.equal(response.actualLocation.line, location.line + 1);
+        // Check that the same breakpoint actor was returned.
+        Assert.equal(response.actor, gBpActor);
+
+        if (++gCount < NUM_BREAKPOINTS) {
+          set_breakpoints(source, location);
+          return;
+        }
+
+        // After setting all the breakpoints, check that only one has effectively
+        // remained.
+        threadClient.addOneTimeListener("paused", function(event, packet) {
+          // Check the return value.
+          Assert.equal(packet.type, "paused");
+          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.line, location.line + 1);
+          Assert.equal(packet.why.type, "breakpoint");
+          Assert.equal(packet.why.actors[0], bpClient.actor);
+          // Check that the breakpoint worked.
+          Assert.equal(debuggee.a, 1);
+          Assert.equal(debuggee.b, undefined);
+
+          threadClient.addOneTimeListener("paused", function(event, packet) {
+            // We don't expect any more pauses after the breakpoint was hit once.
+            Assert.ok(false);
+          });
+          threadClient.resume(function() {
+            // Give any remaining breakpoints a chance to trigger.
+            do_timeout(1000, resolve);
+          });
+        });
+        // Continue until the breakpoint is hit.
+        threadClient.resume();
+      });
+    }
   });
-}
+}));
--- a/devtools/server/tests/unit/test_breakpoint-13.js
+++ b/devtools/server/tests/unit/test_breakpoint-13.js
@@ -4,110 +4,86 @@
 
 "use strict";
 
 /**
  * Check that execution doesn't pause twice while stepping, when encountering
  * either a breakpoint or a debugger statement.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_simple_breakpoint();
-                           });
-  });
-}
-
-function test_simple_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = { line: gDebuggee.line0 + 2 };
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = { line: debuggee.line0 + 2 };
 
-    source.setBreakpoint(location).then(async function([response, bpClient]) {
-      const testCallbacks = [
-        function(packet) {
-          // Check that the stepping worked.
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 5);
-          Assert.equal(packet.why.type, "resumeLimit");
-        },
-        function(packet) {
-          // Entered the foo function call frame.
-          Assert.equal(packet.frame.where.line, location.line);
-          Assert.notEqual(packet.why.type, "breakpoint");
-          Assert.equal(packet.why.type, "resumeLimit");
-        },
-        function(packet) {
-          // At the end of the foo function call frame.
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 3);
-          Assert.notEqual(packet.why.type, "breakpoint");
-          Assert.equal(packet.why.type, "resumeLimit");
-        },
-        function(packet) {
-          // Check that the breakpoint wasn't the reason for this pause, but
-          // that the frame is about to be popped while stepping.
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 3);
-          Assert.notEqual(packet.why.type, "breakpoint");
-          Assert.equal(packet.why.type, "resumeLimit");
-          Assert.equal(packet.why.frameFinished.return.type, "undefined");
-        },
-        function(packet) {
-          // Check that the debugger statement wasn't the reason for this pause.
-          Assert.equal(gDebuggee.a, 1);
-          Assert.equal(gDebuggee.b, undefined);
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 6);
-          Assert.notEqual(packet.why.type, "debuggerStatement");
-          Assert.equal(packet.why.type, "resumeLimit");
-          Assert.equal(packet.poppedFrames.length, 1);
-        },
-        function(packet) {
-          // Check that the debugger statement wasn't the reason for this pause.
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 7);
-          Assert.notEqual(packet.why.type, "debuggerStatement");
-          Assert.equal(packet.why.type, "resumeLimit");
-        },
-      ];
+      source.setBreakpoint(location).then(async function([response, bpClient]) {
+        const testCallbacks = [
+          function(packet) {
+            // Check that the stepping worked.
+            Assert.equal(packet.frame.where.line, debuggee.line0 + 5);
+            Assert.equal(packet.why.type, "resumeLimit");
+          },
+          function(packet) {
+            // Entered the foo function call frame.
+            Assert.equal(packet.frame.where.line, location.line);
+            Assert.notEqual(packet.why.type, "breakpoint");
+            Assert.equal(packet.why.type, "resumeLimit");
+          },
+          function(packet) {
+            // At the end of the foo function call frame.
+            Assert.equal(packet.frame.where.line, debuggee.line0 + 3);
+            Assert.notEqual(packet.why.type, "breakpoint");
+            Assert.equal(packet.why.type, "resumeLimit");
+          },
+          function(packet) {
+            // Check that the breakpoint wasn't the reason for this pause, but
+            // that the frame is about to be popped while stepping.
+            Assert.equal(packet.frame.where.line, debuggee.line0 + 3);
+            Assert.notEqual(packet.why.type, "breakpoint");
+            Assert.equal(packet.why.type, "resumeLimit");
+            Assert.equal(packet.why.frameFinished.return.type, "undefined");
+          },
+          function(packet) {
+            // Check that the debugger statement wasn't the reason for this pause.
+            Assert.equal(debuggee.a, 1);
+            Assert.equal(debuggee.b, undefined);
+            Assert.equal(packet.frame.where.line, debuggee.line0 + 6);
+            Assert.notEqual(packet.why.type, "debuggerStatement");
+            Assert.equal(packet.why.type, "resumeLimit");
+            Assert.equal(packet.poppedFrames.length, 1);
+          },
+          function(packet) {
+            // Check that the debugger statement wasn't the reason for this pause.
+            Assert.equal(packet.frame.where.line, debuggee.line0 + 7);
+            Assert.notEqual(packet.why.type, "debuggerStatement");
+            Assert.equal(packet.why.type, "resumeLimit");
+          },
+        ];
 
-      for (const callback of testCallbacks) {
-        const waiter = waitForPause(gThreadClient);
-        gThreadClient.stepIn();
-        const packet = await waiter;
-        callback(packet);
-      }
+        for (const callback of testCallbacks) {
+          const waiter = waitForPause(threadClient);
+          threadClient.stepIn();
+          const packet = await waiter;
+          callback(packet);
+        }
 
-      // Remove the breakpoint and finish.
-      const waiter = waitForPause(gThreadClient);
-      gThreadClient.stepIn();
-      await waiter;
-      bpClient.remove(() => gThreadClient.resume(() => gClient.close().then(gCallback)));
+        // Remove the breakpoint and finish.
+        const waiter = waitForPause(threadClient);
+        threadClient.stepIn();
+        await waiter;
+        bpClient.remove(() => threadClient.resume(resolve));
+      });
     });
+
+    /* eslint-disable */
+    Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
+                     "function foo() {\n" + // line0 + 1
+                     "  this.a = 1;\n" +    // line0 + 2 <-- Breakpoint is set here.
+                     "}\n" +                // line0 + 3
+                     "debugger;\n" +        // line0 + 4
+                     "foo();\n" +           // line0 + 5
+                     "debugger;\n" +        // line0 + 6
+                     "var b = 2;\n",        // line0 + 7
+                     debuggee);
+    /* eslint-enable */
   });
-
-  /* eslint-disable */
-  Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
-                   "function foo() {\n" + // line0 + 1
-                   "  this.a = 1;\n" +    // line0 + 2 <-- Breakpoint is set here.
-                   "}\n" +                // line0 + 3
-                   "debugger;\n" +        // line0 + 4
-                   "foo();\n" +           // line0 + 5
-                   "debugger;\n" +        // line0 + 6
-                   "var b = 2;\n",        // line0 + 7
-                   gDebuggee);
-  /* eslint-enable */
-}
+}));
--- a/devtools/server/tests/unit/test_breakpoint-14.js
+++ b/devtools/server/tests/unit/test_breakpoint-14.js
@@ -4,108 +4,84 @@
 
 "use strict";
 
 /**
  * Check that a breakpoint or a debugger statement cause execution to pause even
  * in a stepped-over function.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-stack",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_simple_breakpoint();
-                           });
-  });
-}
-
-function test_simple_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = { line: gDebuggee.line0 + 2 };
+add_task(threadClientTest(({ threadClient, debuggee }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = { line: debuggee.line0 + 2 };
 
-    source.setBreakpoint(location).then(async function([response, bpClient]) {
-      const testCallbacks = [
-        function(packet) {
-          // Check that the stepping worked.
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 5);
-          Assert.equal(packet.why.type, "resumeLimit");
-        },
-        function(packet) {
-          // Reached the breakpoint.
-          Assert.equal(packet.frame.where.line, location.line);
-          Assert.equal(packet.why.type, "breakpoint");
-          Assert.notEqual(packet.why.type, "resumeLimit");
-        },
-        function(packet) {
-          // Stepped to the closing brace of the function.
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 3);
-          Assert.equal(packet.why.type, "resumeLimit");
-        },
-        function(packet) {
-          // The frame is about to be popped while stepping.
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 3);
-          Assert.notEqual(packet.why.type, "breakpoint");
-          Assert.equal(packet.why.type, "resumeLimit");
-          Assert.equal(packet.why.frameFinished.return.type, "undefined");
-        },
-        function(packet) {
-          // Check that the debugger statement wasn't the reason for this pause.
-          Assert.equal(gDebuggee.a, 1);
-          Assert.equal(gDebuggee.b, undefined);
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 6);
-          Assert.notEqual(packet.why.type, "debuggerStatement");
-          Assert.equal(packet.why.type, "resumeLimit");
-          Assert.equal(packet.poppedFrames.length, 1);
-        },
-        function(packet) {
-          // Check that the debugger statement wasn't the reason for this pause.
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 7);
-          Assert.notEqual(packet.why.type, "debuggerStatement");
-          Assert.equal(packet.why.type, "resumeLimit");
-        },
-      ];
+      source.setBreakpoint(location).then(async function([response, bpClient]) {
+        const testCallbacks = [
+          function(packet) {
+            // Check that the stepping worked.
+            Assert.equal(packet.frame.where.line, debuggee.line0 + 5);
+            Assert.equal(packet.why.type, "resumeLimit");
+          },
+          function(packet) {
+            // Reached the breakpoint.
+            Assert.equal(packet.frame.where.line, location.line);
+            Assert.equal(packet.why.type, "breakpoint");
+            Assert.notEqual(packet.why.type, "resumeLimit");
+          },
+          function(packet) {
+            // Stepped to the closing brace of the function.
+            Assert.equal(packet.frame.where.line, debuggee.line0 + 3);
+            Assert.equal(packet.why.type, "resumeLimit");
+          },
+          function(packet) {
+            // The frame is about to be popped while stepping.
+            Assert.equal(packet.frame.where.line, debuggee.line0 + 3);
+            Assert.notEqual(packet.why.type, "breakpoint");
+            Assert.equal(packet.why.type, "resumeLimit");
+            Assert.equal(packet.why.frameFinished.return.type, "undefined");
+          },
+          function(packet) {
+            // Check that the debugger statement wasn't the reason for this pause.
+            Assert.equal(debuggee.a, 1);
+            Assert.equal(debuggee.b, undefined);
+            Assert.equal(packet.frame.where.line, debuggee.line0 + 6);
+            Assert.notEqual(packet.why.type, "debuggerStatement");
+            Assert.equal(packet.why.type, "resumeLimit");
+            Assert.equal(packet.poppedFrames.length, 1);
+          },
+          function(packet) {
+            // Check that the debugger statement wasn't the reason for this pause.
+            Assert.equal(packet.frame.where.line, debuggee.line0 + 7);
+            Assert.notEqual(packet.why.type, "debuggerStatement");
+            Assert.equal(packet.why.type, "resumeLimit");
+          },
+        ];
 
-      for (const callback of testCallbacks) {
-        const waiter = waitForPause(gThreadClient);
-        gThreadClient.stepOver();
-        const packet = await waiter;
-        callback(packet);
-      }
+        for (const callback of testCallbacks) {
+          const waiter = waitForPause(threadClient);
+          threadClient.stepOver();
+          const packet = await waiter;
+          callback(packet);
+        }
 
-      // Remove the breakpoint and finish.
-      const waiter = waitForPause(gThreadClient);
-      gThreadClient.stepOver();
-      await waiter;
-      bpClient.remove(() => gThreadClient.resume(() => gClient.close().then(gCallback)));
+        // Remove the breakpoint and finish.
+        const waiter = waitForPause(threadClient);
+        threadClient.stepOver();
+        await waiter;
+        bpClient.remove(() => threadClient.resume(resolve));
+      });
     });
+
+    /* eslint-disable */
+    Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
+                     "function foo() {\n" + // line0 + 1
+                     "  this.a = 1;\n" +    // line0 + 2 <-- Breakpoint is set here.
+                     "}\n" +                // line0 + 3
+                     "debugger;\n" +        // line0 + 4
+                     "foo();\n" +           // line0 + 5
+                     "debugger;\n" +        // line0 + 6
+                     "var b = 2;\n",        // line0 + 7
+                     debuggee);
+    /* eslint-enable */
   });
-
-  /* eslint-disable */
-  Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
-                   "function foo() {\n" + // line0 + 1
-                   "  this.a = 1;\n" +    // line0 + 2 <-- Breakpoint is set here.
-                   "}\n" +                // line0 + 3
-                   "debugger;\n" +        // line0 + 4
-                   "foo();\n" +           // line0 + 5
-                   "debugger;\n" +        // line0 + 6
-                   "var b = 2;\n",        // line0 + 7
-                   gDebuggee);
-  /* eslint-enable */
-}
+}));
--- a/devtools/server/tests/unit/test_breakpoint-16.js
+++ b/devtools/server/tests/unit/test_breakpoint-16.js
@@ -3,81 +3,56 @@
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 /**
  * Check that we can set breakpoints in columns, not just lines.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    // Debugger statement
+    client.addOneTimeListener("paused", function(event, packet) {
+      const source = threadClient.source(packet.frame.where.source);
+      const location = {
+        line: debuggee.line0 + 1,
+        column: 55,
+      };
+      let timesBreakpointHit = 0;
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-breakpoints", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient,
-                           "test-breakpoints",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_column_breakpoint();
-                           });
-  });
-}
+      source.setBreakpoint(location).then(function([response, bpClient]) {
+        threadClient.addListener("paused", function onPaused(event, packet) {
+          Assert.equal(packet.type, "paused");
+          Assert.equal(packet.why.type, "breakpoint");
+          Assert.equal(packet.why.actors[0], bpClient.actor);
+          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.line, location.line);
+          Assert.equal(packet.frame.where.column, location.column);
 
-function test_column_breakpoint() {
-  // Debugger statement
-  gClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    const location = {
-      line: gDebuggee.line0 + 1,
-      column: 55,
-    };
-    let timesBreakpointHit = 0;
+          Assert.equal(debuggee.acc, timesBreakpointHit);
+          Assert.equal(packet.frame.environment.bindings.variables.i.value,
+                       timesBreakpointHit);
 
-    source.setBreakpoint(location).then(function([response, bpClient]) {
-      gThreadClient.addListener("paused", function onPaused(event, packet) {
-        Assert.equal(packet.type, "paused");
-        Assert.equal(packet.why.type, "breakpoint");
-        Assert.equal(packet.why.actors[0], bpClient.actor);
-        Assert.equal(packet.frame.where.source.actor, source.actor);
-        Assert.equal(packet.frame.where.line, location.line);
-        Assert.equal(packet.frame.where.column, location.column);
-
-        Assert.equal(gDebuggee.acc, timesBreakpointHit);
-        Assert.equal(packet.frame.environment.bindings.variables.i.value,
-                     timesBreakpointHit);
+          if (++timesBreakpointHit === 3) {
+            threadClient.removeListener("paused", onPaused);
+            bpClient.remove(function(response) {
+              threadClient.resume(resolve);
+            });
+          } else {
+            threadClient.resume();
+          }
+        });
 
-        if (++timesBreakpointHit === 3) {
-          gThreadClient.removeListener("paused", onPaused);
-          bpClient.remove(function(response) {
-            gThreadClient.resume(() => gClient.close().then(gCallback));
-          });
-        } else {
-          gThreadClient.resume();
-        }
+        // Continue until the breakpoint is hit.
+        threadClient.resume();
       });
+    });
 
-      // Continue until the breakpoint is hit.
-      gThreadClient.resume();
-    });
+    /* eslint-disable */
+    Cu.evalInSandbox(
+      "var line0 = Error().lineNumber;\n" +
+      "(function () { debugger; this.acc = 0; for (var i = 0; i < 3; i++) this.acc++; }());",
+      debuggee
+    );
+    /* eslint-enable */
   });
-
-  /* eslint-disable */
-  Cu.evalInSandbox(
-    "var line0 = Error().lineNumber;\n" +
-    "(function () { debugger; this.acc = 0; for (var i = 0; i < 3; i++) this.acc++; }());",
-    gDebuggee
-  );
-  /* eslint-enable */
-}
+}));
--- a/devtools/server/tests/unit/test_breakpoint-17.js
+++ b/devtools/server/tests/unit/test_breakpoint-17.js
@@ -4,40 +4,16 @@
 
 "use strict";
 
 /**
  * Test that when we add 2 breakpoints to the same line at different columns and
  * then remove one of them, we don't remove them both.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, do_test_finished);
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-breakpoints", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-breakpoints",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_breakpoints_columns();
-                           });
-  });
-}
-
 const code =
 "(" + function(global) {
   global.foo = function() {
     Math.abs(-1); Math.log(0.5);
     debugger;
   };
   debugger;
 } + "(this))";
@@ -47,74 +23,84 @@ const firstLocation = {
   column: 4,
 };
 
 const secondLocation = {
   line: 3,
   column: 18,
 };
 
-function test_breakpoints_columns() {
-  gClient.addOneTimeListener("paused", set_breakpoints);
+add_task(threadClientTest(({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    client.addOneTimeListener("paused", async (event, packet) => {
+      const [ first, second ] = await set_breakpoints(packet, threadClient);
+      test_different_actors(first, second);
+      await test_remove_one(first, second, threadClient, debuggee, client);
+      resolve();
+    });
 
-  Cu.evalInSandbox(code, gDebuggee, "1.8", "http://example.com/", 1);
-}
-
-function set_breakpoints(event, packet) {
-  let first, second;
-  const source = gThreadClient.source(packet.frame.where.source);
+    Cu.evalInSandbox(code, debuggee, "1.8", "http://example.com/", 1);
+  });
+}));
 
-  source.setBreakpoint(firstLocation).then(function([{ actualLocation },
-                                                     breakpointClient]) {
-    Assert.ok(!actualLocation, "Should not get an actualLocation");
-    first = breakpointClient;
+function set_breakpoints(packet, threadClient) {
+  return new Promise(resolve => {
+    let first, second;
+    const source = threadClient.source(packet.frame.where.source);
 
-    source.setBreakpoint(secondLocation).then(function([{ actualLocation },
-                                                        breakpointClient]) {
+    source.setBreakpoint(firstLocation).then(function([{ actualLocation },
+                                                       breakpointClient]) {
       Assert.ok(!actualLocation, "Should not get an actualLocation");
-      second = breakpointClient;
+      first = breakpointClient;
 
-      test_different_actors(first, second);
+      source.setBreakpoint(secondLocation).then(function([{ actualLocation },
+                                                          breakpointClient]) {
+        Assert.ok(!actualLocation, "Should not get an actualLocation");
+        second = breakpointClient;
+
+        resolve([first, second]);
+      });
     });
   });
 }
 
 function test_different_actors(first, second) {
   Assert.notEqual(first.actor, second.actor,
                   "Each breakpoint should have a different actor");
-  test_remove_one(first, second);
 }
 
-function test_remove_one(first, second) {
-  first.remove(function({error}) {
-    Assert.ok(!error, "Should not get an error removing a breakpoint");
+function test_remove_one(first, second, threadClient, debuggee, client) {
+  return new Promise(resolve => {
+    first.remove(function({error}) {
+      Assert.ok(!error, "Should not get an error removing a breakpoint");
 
-    let hitSecond;
-    gClient.addListener("paused", function _onPaused(event, {why, frame}) {
-      if (why.type == "breakpoint") {
-        hitSecond = true;
-        Assert.equal(why.actors.length, 1,
-                     "Should only be paused because of one breakpoint actor");
-        Assert.equal(why.actors[0], second.actor,
-                     "Should be paused because of the correct breakpoint actor");
-        Assert.equal(frame.where.line, secondLocation.line,
-                     "Should be at the right line");
-        Assert.equal(frame.where.column, secondLocation.column,
-                     "Should be at the right column");
-        gThreadClient.resume();
-        return;
-      }
+      let hitSecond;
+      client.addListener("paused", function _onPaused(event, {why, frame}) {
+        if (why.type == "breakpoint") {
+          hitSecond = true;
+          Assert.equal(why.actors.length, 1,
+                       "Should only be paused because of one breakpoint actor");
+          Assert.equal(why.actors[0], second.actor,
+                       "Should be paused because of the correct breakpoint actor");
+          Assert.equal(frame.where.line, secondLocation.line,
+                       "Should be at the right line");
+          Assert.equal(frame.where.column, secondLocation.column,
+                       "Should be at the right column");
+          threadClient.resume();
+          return;
+        }
 
-      if (why.type == "debuggerStatement") {
-        gClient.removeListener("paused", _onPaused);
-        Assert.ok(hitSecond,
-                  "We should still hit `second`, but not `first`.");
+        if (why.type == "debuggerStatement") {
+          client.removeListener("paused", _onPaused);
+          Assert.ok(hitSecond,
+                    "We should still hit `second`, but not `first`.");
 
-        gClient.close().then(gCallback);
-        return;
-      }
+          resolve();
+          return;
+        }
 
-      Assert.ok(false, "Should never get here");
+        Assert.ok(false, "Should never get here");
+      });
+
+      threadClient.resume(() => debuggee.foo());
     });
-
-    gThreadClient.resume(() => gDebuggee.foo());
   });
 }
--- a/devtools/server/tests/unit/test_breakpoint-18.js
+++ b/devtools/server/tests/unit/test_breakpoint-18.js
@@ -3,79 +3,61 @@
 
 "use strict";
 
 /**
  * Check that we only break on offsets that are entry points for the line we are
  * breaking on. Bug 907278.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
+add_task(threadClientTest(({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    // Expose console as the test script uses it
+    debuggee.console = { log: x => void x };
+
+    // Inline all paused listeners as promises won't resolve when paused
+    client.addOneTimeListener("paused", async (event1, packet1) => {
+      await setBreakpoint(packet1, threadClient, client);
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+      client.addOneTimeListener("paused", (event2, { why }) => {
+        Assert.equal(why.type, "breakpoint");
+
+        client.addOneTimeListener("paused", (event3, packet3) => {
+          testDbgStatement(packet3);
+          resolve();
+        });
+        threadClient.resume();
+      });
+      debuggee.test();
+    });
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-breakpoints", server);
-  gDebuggee.console = { log: x => void x };
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient,
-                           "test-breakpoints",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             setUpCode();
-                           });
+    Cu.evalInSandbox(
+      "debugger;\n" +
+      function test() {
+        console.log("foo bar");
+        debugger;
+      },
+      debuggee,
+      "1.8",
+      "http://example.com/",
+      1
+    );
+  });
+}));
+
+function setBreakpoint(packet, threadClient, client) {
+  return new Promise(resolve => {
+    const source = threadClient.source(packet.frame.where.source);
+    client.addOneTimeListener("resumed", resolve);
+
+    source.setBreakpoint({ line: 2 }).then(() => {
+      threadClient.resume();
+    });
   });
 }
 
-function setUpCode() {
-  gClient.addOneTimeListener("paused", setBreakpoint);
-  Cu.evalInSandbox(
-    "debugger;\n" +
-    function test() {
-      console.log("foo bar");
-      debugger;
-    },
-    gDebuggee,
-    "1.8",
-    "http://example.com/",
-    1
-  );
-}
-
-function setBreakpoint(event, packet) {
-  const source = gThreadClient.source(packet.frame.where.source);
-  gClient.addOneTimeListener("resumed", runCode);
-
-  source.setBreakpoint({ line: 2 }).then(() => {
-    gThreadClient.resume();
-  });
-}
-
-function runCode() {
-  gClient.addOneTimeListener("paused", testBPHit);
-  gDebuggee.test();
-}
-
-function testBPHit(event, { why }) {
-  Assert.equal(why.type, "breakpoint");
-  gClient.addOneTimeListener("paused", testDbgStatement);
-  gThreadClient.resume();
-}
-
-function testDbgStatement(event, { why }) {
+function testDbgStatement({ why }) {
   // Should continue to the debugger statement.
   Assert.equal(why.type, "debuggerStatement");
   // Not break on another offset from the same line (that isn't an entry point
   // to the line)
   Assert.notEqual(why.type, "breakpoint");
-  gClient.close().then(gCallback);
 }
--- a/devtools/server/tests/unit/test_breakpoint-19.js
+++ b/devtools/server/tests/unit/test_breakpoint-19.js
@@ -3,68 +3,40 @@
 
 "use strict";
 
 /**
  * Make sure that setting a breakpoint in a not-yet-existing script doesn't throw
  * an error (see bug 897567). Also make sure that this breakpoint works.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-breakpoints", server);
-  gDebuggee.console = { log: x => void x };
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient,
-                           "test-breakpoints",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             testBreakpoint();
-                           });
-  });
-}
-
 const URL = "test.js";
 
-function setUpCode() {
+function setUpCode(debuggee) {
   /* eslint-disable */
   Cu.evalInSandbox(
     "" + function test() { // 1
       var a = 1;           // 2
       debugger;            // 3
     } +                    // 4
     "\ndebugger;",         // 5
-    gDebuggee,
+    debuggee,
     "1.8",
     URL
   );
   /* eslint-enable */
 }
 
-const testBreakpoint = async function() {
-  const source = await getSource(gThreadClient, URL);
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  const source = await getSource(threadClient, URL);
   const [response ] = await setBreakpoint(source, {line: 2});
   ok(!response.error);
 
   const actor = response.actor;
   ok(actor);
 
-  await executeOnNextTickAndWaitForPause(setUpCode, gClient);
-  await resume(gThreadClient);
+  await executeOnNextTickAndWaitForPause(() => setUpCode(debuggee), client);
+  await resume(threadClient);
 
-  const packet = await executeOnNextTickAndWaitForPause(gDebuggee.test, gClient);
+  const packet = await executeOnNextTickAndWaitForPause(debuggee.test, client);
   equal(packet.why.type, "breakpoint");
   notEqual(packet.why.actors.indexOf(actor), -1);
-
-  finishClient(gClient);
-};
+}));
--- a/devtools/server/tests/unit/test_breakpoint-21.js
+++ b/devtools/server/tests/unit/test_breakpoint-21.js
@@ -4,69 +4,45 @@
 "use strict";
 
 /**
  * Bug 1122064 - make sure that scripts introduced via onNewScripts
  * properly populate the `ScriptStore` with all there nested child
  * scripts, so you can set breakpoints on deeply nested scripts
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-breakpoints", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient,
-                           "test-breakpoints",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test();
-                           });
-  });
-}
-
-const test = async function() {
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   // Populate the `ScriptStore` so that we only test that the script
   // is added through `onNewScript`
-  await getSources(gThreadClient);
+  await getSources(threadClient);
 
-  let packet = await executeOnNextTickAndWaitForPause(evalCode, gClient);
-  const source = gThreadClient.source(packet.frame.where.source);
+  let packet = await executeOnNextTickAndWaitForPause(() => {
+    evalCode(debuggee);
+  }, client);
+  const source = threadClient.source(packet.frame.where.source);
   const location = {
-    line: gDebuggee.line0 + 8,
+    line: debuggee.line0 + 8,
   };
 
   const [res, bpClient] = await setBreakpoint(source, location);
   ok(!res.error);
 
-  await resume(gThreadClient);
-  packet = await waitForPause(gClient);
+  await resume(threadClient);
+  packet = await waitForPause(client);
   Assert.equal(packet.type, "paused");
   Assert.equal(packet.why.type, "breakpoint");
   Assert.equal(packet.why.actors[0], bpClient.actor);
   Assert.equal(packet.frame.where.source.actor, source.actor);
   Assert.equal(packet.frame.where.line, location.line);
 
-  await resume(gThreadClient);
-  finishClient(gClient);
-};
+  await resume(threadClient);
+}));
 
 /* eslint-disable */
-function evalCode() {
+function evalCode(debuggee) {
   // Start a new script
   Cu.evalInSandbox(
     "var line0 = Error().lineNumber;\n(" + function () {
       debugger;
       var a = (function () {
         return (function () {
           return (function () {
             return (function () {
@@ -74,11 +50,11 @@ function evalCode() {
                 var x = 10; // This line gets a breakpoint
                 return 1;
               })();
             })();
           })();
         })();
       })();
     } + ")()",
-    gDebuggee
+    debuggee
   );
 }
--- a/devtools/server/tests/unit/test_breakpoint-22.js
+++ b/devtools/server/tests/unit/test_breakpoint-22.js
@@ -3,73 +3,49 @@
 
 "use strict";
 
 /**
  * Bug 1333219 - make that setBreakpoint fails when script is not found
  * at the specified line.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-breakpoints", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient,
-                           "test-breakpoints",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test();
-                           });
-  });
-}
-
-const test = async function() {
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   // Populate the `ScriptStore` so that we only test that the script
   // is added through `onNewScript`
-  await getSources(gThreadClient);
+  await getSources(threadClient);
 
-  const packet = await executeOnNextTickAndWaitForPause(evalCode, gClient);
-  const source = gThreadClient.source(packet.frame.where.source);
+  const packet = await executeOnNextTickAndWaitForPause(() => {
+    evalCode(debuggee);
+  }, client);
+  const source = threadClient.source(packet.frame.where.source);
   const location = {
-    line: gDebuggee.line0 + 2,
+    line: debuggee.line0 + 2,
   };
 
   const [res ] = await setBreakpoint(source, location);
   ok(!res.error);
 
   const location2 = {
-    line: gDebuggee.line0 + 7,
+    line: debuggee.line0 + 7,
   };
 
   await source.setBreakpoint(location2).then(() => {
     do_throw("no code shall not be found the specified line or below it");
   }, reason => {
     Assert.equal(reason.error, "noCodeAtLineColumn");
     ok(reason.message);
   });
 
-  await resume(gThreadClient);
-  finishClient(gClient);
-};
+  await resume(threadClient);
+}));
 
-function evalCode() {
+function evalCode(debuggee) {
   // Start a new script
   Cu.evalInSandbox(`
 var line0 = Error().lineNumber;
 function some_function() {
   // breakpoint is valid here -- it slides one line below (line0 + 2)
 }
 debugger;
 // no breakpoint is allowed after the EOF (line0 + 6)
-`, gDebuggee);
+`, debuggee);
 }
--- a/devtools/server/tests/unit/test_objectgrips-01.js
+++ b/devtools/server/tests/unit/test_objectgrips-01.js
@@ -1,61 +1,35 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
+Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
+registerCleanupFunction(() => {
+  Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
+});
 
-function run_test() {
-  Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-  registerCleanupFunction(() => {
-    Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
-  });
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1) {
-    debugger;
-  }.toString());
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const args = packet.frame.arguments;
 
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-grips",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_object_grip();
-                           });
-  });
-}
+      Assert.equal(args[0].class, "Object");
 
-function test_object_grip() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const args = packet.frame.arguments;
-
-    Assert.equal(args[0].class, "Object");
+      const objClient = threadClient.pauseGrip(args[0]);
+      objClient.getOwnPropertyNames(function(response) {
+        Assert.equal(response.ownPropertyNames.length, 3);
+        Assert.equal(response.ownPropertyNames[0], "a");
+        Assert.equal(response.ownPropertyNames[1], "b");
+        Assert.equal(response.ownPropertyNames[2], "c");
 
-    const objClient = gThreadClient.pauseGrip(args[0]);
-    objClient.getOwnPropertyNames(function(response) {
-      Assert.equal(response.ownPropertyNames.length, 3);
-      Assert.equal(response.ownPropertyNames[0], "a");
-      Assert.equal(response.ownPropertyNames[1], "b");
-      Assert.equal(response.ownPropertyNames[2], "c");
-
-      gThreadClient.resume(function() {
-        gClient.close().then(gCallback);
+        threadClient.resume(resolve);
       });
     });
-  });
 
-  gDebuggee.eval("stopMe({ a: 1, b: true, c: 'foo' })");
-}
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    debuggee.eval("stopMe({ a: 1, b: true, c: 'foo' })");
+  });
+}));
 
--- a/devtools/server/tests/unit/test_objectgrips-02.js
+++ b/devtools/server/tests/unit/test_objectgrips-02.js
@@ -1,70 +1,43 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
+Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
+registerCleanupFunction(() => {
+  Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
+});
 
-function run_test() {
-  Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-  registerCleanupFunction(() => {
-    Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
-  });
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const args = packet.frame.arguments;
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1) {
-    debugger;
-  }.toString());
+      Assert.equal(args[0].class, "Object");
 
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-grips",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_object_grip();
-                           });
-  });
-}
-
-function test_object_grip() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const args = packet.frame.arguments;
+      const objClient = threadClient.pauseGrip(args[0]);
+      objClient.getPrototype(function(response) {
+        Assert.ok(response.prototype != undefined);
 
-    Assert.equal(args[0].class, "Object");
-
-    const objClient = gThreadClient.pauseGrip(args[0]);
-    objClient.getPrototype(function(response) {
-      Assert.ok(response.prototype != undefined);
+        const protoClient = threadClient.pauseGrip(response.prototype);
+        protoClient.getOwnPropertyNames(function(response) {
+          Assert.equal(response.ownPropertyNames.length, 2);
+          Assert.equal(response.ownPropertyNames[0], "b");
+          Assert.equal(response.ownPropertyNames[1], "c");
 
-      const protoClient = gThreadClient.pauseGrip(response.prototype);
-      protoClient.getOwnPropertyNames(function(response) {
-        Assert.equal(response.ownPropertyNames.length, 2);
-        Assert.equal(response.ownPropertyNames[0], "b");
-        Assert.equal(response.ownPropertyNames[1], "c");
-
-        gThreadClient.resume(function() {
-          gClient.close().then(gCallback);
+          threadClient.resume(resolve);
         });
       });
     });
+
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    debuggee.eval(function Constr() {
+      this.a = 1;
+    }.toString());
+    debuggee.eval(
+      "Constr.prototype = { b: true, c: 'foo' }; var o = new Constr(); stopMe(o)");
   });
-
-  gDebuggee.eval(function Constr() {
-    this.a = 1;
-  }.toString());
-  gDebuggee.eval(
-    "Constr.prototype = { b: true, c: 'foo' }; var o = new Constr(); stopMe(o)");
-}
-
+}));
--- a/devtools/server/tests/unit/test_objectgrips-03.js
+++ b/devtools/server/tests/unit/test_objectgrips-03.js
@@ -1,77 +1,50 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
-function run_test() {
-  Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-  registerCleanupFunction(() => {
-    Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
-  });
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1) {
-    debugger;
-  }.toString());
+Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
+registerCleanupFunction(() => {
+  Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
+});
 
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-grips",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_object_grip();
-                           });
-  });
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const args = packet.frame.arguments;
 
-function test_object_grip() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const args = packet.frame.arguments;
-
-    Assert.equal(args[0].class, "Object");
+      Assert.equal(args[0].class, "Object");
 
-    const objClient = gThreadClient.pauseGrip(args[0]);
-    objClient.getProperty("x", function(response) {
-      Assert.equal(response.descriptor.configurable, true);
-      Assert.equal(response.descriptor.enumerable, true);
-      Assert.equal(response.descriptor.writable, true);
-      Assert.equal(response.descriptor.value, 10);
-
-      objClient.getProperty("y", function(response) {
+      const objClient = threadClient.pauseGrip(args[0]);
+      objClient.getProperty("x", function(response) {
         Assert.equal(response.descriptor.configurable, true);
         Assert.equal(response.descriptor.enumerable, true);
         Assert.equal(response.descriptor.writable, true);
-        Assert.equal(response.descriptor.value, "kaiju");
+        Assert.equal(response.descriptor.value, 10);
 
-        objClient.getProperty("a", function(response) {
+        objClient.getProperty("y", function(response) {
           Assert.equal(response.descriptor.configurable, true);
           Assert.equal(response.descriptor.enumerable, true);
-          Assert.equal(response.descriptor.get.type, "object");
-          Assert.equal(response.descriptor.get.class, "Function");
-          Assert.equal(response.descriptor.set.type, "undefined");
+          Assert.equal(response.descriptor.writable, true);
+          Assert.equal(response.descriptor.value, "kaiju");
 
-          gThreadClient.resume(function() {
-            gClient.close().then(gCallback);
+          objClient.getProperty("a", function(response) {
+            Assert.equal(response.descriptor.configurable, true);
+            Assert.equal(response.descriptor.enumerable, true);
+            Assert.equal(response.descriptor.get.type, "object");
+            Assert.equal(response.descriptor.get.class, "Function");
+            Assert.equal(response.descriptor.set.type, "undefined");
+
+            threadClient.resume(resolve);
           });
         });
       });
     });
+
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    debuggee.eval("stopMe({ x: 10, y: 'kaiju', get a() { return 42; } })");
   });
-
-  gDebuggee.eval("stopMe({ x: 10, y: 'kaiju', get a() { return 42; } })");
-}
-
+}));
--- a/devtools/server/tests/unit/test_objectgrips-04.js
+++ b/devtools/server/tests/unit/test_objectgrips-04.js
@@ -1,82 +1,54 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const args = packet.frame.arguments;
+
+      Assert.equal(args[0].class, "Object");
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1) {
-    debugger;
-  }.toString());
-
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-grips",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_object_grip();
-                           });
-  });
-}
-
-function test_object_grip() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const args = packet.frame.arguments;
+      const objClient = threadClient.pauseGrip(args[0]);
+      objClient.getPrototypeAndProperties(function(response) {
+        Assert.equal(response.ownProperties.x.configurable, true);
+        Assert.equal(response.ownProperties.x.enumerable, true);
+        Assert.equal(response.ownProperties.x.writable, true);
+        Assert.equal(response.ownProperties.x.value, 10);
 
-    Assert.equal(args[0].class, "Object");
-
-    const objClient = gThreadClient.pauseGrip(args[0]);
-    objClient.getPrototypeAndProperties(function(response) {
-      Assert.equal(response.ownProperties.x.configurable, true);
-      Assert.equal(response.ownProperties.x.enumerable, true);
-      Assert.equal(response.ownProperties.x.writable, true);
-      Assert.equal(response.ownProperties.x.value, 10);
-
-      Assert.equal(response.ownProperties.y.configurable, true);
-      Assert.equal(response.ownProperties.y.enumerable, true);
-      Assert.equal(response.ownProperties.y.writable, true);
-      Assert.equal(response.ownProperties.y.value, "kaiju");
+        Assert.equal(response.ownProperties.y.configurable, true);
+        Assert.equal(response.ownProperties.y.enumerable, true);
+        Assert.equal(response.ownProperties.y.writable, true);
+        Assert.equal(response.ownProperties.y.value, "kaiju");
 
-      Assert.equal(response.ownProperties.a.configurable, true);
-      Assert.equal(response.ownProperties.a.enumerable, true);
-      Assert.equal(response.ownProperties.a.get.type, "object");
-      Assert.equal(response.ownProperties.a.get.class, "Function");
-      Assert.equal(response.ownProperties.a.set.type, "undefined");
+        Assert.equal(response.ownProperties.a.configurable, true);
+        Assert.equal(response.ownProperties.a.enumerable, true);
+        Assert.equal(response.ownProperties.a.get.type, "object");
+        Assert.equal(response.ownProperties.a.get.class, "Function");
+        Assert.equal(response.ownProperties.a.set.type, "undefined");
 
-      Assert.ok(response.prototype != undefined);
+        Assert.ok(response.prototype != undefined);
 
-      const protoClient = gThreadClient.pauseGrip(response.prototype);
-      protoClient.getOwnPropertyNames(function(response) {
-        Assert.ok(response.ownPropertyNames.toString != undefined);
+        const protoClient = threadClient.pauseGrip(response.prototype);
+        protoClient.getOwnPropertyNames(function(response) {
+          Assert.ok(response.ownPropertyNames.toString != undefined);
 
-        gThreadClient.resume(function() {
-          gClient.close().then(gCallback);
+          threadClient.resume(resolve);
         });
       });
     });
-  });
 
-  gDebuggee.eval("stopMe({ x: 10, y: 'kaiju', get a() { return 42; } })");
-}
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    debuggee.eval("stopMe({ x: 10, y: 'kaiju', get a() { return 42; } })");
+  });
+}));
 
--- a/devtools/server/tests/unit/test_objectgrips-05.js
+++ b/devtools/server/tests/unit/test_objectgrips-05.js
@@ -3,71 +3,43 @@
 
 "use strict";
 
 /**
  * This test checks that frozen objects report themselves as frozen in their
  * grip.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const obj1 = packet.frame.arguments[0];
+      Assert.ok(obj1.frozen);
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1, arg2) {
-    debugger;
-  }.toString());
+      const obj1Client = threadClient.pauseGrip(obj1);
+      Assert.ok(obj1Client.isFrozen);
 
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-grips",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_object_grip();
-                           });
-  });
-}
+      const obj2 = packet.frame.arguments[1];
+      Assert.ok(!obj2.frozen);
+
+      const obj2Client = threadClient.pauseGrip(obj2);
+      Assert.ok(!obj2Client.isFrozen);
 
-function test_object_grip() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const obj1 = packet.frame.arguments[0];
-    Assert.ok(obj1.frozen);
-
-    const obj1Client = gThreadClient.pauseGrip(obj1);
-    Assert.ok(obj1Client.isFrozen);
-
-    const obj2 = packet.frame.arguments[1];
-    Assert.ok(!obj2.frozen);
-
-    const obj2Client = gThreadClient.pauseGrip(obj2);
-    Assert.ok(!obj2Client.isFrozen);
+      threadClient.resume(resolve);
+    });
 
-    gThreadClient.resume(_ => {
-      gClient.close().then(gCallback);
-    });
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    /* eslint-disable no-undef */
+    debuggee.eval("(" + function() {
+      const obj1 = {};
+      Object.freeze(obj1);
+      stopMe(obj1, {});
+    } + "())");
+    /* eslint-enable no-undef */
   });
-
-  /* eslint-disable no-undef */
-  gDebuggee.eval("(" + function() {
-    const obj1 = {};
-    Object.freeze(obj1);
-    stopMe(obj1, {});
-  } + "())");
-  /* eslint-enable no-undef */
-}
+}));
--- a/devtools/server/tests/unit/test_objectgrips-06.js
+++ b/devtools/server/tests/unit/test_objectgrips-06.js
@@ -3,71 +3,43 @@
 
 "use strict";
 
 /**
  * This test checks that sealed objects report themselves as sealed in their
  * grip.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const obj1 = packet.frame.arguments[0];
+      Assert.ok(obj1.sealed);
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1, arg2) {
-    debugger;
-  }.toString());
+      const obj1Client = threadClient.pauseGrip(obj1);
+      Assert.ok(obj1Client.isSealed);
 
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-grips",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_object_grip();
-                           });
-  });
-}
+      const obj2 = packet.frame.arguments[1];
+      Assert.ok(!obj2.sealed);
+
+      const obj2Client = threadClient.pauseGrip(obj2);
+      Assert.ok(!obj2Client.isSealed);
 
-function test_object_grip() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const obj1 = packet.frame.arguments[0];
-    Assert.ok(obj1.sealed);
-
-    const obj1Client = gThreadClient.pauseGrip(obj1);
-    Assert.ok(obj1Client.isSealed);
-
-    const obj2 = packet.frame.arguments[1];
-    Assert.ok(!obj2.sealed);
-
-    const obj2Client = gThreadClient.pauseGrip(obj2);
-    Assert.ok(!obj2Client.isSealed);
+      threadClient.resume(resolve);
+    });
 
-    gThreadClient.resume(_ => {
-      gClient.close().then(gCallback);
-    });
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    /* eslint-disable no-undef */
+    debuggee.eval("(" + function() {
+      const obj1 = {};
+      Object.seal(obj1);
+      stopMe(obj1, {});
+    } + "())");
+    /* eslint-enable no-undef */
   });
-
-  /* eslint-disable no-undef */
-  gDebuggee.eval("(" + function() {
-    const obj1 = {};
-    Object.seal(obj1);
-    stopMe(obj1, {});
-  } + "())");
-  /* eslint-enable no-undef */
-}
+}));
--- a/devtools/server/tests/unit/test_objectgrips-07.js
+++ b/devtools/server/tests/unit/test_objectgrips-07.js
@@ -3,79 +3,51 @@
 
 "use strict";
 
 /**
  * This test checks that objects which are not extensible report themselves as
  * such.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const [f, s, ne, e] = packet.frame.arguments;
+      const [fClient, sClient, neClient, eClient] = packet.frame.arguments.map(
+        a => threadClient.pauseGrip(a));
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1, arg2, arg3, arg4) {
-    debugger;
-  }.toString());
+      Assert.ok(!f.extensible);
+      Assert.ok(!fClient.isExtensible);
+
+      Assert.ok(!s.extensible);
+      Assert.ok(!sClient.isExtensible);
 
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-grips",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_object_grip();
-                           });
-  });
-}
+      Assert.ok(!ne.extensible);
+      Assert.ok(!neClient.isExtensible);
+
+      Assert.ok(e.extensible);
+      Assert.ok(eClient.isExtensible);
 
-function test_object_grip() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const [f, s, ne, e] = packet.frame.arguments;
-    const [fClient, sClient, neClient, eClient] = packet.frame.arguments.map(
-      a => gThreadClient.pauseGrip(a));
-
-    Assert.ok(!f.extensible);
-    Assert.ok(!fClient.isExtensible);
-
-    Assert.ok(!s.extensible);
-    Assert.ok(!sClient.isExtensible);
-
-    Assert.ok(!ne.extensible);
-    Assert.ok(!neClient.isExtensible);
-
-    Assert.ok(e.extensible);
-    Assert.ok(eClient.isExtensible);
+      threadClient.resume(resolve);
+    });
 
-    gThreadClient.resume(_ => {
-      gClient.close().then(gCallback);
-    });
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    /* eslint-disable no-undef */
+    debuggee.eval("(" + function() {
+      const f = {};
+      Object.freeze(f);
+      const s = {};
+      Object.seal(s);
+      const ne = {};
+      Object.preventExtensions(ne);
+      stopMe(f, s, ne, {});
+    } + "())");
+    /* eslint-enable no-undef */
   });
-
-  /* eslint-disable no-undef */
-  gDebuggee.eval("(" + function() {
-    const f = {};
-    Object.freeze(f);
-    const s = {};
-    Object.seal(s);
-    const ne = {};
-    Object.preventExtensions(ne);
-    stopMe(f, s, ne, {});
-  } + "())");
-  /* eslint-enable no-undef */
-}
+}));
--- a/devtools/server/tests/unit/test_objectgrips-08.js
+++ b/devtools/server/tests/unit/test_objectgrips-08.js
@@ -1,78 +1,50 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const args = packet.frame.arguments;
+
+      Assert.equal(args[0].class, "Object");
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1) {
-    debugger;
-  }.toString());
-
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-grips",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_object_grip();
-                           });
-  });
-}
+      const objClient = threadClient.pauseGrip(args[0]);
+      objClient.getPrototypeAndProperties(function(response) {
+        Assert.equal(response.ownProperties.a.configurable, true);
+        Assert.equal(response.ownProperties.a.enumerable, true);
+        Assert.equal(response.ownProperties.a.writable, true);
+        Assert.equal(response.ownProperties.a.value.type, "Infinity");
 
-function test_object_grip() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const args = packet.frame.arguments;
-
-    Assert.equal(args[0].class, "Object");
-
-    const objClient = gThreadClient.pauseGrip(args[0]);
-    objClient.getPrototypeAndProperties(function(response) {
-      Assert.equal(response.ownProperties.a.configurable, true);
-      Assert.equal(response.ownProperties.a.enumerable, true);
-      Assert.equal(response.ownProperties.a.writable, true);
-      Assert.equal(response.ownProperties.a.value.type, "Infinity");
+        Assert.equal(response.ownProperties.b.configurable, true);
+        Assert.equal(response.ownProperties.b.enumerable, true);
+        Assert.equal(response.ownProperties.b.writable, true);
+        Assert.equal(response.ownProperties.b.value.type, "-Infinity");
 
-      Assert.equal(response.ownProperties.b.configurable, true);
-      Assert.equal(response.ownProperties.b.enumerable, true);
-      Assert.equal(response.ownProperties.b.writable, true);
-      Assert.equal(response.ownProperties.b.value.type, "-Infinity");
+        Assert.equal(response.ownProperties.c.configurable, true);
+        Assert.equal(response.ownProperties.c.enumerable, true);
+        Assert.equal(response.ownProperties.c.writable, true);
+        Assert.equal(response.ownProperties.c.value.type, "NaN");
 
-      Assert.equal(response.ownProperties.c.configurable, true);
-      Assert.equal(response.ownProperties.c.enumerable, true);
-      Assert.equal(response.ownProperties.c.writable, true);
-      Assert.equal(response.ownProperties.c.value.type, "NaN");
+        Assert.equal(response.ownProperties.d.configurable, true);
+        Assert.equal(response.ownProperties.d.enumerable, true);
+        Assert.equal(response.ownProperties.d.writable, true);
+        Assert.equal(response.ownProperties.d.value.type, "-0");
 
-      Assert.equal(response.ownProperties.d.configurable, true);
-      Assert.equal(response.ownProperties.d.enumerable, true);
-      Assert.equal(response.ownProperties.d.writable, true);
-      Assert.equal(response.ownProperties.d.value.type, "-0");
-
-      gThreadClient.resume(function() {
-        gClient.close().then(gCallback);
+        threadClient.resume(resolve);
       });
     });
-  });
 
-  gDebuggee.eval("stopMe({ a: Infinity, b: -Infinity, c: NaN, d: -0 })");
-}
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    debuggee.eval("stopMe({ a: Infinity, b: -Infinity, c: NaN, d: -0 })");
+  });
+}));
 
--- a/devtools/server/tests/unit/test_objectgrips-09.js
+++ b/devtools/server/tests/unit/test_objectgrips-09.js
@@ -3,79 +3,51 @@
 
 "use strict";
 
 /**
  * This tests exercises getProtypesAndProperties message accepted
  * by a thread actor.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", function(event, packet) {
+      const args = packet.frame.arguments;
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1, arg2) {
-    debugger;
-  }.toString());
+      threadClient.getPrototypesAndProperties(
+        [args[0].actor, args[1].actor], function(response) {
+          const obj1 = response.actors[args[0].actor];
+          const obj2 = response.actors[args[1].actor];
+          Assert.equal(obj1.ownProperties.x.configurable, true);
+          Assert.equal(obj1.ownProperties.x.enumerable, true);
+          Assert.equal(obj1.ownProperties.x.writable, true);
+          Assert.equal(obj1.ownProperties.x.value, 10);
 
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(gClient, "test-grips",
-                           function(response, targetFront, threadClient) {
-                             gThreadClient = threadClient;
-                             test_object_grip();
-                           });
-  });
-}
-
-function test_object_grip() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const args = packet.frame.arguments;
+          Assert.equal(obj1.ownProperties.y.configurable, true);
+          Assert.equal(obj1.ownProperties.y.enumerable, true);
+          Assert.equal(obj1.ownProperties.y.writable, true);
+          Assert.equal(obj1.ownProperties.y.value, "kaiju");
 
-    gThreadClient.getPrototypesAndProperties(
-      [args[0].actor, args[1].actor], function(response) {
-        const obj1 = response.actors[args[0].actor];
-        const obj2 = response.actors[args[1].actor];
-        Assert.equal(obj1.ownProperties.x.configurable, true);
-        Assert.equal(obj1.ownProperties.x.enumerable, true);
-        Assert.equal(obj1.ownProperties.x.writable, true);
-        Assert.equal(obj1.ownProperties.x.value, 10);
+          Assert.equal(obj2.ownProperties.z.configurable, true);
+          Assert.equal(obj2.ownProperties.z.enumerable, true);
+          Assert.equal(obj2.ownProperties.z.writable, true);
+          Assert.equal(obj2.ownProperties.z.value, 123);
 
-        Assert.equal(obj1.ownProperties.y.configurable, true);
-        Assert.equal(obj1.ownProperties.y.enumerable, true);
-        Assert.equal(obj1.ownProperties.y.writable, true);
-        Assert.equal(obj1.ownProperties.y.value, "kaiju");
+          Assert.ok(obj1.prototype != undefined);
+          Assert.ok(obj2.prototype != undefined);
 
-        Assert.equal(obj2.ownProperties.z.configurable, true);
-        Assert.equal(obj2.ownProperties.z.enumerable, true);
-        Assert.equal(obj2.ownProperties.z.writable, true);
-        Assert.equal(obj2.ownProperties.z.value, 123);
-
-        Assert.ok(obj1.prototype != undefined);
-        Assert.ok(obj2.prototype != undefined);
+          threadClient.resume(resolve);
+        });
+    });
 
-        gThreadClient.resume(function() {
-          gClient.close().then(gCallback);
-        });
-      });
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    debuggee.eval("stopMe({ x: 10, y: 'kaiju'}, { z: 123 })");
   });
+}));
 
-  gDebuggee.eval("stopMe({ x: 10, y: 'kaiju'}, { z: 123 })");
-}
-
--- a/devtools/server/tests/unit/test_objectgrips-16.js
+++ b/devtools/server/tests/unit/test_objectgrips-16.js
@@ -1,153 +1,128 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const [grip] = packet.frame.arguments;
 
-async function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1) {
-    debugger;
-  }.toString());
+      // Checks grip.preview properties.
+      check_preview(grip);
+
+      const objClient = threadClient.pauseGrip(grip);
+      const response = await objClient.getPrototypeAndProperties();
+      // Checks the result of getPrototypeAndProperties.
+      check_prototype_and_properties(response);
 
-  gClient = new DebuggerClient(server.connectPipe());
-  await gClient.connect();
-  const [,, threadClient] = await attachTestTabAndResume(gClient, "test-grips");
-  gThreadClient = threadClient;
-  test_symbol_grip();
-}
-
-async function test_symbol_grip() {
-  gThreadClient.addOneTimeListener("paused", async function(event, packet) {
-    const [grip] = packet.frame.arguments;
+      await threadClient.resume();
+      resolve();
+    });
 
-    // Checks grip.preview properties.
-    check_preview(grip);
-
-    const objClient = gThreadClient.pauseGrip(grip);
-    const response = await objClient.getPrototypeAndProperties();
-    // Checks the result of getPrototypeAndProperties.
-    check_prototype_and_properties(response);
-
-    await gThreadClient.resume();
-    await gClient.close();
-    gCallback();
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    debuggee.eval(`
+      stopMe({
+        [Symbol()]: "first unnamed symbol",
+        [Symbol()]: "second unnamed symbol",
+        [Symbol("named")] : "named symbol",
+        [Symbol.iterator] : function* () {
+          yield 1;
+          yield 2;
+        },
+        x: 10,
+      });
+    `);
   });
 
-  gDebuggee.eval(`
-    stopMe({
-      [Symbol()]: "first unnamed symbol",
-      [Symbol()]: "second unnamed symbol",
-      [Symbol("named")] : "named symbol",
-      [Symbol.iterator] : function* () {
-        yield 1;
-        yield 2;
-      },
-      x: 10,
-    });
-  `);
-}
+  function check_preview(grip) {
+    Assert.equal(grip.class, "Object");
 
-function check_preview(grip) {
-  Assert.equal(grip.class, "Object");
+    const {preview} = grip;
+    Assert.equal(preview.ownProperties.x.configurable, true);
+    Assert.equal(preview.ownProperties.x.enumerable, true);
+    Assert.equal(preview.ownProperties.x.writable, true);
+    Assert.equal(preview.ownProperties.x.value, 10);
+
+    const [
+      firstUnnamedSymbol,
+      secondUnnamedSymbol,
+      namedSymbol,
+      iteratorSymbol,
+    ] = preview.ownSymbols;
 
-  const {preview} = grip;
-  Assert.equal(preview.ownProperties.x.configurable, true);
-  Assert.equal(preview.ownProperties.x.enumerable, true);
-  Assert.equal(preview.ownProperties.x.writable, true);
-  Assert.equal(preview.ownProperties.x.value, 10);
-
-  const [
-    firstUnnamedSymbol,
-    secondUnnamedSymbol,
-    namedSymbol,
-    iteratorSymbol,
-  ] = preview.ownSymbols;
+    Assert.equal(firstUnnamedSymbol.name, undefined);
+    Assert.equal(firstUnnamedSymbol.type, "symbol");
+    Assert.equal(firstUnnamedSymbol.descriptor.configurable, true);
+    Assert.equal(firstUnnamedSymbol.descriptor.enumerable, true);
+    Assert.equal(firstUnnamedSymbol.descriptor.writable, true);
+    Assert.equal(firstUnnamedSymbol.descriptor.value, "first unnamed symbol");
 
-  Assert.equal(firstUnnamedSymbol.name, undefined);
-  Assert.equal(firstUnnamedSymbol.type, "symbol");
-  Assert.equal(firstUnnamedSymbol.descriptor.configurable, true);
-  Assert.equal(firstUnnamedSymbol.descriptor.enumerable, true);
-  Assert.equal(firstUnnamedSymbol.descriptor.writable, true);
-  Assert.equal(firstUnnamedSymbol.descriptor.value, "first unnamed symbol");
+    Assert.equal(secondUnnamedSymbol.name, undefined);
+    Assert.equal(secondUnnamedSymbol.type, "symbol");
+    Assert.equal(secondUnnamedSymbol.descriptor.configurable, true);
+    Assert.equal(secondUnnamedSymbol.descriptor.enumerable, true);
+    Assert.equal(secondUnnamedSymbol.descriptor.writable, true);
+    Assert.equal(secondUnnamedSymbol.descriptor.value, "second unnamed symbol");
 
-  Assert.equal(secondUnnamedSymbol.name, undefined);
-  Assert.equal(secondUnnamedSymbol.type, "symbol");
-  Assert.equal(secondUnnamedSymbol.descriptor.configurable, true);
-  Assert.equal(secondUnnamedSymbol.descriptor.enumerable, true);
-  Assert.equal(secondUnnamedSymbol.descriptor.writable, true);
-  Assert.equal(secondUnnamedSymbol.descriptor.value, "second unnamed symbol");
+    Assert.equal(namedSymbol.name, "named");
+    Assert.equal(namedSymbol.type, "symbol");
+    Assert.equal(namedSymbol.descriptor.configurable, true);
+    Assert.equal(namedSymbol.descriptor.enumerable, true);
+    Assert.equal(namedSymbol.descriptor.writable, true);
+    Assert.equal(namedSymbol.descriptor.value, "named symbol");
 
-  Assert.equal(namedSymbol.name, "named");
-  Assert.equal(namedSymbol.type, "symbol");
-  Assert.equal(namedSymbol.descriptor.configurable, true);
-  Assert.equal(namedSymbol.descriptor.enumerable, true);
-  Assert.equal(namedSymbol.descriptor.writable, true);
-  Assert.equal(namedSymbol.descriptor.value, "named symbol");
+    Assert.equal(iteratorSymbol.name, "Symbol.iterator");
+    Assert.equal(iteratorSymbol.type, "symbol");
+    Assert.equal(iteratorSymbol.descriptor.configurable, true);
+    Assert.equal(iteratorSymbol.descriptor.enumerable, true);
+    Assert.equal(iteratorSymbol.descriptor.writable, true);
+    Assert.equal(iteratorSymbol.descriptor.value.class, "Function");
+  }
 
-  Assert.equal(iteratorSymbol.name, "Symbol.iterator");
-  Assert.equal(iteratorSymbol.type, "symbol");
-  Assert.equal(iteratorSymbol.descriptor.configurable, true);
-  Assert.equal(iteratorSymbol.descriptor.enumerable, true);
-  Assert.equal(iteratorSymbol.descriptor.writable, true);
-  Assert.equal(iteratorSymbol.descriptor.value.class, "Function");
-}
+  function check_prototype_and_properties(response) {
+    Assert.equal(response.ownProperties.x.configurable, true);
+    Assert.equal(response.ownProperties.x.enumerable, true);
+    Assert.equal(response.ownProperties.x.writable, true);
+    Assert.equal(response.ownProperties.x.value, 10);
 
-function check_prototype_and_properties(response) {
-  Assert.equal(response.ownProperties.x.configurable, true);
-  Assert.equal(response.ownProperties.x.enumerable, true);
-  Assert.equal(response.ownProperties.x.writable, true);
-  Assert.equal(response.ownProperties.x.value, 10);
+    const [
+      firstUnnamedSymbol,
+      secondUnnamedSymbol,
+      namedSymbol,
+      iteratorSymbol,
+    ] = response.ownSymbols;
 
-  const [
-    firstUnnamedSymbol,
-    secondUnnamedSymbol,
-    namedSymbol,
-    iteratorSymbol,
-  ] = response.ownSymbols;
+    Assert.equal(firstUnnamedSymbol.name, "Symbol()");
+    Assert.equal(firstUnnamedSymbol.descriptor.configurable, true);
+    Assert.equal(firstUnnamedSymbol.descriptor.enumerable, true);
+    Assert.equal(firstUnnamedSymbol.descriptor.writable, true);
+    Assert.equal(firstUnnamedSymbol.descriptor.value, "first unnamed symbol");
 
-  Assert.equal(firstUnnamedSymbol.name, "Symbol()");
-  Assert.equal(firstUnnamedSymbol.descriptor.configurable, true);
-  Assert.equal(firstUnnamedSymbol.descriptor.enumerable, true);
-  Assert.equal(firstUnnamedSymbol.descriptor.writable, true);
-  Assert.equal(firstUnnamedSymbol.descriptor.value, "first unnamed symbol");
+    Assert.equal(secondUnnamedSymbol.name, "Symbol()");
+    Assert.equal(secondUnnamedSymbol.descriptor.configurable, true);
+    Assert.equal(secondUnnamedSymbol.descriptor.enumerable, true);
+    Assert.equal(secondUnnamedSymbol.descriptor.writable, true);
+    Assert.equal(secondUnnamedSymbol.descriptor.value, "second unnamed symbol");
 
-  Assert.equal(secondUnnamedSymbol.name, "Symbol()");
-  Assert.equal(secondUnnamedSymbol.descriptor.configurable, true);
-  Assert.equal(secondUnnamedSymbol.descriptor.enumerable, true);
-  Assert.equal(secondUnnamedSymbol.descriptor.writable, true);
-  Assert.equal(secondUnnamedSymbol.descriptor.value, "second unnamed symbol");
+    Assert.equal(namedSymbol.name, "Symbol(named)");
+    Assert.equal(namedSymbol.descriptor.configurable, true);
+    Assert.equal(namedSymbol.descriptor.enumerable, true);
+    Assert.equal(namedSymbol.descriptor.writable, true);
+    Assert.equal(namedSymbol.descriptor.value, "named symbol");
 
-  Assert.equal(namedSymbol.name, "Symbol(named)");
-  Assert.equal(namedSymbol.descriptor.configurable, true);
-  Assert.equal(namedSymbol.descriptor.enumerable, true);
-  Assert.equal(namedSymbol.descriptor.writable, true);
-  Assert.equal(namedSymbol.descriptor.value, "named symbol");
-
-  Assert.equal(iteratorSymbol.name, "Symbol(Symbol.iterator)");
-  Assert.equal(iteratorSymbol.descriptor.configurable, true);
-  Assert.equal(iteratorSymbol.descriptor.enumerable, true);
-  Assert.equal(iteratorSymbol.descriptor.writable, true);
-  Assert.equal(iteratorSymbol.descriptor.value.class, "Function");
-}
-
+    Assert.equal(iteratorSymbol.name, "Symbol(Symbol.iterator)");
+    Assert.equal(iteratorSymbol.descriptor.configurable, true);
+    Assert.equal(iteratorSymbol.descriptor.enumerable, true);
+    Assert.equal(iteratorSymbol.descriptor.writable, true);
+    Assert.equal(iteratorSymbol.descriptor.value.class, "Function");
+  }
+}));
--- a/devtools/server/tests/unit/test_objectgrips-18.js
+++ b/devtools/server/tests/unit/test_objectgrips-18.js
@@ -1,167 +1,145 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
-
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  return new Promise(resolve => {
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const [grip] = packet.frame.arguments;
+
+      const objClient = threadClient.pauseGrip(grip);
 
-async function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1) {
-    debugger;
-  }.toString());
+      // Checks the result of enumProperties.
+      let response = await objClient.enumProperties({});
+      await check_enum_properties(response);
+
+      // Checks the result of enumSymbols.
+      response = await objClient.enumSymbols();
+      await check_enum_symbols(response);
+
+      await threadClient.resume();
+      resolve();
+    });
 
-  gClient = new DebuggerClient(server.connectPipe());
-  await gClient.connect();
-  const [,, threadClient] = await attachTestTabAndResume(gClient, "test-grips");
-  gThreadClient = threadClient;
-  test_object_grip();
-}
-
-async function test_object_grip() {
-  gThreadClient.addOneTimeListener("paused", async function(event, packet) {
-    const [grip] = packet.frame.arguments;
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    debuggee.eval(`
+      var obj = Array.from({length: 10})
+        .reduce((res, _, i) => {
+          res["property_" + i + "_key"] = "property_" + i + "_value";
+          res[Symbol("symbol_" + i)] = "symbol_" + i + "_value";
+          return res;
+        }, {});
 
-    const objClient = gThreadClient.pauseGrip(grip);
-
-    // Checks the result of enumProperties.
-    let response = await objClient.enumProperties({});
-    await check_enum_properties(response);
+      obj[Symbol()] = "first unnamed symbol";
+      obj[Symbol()] = "second unnamed symbol";
+      obj[Symbol.iterator] = function* () {
+        yield 1;
+        yield 2;
+      };
 
-    // Checks the result of enumSymbols.
-    response = await objClient.enumSymbols();
-    await check_enum_symbols(response);
-
-    await gThreadClient.resume();
-    await gClient.close();
-    gCallback();
+      stopMe(obj);
+    `);
   });
 
-  gDebuggee.eval(`
-    var obj = Array.from({length: 10})
-      .reduce((res, _, i) => {
-        res["property_" + i + "_key"] = "property_" + i + "_value";
-        res[Symbol("symbol_" + i)] = "symbol_" + i + "_value";
-        return res;
-      }, {});
+  async function check_enum_properties(response) {
+    info("Check enumProperties response");
+    ok(response && Object.getOwnPropertyNames(response).includes("iterator"),
+      "The response object has an iterator property");
 
-    obj[Symbol()] = "first unnamed symbol";
-    obj[Symbol()] = "second unnamed symbol";
-    obj[Symbol.iterator] = function* () {
-      yield 1;
-      yield 2;
-    };
+    const {iterator} = response;
+    equal(iterator.count, 10, "iterator.count has the expected value");
 
-    stopMe(obj);
-  `);
-}
+    info("Check iterator.slice response for all properties");
+    let sliceResponse = await iterator.slice(0, iterator.count);
+    ok(sliceResponse &&
+      Object.getOwnPropertyNames(sliceResponse).includes("ownProperties"),
+      "The response object has an ownProperties property");
 
-async function check_enum_properties(response) {
-  info("Check enumProperties response");
-  ok(response && Object.getOwnPropertyNames(response).includes("iterator"),
-    "The response object has an iterator property");
+    let {ownProperties} = sliceResponse;
+    let names = Object.keys(ownProperties);
+    equal(names.length, iterator.count,
+      "The response has the expected number of properties");
+    for (let i = 0; i < names.length; i++) {
+      const name = names[i];
+      equal(name, `property_${i}_key`);
+      equal(ownProperties[name].value, `property_${i}_value`);
+    }
 
-  const {iterator} = response;
-  equal(iterator.count, 10, "iterator.count has the expected value");
+    info("Check iterator.all response");
+    const allResponse = await iterator.all();
+    deepEqual(allResponse, sliceResponse, "iterator.all response has the expected data");
 
-  info("Check iterator.slice response for all properties");
-  let sliceResponse = await iterator.slice(0, iterator.count);
-  ok(sliceResponse && Object.getOwnPropertyNames(sliceResponse).includes("ownProperties"),
-    "The response object has an ownProperties property");
+    info("Check iterator response for 2 properties only");
+    sliceResponse = await iterator.slice(2, 2);
+    ok(sliceResponse &&
+      Object.getOwnPropertyNames(sliceResponse).includes("ownProperties"),
+      "The response object has an ownProperties property");
 
-  let {ownProperties} = sliceResponse;
-  let names = Object.keys(ownProperties);
-  equal(names.length, iterator.count,
-    "The response has the expected number of properties");
-  for (let i = 0; i < names.length; i++) {
-    const name = names[i];
-    equal(name, `property_${i}_key`);
-    equal(ownProperties[name].value, `property_${i}_value`);
+    ownProperties = sliceResponse.ownProperties;
+    names = Object.keys(ownProperties);
+    equal(names.length, 2, "The response has the expected number of properties");
+    equal(names[0], `property_2_key`);
+    equal(names[1], `property_3_key`);
+    equal(ownProperties[names[0]].value, `property_2_value`);
+    equal(ownProperties[names[1]].value, `property_3_value`);
   }
 
-  info("Check iterator.all response");
-  const allResponse = await iterator.all();
-  deepEqual(allResponse, sliceResponse, "iterator.all response has the expected data");
+  async function check_enum_symbols(response) {
+    info("Check enumProperties response");
+    ok(response && Object.getOwnPropertyNames(response).includes("iterator"),
+      "The response object has an iterator property");
 
-  info("Check iterator response for 2 properties only");
-  sliceResponse = await iterator.slice(2, 2);
-  ok(sliceResponse && Object.getOwnPropertyNames(sliceResponse).includes("ownProperties"),
-    "The response object has an ownProperties property");
+    const {iterator} = response;
+    equal(iterator.count, 13, "iterator.count has the expected value");
 
-  ownProperties = sliceResponse.ownProperties;
-  names = Object.keys(ownProperties);
-  equal(names.length, 2, "The response has the expected number of properties");
-  equal(names[0], `property_2_key`);
-  equal(names[1], `property_3_key`);
-  equal(ownProperties[names[0]].value, `property_2_value`);
-  equal(ownProperties[names[1]].value, `property_3_value`);
-}
+    info("Check iterator.slice response for all symbols");
+    let sliceResponse = await iterator.slice(0, iterator.count);
+    ok(sliceResponse && Object.getOwnPropertyNames(sliceResponse).includes("ownSymbols"),
+      "The response object has an ownSymbols property");
 
-async function check_enum_symbols(response) {
-  info("Check enumProperties response");
-  ok(response && Object.getOwnPropertyNames(response).includes("iterator"),
-    "The response object has an iterator property");
-
-  const {iterator} = response;
-  equal(iterator.count, 13, "iterator.count has the expected value");
-
-  info("Check iterator.slice response for all symbols");
-  let sliceResponse = await iterator.slice(0, iterator.count);
-  ok(sliceResponse && Object.getOwnPropertyNames(sliceResponse).includes("ownSymbols"),
-    "The response object has an ownSymbols property");
+    let {ownSymbols} = sliceResponse;
+    equal(ownSymbols.length, iterator.count,
+      "The response has the expected number of symbols");
+    for (let i = 0; i < 10; i++) {
+      const symbol = ownSymbols[i];
+      equal(symbol.name, `Symbol(symbol_${i})`);
+      equal(symbol.descriptor.value, `symbol_${i}_value`);
+    }
+    const firstUnnamedSymbol = ownSymbols[10];
+    equal(firstUnnamedSymbol.name, "Symbol()");
+    equal(firstUnnamedSymbol.descriptor.value, "first unnamed symbol");
 
-  let {ownSymbols} = sliceResponse;
-  equal(ownSymbols.length, iterator.count,
-    "The response has the expected number of symbols");
-  for (let i = 0; i < 10; i++) {
-    const symbol = ownSymbols[i];
-    equal(symbol.name, `Symbol(symbol_${i})`);
-    equal(symbol.descriptor.value, `symbol_${i}_value`);
-  }
-  const firstUnnamedSymbol = ownSymbols[10];
-  equal(firstUnnamedSymbol.name, "Symbol()");
-  equal(firstUnnamedSymbol.descriptor.value, "first unnamed symbol");
+    const secondUnnamedSymbol = ownSymbols[11];
+    equal(secondUnnamedSymbol.name, "Symbol()");
+    equal(secondUnnamedSymbol.descriptor.value, "second unnamed symbol");
 
-  const secondUnnamedSymbol = ownSymbols[11];
-  equal(secondUnnamedSymbol.name, "Symbol()");
-  equal(secondUnnamedSymbol.descriptor.value, "second unnamed symbol");
+    const iteratorSymbol = ownSymbols[12];
+    equal(iteratorSymbol.name, "Symbol(Symbol.iterator)");
+    equal(iteratorSymbol.descriptor.value.class, "Function");
+
+    info("Check iterator.all response");
+    const allResponse = await iterator.all();
+    deepEqual(allResponse, sliceResponse, "iterator.all response has the expected data");
 
-  const iteratorSymbol = ownSymbols[12];
-  equal(iteratorSymbol.name, "Symbol(Symbol.iterator)");
-  equal(iteratorSymbol.descriptor.value.class, "Function");
-
-  info("Check iterator.all response");
-  const allResponse = await iterator.all();
-  deepEqual(allResponse, sliceResponse, "iterator.all response has the expected data");
+    info("Check iterator response for 2 symbols only");
+    sliceResponse = await iterator.slice(9, 2);
+    ok(sliceResponse && Object.getOwnPropertyNames(sliceResponse).includes("ownSymbols"),
+      "The response object has an ownSymbols property");
 
-  info("Check iterator response for 2 symbols only");
-  sliceResponse = await iterator.slice(9, 2);
-  ok(sliceResponse && Object.getOwnPropertyNames(sliceResponse).includes("ownSymbols"),
-    "The response object has an ownSymbols property");
-
-  ownSymbols = sliceResponse.ownSymbols;
-  equal(ownSymbols.length, 2, "The response has the expected number of symbols");
-  equal(ownSymbols[0].name, "Symbol(symbol_9)");
-  equal(ownSymbols[0].descriptor.value, "symbol_9_value");
-  equal(ownSymbols[1].name, "Symbol()");
-  equal(ownSymbols[1].descriptor.value, "first unnamed symbol");
-}
+    ownSymbols = sliceResponse.ownSymbols;
+    equal(ownSymbols.length, 2, "The response has the expected number of symbols");
+    equal(ownSymbols[0].name, "Symbol(symbol_9)");
+    equal(ownSymbols[0].descriptor.value, "symbol_9_value");
+    equal(ownSymbols[1].name, "Symbol()");
+    equal(ownSymbols[1].descriptor.value, "first unnamed symbol");
+  }
+}));
--- a/devtools/server/tests/unit/test_objectgrips-19.js
+++ b/devtools/server/tests/unit/test_objectgrips-19.js
@@ -1,74 +1,51 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
-var gDebuggee;
-var gThreadClient;
-
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-async function run_test_with_server(server, callback) {
-  initTestDebuggerServer(server);
-  gDebuggee = gDebuggee = addTestGlobal("test-grips", server);
-  gDebuggee.eval(function stopMe(arg1) {
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  debuggee.eval(function stopMe(arg1) {
     debugger;
   }.toString());
-  const client = new DebuggerClient(server.connectPipe());
-  await client.connect();
-  const [,, threadClient] = await attachTestTabAndResume(client, "test-grips");
-  gThreadClient = threadClient;
-  await test_wrapped_primitive_grips();
-  await client.close();
-  callback();
-}
-
-async function test_wrapped_primitive_grips() {
   const tests = [{
     value: true,
     class: "Boolean",
   }, {
     value: 123,
     class: "Number",
   }, {
     value: "foo",
     class: "String",
   }, {
     value: Symbol("bar"),
     class: "Symbol",
     name: "bar",
   }];
   for (const data of tests) {
     await new Promise(function(resolve) {
-      gThreadClient.addOneTimeListener("paused", async function(event, packet) {
+      threadClient.addOneTimeListener("paused", async function(event, packet) {
         const [grip] = packet.frame.arguments;
         check_wrapped_primitive_grip(grip, data);
 
-        await gThreadClient.resume();
+        await threadClient.resume();
         resolve();
       });
-      gDebuggee.primitive = data.value;
-      gDebuggee.eval("stopMe(Object(primitive));");
+      debuggee.primitive = data.value;
+      debuggee.eval("stopMe(Object(primitive));");
     });
   }
-}
+}));
 
 function check_wrapped_primitive_grip(grip, data) {
   strictEqual(grip.class, data.class, "The grip has the proper class.");
 
   if (!grip.preview) {
     // In a worker thread Cu does not exist, the objects are considered unsafe and
     // can't be unwrapped, so there is no preview.
     return;
--- a/devtools/server/tests/unit/test_objectgrips-20.js
+++ b/devtools/server/tests/unit/test_objectgrips-20.js
@@ -3,43 +3,29 @@
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 // Test that onEnumProperties returns the expected data
 // when passing `ignoreNonIndexedProperties` and `ignoreIndexedProperties` options
 // with various objects. (See Bug 1403065)
 
+const DO_NOT_CHECK_VALUE = Symbol();
+
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-async function run_test() {
-  do_test_pending();
-  await run_test_with_server(DebuggerServer);
-  await run_test_with_server(WorkerDebuggerServer);
-  do_test_finished();
-}
-
-const DO_NOT_CHECK_VALUE = Symbol();
-
-async function run_test_with_server(server) {
-  initTestDebuggerServer(server);
-  const debuggee = addTestGlobal("test-grips", server);
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   debuggee.eval(function stopMe(arg1) {
     debugger;
   }.toString());
 
-  const dbgClient = new DebuggerClient(server.connectPipe());
-  await dbgClient.connect();
-  const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
-
-  [{
+  await Promise.all([{
     evaledObject: { a: 10 },
     expectedIndexedProperties: [],
     expectedNonIndexedProperties: [["a", 10]],
   }, {
     evaledObject: { length: 10 },
     expectedIndexedProperties: [],
     expectedNonIndexedProperties: [["length", 10]],
   }, {
@@ -175,22 +161,20 @@ async function run_test_with_server(serv
   }, {
     evaledObject: `(() => {
       x = new Int32Array([1, 2]);
       Object.setPrototypeOf(x, null);
       return x;
     })()`,
     expectedIndexedProperties: [["0", 1], ["1", 2]],
     expectedNonIndexedProperties: [],
-  }].forEach(async (testData) => {
-    await test_object_grip(debuggee, dbgClient, threadClient, testData);
-  });
-
-  await dbgClient.close();
-}
+  }].map(async (testData) => {
+    await test_object_grip(debuggee, client, threadClient, testData);
+  }));
+}));
 
 async function test_object_grip(debuggee, dbgClient, threadClient, testData = {}) {
   const {
     evaledObject,
     expectedIndexedProperties,
     expectedNonIndexedProperties,
   } = testData;
 
--- a/devtools/server/tests/unit/test_objectgrips-22.js
+++ b/devtools/server/tests/unit/test_objectgrips-22.js
@@ -1,58 +1,38 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
-var gDebuggee;
-var gThreadClient;
-
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-add_task(async function run_test() {
-  await run_test_with_server(DebuggerServer);
-  await run_test_with_server(WorkerDebuggerServer);
-});
-
-async function run_test_with_server(server) {
-  initTestDebuggerServer(server);
-  const title = "test_enum_symbols";
-  gDebuggee = addTestGlobal(title, server);
-  gDebuggee.eval(function stopMe(arg) {
-    debugger;
-  }.toString());
-  const client = new DebuggerClient(server.connectPipe());
-  await client.connect();
-  [,, gThreadClient] = await attachTestTabAndResume(client, title);
-  await test_enum_symbols();
-  await client.close();
-}
-
-async function test_enum_symbols() {
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   await new Promise(function(resolve) {
-    gThreadClient.addOneTimeListener("paused", async function(event, packet) {
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
       const [grip] = packet.frame.arguments;
-      const objClient = gThreadClient.pauseGrip(grip);
+      const objClient = threadClient.pauseGrip(grip);
       const {iterator} = await objClient.enumSymbols();
       const {ownSymbols} = await iterator.slice(0, iterator.count);
 
       strictEqual(ownSymbols.length, 1, "There is 1 symbol property.");
       const {name, descriptor} = ownSymbols[0];
       strictEqual(name, "Symbol(sym)", "Got right symbol name.");
       deepEqual(descriptor, {
         configurable: false,
         enumerable: false,
         writable: false,
         value: 1,
       }, "Got right property descriptor.");
 
-      await gThreadClient.resume();
+      await threadClient.resume();
       resolve();
     });
-    gDebuggee.eval(`stopMe(Object.defineProperty({}, Symbol("sym"), {value: 1}));`);
+    debuggee.eval(function stopMe(arg1) {
+      debugger;
+    }.toString());
+    debuggee.eval(`stopMe(Object.defineProperty({}, Symbol("sym"), {value: 1}));`);
   });
-}
+}));
--- a/devtools/server/tests/unit/test_objectgrips-array-like-object.js
+++ b/devtools/server/tests/unit/test_objectgrips-array-like-object.js
@@ -3,42 +3,28 @@
 
 "use strict";
 
 // Test that objects are labeled as ArrayLike only when they have sequential
 // numeric keys, and if they have a length property, that it matches the number
 // of numeric keys. (See Bug 1371936)
 
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-async function run_test() {
-  do_test_pending();
-  await run_test_with_server(DebuggerServer);
-  await run_test_with_server(WorkerDebuggerServer);
-  do_test_finished();
-}
-
-async function run_test_with_server(server) {
-  initTestDebuggerServer(server);
-  const debuggee = addTestGlobal("test-grips", server);
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   debuggee.eval(function stopMe(arg1) {
     debugger;
   }.toString());
 
-  const dbgClient = new DebuggerClient(server.connectPipe());
-  await dbgClient.connect();
-  const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
-
   // Currying test function so we don't have to pass the debuggee and clients
   const isArrayLike = object => test_object_grip_is_array_like(
-    debuggee, dbgClient, threadClient, object);
+    debuggee, client, threadClient, object);
 
   equal(await isArrayLike({}), false, "An empty object is not ArrayLike");
   equal(await isArrayLike({length: 0}), false,
     "An object with only a length property is not ArrayLike");
   equal(await isArrayLike({2: "two"}), false,
     "Object not starting at 0 is not ArrayLike");
   equal(await isArrayLike({0: "zero", 2: "two"}), false,
     "Object with non-consecutive numeric keys is not ArrayLike");
@@ -49,19 +35,17 @@ async function run_test_with_server(serv
   equal(await isArrayLike({0: "zero", 1: "one", 2: "two", three: 3, length: 3}), false,
     "Object with a non-numeric property other than `length` is not ArrayLike");
   equal(await isArrayLike({0: "zero", 1: "one", 2: "two", length: 30}), false,
     "Object with a wrongful `length` property is not ArrayLike");
 
   equal(await isArrayLike({0: "zero"}), true);
   equal(await isArrayLike({0: "zero", 1: "two"}), true);
   equal(await isArrayLike({0: "zero", 1: "one", 2: "two", length: 3}), true);
-
-  await dbgClient.close();
-}
+}));
 
 async function test_object_grip_is_array_like(debuggee, dbgClient, threadClient, object) {
   return new Promise((resolve, reject) => {
     threadClient.addOneTimeListener("paused", async function(event, packet) {
       const [grip] = packet.frame.arguments;
       await threadClient.resume();
       resolve(grip.preview.kind === "ArrayLike");
     });
--- a/devtools/server/tests/unit/test_objectgrips-fn-apply-01.js
+++ b/devtools/server/tests/unit/test_objectgrips-fn-apply-01.js
@@ -1,47 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-async function run_test() {
-  try {
-    do_test_pending();
-    await run_test_with_server(DebuggerServer);
-    await run_test_with_server(WorkerDebuggerServer);
-  } finally {
-    do_test_finished();
-  }
-}
-
-async function run_test_with_server(server) {
-  initTestDebuggerServer(server);
-  const debuggee = addTestGlobal("test-grips", server);
-  debuggee.eval(`
-    function stopMe(arg1) {
-      debugger;
-    }
-  `);
-
-  const dbgClient = new DebuggerClient(server.connectPipe());
-  await dbgClient.connect();
-  const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  debuggee.eval(function stopMe(arg1) {
+    debugger;
+  }.toString());
 
   await test_object_grip(debuggee, threadClient);
-
-  await dbgClient.close();
-}
+}));
 
 async function test_object_grip(debuggee, threadClient) {
   await assert_object_argument(
     debuggee,
     threadClient,
     `
       stopMe({
         obj1: {},
--- a/devtools/server/tests/unit/test_objectgrips-fn-apply-02.js
+++ b/devtools/server/tests/unit/test_objectgrips-fn-apply-02.js
@@ -1,47 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-async function run_test() {
-  try {
-    do_test_pending();
-    await run_test_with_server(DebuggerServer);
-    await run_test_with_server(WorkerDebuggerServer);
-  } finally {
-    do_test_finished();
-  }
-}
-
-async function run_test_with_server(server) {
-  initTestDebuggerServer(server);
-  const debuggee = addTestGlobal("test-grips", server);
-  debuggee.eval(`
-    function stopMe(arg1) {
-      debugger;
-    }
-  `);
-
-  const dbgClient = new DebuggerClient(server.connectPipe());
-  await dbgClient.connect();
-  const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  debuggee.eval(function stopMe(arg1) {
+    debugger;
+  }.toString());
 
   await test_object_grip(debuggee, threadClient);
-
-  await dbgClient.close();
-}
+}));
 
 async function test_object_grip(debuggee, threadClient) {
   const code = `
     stopMe({
       method(){
         debugger;
       },
     });
--- a/devtools/server/tests/unit/test_objectgrips-fn-apply-03.js
+++ b/devtools/server/tests/unit/test_objectgrips-fn-apply-03.js
@@ -1,50 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-async function run_test() {
-  try {
-    do_test_pending();
-    await run_test_with_server(DebuggerServer);
-
-    // TODO: The server currently doesn't handle request errors
-    // in workers well, so this test doesn't work with the worker server.
-    // await run_test_with_server(WorkerDebuggerServer);
-  } finally {
-    do_test_finished();
-  }
-}
-
-async function run_test_with_server(server) {
-  initTestDebuggerServer(server);
-  const debuggee = addTestGlobal("test-grips", server);
-  debuggee.eval(`
-    function stopMe(arg1) {
-      debugger;
-    }
-  `);
-
-  const dbgClient = new DebuggerClient(server.connectPipe());
-  await dbgClient.connect();
-  const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  debuggee.eval(function stopMe(arg1) {
+    debugger;
+  }.toString());
 
   await test_object_grip(debuggee, threadClient);
-
-  await dbgClient.close();
-}
+}));
 
 async function test_object_grip(debuggee, threadClient) {
   const code = `
     stopMe({
       method: {},
     });
   `;
   const obj = await eval_and_resume(debuggee, threadClient, code, async frame => {
--- a/devtools/server/tests/unit/test_objectgrips-property-value-01.js
+++ b/devtools/server/tests/unit/test_objectgrips-property-value-01.js
@@ -1,47 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-async function run_test() {
-  try {
-    do_test_pending();
-    await run_test_with_server(DebuggerServer);
-    await run_test_with_server(WorkerDebuggerServer);
-  } finally {
-    do_test_finished();
-  }
-}
-
-async function run_test_with_server(server) {
-  initTestDebuggerServer(server);
-  const debuggee = addTestGlobal("test-grips", server);
-  debuggee.eval(`
-    function stopMe(arg1) {
-      debugger;
-    }
-  `);
-
-  const dbgClient = new DebuggerClient(server.connectPipe());
-  await dbgClient.connect();
-  const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  debuggee.eval(function stopMe(arg1) {
+    debugger;
+  }.toString());
 
   await test_object_grip(debuggee, threadClient);
-
-  await dbgClient.close();
-}
+}));
 
 async function test_object_grip(debuggee, threadClient) {
   await assert_object_argument(
     debuggee,
     threadClient,
     `
       var obj = {
         stringProp: "a value",
--- a/devtools/server/tests/unit/test_objectgrips-property-value-02.js
+++ b/devtools/server/tests/unit/test_objectgrips-property-value-02.js
@@ -1,47 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
 });
 
-async function run_test() {
-  try {
-    do_test_pending();
-    await run_test_with_server(DebuggerServer);
-    await run_test_with_server(WorkerDebuggerServer);
-  } finally {
-    do_test_finished();
-  }
-}
-
-async function run_test_with_server(server) {
-  initTestDebuggerServer(server);
-  const debuggee = addTestGlobal("test-grips", server);
-  debuggee.eval(`
-    function stopMe(arg1) {
-      debugger;
-    }
-  `);
-
-  const dbgClient = new DebuggerClient(server.connectPipe());
-  await dbgClient.connect();
-  const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  debuggee.eval(function stopMe(arg1) {
+    debugger;
+  }.toString());
 
   await test_object_grip(debuggee, threadClient);
-
-  await dbgClient.close();
-}
+}));
 
 async function test_object_grip(debuggee, threadClient) {
   const code = `
     stopMe({
       get prop(){
         debugger;
       },
     });
--- a/devtools/server/tests/unit/test_stepping-02.js
+++ b/devtools/server/tests/unit/test_stepping-02.js
@@ -3,79 +3,52 @@
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 /**
  * Check basic step-in functionality.
  */
 
-var gDebuggee;
-var gClient;
-var gCallback;
-
-function run_test() {
-  do_test_pending();
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  dumpn("Evaluating test code and waiting for first debugger statement");
+  const dbgStmt = await executeOnNextTickAndWaitForPause(
+    () => evaluateTestCode(debuggee), client);
+  equal(dbgStmt.frame.where.line, 2, "Should be at debugger statement on line 2");
+  equal(debuggee.a, undefined);
+  equal(debuggee.b, undefined);
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stepping", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect(test_simple_stepping);
-}
-
-async function test_simple_stepping() {
-  const [attachResponse,, threadClient] = await attachTestTabAndResume(
-    gClient,
-    "test-stepping"
-  );
-
-  ok(!attachResponse.error, "Should not get an error attaching");
-
-  dumpn("Evaluating test code and waiting for first debugger statement");
-  const dbgStmt = await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
-  equal(dbgStmt.frame.where.line, 2, "Should be at debugger statement on line 2");
-  equal(gDebuggee.a, undefined);
-  equal(gDebuggee.b, undefined);
-
-  const step1 = await stepIn(gClient, threadClient);
+  const step1 = await stepIn(client, threadClient);
   equal(step1.type, "paused");
   equal(step1.why.type, "resumeLimit");
   equal(step1.frame.where.line, 3);
-  equal(gDebuggee.a, undefined);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, undefined);
+  equal(debuggee.b, undefined);
 
-  const step3 = await stepIn(gClient, threadClient);
+  const step3 = await stepIn(client, threadClient);
   equal(step3.type, "paused");
   equal(step3.why.type, "resumeLimit");
   equal(step3.frame.where.line, 4);
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, 1);
+  equal(debuggee.b, undefined);
 
-  const step4 = await stepIn(gClient, threadClient);
+  const step4 = await stepIn(client, threadClient);
   equal(step4.type, "paused");
   equal(step4.why.type, "resumeLimit");
   equal(step4.frame.where.line, 4);
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, 2);
+  equal(debuggee.a, 1);
+  equal(debuggee.b, 2);
+}));
 
-  finishClient(gClient, gCallback);
-}
-
-function evaluateTestCode() {
+function evaluateTestCode(debuggee) {
   /* eslint-disable */
   Cu.evalInSandbox(
     `                                   // 1
     debugger;                           // 2
     var a = 1;                          // 3
     var b = 2;`,                        // 4
-    gDebuggee,
+    debuggee,
     "1.8",
     "test_stepping-01-test-code.js",
     1
   );
   /* eslint-disable */
 }
--- a/devtools/server/tests/unit/test_stepping-03.js
+++ b/devtools/server/tests/unit/test_stepping-03.js
@@ -3,64 +3,39 @@
 /* eslint-disable no-shadow */
 
 "use strict";
 
 /**
  * Check basic step-out functionality.
  */
 
-var gDebuggee;
-var gClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  dumpn("Evaluating test code and waiting for first debugger statement");
+  await executeOnNextTickAndWaitForPause(() => evaluateTestCode(debuggee), client);
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stepping", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect(test_simple_stepping);
-}
-
-async function test_simple_stepping() {
-  const [attachResponse,, threadClient] = await attachTestTabAndResume(gClient,
-                                                                       "test-stepping");
-  ok(!attachResponse.error, "Should not get an error attaching");
-
-  dumpn("Evaluating test code and waiting for first debugger statement");
-  await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
-
-  const step1 = await stepOut(gClient, threadClient);
+  const step1 = await stepOut(client, threadClient);
   equal(step1.type, "paused");
   equal(step1.frame.where.line, 8);
   equal(step1.why.type, "resumeLimit");
 
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, 2);
+  equal(debuggee.a, 1);
+  equal(debuggee.b, 2);
+}));
 
-  finishClient(gClient, gCallback);
-}
-
-function evaluateTestCode() {
+function evaluateTestCode(debuggee) {
   /* eslint-disable */
   Cu.evalInSandbox(
     `                                   // 1
     function f() {                      // 2
       debugger;                         // 3
       this.a = 1;                       // 4
       this.b = 2;                       // 5
     }                                   // 6
     f();                                // 7
     `,                                  // 8
-    gDebuggee,
+    debuggee,
     "1.8",
     "test_stepping-01-test-code.js",
     1
   );
   /* eslint-disable */
 }
--- a/devtools/server/tests/unit/test_stepping-04.js
+++ b/devtools/server/tests/unit/test_stepping-04.js
@@ -3,75 +3,47 @@
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 /**
  * Check that stepping over a function call does not pause inside the function.
  */
 
-var gDebuggee;
-var gClient;
-var gCallback;
-
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stepping", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect(test_simple_stepping);
-}
-
-async function test_simple_stepping() {
-  const [attachResponse,, threadClient] = await attachTestTabAndResume(
-    gClient,
-    "test-stepping"
-  );
-
-  ok(!attachResponse.error, "Should not get an error attaching");
-
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   dumpn("Evaluating test code and waiting for first debugger statement");
-  await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
+  await executeOnNextTickAndWaitForPause(() => evaluateTestCode(debuggee), client);
 
   dumpn("Step Over to f()");
-  const step1 = await stepOver(gClient, threadClient);
+  const step1 = await stepOver(client, threadClient);
   equal(step1.type, "paused");
   equal(step1.why.type, "resumeLimit");
   equal(step1.frame.where.line, 6);
-  equal(gDebuggee.a, undefined);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, undefined);
+  equal(debuggee.b, undefined);
 
   dumpn("Step Over f()");
-  const step2 = await stepOver(gClient, threadClient);
+  const step2 = await stepOver(client, threadClient);
   equal(step2.type, "paused");
   equal(step2.frame.where.line, 7);
   equal(step2.why.type, "resumeLimit");
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, 1);
+  equal(debuggee.b, undefined);
+}));
 
-  finishClient(gClient, gCallback);
-}
-
-function evaluateTestCode() {
+function evaluateTestCode(debuggee) {
   /* eslint-disable */
   Cu.evalInSandbox(
     `                                   // 1
     function f() {                      // 2
       this.a = 1;                       // 3
     }                                   // 4
     debugger;                           // 5
     f();                                // 6
     let b = 2;                          // 7
     `,                                  // 8
-    gDebuggee,
+    debuggee,
     "1.8",
     "test_stepping-01-test-code.js",
     1
   );
   /* eslint-disable */
 }
--- a/devtools/server/tests/unit/test_stepping-05.js
+++ b/devtools/server/tests/unit/test_stepping-05.js
@@ -5,89 +5,60 @@
 "use strict";
 
 /**
  * Make sure that stepping in the last statement of the last frame doesn't
  * cause an unexpected pause, when another JS frame is pushed on the stack
  * (bug 785689).
  */
 
-var gDebuggee;
-var gClient;
-var gCallback;
-
-Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
-
-registerCleanupFunction(() => {
-  Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
-});
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
+  dumpn("Evaluating test code and waiting for first debugger statement");
+  await executeOnNextTickAndWaitForPause(() => evaluateTestCode(debuggee), client);
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
-}
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stepping", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect(test_simple_stepping);
-}
-
-async function test_simple_stepping() {
-  const [attachResponse,, threadClient] = await attachTestTabAndResume(
-    gClient,
-    "test-stepping"
-  );
-
-  ok(!attachResponse.error, "Should not get an error attaching");
-
-  dumpn("Evaluating test code and waiting for first debugger statement");
-  await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
-
-  const step1 = await stepIn(gClient, threadClient);
+  const step1 = await stepIn(client, threadClient);
   equal(step1.type, "paused");
   equal(step1.frame.where.line, 3);
   equal(step1.why.type, "resumeLimit");
-  equal(gDebuggee.a, undefined);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, undefined);
+  equal(debuggee.b, undefined);
 
-  const step2 = await stepIn(gClient, threadClient);
+  const step2 = await stepIn(client, threadClient);
   equal(step2.type, "paused");
   equal(step2.frame.where.line, 4);
   equal(step2.why.type, "resumeLimit");
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, 1);
+  equal(debuggee.b, undefined);
 
-  const step3 = await stepIn(gClient, threadClient);
+  const step3 = await stepIn(client, threadClient);
   equal(step3.type, "paused");
   equal(step3.frame.where.line, 4);
   equal(step3.why.type, "resumeLimit");
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, 2);
+  equal(debuggee.a, 1);
+  equal(debuggee.b, 2);
 
-  threadClient.stepIn(() => {
-    threadClient.addOneTimeListener("paused", (event, packet) => {
-      equal(packet.type, "paused");
-      // Before fixing bug 785689, the type was resumeLimit.
-      equal(packet.why.type, "debuggerStatement");
-      finishClient(gClient, gCallback);
+  await new Promise(resolve => {
+    threadClient.stepIn(() => {
+      threadClient.addOneTimeListener("paused", (event, packet) => {
+        equal(packet.type, "paused");
+        // Before fixing bug 785689, the type was resumeLimit.
+        equal(packet.why.type, "debuggerStatement");
+        resolve();
+      });
+      debuggee.eval("debugger;");
     });
-    gDebuggee.eval("debugger;");
   });
-}
+}));
 
-function evaluateTestCode() {
+function evaluateTestCode(debuggee) {
   /* eslint-disable */
   Cu.evalInSandbox(
     `                                   // 1                       
     debugger;                           // 2
     var a = 1;                          // 3
     var b = 2;`,                        // 4
-    gDebuggee,
+    debuggee,
     "1.8",
     "test_stepping-05-test-code.js",
     1
   );
   /* eslint-disable */
 }
--- a/devtools/server/tests/unit/test_stepping-07.js
+++ b/devtools/server/tests/unit/test_stepping-07.js
@@ -2,79 +2,52 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /**
  * Check that stepping over an implicit return makes sense. Bug 1155966.
  */
 
-var gDebuggee;
-var gClient;
-var gCallback;
-
-function run_test() {
-  do_test_pending();
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stepping", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect(testSteppingAndReturns);
-}
-
-async function testSteppingAndReturns() {
-  const [attachResponse,, threadClient] = await attachTestTabAndResume(
-    gClient,
-    "test-stepping"
-  );
-
-  ok(!attachResponse.error, "Should not get an error attaching");
-
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   dumpn("Evaluating test code and waiting for first debugger statement");
-  const dbgStmt1 = await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
+  const dbgStmt1 = await executeOnNextTickAndWaitForPause(
+    () => evaluateTestCode(debuggee), client);
   equal(dbgStmt1.frame.where.line, 3,
         "Should be at debugger statement on line 3");
 
   dumpn("Testing stepping with implicit return");
-  const step1 = await stepOver(gClient, threadClient);
+  const step1 = await stepOver(client, threadClient);
   equal(step1.frame.where.line, 4, "Should step to line 4");
-  const step2 = await stepOver(gClient, threadClient);
+  const step2 = await stepOver(client, threadClient);
   equal(step2.frame.where.line, 7,
         "Should step to line 7, the implicit return at the last line of the function");
   // This assertion doesn't pass yet. You would need to do *another*
   // step at the end of this function to get the frameFinished.
   // See bug 923975.
   //
   // ok(step2.why.frameFinished, "This should be the implicit function return");
 
   dumpn("Continuing and waiting for second debugger statement");
-  const dbgStmt2 = await resumeAndWaitForPause(gClient, threadClient);
+  const dbgStmt2 = await resumeAndWaitForPause(client, threadClient);
   equal(dbgStmt2.frame.where.line, 12,
         "Should be at debugger statement on line 3");
 
   dumpn("Testing stepping with explicit return");
-  const step3 = await stepOver(gClient, threadClient);
+  const step3 = await stepOver(client, threadClient);
   equal(step3.frame.where.line, 13, "Should step to line 13");
-  const step4 = await stepOver(gClient, threadClient);
+  const step4 = await stepOver(client, threadClient);
   equal(step4.frame.where.line, 15, "Should step out of the function from line 15");
   // This step is a bit funny, see bug 1013219 for details.
-  const step5 = await stepOver(gClient, threadClient);
+  const step5 = await stepOver(client, threadClient);
   equal(step5.frame.where.line, 15, "Should step out of the function from line 15");
   ok(step5.why.frameFinished, "This should be the explicit function return");
+}));
 
-  finishClient(gClient, gCallback);
-}
-
-function evaluateTestCode() {
+function evaluateTestCode(debuggee) {
   /* eslint-disable */
   Cu.evalInSandbox(
     `                                   //  1
     function implicitReturn() {         //  2
       debugger;                         //  3
       if (this.someUndefinedProperty) { //  4
         yikes();                        //  5
       }                                 //  6
@@ -86,15 +59,15 @@ function evaluateTestCode() {
         debugger;                       // 12
         return 1;                       // 13
       }                                 // 14
     }                                   // 15
                                         // 16
     implicitReturn();                   // 17
     explicitReturn();                   // 18
     `,                                  // 19
-    gDebuggee,
+    debuggee,
     "1.8",
     "test_stepping-07-test-code.js",
     1
   );
   /* eslint-enable */
 }
--- a/devtools/server/tests/unit/test_stepping-08.js
+++ b/devtools/server/tests/unit/test_stepping-08.js
@@ -2,74 +2,50 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /**
  * Check that step out doesn't double stop on a breakpoint.  Bug 970469.
  */
 
-var gDebuggee;
-var gClient;
-var gCallback;
-
-function run_test() {
-  do_test_pending();
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stepping", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect(testStepOutWithBreakpoint);
-}
-
-async function testStepOutWithBreakpoint() {
-  const [attachResponse,, threadClient] = await attachTestTabAndResume(gClient,
-                                                                       "test-stepping");
-  ok(!attachResponse.error, "Should not get an error attaching");
-
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   dumpn("Evaluating test code and waiting for first debugger statement");
-  const dbgStmt = await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
+  const dbgStmt = await executeOnNextTickAndWaitForPause(
+    () => evaluateTestCode(debuggee), client);
   equal(dbgStmt.frame.where.line, 3, "Should be at debugger statement on line 3");
 
   dumpn("Setting breakpoint in innerFunction");
   const source = threadClient.source(dbgStmt.frame.where.source);
   await source.setBreakpoint({ line: 7 });
 
   dumpn("Step in to innerFunction");
-  const step1 = await stepIn(gClient, threadClient);
+  const step1 = await stepIn(client, threadClient);
   equal(step1.frame.where.line, 7);
 
   dumpn("Step out of innerFunction");
-  const step2 = await stepOut(gClient, threadClient);
+  const step2 = await stepOut(client, threadClient);
   // The bug was that we'd stop again at the breakpoint on line 7.
   equal(step2.frame.where.line, 4);
+}));
 
-  finishClient(gClient, gCallback);
-}
-
-function evaluateTestCode() {
+function evaluateTestCode(debuggee) {
   /* eslint-disable */
   Cu.evalInSandbox(
     `                                   //  1
     function outerFunction() {          //  2
       debugger; innerFunction();        //  3
     }                                   //  4
                                         //  5
     function innerFunction() {          //  6
       var x = 0;                        //  7
       var y = 72;                       //  8
       return x+y;                       //  9
     }                                   // 10
     outerFunction();                    // 11
     `,                                  // 12
-    gDebuggee,
+    debuggee,
     "1.8",
     "test_stepping-08-test-code.js",
     1
   );
   /* eslint-enable */
 }
--- a/devtools/server/tests/unit/test_stepping-09.js
+++ b/devtools/server/tests/unit/test_stepping-09.js
@@ -3,60 +3,36 @@
 
 "use strict";
 
 /**
  * Check that step out stops at the end of the parent if it fails to stop
  * anywhere else. Bug 1504358.
  */
 
-var gDebuggee;
-var gClient;
-var gCallback;
-
-function run_test() {
-  do_test_pending();
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stepping", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect(testStepOutWithBreakpoint);
-}
-
-async function testStepOutWithBreakpoint() {
-  const [attachResponse,, threadClient] = await attachTestTabAndResume(gClient,
-                                                                      "test-stepping");
-  ok(!attachResponse.error, "Should not get an error attaching");
-
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   dumpn("Evaluating test code and waiting for first debugger statement");
-  const dbgStmt = await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
+  const dbgStmt = await executeOnNextTickAndWaitForPause(
+    () => evaluateTestCode(debuggee), client);
   equal(dbgStmt.frame.where.line, 2, "Should be at debugger statement on line 2");
 
   dumpn("Step out of inner and into outer");
-  const step2 = await stepOut(gClient, threadClient);
+  const step2 = await stepOut(client, threadClient);
   // The bug was that we'd step right past the end of the function and never pause.
   equal(step2.frame.where.line, 2);
   equal(step2.why.frameFinished.return, 42);
+}));
 
-  finishClient(gClient, gCallback);
-}
-
-function evaluateTestCode() {
+function evaluateTestCode(debuggee) {
   // By placing the inner and outer on the same line, this triggers the server's
   // logic to skip steps for these functions, meaning that onPop is the only
   // thing that will cause it to pop.
   Cu.evalInSandbox(
     `
     function outer(){ inner(); return 42; } function inner(){ debugger; }
     outer();
     `,
-    gDebuggee,
+    debuggee,
     "1.8",
     "test_stepping-09-test-code.js",
     1
   );
 }
--- a/devtools/server/tests/unit/test_stepping-with-pause-points.js
+++ b/devtools/server/tests/unit/test_stepping-with-pause-points.js
@@ -4,97 +4,73 @@
 
 "use strict";
 
 /**
  * Check basic step-over functionality with pause points
  * for the first statement and end of the last statement.
  */
 
-var gDebuggee;
-var gClient;
-var gCallback;
-
-function run_test() {
-  do_test_pending();
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stepping", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect(test_simple_stepping);
-}
-
-async function test_simple_stepping() {
-  const [attachResponse,, threadClient] = await attachTestTabAndResume(gClient,
-                                                                       "test-stepping");
-  ok(!attachResponse.error, "Should not get an error attaching");
-
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   dumpn("Evaluating test code and waiting for first debugger statement");
-  const dbgStmt = await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
+  const dbgStmt = await executeOnNextTickAndWaitForPause(
+    () => evaluateTestCode(debuggee), client);
   equal(dbgStmt.frame.where.line, 2, "Should be at debugger statement on line 2");
-  equal(gDebuggee.a, undefined);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, undefined);
+  equal(debuggee.b, undefined);
 
   const source = await getSource(threadClient, "test_stepping-01-test-code.js");
 
   // Add pause points for the first and end of the last statement.
   // Note: we intentionally ignore the second statement.
   source.setPausePoints([{
     location: {line: 3, column: 8},
     types: {breakpoint: true, stepOver: true},
   },
   {
     location: {line: 4, column: 14},
     types: {breakpoint: true, stepOver: true},
   }]);
 
   dumpn("Step Over to line 3");
-  const step1 = await stepOver(gClient, threadClient);
+  const step1 = await stepOver(client, threadClient);
   equal(step1.type, "paused");
   equal(step1.why.type, "resumeLimit");
   equal(step1.frame.where.line, 3);
   equal(step1.frame.where.column, 8);
 
-  equal(gDebuggee.a, undefined);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, undefined);
+  equal(debuggee.b, undefined);
 
   dumpn("Step Over to line 4");
-  const step2 = await stepOver(gClient, threadClient);
+  const step2 = await stepOver(client, threadClient);
   equal(step2.type, "paused");
   equal(step2.why.type, "resumeLimit");
   equal(step2.frame.where.line, 4);
   equal(step2.frame.where.column, 8);
 
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, 1);
+  equal(debuggee.b, undefined);
 
   dumpn("Step Over to the end of line 4");
-  const step3 = await stepOver(gClient, threadClient);
+  const step3 = await stepOver(client, threadClient);
   equal(step3.type, "paused");
   equal(step3.why.type, "resumeLimit");
   equal(step3.frame.where.line, 4);
   equal(step3.frame.where.column, 14);
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, 2);
+  equal(debuggee.a, 1);
+  equal(debuggee.b, 2);
+}));
 
-  finishClient(gClient, gCallback);
-}
-
-function evaluateTestCode() {
+function evaluateTestCode(debuggee) {
   /* eslint-disable */
   Cu.evalInSandbox(
     `                                   // 1
     debugger;                           // 2
     var a = 1;                          // 3
     var b = 2;`,                        // 4
-    gDebuggee,
+    debuggee,
     "1.8",
     "test_stepping-01-test-code.js",
     1
   );
   /* eslint-disable */
 }
--- a/devtools/server/tests/unit/test_stepping-with-skip-breakpoints.js
+++ b/devtools/server/tests/unit/test_stepping-with-skip-breakpoints.js
@@ -4,97 +4,73 @@
 
 "use strict";
 
 /**
  * Check basic step-over functionality with pause points
  * for the first statement and end of the last statement.
  */
 
-var gDebuggee;
-var gClient;
-var gCallback;
-
-function run_test() {
-  do_test_pending();
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-}
-
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stepping", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect(test_simple_stepping);
-}
-
-async function test_simple_stepping() {
-  const [attachResponse,, threadClient] = await attachTestTabAndResume(gClient,
-                                                                       "test-stepping");
-  ok(!attachResponse.error, "Should not get an error attaching");
-
+add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   dumpn("Evaluating test code and waiting for first debugger statement");
-  const dbgStmt = await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
+  const dbgStmt = await executeOnNextTickAndWaitForPause(
+    () => evaluateTestCode(debuggee), client);
   equal(dbgStmt.frame.where.line, 2, "Should be at debugger statement on line 2");
-  equal(gDebuggee.a, undefined);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, undefined);
+  equal(debuggee.b, undefined);
 
   const source = await getSource(threadClient, "test_stepping-01-test-code.js");
 
   // Add pause points for the first and end of the last statement.
   // Note: we intentionally ignore the second statement.
   source.setPausePoints([{
     location: {line: 3, column: 8},
     types: {breakpoint: true, stepOver: true},
   },
   {
     location: {line: 4, column: 14},
     types: {breakpoint: true, stepOver: true},
   }]);
 
   dumpn("Step Over to line 3");
-  const step1 = await stepOver(gClient, threadClient);
+  const step1 = await stepOver(client, threadClient);
   equal(step1.type, "paused");
   equal(step1.why.type, "resumeLimit");
   equal(step1.frame.where.line, 3);
   equal(step1.frame.where.column, 8);
 
-  equal(gDebuggee.a, undefined);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, undefined);
+  equal(debuggee.b, undefined);
 
   dumpn("Step Over to line 4");
-  const step2 = await stepOver(gClient, threadClient);
+  const step2 = await stepOver(client, threadClient);
   equal(step2.type, "paused");
   equal(step2.why.type, "resumeLimit");
   equal(step2.frame.where.line, 4);
   equal(step2.frame.where.column, 8);
 
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, undefined);
+  equal(debuggee.a, 1);
+  equal(debuggee.b, undefined);
 
   dumpn("Step Over to the end of line 4");
-  const step3 = await stepOver(gClient, threadClient);
+  const step3 = await stepOver(client, threadClient);
   equal(step3.type, "paused");
   equal(step3.why.type, "resumeLimit");
   equal(step3.frame.where.line, 4);
   equal(step3.frame.where.column, 14);
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, 2);
+  equal(debuggee.a, 1);
+  equal(debuggee.b, 2);
+}));
 
-  finishClient(gClient, gCallback);
-}
-
-function evaluateTestCode() {
+function evaluateTestCode(debuggee) {
   /* eslint-disable */
   Cu.evalInSandbox(
     `                                   // 1
     debugger;                           // 2
     var a = 1;                          // 3
     var b = 2;`,                        // 4
-    gDebuggee,
+    debuggee,
     "1.8",
     "test_stepping-01-test-code.js",
     1
   );
   /* eslint-disable */
 }
--- a/devtools/server/tests/unit/testactors.js
+++ b/devtools/server/tests/unit/testactors.js
@@ -6,19 +6,22 @@
 const { LazyPool, createExtraActors } = require("devtools/shared/protocol/lazy-pool");
 const { RootActor } = require("devtools/server/actors/root");
 const { ThreadActor } = require("devtools/server/actors/thread");
 const { DebuggerServer } = require("devtools/server/main");
 const { ActorRegistry } = require("devtools/server/actors/utils/actor-registry");
 const { TabSources } = require("devtools/server/actors/utils/TabSources");
 const makeDebugger = require("devtools/server/actors/utils/make-debugger");
 
-var gTestGlobals = [];
+var gTestGlobals = new Set();
 DebuggerServer.addTestGlobal = function(global) {
-  gTestGlobals.push(global);
+  gTestGlobals.add(global);
+};
+DebuggerServer.removeTestGlobal = function(global) {
+  gTestGlobals.delete(global);
 };
 
 DebuggerServer.getTestGlobal = function(name) {
   for (const g of gTestGlobals) {
     if (g.__name == name) {
       return g;
     }
   }