Bug 1509315 - Use TargetFactory.forTab for creating targets in tests. r=yulia
authorAlexandre Poirot <poirot.alex@gmail.com>
Tue, 27 Nov 2018 21:47:59 +0000
changeset 504825 18f76c41550516fb1cf4bcbe8bfaf82d480322e7
parent 504824 ce2018b0349dc53c3394559a20e729797034ce8c
child 504826 322f2dd202990fc3bc215a7296423ca683738244
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyulia
bugs1509315
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 1509315 - Use TargetFactory.forTab for creating targets in tests. r=yulia There is 4 patterns here: * Tests using attachThreadActorForUrl like event-listeners ones. I augmented this helper method to call TargetFactory. * Tests using attachTargetActorForUrl like debugger-statement, dbg-navigation and target-scoped-actor. Uses TargetFactory directly. * Tests using connectDebuggerClient like navigateEvents and spaw_actor_in_parent. Uses TargetFactory directly. * All the others, where creating DebuggerClient on their own, and calling listTabs+attachTarget. They now use TargetFactory directly. A note about webconsole-helpers, only consoleClient attribute was used from tests using this helper. Also, in various tests I remove the call to client.destroy, that's because shared-head will close all the tabs/toolboxes and it should lead to target/client destruction. Finally, debugger-statement now request the thread actor via the client instead of manual request, it should help the refactoring to a front! MozReview-Commit-ID: 2ah4UmSjuoi Depends on D12730 Differential Revision: https://phabricator.services.mozilla.com/D12731
devtools/client/debugger/test/mochitest/head.js
devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
devtools/client/shared/test/browser_dbg_WorkerTargetActor.attach.js
devtools/client/shared/test/browser_dbg_debugger-statement.js
devtools/client/shared/test/browser_dbg_event-listeners-01.js
devtools/client/shared/test/browser_dbg_event-listeners-02.js
devtools/client/shared/test/browser_dbg_event-listeners-03.js
devtools/client/shared/test/browser_dbg_listtabs-01.js
devtools/client/shared/test/browser_dbg_listworkers.js
devtools/client/shared/test/browser_dbg_navigation.js
devtools/client/shared/test/browser_dbg_target-scoped-actor-01.js
devtools/client/shared/test/browser_dbg_target-scoped-actor-02.js
devtools/client/shared/test/browser_dbg_worker-window.js
devtools/client/shared/test/helper_workers.js
devtools/server/tests/browser/browser_navigateEvents.js
devtools/server/tests/browser/browser_spawn_actor_in_parent.js
devtools/server/tests/browser/head.js
devtools/server/tests/mochitest/webconsole-helpers.js
--- a/devtools/client/debugger/test/mochitest/head.js
+++ b/devtools/client/debugger/test/mochitest/head.js
@@ -147,40 +147,16 @@ function removeAddon(aAddon) {
     }
   };
   AddonManager.addAddonListener(listener);
   aAddon.uninstall();
 
   return deferred.promise;
 }
 
