Backed out changeset b8c3e2f3cd42 (bug 1595012) for causing DevTools failures in devtools/client/webconsole/test/browser/browser_webconsole_stubs_evaluation_result.js. CLOSED TREE
authorDorel Luca <dluca@mozilla.com>
Sun, 10 Nov 2019 05:14:38 +0200
changeset 501413 8f0a0c1d6868be403c601cecee01ef9e26a23bb4
parent 501412 cdfe04574b0c6afba17637ee8e7419c3f2d6068f
child 501414 74ae5427c21f848b01a2e72fd81f339ba2a5b7a3
push id36791
push usercsabou@mozilla.com
push dateSun, 10 Nov 2019 09:53:30 +0000
treeherdermozilla-central@72c52c0101cf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1595012
milestone72.0a1
backs outb8c3e2f3cd42febd74097e090589fe9a9019cfbe
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset b8c3e2f3cd42 (bug 1595012) for causing DevTools failures in devtools/client/webconsole/test/browser/browser_webconsole_stubs_evaluation_result.js. CLOSED TREE
devtools/client/debugger/src/client/firefox/types.js
devtools/client/debugger/test/mochitest/helpers.js
devtools/client/webconsole/test/browser/browser_console_cpow.js
devtools/client/webconsole/test/browser/browser_webconsole_stubs_evaluation_result.js
devtools/client/webreplay/mochitest/head.js
devtools/server/tests/browser/browser_resource_list-remote-frames.js
devtools/server/tests/browser/browser_webextension_inspected_window.js
devtools/server/tests/mochitest/test_getProcess.html
devtools/server/tests/mochitest/test_webconsole-node-grip.html
devtools/shared/fronts/webconsole.js
devtools/shared/specs/webconsole.js
devtools/shared/webconsole/test/browser/browser_commands_registration.js
devtools/shared/webconsole/test/common.js
devtools/shared/webconsole/test/test_bug819670_getter_throws.html
devtools/shared/webconsole/test/test_commands_other.html
devtools/shared/webconsole/test/test_console_worker.html
devtools/shared/webconsole/test/test_jsterm.html
devtools/shared/webconsole/test/test_jsterm_cd_iframe.html
devtools/shared/webconsole/test/test_jsterm_queryselector.html
devtools/shared/webconsole/test/test_throw.html
--- a/devtools/client/debugger/src/client/firefox/types.js
+++ b/devtools/client/debugger/src/client/firefox/types.js
@@ -194,16 +194,21 @@ export type Actions = {
   newQueuedSources: (QueuedSourceData[]) => void,
   fetchEventListeners: () => void,
   updateThreads: typeof actions.updateThreads,
   ensureHasThread: typeof actions.ensureHasThread,
   setFramePositions: typeof actions.setFramePositions,
 };
 
 type ConsoleClient = {
+  evaluateJS: (
+    script: Script,
+    func: Function,
+    params?: { frameActor: ?FrameId }
+  ) => void,
   evaluateJSAsync: (
     script: Script,
     func: Function,
     params?: { frameActor: ?FrameId }
   ) => Promise<{ result: Grip | null }>,
   autocomplete: (
     input: string,
     cursor: number,
--- a/devtools/client/debugger/test/mochitest/helpers.js
+++ b/devtools/client/debugger/test/mochitest/helpers.js
@@ -1865,17 +1865,17 @@ async function getDebuggerSplitConsole(d
 // Return a promise that resolves with the result of a thread evaluating a
 // string in the topmost frame.
 async function evaluateInTopFrame(dbg, text) {
   const threadFront = dbg.toolbox.target.threadFront;
   const consoleFront = await dbg.toolbox.target.getFront("console");
   const { frames } = await threadFront.getFrames(0, 1);
   ok(frames.length == 1, "Got one frame");
   const options = { thread: threadFront.actor, frameActor: frames[0].actorID };
-  const response = await consoleFront.evaluateJSAsync(text, options);
+  const response = await consoleFront.evaluateJS(text, options);
   return response.result.type == "undefined" ? undefined : response.result;
 }
 
 // Return a promise that resolves when a thread evaluates a string in the
 // topmost frame, ensuring the result matches the expected value.
 async function checkEvaluateInTopFrame(dbg, text, expected) {
   const rval = await evaluateInTopFrame(dbg, text);
   ok(rval == expected, `Eval returned ${expected}`);
--- a/devtools/client/webconsole/test/browser/browser_console_cpow.js
+++ b/devtools/client/webconsole/test/browser/browser_console_cpow.js
@@ -28,17 +28,17 @@ async function obtainObjectWithCPOW(hud)
       Services.ppmm.removeMessageListener("cpow", listener);
       console.log(message.objects);
       globalThis.result = message.objects;
     });
   `);
 
   info("Open the browser content toolbox and send a message");
   const toolbox = await gDevToolsBrowser.openContentProcessToolbox(gBrowser);
-  await toolbox.target.activeConsole.evaluateJSAsync(`
+  await toolbox.target.activeConsole.evaluateJS(`
     let {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
     Services.cpmm.sendAsyncMessage("cpow", null, {cpow: {a:1}});
   `);
 
   info("Obtain the object with CPOW");
   const message = await waitFor(() => findMessage(hud, "cpow"));
   const result = await hud.ui.evaluateJSAsync("result");
   const { actor } = result.result;
--- a/devtools/client/webconsole/test/browser/browser_webconsole_stubs_evaluation_result.js
+++ b/devtools/client/webconsole/test/browser/browser_webconsole_stubs_evaluation_result.js
@@ -59,17 +59,17 @@ add_task(async function() {
   }
 });
 
 async function generateEvaluationResultStubs() {
   const stubs = new Map();
   const toolbox = await openNewTabAndToolbox(TEST_URI, "webconsole");
 
   for (const [key, code] of getCommands()) {
-    const packet = await toolbox.target.activeConsole.evaluateJSAsync(code);
+    const packet = await toolbox.target.activeConsole.evaluateJS(code);
     stubs.set(key, getCleanedPacket(key, packet));
   }
 
   await closeTabAndToolbox();
   return stubs;
 }
 
 function getCommands() {
--- a/devtools/client/webreplay/mochitest/head.js
+++ b/devtools/client/webreplay/mochitest/head.js
@@ -100,17 +100,17 @@ var stepOutToLine = resumeThenPauseAtLin
 // Return a promise that resolves when a thread evaluates a string in the
 // topmost frame, with the result throwing an exception.
 async function checkEvaluateInTopFrameThrows(dbg, text) {
   const threadFront = dbg.toolbox.target.threadFront;
   const consoleFront = await dbg.toolbox.target.getFront("console");
   const { frames } = await threadFront.getFrames(0, 1);
   ok(frames.length == 1, "Got one frame");
   const options = { thread: threadFront.actor, frameActor: frames[0].actor };
-  const response = await consoleFront.evaluateJSAsync(text, options);
+  const response = await consoleFront.evaluateJS(text, options);
   ok(response.exception, "Eval threw an exception");
 }
 
 // Return a pathname that can be used for a new recording file.
 function newRecordingFile() {
   const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
   return OS.Path.join(
     OS.Constants.Path.tmpDir,
--- a/devtools/server/tests/browser/browser_resource_list-remote-frames.js
+++ b/devtools/server/tests/browser/browser_resource_list-remote-frames.js
@@ -60,17 +60,17 @@ async function getFrames(target) {
   const descriptor = frames.find(f => f.url && f.url.includes("doc_iframe"));
   ok(descriptor, "we have a descriptor with the url 'doc_iframe'");
 
   const front = await descriptor.getTarget();
   ok(front.hasActor("console"), "Got the console actor");
   ok(front.hasActor("thread"), "Got the thread actor");
   // Ensure sending at least one request to an actor...
   const consoleFront = await front.getFront("console");
-  const { result } = await consoleFront.evaluateJSAsync("var a = 42; a");
+  const { result } = await consoleFront.evaluateJS("var a = 42; a");
   is(result, 42, "console.eval worked");
 
   // Although we can get metadata about the child frames,
   // since we do not have access to remote frames yet, this will return null.
   // This test should be updated when we have access to remote frames.
   const childFrames = frames.filter(d => d.parentID === descriptor.id);
   for (const frame of childFrames) {
     const frameTarget = await frame.getTarget();
--- a/devtools/server/tests/browser/browser_webextension_inspected_window.js
+++ b/devtools/server/tests/browser/browser_webextension_inspected_window.js
@@ -340,34 +340,34 @@ add_task(async function test_exception_i
 
   ok(
     !reloadResult,
     "Got the expected undefined result from inspectedWindow reload"
   );
 
   await waitForNoBypassCacheReload;
 
-  const noBypassCacheEval = await webConsoleFront.evaluateJSAsync(
+  const noBypassCacheEval = await webConsoleFront.evaluateJS(
     "document.body.textContent"
   );
 
   is(
     noBypassCacheEval.result,
     "empty cache headers",
     "Got the expected result with reload forceBypassCache=false"
   );
 
   // Test reload with bypassCache=true.
 
   const waitForForceBypassCacheReload = waitForNextTabNavigated(target);
   await inspectedWindowFront.reload(fakeExtCallerInfo, { ignoreCache: true });
 
   await waitForForceBypassCacheReload;
 
-  const forceBypassCacheEval = await webConsoleFront.evaluateJSAsync(
+  const forceBypassCacheEval = await webConsoleFront.evaluateJS(
     "document.body.textContent"
   );
 
   is(
     forceBypassCacheEval.result,
     "no-cache:no-cache",
     "Got the expected result with reload forceBypassCache=true"
   );
@@ -389,34 +389,34 @@ add_task(async function test_exception_i
 
   const waitForCustomUserAgentReload = waitForNextTabNavigated(target);
   await inspectedWindowFront.reload(fakeExtCallerInfo, {
     userAgent: "Customized User Agent",
   });
 
   await waitForCustomUserAgentReload;
 
-  const customUserAgentEval = await webConsoleFront.evaluateJSAsync(
+  const customUserAgentEval = await webConsoleFront.evaluateJS(
     "document.body.textContent"
   );
 
   is(
     customUserAgentEval.result,
     "Customized User Agent",
     "Got the expected result on reload with a customized userAgent"
   );
 
   // Test reload with no custom userAgent.
 
   const waitForNoCustomUserAgentReload = waitForNextTabNavigated(target);
   await inspectedWindowFront.reload(fakeExtCallerInfo, {});
 
   await waitForNoCustomUserAgentReload;
 
-  const noCustomUserAgentEval = await webConsoleFront.evaluateJSAsync(
+  const noCustomUserAgentEval = await webConsoleFront.evaluateJS(
     "document.body.textContent"
   );
 
   is(
     noCustomUserAgentEval.result,
     window.navigator.userAgent,
     "Got the expected result with reload without a customized userAgent"
   );
@@ -437,17 +437,17 @@ add_task(async function test_exception_i
   // Test reload with an injectedScript.
 
   const waitForInjectedScriptReload = waitForNextTabNavigated(target);
   await inspectedWindowFront.reload(fakeExtCallerInfo, {
     injectedScript: `new ${injectedScript}`,
   });
   await waitForInjectedScriptReload;
 
-  const injectedScriptEval = await webConsoleFront.evaluateJSAsync(
+  const injectedScriptEval = await webConsoleFront.evaluateJS(
     `(${collectEvalResults})()`
   );
 
   const expectedResult = new Array(5).fill("injected script executed first");
 
   SimpleTest.isDeeply(
     JSON.parse(injectedScriptEval.result),
     expectedResult,
@@ -455,17 +455,17 @@ add_task(async function test_exception_i
   );
 
   // Test reload without an injectedScript.
 
   const waitForNoInjectedScriptReload = waitForNextTabNavigated(target);
   await inspectedWindowFront.reload(fakeExtCallerInfo, {});
   await waitForNoInjectedScriptReload;
 
-  const noInjectedScriptEval = await webConsoleFront.evaluateJSAsync(
+  const noInjectedScriptEval = await webConsoleFront.evaluateJS(
     `(${collectEvalResults})()`
   );
 
   const newExpectedResult = new Array(5).fill("injected script NOT executed");
 
   SimpleTest.isDeeply(
     JSON.parse(noInjectedScriptEval.result),
     newExpectedResult,
@@ -494,34 +494,34 @@ add_task(async function test_exception_i
     userAgent: "Customized User Agent 1",
   });
   inspectedWindowFront.reload(fakeExtCallerInfo, {
     userAgent: "Customized User Agent 2",
   });
 
   await waitForCustomUserAgentReload;
 
-  const customUserAgentEval = await webConsoleFront.evaluateJSAsync(
+  const customUserAgentEval = await webConsoleFront.evaluateJS(
     "document.body.textContent"
   );
 
   is(
     customUserAgentEval.result,
     "Customized User Agent 1",
     "Got the expected result on reload with a customized userAgent"
   );
 
   // Test reload with no custom userAgent.
 
   const waitForNoCustomUserAgentReload = waitForNextTabNavigated(target);
   await inspectedWindowFront.reload(fakeExtCallerInfo, {});
 
   await waitForNoCustomUserAgentReload;
 
-  const noCustomUserAgentEval = await webConsoleFront.evaluateJSAsync(
+  const noCustomUserAgentEval = await webConsoleFront.evaluateJS(
     "document.body.textContent"
   );
 
   is(
     noCustomUserAgentEval.result,
     window.navigator.userAgent,
     "Got the expected result with reload without a customized userAgent"
   );
@@ -552,17 +552,17 @@ add_task(async function test_exception_i
 
   info("Starting a reload with an injectedScript");
   const waitForInjectedScriptReload = waitForNextTabNavigated(target);
   await inspectedWindowFront.reload(fakeExtCallerInfo, {
     injectedScript: `new ${injectedScript}`,
   });
   await waitForInjectedScriptReload;
 
-  const injectedScriptEval = await webConsoleFront.evaluateJSAsync(
+  const injectedScriptEval = await webConsoleFront.evaluateJS(
     `(${collectEvalResults})()`
   );
 
   // The page should have stopped during the reload and only one injected script
   // is expected.
   const expectedResult = new Array(1).fill("injected script executed first");
 
   SimpleTest.isDeeply(
@@ -573,17 +573,17 @@ add_task(async function test_exception_i
 
   // Reload again with no options.
 
   info("Reload the tab again without any reload options");
   const waitForNoInjectedScriptReload = waitForNextTabNavigated(target);
   await inspectedWindowFront.reload(fakeExtCallerInfo, {});
   await waitForNoInjectedScriptReload;
 
-  const noInjectedScriptEval = await webConsoleFront.evaluateJSAsync(
+  const noInjectedScriptEval = await webConsoleFront.evaluateJS(
     `(${collectEvalResults})()`
   );
 
   // The page should have stopped during the reload and no injected script should
   // have been executed during this second reload (or it would mean that the previous
   // customized reload was still pending and has wrongly affected the second reload)
   const newExpectedResult = new Array(1).fill("injected script NOT executed");
 
--- a/devtools/server/tests/mochitest/test_getProcess.html
+++ b/devtools/server/tests/mochitest/test_getProcess.html
@@ -87,17 +87,17 @@ function runTests() {
 
       client.mainRoot.getProcess(content.id).then(async front => {
         const targetForm = front.targetForm;
         ok(targetForm.consoleActor, "Got the console actor");
         ok(targetForm.threadActor, "Got the thread actor");
 
         // Ensure sending at least one request to an actor...
         const consoleFront = await front.getFront("console");
-        const { result } = await consoleFront.evaluateJSAsync("var a = 42; a");
+        const { result } = await consoleFront.evaluateJS("var a = 42; a");
         is(result, 42, "console.eval worked");
 
         getProcessAgain(front, content.id);
       });
     });
   }
 
   // Assert that calling client.getProcess against the same process id is
@@ -146,10 +146,10 @@ function runTests() {
     SimpleTest.finish();
   }
 
   connect();
 }
 
 </script>
 </pre>
-  </body>
+</body>
 </html>
--- a/devtools/server/tests/mochitest/test_webconsole-node-grip.html
+++ b/devtools/server/tests/mochitest/test_webconsole-node-grip.html
@@ -25,38 +25,38 @@ window.onload = async function() {
   } catch (e) {
     ok(false, `Error thrown: ${e.message}`);
   }
   SimpleTest.finish();
 };
 
 async function testNotInTreeElementNode(webConsoleFront) {
   info("Testing isConnected property on a ElementNode not in the DOM tree");
-  const {result} = await webConsoleFront.evaluateJSAsync("document.createElement(\"div\")");
+  const {result} = await webConsoleFront.evaluateJS("document.createElement(\"div\")");
   is(result.preview.isConnected, false,
     "isConnected is false since we only created the element");
 }
 
 async function testInTreeElementNode(webConsoleFront) {
   info("Testing isConnected property on a ElementNode in the DOM tree");
-  const {result} = await webConsoleFront.evaluateJSAsync("document.body");
+  const {result} = await webConsoleFront.evaluateJS("document.body");
   is(result.preview.isConnected, true,
     "isConnected is true as expected, since the element was retrieved from the DOM tree");
 }
 
 async function testNotInTreeTextNode(webConsoleFront) {
   info("Testing isConnected property on a TextNode not in the DOM tree");
-  const {result} = await webConsoleFront.evaluateJSAsync("document.createTextNode(\"Hello\")");
+  const {result} = await webConsoleFront.evaluateJS("document.createTextNode(\"Hello\")");
   is(result.preview.isConnected, false,
     "isConnected is false since we only created the element");
 }
 
 async function testInTreeTextNode(webConsoleFront) {
   info("Testing isConnected property on a TextNode in the DOM tree");
-  const {result} = await webConsoleFront.evaluateJSAsync("document.body.firstChild");
+  const {result} = await webConsoleFront.evaluateJS("document.body.firstChild");
   is(result.preview.isConnected, true,
     "isConnected is true as expected, since the element was retrieved from the DOM tree");
 }
 
   </script>
 </head>
 <body>
   <p id="display"></p>
--- a/devtools/shared/fronts/webconsole.js
+++ b/devtools/shared/fronts/webconsole.js
@@ -158,38 +158,52 @@ class WebConsoleFront extends FrontClass
 
     this.emit("networkEventUpdate", {
       packet: packet,
       networkInfo,
     });
   }
 
   /**
-   * Evaluate a JavaScript expression asynchronously.
+   * Evaluate a JavaScript expression.
    *
-   * @param {String} string: The code you want to evaluate.
-   * @param {Object} opts: Options for evaluation:
+   * @param string string
+   *        The code you want to evaluate.
+   * @param object [options={}]
+   *        Options for evaluation:
    *
-   *        - {String} frameActor: a FrameActor ID. The FA holds a reference to
+   *        - frameActor: a FrameActor ID. The FA holds a reference to
    *        a Debugger.Frame. This option allows you to evaluate the string in
    *        the frame of the given FA.
    *
-   *        - {String} url: the url to evaluate the script as. Defaults to
+   *        - url: the url to evaluate the script as. Defaults to
    *        "debugger eval code".
    *
-   *        - {String} selectedNodeActor: the NodeActor ID of the current
+   *        - selectedNodeActor: the NodeActor ID of the current
    *        selection in the Inspector, if such a selection
    *        exists. This is used by helper functions that can
-   *        reference the currently selected node in the Inspector, like $0.
-   *
-   *        - {String} selectedObjectActor: the actorID of a given objectActor.
-   *        This is used by context menu entries to get a reference to an object, in order
-   *        to perform some operation on it (copy it, store it as a global variable, …).
-   *
-   * @return {Promise}: A promise that resolves with the response.
+   *        reference the currently selected node in the Inspector,
+   *        like $0.
+   * @return request
+   *         Request object that implements both Promise and EventEmitter interfaces
+   */
+  evaluateJS(string, opts = {}) {
+    const options = {
+      text: string,
+      frameActor: opts.frameActor,
+      url: opts.url,
+      selectedNodeActor: opts.selectedNodeActor,
+      selectedObjectActor: opts.selectedObjectActor,
+    };
+    return super.evaluateJS(options);
+  }
+
+  /**
+   * Evaluate a JavaScript expression asynchronously.
+   * See evaluateJS for parameter and response information.
    */
   async evaluateJSAsync(string, opts = {}) {
     const options = {
       text: string,
       frameActor: opts.frameActor,
       url: opts.url,
       selectedNodeActor: opts.selectedNodeActor,
       selectedObjectActor: opts.selectedObjectActor,
--- a/devtools/shared/specs/webconsole.js
+++ b/devtools/shared/specs/webconsole.js
@@ -140,16 +140,27 @@ const webconsoleSpecPrototype = {
       request: {
         messageTypes: Arg(0, "array:string"),
       },
       // the return value here has a field "string" which can either be a longStringActor
       // or a plain string. Since we do not have union types, we cannot fully type this
       // response
       response: RetVal("console.cachedmessages"),
     },
+    evaluateJS: {
+      request: {
+        text: Option(0, "string"),
+        frameActor: Option(0, "string"),
+        url: Option(0, "string"),
+        selectedNodeActor: Option(0, "string"),
+        selectedObjectActor: Option(0, "string"),
+        mapped: Option(0, "nullable:json"),
+      },
+      response: RetVal("json"),
+    },
     evaluateJSAsync: {
       request: {
         text: Option(0, "string"),
         frameActor: Option(0, "string"),
         url: Option(0, "string"),
         selectedNodeActor: Option(0, "string"),
         selectedObjectActor: Option(0, "string"),
         mapped: Option(0, "nullable:json"),
--- a/devtools/shared/webconsole/test/browser/browser_commands_registration.js
+++ b/devtools/shared/webconsole/test/browser/browser_commands_registration.js
@@ -27,17 +27,17 @@ add_task(async function() {
   await registerNewCommand(webConsoleFront);
   await wrapCommand(webConsoleFront);
   await unregisterCommand(webConsoleFront);
   await registerAccessor(webConsoleFront);
   await unregisterAfterOverridingTwice(webConsoleFront);
 });
 
 async function evaluateJSAndCheckResult(webConsoleFront, input, expected) {
-  const response = await webConsoleFront.evaluateJSAsync(input);
+  const response = await webConsoleFront.evaluateJS(input);
   checkObject(response, expected);
 }
 
 async function registerNewCommand(webConsoleFront) {
   await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
     this.WebConsoleCommands.register("setFoo", (owner, value) => {
       owner.window.foo = value;
       return "ok";
@@ -46,16 +46,17 @@ async function registerNewCommand(webCon
     ok(
       this.WebConsoleCommands.hasCommand("setFoo"),
       "The command should be registered"
     );
   });
 
   const command = "setFoo('bar')";
   await evaluateJSAndCheckResult(webConsoleFront, command, {
+    from: webConsoleFront.actor,
     input: command,
     result: "ok",
   });
 
   await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
     is(content.top.foo, "bar", "top.foo should equal to 'bar'");
   });
 }
@@ -78,20 +79,22 @@ async function wrapCommand(webConsoleFro
       newKeys,
       "the keys() command should have been replaced"
     );
 
     this.origKeys = origKeys;
   });
 
   await evaluateJSAndCheckResult(webConsoleFront, "keys('>o_/')", {
+    from: webConsoleFront.actor,
     result: "bang!",
   });
 
   await evaluateJSAndCheckResult(webConsoleFront, "keys({foo: 'bar'})", {
+    from: webConsoleFront.actor,
     result: {
       class: "Array",
       preview: {
         items: ["foo"],
       },
     },
   });
 
@@ -107,16 +110,17 @@ async function wrapCommand(webConsoleFro
 }
 
 async function unregisterCommand(webConsoleFront) {
   await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
     this.WebConsoleCommands.unregister("setFoo");
   });
 
   await evaluateJSAndCheckResult(webConsoleFront, "setFoo", {
+    from: webConsoleFront.actor,
     input: "setFoo",
     result: {
       type: "undefined",
     },
     exceptionMessage: /setFoo is not defined/,
   });
 }
 
@@ -127,16 +131,17 @@ async function registerAccessor(webConso
         const foo = owner.window.document.getElementById("quack");
         return owner.makeDebuggeeValue(foo);
       },
     });
   });
 
   const command = "$foo.textContent = '>o_/'";
   await evaluateJSAndCheckResult(webConsoleFront, command, {
+    from: webConsoleFront.actor,
     input: command,
     result: ">o_/",
   });
 
   await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
     is(
       content.document.getElementById("quack").textContent,
       ">o_/",
--- a/devtools/shared/webconsole/test/common.js
+++ b/devtools/shared/webconsole/test/common.js
@@ -32,34 +32,25 @@ async function connectToDebugger() {
   const client = new DebuggerClient(transport);
 
   await client.connect();
   return client;
 }
 
 async function attachConsole(listeners, callback) {
   const { state, response } = await _attachConsole(listeners);
-  if (callback) {
-    return callback(state, response);
-  }
-  return { state, response };
+  callback(state, response);
 }
 async function attachConsoleToTab(listeners, callback) {
   const { state, response } = await _attachConsole(listeners, true);
-  if (callback) {
-    return callback(state, response);
-  }
-  return { state, response };
+  callback(state, response);
 }
 async function attachConsoleToWorker(listeners, callback) {
   const { state, response } = await _attachConsole(listeners, true, true);
-  if (callback) {
-    return callback(state, response);
-  }
-  return { state, response };
+  callback(state, response);
 }
 
 var _attachConsole = async function(listeners, attachToTab, attachToWorker) {
   try {
     const client = await connectToDebugger();
 
     function waitForMessage(target) {
       return new Promise(resolve => {
@@ -150,20 +141,16 @@ function checkConsoleAPICall(call, expec
   if (expected.level != "trace" && expected.arguments) {
     is(call.arguments.length, expected.arguments.length, "number of arguments");
   }
 
   checkObject(call, expected);
 }
 
 function checkObject(object, expected) {
-  if (object && object.getGrip) {
-    object = object.getGrip();
-  }
-
   for (const name of Object.keys(expected)) {
     const expectedValue = expected[name];
     const value = object[name];
     checkValue(name, value, expectedValue);
   }
 }
 
 function checkValue(name, value, expected) {
--- a/devtools/shared/webconsole/test/test_bug819670_getter_throws.html
+++ b/devtools/shared/webconsole/test/test_bug819670_getter_throws.html
@@ -18,22 +18,23 @@ function startTest()
 {
   removeEventListener("load", startTest);
   attachConsoleToTab([], onAttach);
 }
 
 function onAttach(aState, aResponse)
 {
   onEvaluate = onEvaluate.bind(null, aState);
-  aState.webConsoleFront.evaluateJSAsync("document.__proto__").then(onEvaluate);
+  aState.webConsoleFront.evaluateJS("document.__proto__").then(onEvaluate);
 }
 
 function onEvaluate(aState, aResponse)
 {
   checkObject(aResponse, {
+    from: aState.actor,
     input: "document.__proto__",
     result: {
       type: "object",
       actor: /[a-z]/,
     },
   });
 
   ok(!aResponse.exception, "no eval exception");
--- a/devtools/shared/webconsole/test/test_commands_other.html
+++ b/devtools/shared/webconsole/test/test_commands_other.html
@@ -13,17 +13,17 @@
 
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 let gState;
 let gWin;
 let tests;
 
 function evaluateJS(input) {
-  return gState.webConsoleFront.evaluateJSAsync(input);
+  return gState.webConsoleFront.evaluateJS(input);
 }
 
 function startTest() {
   info ("Content window opened, attaching console to it");
 
   let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
   ok (!gWin.document.nodePrincipal.equals(systemPrincipal),
       "The test document is not using the system principal");
@@ -33,28 +33,30 @@ function startTest() {
     runTests(tests, testEnd);
   });
 }
 
 tests = [
   async function keys() {
     let response = await evaluateJS("keys({foo: 'bar'})");
     checkObject(response, {
+      from: gState.actor,
       result: {
         class: "Array",
         preview: {
           items: ["foo"]
         }
       }
     });
     nextTest();
   },
   async function values() {
     let response = await evaluateJS("values({foo: 'bar'})");
     checkObject(response, {
+      from: gState.actor,
       result: {
         class: "Array",
         preview: {
           items: ["bar"]
         }
       }
     });
     nextTest();
--- a/devtools/shared/webconsole/test/test_console_worker.html
+++ b/devtools/shared/webconsole/test/test_console_worker.html
@@ -66,16 +66,16 @@ let testConsoleAPI = async function (sta
       checkConsoleAPICalls([packet.message], expectedConsoleAPICalls);
       state.webConsoleFront.off("consoleAPICall", onConsoleAPICall);
       resolve();
     }
 
     info("testConsoleAPI: adding listener for consoleAPICall");
     state.webConsoleFront.on("consoleAPICall", onConsoleAPICall);
 
-    state.webConsoleFront.evaluateJSAsync("console.log('Log was requested from worker')",
+    state.webConsoleFront.evaluateJS("console.log('Log was requested from worker')",
       () => { });
   });
 };
 
 </script>
 </body>
 </html>
--- a/devtools/shared/webconsole/test/test_jsterm.html
+++ b/devtools/shared/webconsole/test/test_jsterm.html
@@ -15,19 +15,25 @@
 
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 
 let gState;
 
 let {MAX_AUTOCOMPLETE_ATTEMPTS,MAX_AUTOCOMPLETIONS} = require("devtools/shared/webconsole/js-property-provider");
 
-
+// This test runs all of its assertions twice - once with
+// evaluateJS and once with evaluateJSAsync.
+let evaluatingSync = true;
 function evaluateJS(input, options = {}) {
-  return gState.webConsoleFront.evaluateJSAsync(input, options);
+  if (evaluatingSync) {
+    return gState.webConsoleFront.evaluateJS(input, options);
+  } else {
+    return gState.webConsoleFront.evaluateJSAsync(input, options);
+  }
 }
 
 function startTest()
 {
   removeEventListener("load", startTest);
 
   attachConsoleToTab(["PageError"], onAttach);
 }
@@ -255,16 +261,21 @@ async function forceLexicalInit() {
 }
 
 function testEnd()
 {
   // If this is the first run, reload the page and do it again.
   // Otherwise, end the test.
   closeDebugger(gState, function() {
     gState = null;
-    SimpleTest.finish();
+    if (evaluatingSync) {
+      evaluatingSync = false;
+      startTest();
+    } else {
+      SimpleTest.finish();
+    }
   });
 }
 
 addEventListener("load", startTest);
 </script>
 </body>
 </html>
--- a/devtools/shared/webconsole/test/test_jsterm_cd_iframe.html
+++ b/devtools/shared/webconsole/test/test_jsterm_cd_iframe.html
@@ -42,160 +42,168 @@ function onAttach(aState, aResponse)
       doCdParent,
       doCheckParent2];
   runTests(tests, testEnd);
 }
 
 function doCheckParent()
 {
   info("check parent window");
-  gState.webConsoleFront.evaluateJSAsync("window.foobarObject.bug609872")
+  gState.webConsoleFront.evaluateJS("window.foobarObject.bug609872")
     .then(onFooObjectFromParent);
 }
 
 function onFooObjectFromParent(aResponse)
 {
   checkObject(aResponse, {
+    from: gState.actor,
     input: "window.foobarObject.bug609872",
     result: "parent",
   });
 
   ok(!aResponse.exception, "no eval exception");
   ok(!aResponse.helperResult, "no helper result");
 
   nextTest();
 }
 
 function doCdIframe()
 {
   info("test cd('iframe')");
-  gState.webConsoleFront.evaluateJSAsync("cd('iframe')").then(onCdIframe);
+  gState.webConsoleFront.evaluateJS("cd('iframe')").then(onCdIframe);
 }
 
 function onCdIframe(aResponse)
 {
   checkObject(aResponse, {
+    from: gState.actor,
     input: "cd('iframe')",
     result: { type: "undefined" },
     helperResult: { type: "cd" },
   });
 
   ok(!aResponse.exception, "no eval exception");
 
   nextTest();
 }
 
 function doCheckIframe()
 {
   info("check foobarObject from the iframe");
-  gState.webConsoleFront.evaluateJSAsync("window.foobarObject.bug609872")
+  gState.webConsoleFront.evaluateJS("window.foobarObject.bug609872")
     .then(onFooObjectFromIframe);
 }
 
 function onFooObjectFromIframe(aResponse)
 {
   checkObject(aResponse, {
+    from: gState.actor,
     input: "window.foobarObject.bug609872",
     result: "child",
   });
 
   ok(!aResponse.exception, "no js eval exception");
   ok(!aResponse.helperResult, "no helper result");
 
   nextTest();
 }
 
 function doCdContentIframe()
 {
   info("test cd('#content-iframe')");
-  gState.webConsoleFront.evaluateJSAsync("cd('#content-iframe')").then(onCdContentIframe);
+  gState.webConsoleFront.evaluateJS("cd('#content-iframe')").then(onCdContentIframe);
 }
 
 function onCdContentIframe(aResponse)
 {
   checkObject(aResponse, {
+    from: gState.actor,
     input: "cd('#content-iframe')",
     result: { type: "undefined" },
     helperResult: { type: "cd" },
   });
 
   ok(!aResponse.exception, "no eval exception");
 
   nextTest();
 }
 function doCdSandboxedIframe()
 {
   // Don't use string to ensure we don't get security exception
   // when passing a content window reference.
   let cmd = "cd(document.getElementById('sandboxed-iframe').contentWindow)";
   info("test " + cmd);
-  gState.webConsoleFront.evaluateJSAsync(cmd).then(onCdSandboxedIframe.bind(null, cmd));
+  gState.webConsoleFront.evaluateJS(cmd).then(onCdSandboxedIframe.bind(null, cmd));
 }
 
 function onCdSandboxedIframe(cmd, aResponse)
 {
   checkObject(aResponse, {
+    from: gState.actor,
     input: cmd,
     result: { type: "undefined" },
     helperResult: { type: "cd" },
   });
 
   ok(!aResponse.exception, "no eval exception");
 
   nextTest();
 }
 
 function doCheckSandboxedIframe()
 {
   info("check foobarObject from the sandboxed iframe");
-  gState.webConsoleFront.evaluateJSAsync("window.foobarObject.bug1051224")
+  gState.webConsoleFront.evaluateJS("window.foobarObject.bug1051224")
     .then(onFooObjectFromSandboxedIframe);
 }
 
 function onFooObjectFromSandboxedIframe(aResponse)
 {
   checkObject(aResponse, {
+    from: gState.actor,
     input: "window.foobarObject.bug1051224",
     result: "sandboxed",
   });
 
   ok(!aResponse.exception, "no js eval exception");
   ok(!aResponse.helperResult, "no helper result");
 
   nextTest();
 }
 
 function doCdParent()
 {
   info("test cd() back to parent");
-  gState.webConsoleFront.evaluateJSAsync("cd()").then(onCdParent);
+  gState.webConsoleFront.evaluateJS("cd()").then(onCdParent);
 }
 
 function onCdParent(aResponse)
 {
   checkObject(aResponse, {
+    from: gState.actor,
     input: "cd()",
     result: { type: "undefined" },
     helperResult: { type: "cd" },
   });
 
   ok(!aResponse.exception, "no eval exception");
 
   nextTest();
 }
 
 function doCheckParent2()
 {
-  gState.webConsoleFront.evaluateJSAsync("window.foobarObject.bug609872")
+  gState.webConsoleFront.evaluateJS("window.foobarObject.bug609872")
     .then(onFooObjectFromParent2);
 }
 
 function onFooObjectFromParent2(aResponse)
 {
   checkObject(aResponse, {
+    from: gState.actor,
     input: "window.foobarObject.bug609872",
     result: "parent",
   });
 
   ok(!aResponse.exception, "no eval exception");
   ok(!aResponse.helperResult, "no helper result");
 
   nextTest();
--- a/devtools/shared/webconsole/test/test_jsterm_queryselector.html
+++ b/devtools/shared/webconsole/test/test_jsterm_queryselector.html
@@ -12,17 +12,17 @@
 <p>Test for the querySelector / querySelectorAll helpers</p>
 
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 let gState;
 let gWin;
 
 function evaluateJS(input) {
-  return gState.webConsoleFront.evaluateJSAsync(input);
+  return gState.webConsoleFront.evaluateJS(input);
 }
 
 function startTest() {
   info ("Content window opened, attaching console to it");
 
   let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
   ok (!gWin.document.nodePrincipal.equals(systemPrincipal),
       "The test document is not using the system principal");
@@ -123,16 +123,17 @@ let checkQuerySelectorAllException = asy
       }
     }
   });
   nextTest();
 };
 
 function basicResultCheck(response, input, output) {
   checkObject(response, {
+    from: gState.actor,
     input: input,
     result: output,
   });
   ok(!response.exception, "no eval exception");
   ok(!response.helperResult, "no helper result");
 }
 
 function testEnd() {
--- a/devtools/shared/webconsole/test/test_throw.html
+++ b/devtools/shared/webconsole/test/test_throw.html
@@ -22,56 +22,56 @@ function startTest()
 
 function onAttach(aState, aResponse)
 {
   let tests = [];
 
   let falsyValues = ["-0", "null", "undefined", "Infinity", "-Infinity", "NaN"];
   falsyValues.forEach(function(value) {
     tests.push(async function() {
-      const aResponse = await aState.webConsoleFront.evaluateJSAsync("throw " + value + ";")
+      const aResponse = await aState.webConsoleFront.evaluateJS("throw " + value + ";")
       let type = aResponse.exception.type;
       is(type, value, "exception.type for throw " + value);
       nextTest();
     });
   });
 
   let identityTestValues = [false, 0];
   identityTestValues.forEach(function(value) {
     tests.push(async function() {
-      const aResponse = await aState.webConsoleFront.evaluateJSAsync("throw " + value + ";")
+      const aResponse = await aState.webConsoleFront.evaluateJS("throw " + value + ";")
       let exception = aResponse.exception;
       is(exception, value, "response.exception for throw " + value);
       nextTest();
     });
   });
 
   let longString = Array(DebuggerServer.LONG_STRING_LENGTH + 1).join("a"),
       shortedString = longString.substring(0,
                         DebuggerServer.LONG_STRING_INITIAL_LENGTH
                       );
   tests.push(async function() {
-    const aResponse = await aState.webConsoleFront.evaluateJSAsync("throw '" + longString + "';")
+    const aResponse = await aState.webConsoleFront.evaluateJS("throw '" + longString + "';")
     is(aResponse.exception.initial, shortedString,
       "exception.initial for throw longString"
     );
     is(aResponse.exceptionMessage.initial, shortedString,
       "exceptionMessage.initial for throw longString"
     );
     nextTest();
   });
 
   let symbolTestValues = [
     ["Symbol.iterator", "Symbol(Symbol.iterator)"],
     ["Symbol('foo')", "Symbol(foo)"],
     ["Symbol()", "Symbol()"],
   ];
   symbolTestValues.forEach(function([expr, message]) {
     tests.push(async function() {
-      const aResponse = await aState.webConsoleFront.evaluateJSAsync("throw " + expr + ";");
+      const aResponse = await aState.webConsoleFront.evaluateJS("throw " + expr + ";");
       is(aResponse.exceptionMessage, message,
          "response.exception for throw " + expr);
       nextTest();
     });
   });
 
   runTests(tests, endTest.bind(null, aState));
 }