-function getTargetActorForUrl(aClient, aUrl) {
-  let deferred = promise.defer();
-
-  aClient.listTabs().then(aResponse => {
-    let targetActor = aResponse.tabs.filter(aGrip => aGrip.url == aUrl).pop();
-    deferred.resolve(targetActor);
-  });
-
-  return deferred.promise;
-}
-
-async function attachTargetActorForUrl(aClient, aUrl) {
-  let grip = await getTargetActorForUrl(aClient, aUrl);
-  let [ response, front ] = await aClient.attachTarget(grip.actor);
-  return [grip, response, front];
-}
-
-async function attachThreadActorForUrl(aClient, aUrl) {
-  let [grip, response] = await attachTargetActorForUrl(aClient, aUrl);
-  let [response2, threadClient] = await aClient.attachThread(response.threadActor);
-  await threadClient.resume();
-  return threadClient;
-}
-
 // Override once from shared-head, as some tests depend on trying native DOM listeners
 // before EventEmitter.  Since this directory is deprecated, there's little value in
 // resolving the descrepency here.
 this.once = function (aTarget, aEventName, aUseCapture = false) {
   info("Waiting for event: '" + aEventName + "' on " + aTarget + ".");
 
   let deferred = promise.defer();
 
--- a/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
+++ b/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
@@ -1,17 +1,16 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const { DebuggerServer } = require("devtools/server/main");
-const { DebuggerClient } = require("devtools/shared/client/debugger-client");
 
 // Bug 1277805: Too slow for debug runs
 requestLongerTimeout(2);
 
 /**
  * Bug 979536: Ensure fronts are destroyed after toolbox close.
  *
  * The fronts need to be destroyed manually to unbind their onPacket handlers.
@@ -55,46 +54,23 @@ function runTools(target) {
       const panel = toolbox.getCurrentPanel();
       ok(panel.isReady, toolId + " panel should be ready");
     }
 
     await toolbox.destroy();
   })();
 }
 
-function getClient() {
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
-
-  const transport = DebuggerServer.connectPipe();
-  const client = new DebuggerClient(transport);
-
-  return client.connect().then(() => client);
-}
-
-function getTarget(client) {
-  return new Promise(resolve => {
-    client.listTabs().then(tabList => {
-      const target = TargetFactory.forRemoteTab({
-        client: client,
-        form: tabList.tabs[tabList.selected],
-        chrome: false,
-      });
-      resolve(target);
-    });
-  });
-}
-
 function test() {
   (async function() {
     toggleAllTools(true);
-    await addTab("about:blank");
+    const tab = await addTab("about:blank");
 
-    const client = await getClient();
-    const target = await getTarget(client);
+    const target = await TargetFactory.forTab(tab);
+    const { client } = target;
     await runTools(target);
 
     const rootFronts = [...client.mainRoot.fronts.values()];
 
     // Actor fronts should be destroyed now that the toolbox has closed, but
     // look for any that remain.
     for (const pool of client.__pools) {
       if (!pool.__poolMap) {
--- a/devtools/client/shared/test/browser_dbg_WorkerTargetActor.attach.js
+++ b/devtools/client/shared/test/browser_dbg_WorkerTargetActor.attach.js
@@ -21,25 +21,20 @@ var TAB2_URL = EXAMPLE_URL + "doc_Worker
 var WORKER1_URL = "code_WorkerTargetActor.attach-worker1.js";
 var WORKER2_URL = "code_WorkerTargetActor.attach-worker2.js";
 
 function test() {
   Task.spawn(function* () {
     const oldMaxTotalViewers = SpecialPowers.getIntPref(MAX_TOTAL_VIEWERS);
     SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, 10);
 
-    DebuggerServer.init();
-    DebuggerServer.registerAllActors();
-
-    const client = new DebuggerClient(DebuggerServer.connectPipe());
-    yield connect(client);
-
     const tab = yield addTab(TAB1_URL);
-    const { tabs } = yield listTabs(client);
-    const [, targetFront] = yield attachTarget(client, findTab(tabs, TAB1_URL));
+    const target = yield TargetFactory.forTab(tab);
+    yield target.attach();
+    const targetFront = target.activeTab;
     yield listWorkers(targetFront);
 
     // If a page still has pending network requests, it will not be moved into
     // the bfcache. Consequently, we cannot use waitForWorkerListChanged here,
     // because the worker is not guaranteed to have finished loading when it is
     // registered. Instead, we have to wait for the promise returned by
     // createWorker in the tab to be resolved.
     yield createWorkerInTab(tab, WORKER1_URL);
@@ -66,13 +61,13 @@ function test() {
     yield waitForWorkerClose(workerTargetFront2);
     is(workerTargetFront2.isClosed, true, "worker in tab 2 should be closed");
 
     ({ workers } = yield listWorkers(targetFront));
     workerTargetFront1 = findWorker(workers, WORKER1_URL);
     yield workerTargetFront1.attach();
     is(workerTargetFront1.isClosed, false, "worker in tab 1 should not be closed");
 
-    yield close(client);
+    yield target.destroy();
     SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, oldMaxTotalViewers);
     finish();
   });
 }
--- a/devtools/client/shared/test/browser_dbg_debugger-statement.js
+++ b/devtools/client/shared/test/browser_dbg_debugger-statement.js
@@ -10,87 +10,58 @@
  */
 
 // Import helpers for the workers
 /* import-globals-from helper_workers.js */
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
   this);
 
-var { DebuggerServer } = require("devtools/server/main");
-var { DebuggerClient } = require("devtools/shared/client/debugger-client");
-
 const TAB_URL = TEST_URI_ROOT + "doc_inline-debugger-statement.html";
 
-var gClient;
-var gTab;
-
-function test() {
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
-
-  const transport = DebuggerServer.connectPipe();
-  gClient = new DebuggerClient(transport);
-  gClient.connect().then(([aType, aTraits]) => {
-    is(aType, "browser",
-      "Root actor should identify itself as a browser.");
+add_task(async () => {
+  const tab = await addTab(TAB_URL);
+  const target = await TargetFactory.forTab(tab);
+  await target.attach();
+  const { client } = target;
+  const targetFront = target.activeTab;
 
-    addTab(TAB_URL)
-      .then(tab => {
-        gTab = tab;
-        return attachTargetActorForUrl(gClient, TAB_URL);
-      })
-      .then(testEarlyDebuggerStatement)
-      .then(testDebuggerStatement)
-      .then(() => gClient.close())
-      .then(finish)
-      .catch(error => {
-        ok(false, "Got an error: " + error.message + "\n" + error.stack);
-      });
-  });
-}
+  const threadClient = await testEarlyDebuggerStatement(client, tab, targetFront);
+  await testDebuggerStatement(client, tab, threadClient);
 
-function testEarlyDebuggerStatement([aGrip, aResponse]) {
-  const deferred = getDeferredPromise().defer();
+  await target.destroy();
+});
 
+async function testEarlyDebuggerStatement(client, tab, targetFront) {
   const onPaused = function(event, packet) {
     ok(false, "Pause shouldn't be called before we've attached!");
-    deferred.reject();
   };
 
-  gClient.addListener("paused", onPaused);
+  client.addListener("paused", onPaused);
 
   // This should continue without nesting an event loop and calling
   // the onPaused hook, because we haven't attached yet.
-  callInTab(gTab, "runDebuggerStatement");
+  callInTab(tab, "runDebuggerStatement");
 
-  gClient.removeListener("paused", onPaused);
+  client.removeListener("paused", onPaused);
 
   // Now attach and resume...
-  gClient.request({ to: aResponse.threadActor, type: "attach" }, () => {
-    gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
-      ok(true, "Pause wasn't called before we've attached.");
-      deferred.resolve([aGrip, aResponse]);
-    });
-  });
+  const [, threadClient] = await targetFront.attachThread();
+  await threadClient.resume();
+  ok(true, "Pause wasn't called before we've attached.");
 
-  return deferred.promise;
+  return threadClient;
 }
 
-function testDebuggerStatement([aGrip, aResponse]) {
-  const deferred = getDeferredPromise().defer();
-
-  gClient.addListener("paused", (event, packet) => {
-    gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
+async function testDebuggerStatement(client, tab, threadClient) {
+  const onPaused = new Promise(resolve => {
+    client.addListener("paused", async (event, packet) => {
+      await threadClient.resume();
       ok(true, "The pause handler was triggered on a debugger statement.");
-      deferred.resolve();
+      resolve();
     });
   });
 
   // Reach around the debugging protocol and execute the debugger statement.
-  callInTab(gTab, "runDebuggerStatement");
+  callInTab(tab, "runDebuggerStatement");
 
-  return deferred.promise;
+  return onPaused;
 }
-
-registerCleanupFunction(function() {
-  gClient = null;
-});
--- a/devtools/client/shared/test/browser_dbg_event-listeners-01.js
+++ b/devtools/client/shared/test/browser_dbg_event-listeners-01.js
@@ -10,38 +10,24 @@
  */
 
 // Import helpers for the workers
 /* import-globals-from helper_workers.js */
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
   this);
 
-var { DebuggerServer } = require("devtools/server/main");
-var { DebuggerClient } = require("devtools/shared/client/debugger-client");
-
 const TAB_URL = TEST_URI_ROOT + "doc_event-listeners-01.html";
 
 add_task(async function() {
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
+  const tab = await addTab(TAB_URL);
+  const { client, threadClient } = await attachThreadActorForTab(tab);
 
-  const transport = DebuggerServer.connectPipe();
-  const client = new DebuggerClient(transport);
-  const [type] = await client.connect();
-
-  Assert.equal(type, "browser",
-    "Root actor should identify itself as a browser.");
-
-  const tab = await addTab(TAB_URL);
-  const threadClient = await attachThreadActorForUrl(client, TAB_URL);
   await pauseDebuggee(tab, client, threadClient);
   await testEventListeners(client, threadClient);
-
-  await client.close();
 });
 
 function pauseDebuggee(tab, client, threadClient) {
   const deferred = getDeferredPromise().defer();
 
   client.addOneTimeListener("paused", (event, packet) => {
     is(packet.type, "paused",
       "We should now be paused.");
--- a/devtools/client/shared/test/browser_dbg_event-listeners-02.js
+++ b/devtools/client/shared/test/browser_dbg_event-listeners-02.js
@@ -11,37 +11,24 @@
  */
 
 // Import helpers for the workers
 /* import-globals-from helper_workers.js */
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
   this);
 
-var { DebuggerServer } = require("devtools/server/main");
-var { DebuggerClient } = require("devtools/shared/client/debugger-client");
-
 const TAB_URL = TEST_URI_ROOT + "doc_event-listeners-03.html";
 
 add_task(async function() {
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
+  const tab = await addTab(TAB_URL);
+  const { client, threadClient } = await attachThreadActorForTab(tab);
 
-  const transport = DebuggerServer.connectPipe();
-  const client = new DebuggerClient(transport);
-  const [type] = await client.connect();
-
-  Assert.equal(type, "browser",
-    "Root actor should identify itself as a browser.");
-
-  const tab = await addTab(TAB_URL);
-  const threadClient = await attachThreadActorForUrl(client, TAB_URL);
   await pauseDebuggee(tab, client, threadClient);
   await testEventListeners(client, threadClient);
-  await client.close();
 });
 
 function pauseDebuggee(tab, client, threadClient) {
   const deferred = getDeferredPromise().defer();
 
   client.addOneTimeListener("paused", (event, packet) => {
     is(packet.type, "paused",
       "We should now be paused.");
--- a/devtools/client/shared/test/browser_dbg_event-listeners-03.js
+++ b/devtools/client/shared/test/browser_dbg_event-listeners-03.js
@@ -11,62 +11,39 @@
  */
 
 // Import helpers for the workers
 /* import-globals-from helper_workers.js */
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
   this);
 
-var { DebuggerServer } = require("devtools/server/main");
-var { DebuggerClient } = require("devtools/shared/client/debugger-client");
-
 const TAB_URL = TEST_URI_ROOT + "doc_native-event-handler.html";
 
-var gClient;
-var gTab;
-
-function test() {
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
-
-  const transport = DebuggerServer.connectPipe();
-  gClient = new DebuggerClient(transport);
-  gClient.connect().then(([aType, aTraits]) => {
-    is(aType, "browser",
-      "Root actor should identify itself as a browser.");
+add_task(async () => {
+  const tab = await addTab(TAB_URL);
+  const { client, threadClient } = await attachThreadActorForTab(tab);
 
-    addTab(TAB_URL)
-      .then((tab) => {
-        gTab = tab;
-        return attachThreadActorForUrl(gClient, TAB_URL);
-      })
-      .then(pauseDebuggee)
-      .then(testEventListeners)
-      .then(() => gClient.close())
-      .then(finish)
-      .catch(error => {
-        ok(false, "Got an error: " + error.message + "\n" + error.stack);
-      });
-  });
-}
+  await pauseDebuggee(client, tab, threadClient);
+  await testEventListeners(threadClient);
+});
 
-function pauseDebuggee(threadClient) {
+function pauseDebuggee(client, tab, threadClient) {
   const deferred = getDeferredPromise().defer();
 
-  gClient.addOneTimeListener("paused", (event, packet) => {
+  client.addOneTimeListener("paused", (event, packet) => {
     is(packet.type, "paused",
       "We should now be paused.");
     is(packet.why.type, "debuggerStatement",
       "The debugger statement was hit.");
 
     deferred.resolve(threadClient);
   });
 
-  generateMouseClickInTab(gTab, "content.document.querySelector('button')");
+  generateMouseClickInTab(tab, "content.document.querySelector('button')");
 
   return deferred.promise;
 }
 
 function testEventListeners(threadClient) {
   const deferred = getDeferredPromise().defer();
 
   threadClient.eventListeners(packet => {
@@ -81,12 +58,8 @@ function testEventListeners(threadClient
     // The video element controls listeners are skipped — they cannot be
     // unwrapped but they shouldn't cause us to throw either.
     is(packet.listeners.length, 2, "Found all event listeners.");
     threadClient.resume(deferred.resolve);
   });
 
   return deferred.promise;
 }
-
-registerCleanupFunction(function() {
-  gClient = null;
-});
--- a/devtools/client/shared/test/browser_dbg_listtabs-01.js
+++ b/devtools/client/shared/test/browser_dbg_listtabs-01.js
@@ -39,19 +39,19 @@ function test() {
       });
   });
 }
 
 function testFirstTab() {
   return addTab(TAB1_URL).then(tab => {
     gTab1 = tab;
 
-    return getTargetActorForUrl(gClient, TAB1_URL).then(grip => {
-      ok(grip, "Should find a target actor for the first tab.");
-      gTab1Actor = grip.actor;
+    return getTargetActorForUrl(gClient, TAB1_URL).then(form => {
+      ok(form, "Should find a target actor for the first tab.");
+      gTab1Actor = form.actor;
     });
   });
 }
 
 function testSecondTab() {
   return addTab(TAB2_URL).then(tab => {
     gTab2 = tab;
 
@@ -62,18 +62,18 @@ function testSecondTab() {
         gTab2Actor = secondGrip.actor;
       });
     });
   });
 }
 
 function testRemoveTab() {
   return removeTab(gTab1).then(() => {
-    return getTargetActorForUrl(gClient, TAB1_URL).then(grip => {
-      ok(!grip, "Shouldn't find a target actor for the first tab anymore.");
+    return getTargetActorForUrl(gClient, TAB1_URL).then(form => {
+      ok(!form, "Shouldn't find a target actor for the first tab anymore.");
     });
   });
 }
 
 function testAttachRemovedTab() {
   return removeTab(gTab2).then(() => {
     const deferred = promise.defer();
 
@@ -95,18 +95,13 @@ function testAttachRemovedTab() {
 registerCleanupFunction(function() {
   gTab1 = null;
   gTab1Actor = null;
   gTab2 = null;
   gTab2Actor = null;
   gClient = null;
 });
 
-function getTargetActorForUrl(client, url) {
-  const deferred = promise.defer();
-
-  client.listTabs().then(response => {
-    const targetActor = response.tabs.filter(grip => grip.url == url).pop();
-    deferred.resolve(targetActor);
-  });
-
-  return deferred.promise;
+async function getTargetActorForUrl(client, url) {
+  const { tabs } = await client.listTabs();
+  const targetActor = tabs.filter(form => form.url == url).pop();
+  return targetActor;
 }
--- a/devtools/client/shared/test/browser_dbg_listworkers.js
+++ b/devtools/client/shared/test/browser_dbg_listworkers.js
@@ -12,33 +12,25 @@ registerCleanupFunction(() => {
 });
 
 // Import helpers for the workers
 /* import-globals-from helper_workers.js */
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
   this);
 
-var { DebuggerServer } = require("devtools/server/main");
-var { DebuggerClient } = require("devtools/shared/client/debugger-client");
-
 var TAB_URL = EXAMPLE_URL + "doc_listworkers-tab.html";
 var WORKER1_URL = "code_listworkers-worker1.js";
 var WORKER2_URL = "code_listworkers-worker2.js";
 
 add_task(async function test() {
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
-
-  const client = new DebuggerClient(DebuggerServer.connectPipe());
-  await connect(client);
-
   const tab = await addTab(TAB_URL);
-  const { tabs } = await listTabs(client);
-  const [, targetFront] = await attachTarget(client, findTab(tabs, TAB_URL));
+  const target = await TargetFactory.forTab(tab);
+  await target.attach();
+  const targetFront = target.activeTab;
 
   let { workers } = await listWorkers(targetFront);
   is(workers.length, 0);
 
   executeSoon(() => {
     evalInTab(tab, "var worker1 = new Worker('" + WORKER1_URL + "');");
   });
   await waitForWorkerListChanged(targetFront);
@@ -69,11 +61,11 @@ add_task(async function test() {
   executeSoon(() => {
     evalInTab(tab, "worker2.terminate()");
   });
   await waitForWorkerListChanged(targetFront);
 
   ({ workers } = await listWorkers(targetFront));
   is(workers.length, 0);
 
-  await close(client);
+  await target.destroy();
   finish();
 });
--- a/devtools/client/shared/test/browser_dbg_navigation.js
+++ b/devtools/client/shared/test/browser_dbg_navigation.js
@@ -4,45 +4,29 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /**
  * Check tab attach/navigation.
  */
 
-var { DebuggerServer } = require("devtools/server/main");
-var { DebuggerClient } = require("devtools/shared/client/debugger-client");
-
 const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
 const TAB2_FILE = "doc_empty-tab-02.html";
 const TAB2_URL = EXAMPLE_URL + TAB2_FILE;
 
-var gClient;
-
-function test() {
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
+add_task(async () => {
+  const tab = await addTab(TAB1_URL);
+  const target = await TargetFactory.forTab(tab);
+  await target.attach();
+  const targetFront = target.activeTab;
 
-  const transport = DebuggerServer.connectPipe();
-  gClient = new DebuggerClient(transport);
-  gClient.connect().then(([aType, aTraits]) => {
-    is(aType, "browser",
-      "Root actor should identify itself as a browser.");
-
-    addTab(TAB1_URL)
-      .then(() => attachTargetActorForUrl(gClient, TAB1_URL))
-      .then(testNavigate)
-      .then(testDetach)
-      .then(finish)
-      .catch(error => {
-        ok(false, "Got an error: " + error.message + "\n" + error.stack);
-      });
-  });
-}
+  await testNavigate(targetFront);
+  await testDetach(target);
+});
 
 function testNavigate(targetFront) {
   const outstanding = [promise.defer(), promise.defer()];
 
   targetFront.on("tabNavigated", function onTabNavigated(packet) {
     is(packet.url.split("/").pop(), TAB2_FILE,
       "Got a tab navigation notification.");
 
@@ -54,45 +38,21 @@ function testNavigate(targetFront) {
     } else {
       ok(true, "Tab finished navigating.");
       targetFront.off("tabNavigated", onTabNavigated);
       outstanding[1].resolve();
     }
   });
 
   BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TAB2_URL);
-  return promise.all(outstanding.map(e => e.promise))
-                .then(() => targetFront);
+  return promise.all(outstanding.map(e => e.promise));
 }
 
-async function testDetach(targetFront) {
-  const onDetached = targetFront.once("tabDetached");
+async function testDetach(target) {
+  // We can't listen for tabDetached at it is received by Target first
+  // and target is destroyed
+  const onDetached = target.once("close");
 
   removeTab(gBrowser.selectedTab);
 
-  const packet = await onDetached;
+  await onDetached;
   ok(true, "Got a tab detach notification.");
-  is(packet.from, targetFront.actorID,
-    "tab detach message comes from the expected actor");
-
-  return gClient.close();
 }
-
-registerCleanupFunction(function() {
-  gClient = null;
-});
-
-async function attachTargetActorForUrl(client, url) {
-  const grip = await getTargetActorForUrl(client, url);
-  const [, targetFront] = await client.attachTarget(grip.actor);
-  return targetFront;
-}
-
-function getTargetActorForUrl(client, url) {
-  const deferred = promise.defer();
-
-  client.listTabs().then(response => {
-    const targetActor = response.tabs.filter(grip => grip.url == url).pop();
-    deferred.resolve(targetActor);
-  });
-
-  return deferred.promise;
-}
--- a/devtools/client/shared/test/browser_dbg_target-scoped-actor-01.js
+++ b/devtools/client/shared/test/browser_dbg_target-scoped-actor-01.js
@@ -4,63 +4,40 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /**
  * Check target-scoped actor lifetimes.
  */
 
-var { DebuggerServer } = require("devtools/server/main");
-var { DebuggerClient } = require("devtools/shared/client/debugger-client");
-
 const ACTORS_URL = EXAMPLE_URL + "testactors.js";
 const TAB_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
 
 add_task(async function test() {
-  await addTab(TAB_URL);
-
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
+  const tab = await addTab(TAB_URL);
 
   await registerActorInContentProcess(ACTORS_URL, {
     prefix: "testOne",
     constructor: "TestActor1",
     type: { target: true },
   });
 
-  const transport = DebuggerServer.connectPipe();
-  const client = new DebuggerClient(transport);
-  const [ type ] = await client.connect();
-  is(type, "browser", "Root actor should identify itself as a browser.");
+  const target = await TargetFactory.forTab(tab);
+  await target.attach();
+  const { client } = target;
+  const targetFront = target.activeTab;
+  const form = targetFront.targetForm;
 
-  const [ grip ] = await attachTargetActorForUrl(client, TAB_URL);
-  await testTargetScopedActor(client, grip);
+  await testTargetScopedActor(client, form);
   await removeTab(gBrowser.selectedTab);
-  await client.close();
+  await target.destroy();
 });
 
-async function testTargetScopedActor(client, grip) {
-  ok(grip.testOneActor,
+async function testTargetScopedActor(client, form) {
+  ok(form.testOneActor,
     "Found the test target-scoped actor.");
-  ok(grip.testOneActor.includes("testOne"),
+  ok(form.testOneActor.includes("testOne"),
     "testOneActor's actorPrefix should be used.");
 
-  const response = await client.request({ to: grip.testOneActor, type: "ping" });
+  const response = await client.request({ to: form.testOneActor, type: "ping" });
   is(response.pong, "pong", "Actor should respond to requests.");
 }
-
-async function attachTargetActorForUrl(client, url) {
-  const grip = await getTargetActorForUrl(client, url);
-  const [ response ] = await client.attachTarget(grip.actor);
-  return [grip, response];
-}
-
-function getTargetActorForUrl(client, url) {
-  const deferred = promise.defer();
-
-  client.listTabs().then(response => {
-    const targetActor = response.tabs.filter(grip => grip.url == url).pop();
-    deferred.resolve(targetActor);
-  });
-
-  return deferred.promise;
-}
--- a/devtools/client/shared/test/browser_dbg_target-scoped-actor-02.js
+++ b/devtools/client/shared/test/browser_dbg_target-scoped-actor-02.js
@@ -4,74 +4,50 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /**
  * Check target-scoped actor lifetimes.
  */
 
-var { DebuggerServer } = require("devtools/server/main");
-var { DebuggerClient } = require("devtools/shared/client/debugger-client");
-
 const ACTORS_URL = EXAMPLE_URL + "testactors.js";
 const TAB_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
 
 add_task(async function() {
-  await addTab(TAB_URL);
-
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
+  const tab = await addTab(TAB_URL);
 
   await registerActorInContentProcess(ACTORS_URL, {
     prefix: "testOne",
     constructor: "TestActor1",
     type: { target: true },
   });
 
-  const transport = DebuggerServer.connectPipe();
-  const client = new DebuggerClient(transport);
-  const [type] = await client.connect();
-  is(type, "browser",
-    "Root actor should identify itself as a browser.");
+  const target = await TargetFactory.forTab(tab);
+  await target.attach();
+  const { client } = target;
+  const targetFront = target.activeTab;
+  const form = targetFront.targetForm;
 
-  const [grip] = await attachTargetActorForUrl(client, TAB_URL);
-  await testTargetScopedActor(client, grip);
-  await closeTab(client, grip);
-  await client.close();
+  await testTargetScopedActor(client, form);
+  await closeTab(client, form);
+  await target.destroy();
 });
 
-async function testTargetScopedActor(client, grip) {
-  ok(grip.testOneActor,
+async function testTargetScopedActor(client, form) {
+  ok(form.testOneActor,
     "Found the test target-scoped actor.");
-  ok(grip.testOneActor.includes("testOne"),
+  ok(form.testOneActor.includes("testOne"),
     "testOneActor's actorPrefix should be used.");
 
-  const response = await client.request({ to: grip.testOneActor, type: "ping" });
+  const response = await client.request({ to: form.testOneActor, type: "ping" });
   is(response.pong, "pong",
      "Actor should respond to requests.");
 }
 
-async function closeTab(client, grip) {
+async function closeTab(client, form) {
   await removeTab(gBrowser.selectedTab);
   await Assert.rejects(
-    client.request({ to: grip.testOneActor, type: "ping" }),
-    err => err.message === `'ping' active request packet to '${grip.testOneActor}' ` +
+    client.request({ to: form.testOneActor, type: "ping" }),
+    err => err.message === `'ping' active request packet to '${form.testOneActor}' ` +
                            `can't be sent as the connection just closed.`,
     "testOneActor went away.");
 }
-
-async function attachTargetActorForUrl(client, url) {
-  const grip = await getTargetActorForUrl(client, url);
-  const [ response ] = await client.attachTarget(grip.actor);
-  return [grip, response];
-}
-
-function getTargetActorForUrl(client, url) {
-  const deferred = promise.defer();
-
-  client.listTabs().then(response => {
-    const targetActor = response.tabs.filter(grip => grip.url == url).pop();
-    deferred.resolve(targetActor);
-  });
-
-  return deferred.promise;
-}
--- a/devtools/client/shared/test/browser_dbg_worker-window.js
+++ b/devtools/client/shared/test/browser_dbg_worker-window.js
@@ -10,25 +10,20 @@ Services.scriptloader.loadSubScript(
   this);
 
 const TAB_URL = EXAMPLE_URL + "doc_WorkerTargetActor.attachThread-tab.html";
 const WORKER_URL = "code_WorkerTargetActor.attachThread-worker.js";
 
 add_task(async function() {
   await pushPrefs(["devtools.scratchpad.enabled", true]);
 
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
-
-  const client = new DebuggerClient(DebuggerServer.connectPipe());
-  await connect(client);
-
   const tab = await addTab(TAB_URL);
-  const { tabs } = await listTabs(client);
-  const [, targetFront] = await attachTarget(client, findTab(tabs, TAB_URL));
+  const target = await TargetFactory.forTab(tab);
+  await target.attach();
+  const targetFront = target.activeTab;
 
   await listWorkers(targetFront);
   await createWorkerInTab(tab, WORKER_URL);
 
   const { workers } = await listWorkers(targetFront);
   const workerTargetFront = findWorker(workers, WORKER_URL);
 
   const toolbox = await gDevTools.showToolbox(TargetFactory.forWorker(workerTargetFront),
@@ -51,12 +46,12 @@ add_task(async function() {
   const toolTabs = toolbox.doc.querySelectorAll(".devtools-tab");
   const activeTools = [...toolTabs].map(toolTab => toolTab.getAttribute("data-id"));
 
   is(activeTools.join(","), "webconsole,jsdebugger,scratchpad",
     "Correct set of tools supported by worker");
 
   terminateWorkerInTab(tab, WORKER_URL);
   await waitForWorkerClose(workerTargetFront);
-  await close(client);
+  await target.destroy();
 
   await toolbox.destroy();
 });
--- a/devtools/client/shared/test/helper_workers.js
+++ b/devtools/client/shared/test/helper_workers.js
@@ -167,25 +167,21 @@ function getSplitConsole(toolbox, win) {
       ok(toolbox.splitConsole, "Split console is shown.");
       const jsterm = toolbox.getPanel("webconsole").hud.jsterm;
       resolve(jsterm);
     });
   });
 }
 
 async function initWorkerDebugger(TAB_URL, WORKER_URL) {
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
-
-  const client = new DebuggerClient(DebuggerServer.connectPipe());
-  await connect(client);
-
   const tab = await addTab(TAB_URL);
-  const { tabs } = await listTabs(client);
-  const [, targetFront] = await attachTarget(client, findTab(tabs, TAB_URL));
+  const target = await TargetFactory.forTab(tab);
+  await target.attach();
+  const { client } = target;
+  const targetFront = target.activeTab;
 
   await createWorkerInTab(tab, WORKER_URL);
 
   const { workers } = await listWorkers(targetFront);
   const workerTargetFront = findWorker(workers, WORKER_URL);
 
   const toolbox = await gDevTools.showToolbox(TargetFactory.forWorker(workerTargetFront),
                                             "jsdebugger",
@@ -237,38 +233,23 @@ this.removeTab = function removeTab(tab,
     info("Tab removed and finished closing.");
     deferred.resolve();
   }, {once: true});
 
   targetBrowser.removeTab(tab);
   return deferred.promise;
 };
 
-async function attachTargetActorForUrl(client, url) {
-  const grip = await getTargetActorForUrl(client, url);
-  const [ response, front ] = await client.attachTarget(grip.actor);
-  return [grip, response, front];
-}
-
-async function attachThreadActorForUrl(client, url) {
-  const [, response] = await attachTargetActorForUrl(client, url);
-  const [, threadClient] = await client.attachThread(response.threadActor);
+async function attachThreadActorForTab(tab) {
+  const target = await TargetFactory.forTab(tab);
+  await target.attach();
+  const targetFront = target.activeTab;
+  const [, threadClient] = await targetFront.attachThread();
   await threadClient.resume();
-  return threadClient;
-}
-
-function getTargetActorForUrl(client, url) {
-  const deferred = getDeferredPromise().defer();
-
-  client.listTabs().then(response => {
-    const targetActor = response.tabs.filter(grip => grip.url == url).pop();
-    deferred.resolve(targetActor);
-  });
-
-  return deferred.promise;
+  return { client: target.client, threadClient };
 }
 
 function pushPrefs(...aPrefs) {
   const deferred = getDeferredPromise().defer();
   SpecialPowers.pushPrefEnv({"set": aPrefs}, deferred.resolve);
   return deferred.promise;
 }
 
--- a/devtools/server/tests/browser/browser_navigateEvents.js
+++ b/devtools/server/tests/browser/browser_navigateEvents.js
@@ -90,47 +90,43 @@ var httpObserver = function(subject, top
   }
 };
 Services.obs.addObserver(httpObserver, "http-on-modify-request");
 
 function onMessage({ data }) {
   assertEvent(data.event, data.data);
 }
 
-async function connectAndAttachTab() {
-  // Ensure having a minimal server
-  initDebuggerServer();
-
-  // Connect to this tab
-  const transport = DebuggerServer.connectPipe();
-  const client = new DebuggerClient(transport);
-  const form = await connectDebuggerClient(client);
-  const actorID = form.actor;
-  const [, targetFront ] = await client.attachTarget(actorID);
+async function connectAndAttachTab(tab) {
+  const target = await TargetFactory.forTab(tab);
+  await target.attach();
+  const targetFront = target.activeTab;
+  const actorID = targetFront.targetForm.actor;
   targetFront.on("tabNavigated", function(packet) {
     assertEvent("tabNavigated", packet);
   });
-  return { client, actorID };
+  return { target, actorID };
 }
 
 add_task(async function() {
   // Open a test tab
   const browser = await addTab(URL1);
 
   // Listen for alert() call being made in navigate-first during unload
   waitForOnBeforeUnloadDialog(browser, function(btnLeave, btnStay) {
     assertEvent("unload-dialog");
     // accept to quit this page to another
     btnLeave.click();
   });
 
   // Listen for messages sent by the content task
   browser.messageManager.addMessageListener("devtools-test:event", onMessage);
 
-  const { client, actorID } = await connectAndAttachTab();
+  const tab = gBrowser.getTabForBrowser(browser);
+  const { target, actorID } = await connectAndAttachTab(tab);
   await ContentTask.spawn(browser, [actorID], async function(actorId) {
     const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
     const { DebuggerServer } = require("devtools/server/main");
     const EventEmitter = require("devtools/shared/event-emitter");
 
     // !Hack! Retrieve a server side object, the FrameTargetActor instance
     const targetActor = DebuggerServer.searchAllConnectionsForActor(actorId);
     // In order to listen to internal will-navigate/navigate events
@@ -165,12 +161,12 @@ add_task(async function() {
   assertEvent("load-new-document");
   BrowserTestUtils.loadURI(browser, URL2);
 
   // Wait for all events to be received
   await onAllEventsReceived;
 
   // Cleanup
   browser.messageManager.removeMessageListener("devtools-test:event", onMessage);
-  await client.close();
+  await target.destroy();
   Services.obs.addObserver(httpObserver, "http-on-modify-request");
   DebuggerServer.destroy();
 });
--- a/devtools/server/tests/browser/browser_spawn_actor_in_parent.js
+++ b/devtools/server/tests/browser/browser_spawn_actor_in_parent.js
@@ -8,28 +8,32 @@
 // This test instanciates a first test actor "InContentActor" that uses
 // spawnActorInParentProcess to instanciate the second test actor "InParentActor"
 
 const ACTOR_URL = "chrome://mochitests/content/browser/devtools/server/tests/browser/test-spawn-actor-in-parent.js";
 
 const { InContentFront, InParentFront } = require(ACTOR_URL);
 
 add_task(async function() {
-  await addTab("data:text/html;charset=utf-8,foo");
+  const browser = await addTab("data:text/html;charset=utf-8,foo");
 
   info("Register target-scoped actor in the content process");
   await registerActorInContentProcess(ACTOR_URL, {
     prefix: "inContent",
     constructor: "InContentActor",
     type: { target: true },
   });
 
-  initDebuggerServer();
-  const client = new DebuggerClient(DebuggerServer.connectPipe());
-  const form = await connectDebuggerClient(client);
+  const tab = gBrowser.getTabForBrowser(browser);
+  const target = await TargetFactory.forTab(tab);
+  await target.attach();
+  const targetFront = target.activeTab;
+  const { client } = target;
+  const form = targetFront.targetForm;
+
   const inContentFront = InContentFront(client, form);
   const isInContent = await inContentFront.isInContent();
   ok(isInContent, "ContentActor really runs in the content process");
   const formSpawn = await inContentFront.spawnInParent(ACTOR_URL);
   const inParentFront = InParentFront(client, formSpawn);
   const {
     args,
     isInParent,
@@ -38,11 +42,11 @@ add_task(async function() {
   } = await inParentFront.test();
   is(args[0], 1, "first actor constructor arg is correct");
   is(args[1], 2, "first actor constructor arg is correct");
   is(args[2], 3, "first actor constructor arg is correct");
   ok(isInParent, "The ParentActor really runs in the parent process");
   ok(conn, "`conn`, first contructor argument is a DebuggerServerConnection instance");
   is(mm, "ChromeMessageSender", "`mm`, last constructor argument is a message manager");
 
-  await client.close();
+  await target.destroy();
   gBrowser.removeCurrentTab();
 });
--- a/devtools/server/tests/browser/head.js
+++ b/devtools/server/tests/browser/head.js
@@ -132,31 +132,16 @@ function getRootForm(client) {
  */
 function waitUntilClientConnected(client) {
   return new Promise(resolve => {
     client.addOneTimeListener("connected", resolve);
   });
 }
 
 /**
- * Connect a debugger client.
- *
- * @param {DebuggerClient}
- * @return {Promise} Resolves to the targetActor form for the selected tab when the client
- *         is connected.
- */
-function connectDebuggerClient(client) {
-  return client.connect()
-    .then(() => client.listTabs())
-    .then(tabs => {
-      return tabs.tabs[tabs.selected];
-    });
-}
-
-/**
  * Wait for eventName on target.
  * @param {Object} target An observable object that either supports on/off or
  * addEventListener/removeEventListener
  * @param {String} eventName
  * @param {Boolean} useCapture Optional, for addEventListener/removeEventListener
  * @return A promise that resolves when the event has been handled
  */
 function once(target, eventName, useCapture = false) {
--- a/devtools/server/tests/mochitest/webconsole-helpers.js
+++ b/devtools/server/tests/mochitest/webconsole-helpers.js
@@ -1,14 +1,14 @@
 /* exported attachURL, evaluateJS */
 "use strict";
 
 const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-const {DebuggerClient} = require("devtools/shared/client/debugger-client");
 const {DebuggerServer} = require("devtools/server/main");
+const {TargetFactory} = require("devtools/client/framework/target");
 
 const Services = require("Services");
 
 // Always log packets when running tests.
 Services.prefs.setBoolPref("devtools.debugger.log", true);
 SimpleTest.registerCleanupFunction(function() {
   Services.prefs.clearUserPref("devtools.debugger.log");
 });
@@ -30,42 +30,29 @@ if (!DebuggerServer.initialized) {
  *         The Promise resolves with an object containing :
  *           - tab: the attached tab
  *           - targetFront: the target front
  *           - consoleClient: the console client
  *           - cleanup: a generator function which can be called to close
  *             the opened tab and disconnect its debugger client.
  */
 async function attachURL(url) {
-  let win = window.open(url, "_blank");
-  let client = null;
-
-  const cleanup = async function() {
-    if (client) {
-      await client.close();
-      client = null;
-    }
-    if (win) {
-      win.close();
-      win = null;
-    }
-  };
-  SimpleTest.registerCleanupFunction(cleanup);
-
-  client = new DebuggerClient(DebuggerServer.connectPipe());
-  await client.connect();
-  const {tabs} = await client.listTabs();
-  const attachedTab = tabs.find(tab => tab.url === url);
-
-  if (!attachedTab) {
-    throw new Error(`Could not find a tab matching URL ${url}`);
-  }
-
-  const [, targetFront] = await client.attachTarget(attachedTab.actor);
-  const [, consoleClient] = await client.attachConsole(attachedTab.consoleActor, []);
+  const tab = await addTab(url);
+  const target = await TargetFactory.forTab(tab);
+  const { client } = target;
+  const { consoleActor } = target.form;
+  const [, consoleClient] = await client.attachConsole(consoleActor, []);
 
   return {
-    tab: attachedTab,
-    targetFront,
     consoleClient,
-    cleanup,
   };
 }
+
+/**
+ * Naive implementaion of addTab working from a mochitest-chrome test.
+ */
+async function addTab(url) {
+  const { gBrowser } = Services.wm.getMostRecentWindow("navigator:browser");
+  const {BrowserTestUtils} = require("resource://testing-common/BrowserTestUtils.jsm");
+  const tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, url);
+  await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+  return tab;
+}