Bug 1388082 - Make WebDriver service use async/await. r?automatedtester draft
authorAndreas Tolfsen <ato@sny.no>
Mon, 07 Aug 2017 16:52:37 +0100
changeset 645931 23c9f135e2bf2948d164fea9179675c89e9bdf1d
parent 645833 df9beb781895fcd0493c21e95ad313e0044515ec
child 645932 ac8d5d3c73ad4808401d4585c2ee30d783f16e95
push id73947
push userbmo:ato@sny.no
push dateMon, 14 Aug 2017 16:03:22 +0000
reviewersautomatedtester
bugs1388082
milestone57.0a1
Bug 1388082 - Make WebDriver service use async/await. r?automatedtester MozReview-Commit-ID: A1dW91OvGcG
testing/marionette/driver.js
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -132,17 +132,17 @@ function* enumeratorIterator(enumerator)
 }
 
 /**
  * Implements (parts of) the W3C WebDriver protocol.  GeckoDriver lives
  * in chrome space and mediates calls to the message listener of the current
  * browsing context's content frame message listener via ListenerProxy.
  *
  * Throughout this prototype, functions with the argument <var>cmd</var>'s
- * documentation refers to the contents of the <code>cmd.parameter</code>}
+ * documentation refers to the contents of the <code>cmd.parameter</code>
  * object.
  *
  * @class GeckoDriver
  *
  * @param {string} appName
  *     Description of the product, for example "Firefox".
  * @param {MarionetteServer} server
  *     The instance of Marionette server.
@@ -762,17 +762,17 @@ GeckoDriver.prototype.listeningPromise =
  *     above.
  *
  * @return {Object}
  *     Session ID and capabilities offered by the WebDriver service.
  *
  * @throws {SessionNotCreatedError}
  *     If, for whatever reason, a session could not be created.
  */
-GeckoDriver.prototype.newSession = function* (cmd, resp) {
+GeckoDriver.prototype.newSession = async function(cmd, resp) {
   if (this.sessionID) {
     throw new SessionNotCreatedError("Maximum number of active sessions");
   }
   this.sessionID = element.generateUUID();
   this.newSessionCommandId = cmd.id;
   try {
     this.capabilities = session.Capabilities.fromJSON(cmd.parameters);
   } catch (e) {
@@ -835,18 +835,18 @@ GeckoDriver.prototype.newSession = funct
     this.addBrowser(win);
     this.whenBrowserStarted(win, false);
     this.mm.broadcastAsyncMessage("Marionette:restart", {});
   } else {
     throw new WebDriverError("Session already running");
   }
   this.switchToGlobalMessageManager();
 
-  yield registerBrowsers;
-  yield browserListening;
+  await registerBrowsers;
+  await browserListening;
 
   if (this.curBrowser.tab) {
     this.curBrowser.contentBrowser.focus();
   }
 
   // Setup global listener for modal dialogs, and check if there is already
   // one open for the currently selected browser window.
   modal.addHandler(this.dialogHandler);
@@ -1090,17 +1090,17 @@ GeckoDriver.prototype.execute_ = functio
  *
  * @throws {UnsupportedOperationError}
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.get = function* (cmd, resp) {
+GeckoDriver.prototype.get = async function(cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let url = cmd.parameters.url;
 
   let get = this.listener.get({url, pageTimeout: this.timeouts.pageLoad});
 
@@ -1114,17 +1114,17 @@ GeckoDriver.prototype.get = function* (c
       pageTimeout: this.timeouts.pageLoad,
       startTime: new Date().getTime(),
     };
     this.mm.broadcastAsyncMessage(
         "Marionette:waitForPageLoaded" + this.curBrowser.curFrameId,
         parameters);
   });
 
-  yield get;
+  await get;
 
   this.curBrowser.contentBrowser.focus();
 };
 
 /**
  * Get a string representing the current URL.
  *
  * On Desktop this returns a string representation of the URL of the
@@ -1152,17 +1152,17 @@ GeckoDriver.prototype.getCurrentUrl = fu
  * @return {string}
  *     Document title of the top-level browsing context.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getTitle = function* (cmd, resp) {
+GeckoDriver.prototype.getTitle = function(cmd, resp) {
   assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   return this.title;
 };
 
 /** Gets the current type of the window. */
 GeckoDriver.prototype.getWindowType = function(cmd, resp) {
@@ -1178,44 +1178,44 @@ GeckoDriver.prototype.getWindowType = fu
  *     String serialisation of the DOM of the current browsing context's
  *     active document.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getPageSource = function* (cmd, resp) {
+GeckoDriver.prototype.getPageSource = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   switch (this.context) {
     case Context.CHROME:
       let s = new win.XMLSerializer();
       resp.body.value = s.serializeToString(win.document);
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.getPageSource();
+      resp.body.value = await this.listener.getPageSource();
       break;
   }
 };
 
 /**
  * Cause the browser to traverse one step backward in the joint history
  * of the current browsing context.
  *
  * @throws {UnsupportedOperationError}
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.goBack = function* (cmd, resp) {
+GeckoDriver.prototype.goBack = async function(cmd, resp) {
   assert.content(this.context);
   assert.contentBrowser(this.curBrowser);
   assert.noUserPrompt(this.dialog);
 
   // If there is no history, just return
   if (!this.curBrowser.contentBrowser.webNavigation.canGoBack) {
     return;
   }
@@ -1234,31 +1234,31 @@ GeckoDriver.prototype.goBack = function*
       pageTimeout: this.timeouts.pageLoad,
       startTime: new Date().getTime(),
     };
     this.mm.broadcastAsyncMessage(
         "Marionette:waitForPageLoaded" + this.curBrowser.curFrameId,
         parameters);
   });
 
-  yield goBack;
+  await goBack;
 };
 
 /**
  * Cause the browser to traverse one step forward in the joint history
  * of the current browsing context.
  *
  * @throws {UnsupportedOperationError}
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.goForward = function* (cmd, resp) {
+GeckoDriver.prototype.goForward = async function(cmd, resp) {
   assert.content(this.context);
   assert.contentBrowser(this.curBrowser);
   assert.noUserPrompt(this.dialog);
 
   // If there is no history, just return
   if (!this.curBrowser.contentBrowser.webNavigation.canGoForward) {
     return;
   }
@@ -1278,31 +1278,31 @@ GeckoDriver.prototype.goForward = functi
       pageTimeout: this.timeouts.pageLoad,
       startTime: new Date().getTime(),
     };
     this.mm.broadcastAsyncMessage(
         "Marionette:waitForPageLoaded" + this.curBrowser.curFrameId,
         parameters);
   });
 
-  yield goForward;
+  await goForward;
 };
 
 /**
  * Causes the browser to reload the page in current top-level browsing
  * context.
  *
  * @throws {UnsupportedOperationError}
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.refresh = function* (cmd, resp) {
+GeckoDriver.prototype.refresh = async function(cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let refresh = this.listener.refresh(
       {pageTimeout: this.timeouts.pageLoad});
 
   // If a reload of the frame script interrupts our page load, this will
@@ -1315,17 +1315,17 @@ GeckoDriver.prototype.refresh = function
       pageTimeout: this.timeouts.pageLoad,
       startTime: new Date().getTime(),
     };
     this.mm.broadcastAsyncMessage(
         "Marionette:waitForPageLoaded" + this.curBrowser.curFrameId,
         parameters);
   });
 
-  yield refresh;
+  await refresh;
 };
 
 /**
  * Forces an update for the given browser's id.
  */
 GeckoDriver.prototype.updateIdForBrowser = function(browser, newId) {
   this._browserIds.set(browser.permanentKey, newId);
 };
@@ -1565,17 +1565,17 @@ GeckoDriver.prototype.setWindowRect = as
  * precedence.
  *
  * @param {string} name
  *     Target name or ID of the window to switch to.
  * @param {boolean=} focus
  *      A boolean value which determines whether to focus
  *      the window. Defaults to true.
  */
-GeckoDriver.prototype.switchToWindow = function* (cmd, resp) {
+GeckoDriver.prototype.switchToWindow = async function(cmd, resp) {
   let focus = true;
   if (typeof cmd.parameters.focus != "undefined") {
     focus = cmd.parameters.focus;
   }
 
   // Window IDs are internally handled as numbers, but here it could
   // also be the name of the window.
   let switchTo = parseInt(cmd.parameters.name);
@@ -1585,17 +1585,17 @@ GeckoDriver.prototype.switchToWindow = f
 
   let byNameOrId = function(win, windowId) {
     return switchTo === win.name || switchTo === windowId;
   };
 
   let found = this.findWindow(this.windows, byNameOrId);
 
   if (found) {
-    yield this.setWindowHandle(found, focus);
+    await this.setWindowHandle(found, focus);
   } else {
     throw new NoSuchWindowError(`Unable to locate window: ${switchTo}`);
   }
 };
 
 /**
  * Find a specific window according to some filter function.
  *
@@ -1649,33 +1649,33 @@ GeckoDriver.prototype.findWindow = funct
  *
  * @param {Object} winProperties
  *     Object containing window properties such as returned from
  *     GeckoDriver#findWindow
  * @param {boolean=} focus
  *     A boolean value which determines whether to focus the window.
  *     Defaults to true.
  */
-GeckoDriver.prototype.setWindowHandle = function* (
+GeckoDriver.prototype.setWindowHandle = async function(
     winProperties, focus = true) {
   if (!(winProperties.outerId in this.browsers)) {
     // Initialise Marionette if the current chrome window has not been seen
     // before. Also register the initial tab, if one exists.
     let registerBrowsers, browserListening;
 
     if (winProperties.hasTabBrowser) {
       registerBrowsers = this.registerPromise();
       browserListening = this.listeningPromise();
     }
 
     this.startBrowser(winProperties.win, false /* isNewSession */);
 
     if (registerBrowsers && browserListening) {
-      yield registerBrowsers;
-      yield browserListening;
+      await registerBrowsers;
+      await browserListening;
     }
 
   } else {
     // Otherwise switch to the known chrome window, and activate the tab
     // if it's a content browser.
     this.curBrowser = this.browsers[winProperties.outerId];
 
     if ("tabIndex" in winProperties) {
@@ -1714,38 +1714,38 @@ GeckoDriver.prototype.getActiveFrame = f
  * Set the current browsing context for future commands to the parent
  * of the current browsing context.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.switchToParentFrame = function* (cmd, resp) {
+GeckoDriver.prototype.switchToParentFrame = async function(cmd, resp) {
   assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
-  yield this.listener.switchToParentFrame();
+  await this.listener.switchToParentFrame();
 };
 
 /**
  * Switch to a given frame within the current window.
  *
  * @param {Object} element
  *     A web element reference to the element to switch to.
  * @param {(string|number)} id
  *     If element is not defined, then this holds either the id, name,
  *     or index of the frame to switch to.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.switchToFrame = function* (cmd, resp) {
+GeckoDriver.prototype.switchToFrame = async function(cmd, resp) {
   assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let {id, element, focus} = cmd.parameters;
 
   const otherErrorsExpr = /about:.+(error)|(blocked)\?/;
   const checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 
@@ -1893,29 +1893,29 @@ GeckoDriver.prototype.switchToFrame = fu
       // so this request indicates we need to switch back to the top-level
       // (parent) frame.  We'll first switch to the parent's (global)
       // ChromeMessageBroadcaster, so we send the message to the right
       // listener.
       this.switchToGlobalMessageManager();
     }
     cmd.command_id = cmd.id;
 
-    let res = yield this.listener.switchToFrame(cmd.parameters);
+    let res = await this.listener.switchToFrame(cmd.parameters);
     if (res) {
       let {win: winId, frame: frameId} = res;
       this.mm = this.curBrowser.frameManager.getFrameMM(winId, frameId);
 
       let registerBrowsers = this.registerPromise();
       let browserListening = this.listeningPromise();
 
       this.oopFrameId =
           this.curBrowser.frameManager.switchToFrame(winId, frameId);
 
-      yield registerBrowsers;
-      yield browserListening;
+      await registerBrowsers;
+      await browserListening;
     }
   }
 };
 
 GeckoDriver.prototype.getTimeouts = function(cmd, resp) {
   return this.timeouts;
 };
 
@@ -1932,29 +1932,29 @@ GeckoDriver.prototype.getTimeouts = func
  */
 GeckoDriver.prototype.setTimeouts = function(cmd, resp) {
   // merge with existing timeouts
   let merged = Object.assign(this.timeouts.toJSON(), cmd.parameters);
   this.timeouts = session.Timeouts.fromJSON(merged);
 };
 
 /** Single tap. */
-GeckoDriver.prototype.singleTap = function*(cmd, resp) {
+GeckoDriver.prototype.singleTap = async function(cmd, resp) {
   assert.window(this.getCurrentWindow());
 
   let {id, x, y} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       throw new UnsupportedOperationError(
           "Command 'singleTap' is not yet available in chrome context");
 
     case Context.CONTENT:
       this.addFrameCloseListener("tap");
-      yield this.listener.singleTap(id, x, y);
+      await this.listener.singleTap(id, x, y);
       break;
   }
 };
 
 /**
  * Perform a series of grouped actions at the specified points in time.
  *
  * @param {Array.<?>} actions
@@ -1962,42 +1962,42 @@ GeckoDriver.prototype.singleTap = functi
  *
  * @throws {UnsupportedOperationError}
  *     Not yet available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.performActions = function* (cmd, resp) {
+GeckoDriver.prototype.performActions = async function(cmd, resp) {
   assert.content(this.context,
       "Command 'performActions' is not yet available in chrome context");
   assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let actions = cmd.parameters.actions;
-  yield this.listener.performActions({"actions": actions});
+  await this.listener.performActions({"actions": actions});
 };
 
 /**
  * Release all the keys and pointer buttons that are currently depressed.
  *
  * @throws {UnsupportedOperationError}
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.releaseActions = function*(cmd, resp) {
+GeckoDriver.prototype.releaseActions = async function(cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
-  yield this.listener.releaseActions();
+  await this.listener.releaseActions();
 };
 
 /**
  * An action chain.
  *
  * @param {Object} value
  *     A nested array where the inner array represents each event,
  *     and the outer array represents a collection of events.
@@ -2007,35 +2007,35 @@ GeckoDriver.prototype.releaseActions = f
  *
  * @throws {UnsupportedOperationError}
  *     Not applicable to application.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.actionChain = function*(cmd, resp) {
+GeckoDriver.prototype.actionChain = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let {chain, nextId} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       // be conservative until this has a use case and is established
       // to work as expected in Fennec
       assert.firefox();
 
-      resp.body.value = yield this.legacyactions.dispatchActions(
+      resp.body.value = await this.legacyactions.dispatchActions(
           chain, nextId, {frame: win}, this.curBrowser.seenEls);
       break;
 
     case Context.CONTENT:
       this.addFrameCloseListener("action chain");
-      resp.body.value = yield this.listener.actionChain(chain, nextId);
+      resp.body.value = await this.listener.actionChain(chain, nextId);
       break;
   }
 };
 
 /**
  * A multi-action chain.
  *
  * @param {Object} value
@@ -2045,41 +2045,41 @@ GeckoDriver.prototype.actionChain = func
  *
  * @throws {UnsupportedOperationError}
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.multiAction = function* (cmd, resp) {
+GeckoDriver.prototype.multiAction = async function(cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let {value, max_length} = cmd.parameters;
 
   this.addFrameCloseListener("multi action chain");
-  yield this.listener.multiAction(value, max_length);
+  await this.listener.multiAction(value, max_length);
 };
 
 /**
  * Find an element using the indicated search strategy.
  *
  * @param {string} using
  *     Indicates which search method to use.
  * @param {string} value
  *     Value the client is looking for.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.findElement = function* (cmd, resp) {
+GeckoDriver.prototype.findElement = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let strategy = cmd.parameters.using;
   let expr = cmd.parameters.value;
   let opts = {
     startNode: cmd.parameters.element,
     timeout: this.timeouts.implicit,
@@ -2092,41 +2092,41 @@ GeckoDriver.prototype.findElement = func
         throw new InvalidSelectorError(`Strategy not supported: ${strategy}`);
       }
 
       let container = {frame: win};
       if (opts.startNode) {
         opts.startNode = this.curBrowser.seenEls.get(
             opts.startNode, container);
       }
-      let el = yield element.find(container, strategy, expr, opts);
+      let el = await element.find(container, strategy, expr, opts);
       let elRef = this.curBrowser.seenEls.add(el);
       let webEl = element.makeWebElement(elRef);
 
       resp.body.value = webEl;
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.findElementContent(
+      resp.body.value = await this.listener.findElementContent(
           strategy,
           expr,
           opts);
       break;
   }
 };
 
 /**
  * Find elements using the indicated search strategy.
  *
  * @param {string} using
  *     Indicates which search method to use.
  * @param {string} value
  *     Value the client is looking for.
  */
-GeckoDriver.prototype.findElements = function*(cmd, resp) {
+GeckoDriver.prototype.findElements = async function(cmd, resp) {
   let win = assert.window(this.getCurrentWindow());
 
   let strategy = cmd.parameters.using;
   let expr = cmd.parameters.value;
   let opts = {
     startNode: cmd.parameters.element,
     timeout: this.timeouts.implicit,
     all: true,
@@ -2138,25 +2138,25 @@ GeckoDriver.prototype.findElements = fun
         throw new InvalidSelectorError(`Strategy not supported: ${strategy}`);
       }
 
       let container = {frame: win};
       if (opts.startNode) {
         opts.startNode = this.curBrowser.seenEls.get(
             opts.startNode, container);
       }
-      let els = yield element.find(container, strategy, expr, opts);
+      let els = await element.find(container, strategy, expr, opts);
 
       let elRefs = this.curBrowser.seenEls.addAll(els);
       let webEls = elRefs.map(element.makeWebElement);
       resp.body = webEls;
       break;
 
     case Context.CONTENT:
-      resp.body = yield this.listener.findElementsContent(
+      resp.body = await this.listener.findElementsContent(
           cmd.parameters.using,
           cmd.parameters.value,
           opts);
       break;
   }
 };
 
 /**
@@ -2167,22 +2167,22 @@ GeckoDriver.prototype.findElements = fun
  *
  * @throws {UnsupportedOperationError}
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getActiveElement = function* (cmd, resp) {
+GeckoDriver.prototype.getActiveElement = async function(cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
-  resp.body.value = yield this.listener.getActiveElement();
+  resp.body.value = await this.listener.getActiveElement();
 };
 
 /**
  * Send click event to element.
  *
  * @param {string} id
  *     Reference ID to the element that will be clicked.
  *
@@ -2245,30 +2245,30 @@ GeckoDriver.prototype.clickElement = asy
  * @return {string}
  *     Value of the attribute.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementAttribute = function*(cmd, resp) {
+GeckoDriver.prototype.getElementAttribute = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let {id, name} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = el.getAttribute(name);
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.getElementAttribute(id, name);
+      resp.body.value = await this.listener.getElementAttribute(id, name);
       break;
   }
 };
 
 /**
  * Returns the value of a property associated with given element.
  *
  * @param {string} id
@@ -2279,30 +2279,30 @@ GeckoDriver.prototype.getElementAttribut
  * @return {string}
  *     Value of the property.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementProperty = function*(cmd, resp) {
+GeckoDriver.prototype.getElementProperty = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let {id, name} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = el[name];
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.getElementProperty(id, name);
+      resp.body.value = await this.listener.getElementProperty(id, name);
       break;
   }
 };
 
 /**
  * Get the text of an element, if any.  Includes the text of all child
  * elements.
  *
@@ -2312,33 +2312,33 @@ GeckoDriver.prototype.getElementProperty
  * @return {string}
  *     Element's text "as rendered".
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementText = function*(cmd, resp) {
+GeckoDriver.prototype.getElementText = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // for chrome, we look at text nodes, and any node with a "label" field
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       let lines = [];
       this.getVisibleText(el, lines);
       resp.body.value = lines.join("\n");
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.getElementText(id);
+      resp.body.value = await this.listener.getElementText(id);
       break;
   }
 };
 
 /**
  * Get the tag name of the element.
  *
  * @param {string} id
@@ -2347,30 +2347,30 @@ GeckoDriver.prototype.getElementText = f
  * @return {string}
  *     Local tag name of element.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementTagName = function*(cmd, resp) {
+GeckoDriver.prototype.getElementTagName = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = el.tagName.toLowerCase();
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.getElementTagName(id);
+      resp.body.value = await this.listener.getElementTagName(id);
       break;
   }
 };
 
 /**
  * Check if element is displayed.
  *
  * @param {string} id
@@ -2379,31 +2379,31 @@ GeckoDriver.prototype.getElementTagName 
  * @return {boolean}
  *     True if displayed, false otherwise.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.isElementDisplayed = function*(cmd, resp) {
+GeckoDriver.prototype.isElementDisplayed = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
-      resp.body.value = yield interaction.isElementDisplayed(
+      resp.body.value = await interaction.isElementDisplayed(
           el, this.a11yChecks);
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.isElementDisplayed(id);
+      resp.body.value = await this.listener.isElementDisplayed(id);
       break;
   }
 };
 
 /**
  * Return the property of the computed style of an element.
  *
  * @param {string} id
@@ -2414,31 +2414,32 @@ GeckoDriver.prototype.isElementDisplayed
  * @return {string}
  *     Value of |propertyName|.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementValueOfCssProperty = function*(cmd, resp) {
+GeckoDriver.prototype.getElementValueOfCssProperty = async function(
+    cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let {id, propertyName: prop} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       let sty = win.document.defaultView.getComputedStyle(el);
       resp.body.value = sty.getPropertyValue(prop);
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener
+      resp.body.value = await this.listener
           .getElementValueOfCssProperty(id, prop);
       break;
   }
 };
 
 /**
  * Check if element is enabled.
  *
@@ -2448,32 +2449,32 @@ GeckoDriver.prototype.getElementValueOfC
  * @return {boolean}
  *     True if enabled, false if disabled.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.isElementEnabled = function*(cmd, resp) {
+GeckoDriver.prototype.isElementEnabled = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // Selenium atom doesn't quite work here
       let el = this.curBrowser.seenEls.get(id, {frame: win});
-      resp.body.value = yield interaction.isElementEnabled(
+      resp.body.value = await interaction.isElementEnabled(
           el, this.a11yChecks);
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.isElementEnabled(id);
+      resp.body.value = await this.listener.isElementEnabled(id);
       break;
   }
 };
 
 /**
  * Check if element is selected.
  *
  * @param {string} id
@@ -2482,43 +2483,43 @@ GeckoDriver.prototype.isElementEnabled =
  * @return {boolean}
  *     True if selected, false if unselected.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.isElementSelected = function*(cmd, resp) {
+GeckoDriver.prototype.isElementSelected = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // Selenium atom doesn't quite work here
       let el = this.curBrowser.seenEls.get(id, {frame: win});
-      resp.body.value = yield interaction.isElementSelected(
+      resp.body.value = await interaction.isElementSelected(
           el, this.a11yChecks);
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.isElementSelected(id);
+      resp.body.value = await this.listener.isElementSelected(id);
       break;
   }
 };
 
 /**
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementRect = function*(cmd, resp) {
+GeckoDriver.prototype.getElementRect = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
@@ -2527,17 +2528,17 @@ GeckoDriver.prototype.getElementRect = f
         x: rect.x + win.pageXOffset,
         y: rect.y + win.pageYOffset,
         width: rect.width,
         height: rect.height,
       };
       break;
 
     case Context.CONTENT:
-      resp.body = yield this.listener.getElementRect(id);
+      resp.body = await this.listener.getElementRect(id);
       break;
   }
 };
 
 /**
  * Send key presses to element after focusing on it.
  *
  * @param {string} id
@@ -2545,48 +2546,48 @@ GeckoDriver.prototype.getElementRect = f
  * @param {string} value
  *     Value to send to the element.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.sendKeysToElement = function*(cmd, resp) {
+GeckoDriver.prototype.sendKeysToElement = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let {id, text} = cmd.parameters;
   assert.string(text);
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
-      yield interaction.sendKeysToElement(
+      await interaction.sendKeysToElement(
           el, text, true, this.a11yChecks);
       break;
 
     case Context.CONTENT:
-      yield this.listener.sendKeysToElement(id, text);
+      await this.listener.sendKeysToElement(id, text);
       break;
   }
 };
 
 /**
  * Clear the text of an element.
  *
  * @param {string} id
  *     Reference ID to the element that will be cleared.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.clearElement = function*(cmd, resp) {
+GeckoDriver.prototype.clearElement = async function(cmd, resp) {
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // the selenium atom doesn't work here
@@ -2594,32 +2595,32 @@ GeckoDriver.prototype.clearElement = fun
       if (el.nodeName == "textbox") {
         el.value = "";
       } else if (el.nodeName == "checkbox") {
         el.checked = false;
       }
       break;
 
     case Context.CONTENT:
-      yield this.listener.clearElement(id);
+      await this.listener.clearElement(id);
       break;
   }
 };
 
 /**
  * Switch to shadow root of the given host element.
  *
  * @param {string} id element id.
  */
-GeckoDriver.prototype.switchToShadowRoot = function*(cmd, resp) {
+GeckoDriver.prototype.switchToShadowRoot = async function(cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
 
   let id = cmd.parameters.id;
-  yield this.listener.switchToShadowRoot(id);
+  await this.listener.switchToShadowRoot(id);
 };
 
 /**
  * Add a single cookie to the cookie store associated with the active
  * document's address.
  *
  * @param {Map.<string, (string|number|boolean)> cookie
  *     Cookie object.
@@ -2735,17 +2736,17 @@ GeckoDriver.prototype.deleteCookie = fun
  * @return {Array.<string>}
  *     Unique window handles of remaining windows.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.close = function(cmd, resp) {
+GeckoDriver.prototype.close = async function(cmd, resp) {
   assert.contentBrowser(this.curBrowser);
   assert.noUserPrompt(this.dialog);
 
   let nwins = 0;
 
   for (let win of this.windows) {
     // For browser windows count the tabs. Otherwise take the window itself.
     let tabbrowser = browser.getTabBrowser(win);
@@ -2762,31 +2763,31 @@ GeckoDriver.prototype.close = function(c
   if (nwins === 1) {
     return [];
   }
 
   if (this.mm != globalMessageManager) {
     this.mm.removeDelayedFrameScript(FRAME_SCRIPT);
   }
 
-  return this.curBrowser.closeTab()
-      .then(() => this.windowHandles.map(String));
+  await this.curBrowser.closeTab();
+  return this.windowHandles.map(String);
 };
 
 /**
  * Close the currently selected chrome window.
  *
  * If it is the last window currently open, the chrome window will not be
  * closed to prevent a shutdown of the application. Instead the returned
  * list of chrome window handles is empty.
  *
  * @return {Array.<string>}
  *     Unique chrome window handles of remaining chrome windows.
  */
-GeckoDriver.prototype.closeChromeWindow = function(cmd, resp) {
+GeckoDriver.prototype.closeChromeWindow = async function(cmd, resp) {
   assert.firefox();
   assert.window(this.getCurrentWindow(Context.CHROME));
 
   let nwins = 0;
 
   // eslint-disable-next-line
   for (let _ of this.windows) {
     nwins++;
@@ -2801,18 +2802,18 @@ GeckoDriver.prototype.closeChromeWindow 
 
   // reset frame to the top-most frame
   this.curFrame = null;
 
   if (this.mm != globalMessageManager) {
     this.mm.removeDelayedFrameScript(FRAME_SCRIPT);
   }
 
-  return this.curBrowser.closeWindow()
-      .then(() => this.chromeWindowHandles.map(String));
+  await this.curBrowser.closeWindow();
+  return this.chromeWindowHandles.map(String);
 };
 
 /** Delete Marionette session. */
 GeckoDriver.prototype.deleteSession = function(cmd, resp) {
   if (this.curBrowser !== null) {
     // frame scripts can be safely reused
     Preferences.set(CONTENT_LISTENER_PREF, false);
 
@@ -3004,22 +3005,22 @@ GeckoDriver.prototype.setScreenOrientati
  *
  * @throws {UnsupportedOperationError}
  *     Not available for current application.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.minimizeWindow = function* (cmd, resp) {
+GeckoDriver.prototype.minimizeWindow = async function(cmd, resp) {
   assert.firefox();
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
-  yield new Promise(resolve => {
+  await new Promise(resolve => {
     win.addEventListener("sizemodechange", resolve, {once: true});
 
     if (win.windowState == win.STATE_MINIMIZED) {
       win.restore();
     } else {
       win.minimize();
     }
   });
@@ -3119,22 +3120,22 @@ GeckoDriver.prototype.maximizeWindow = a
  *
  * @throws {UnsupportedOperationError}
  *     Not available for current application.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.fullscreen = function* (cmd, resp) {
+GeckoDriver.prototype.fullscreen = async function(cmd, resp) {
   assert.firefox();
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
-  yield new Promise(resolve => {
+  await new Promise(resolve => {
     win.addEventListener("sizemodechange", resolve, {once: true});
     win.fullScreen = !win.fullScreen;
   });
 
   return this.curBrowser.rect;
 };
 
 /**
@@ -3259,20 +3260,20 @@ GeckoDriver.prototype.acceptConnections 
  *     If empty or undefined, |nsIAppStartup.eAttemptQuit| is used.
  *
  * @return {string}
  *     Explaining the reason why the application quit.  This can be
  *     in response to a normal shutdown or restart, yielding "shutdown"
  *     or "restart", respectively.
  *
  * @throws {InvalidArgumentError}
- *     If |flags| contains unknown or incompatible flags, for example
- *     multiple Quit flags.
+ *     If <var>flags</var> contains unknown or incompatible flags,
+ *     for example multiple Quit flags.
  */
-GeckoDriver.prototype.quit = function* (cmd, resp) {
+GeckoDriver.prototype.quit = async function(cmd, resp) {
   const quits = ["eConsiderQuit", "eAttemptQuit", "eForceQuit"];
 
   let flags = [];
   if (typeof cmd.parameters.flags != "undefined") {
     flags = assert.array(cmd.parameters.flags);
   }
 
   // bug 1298921
@@ -3305,19 +3306,18 @@ GeckoDriver.prototype.quit = function* (
   let quitApplication = new Promise(resolve => {
     Services.obs.addObserver(
         (subject, topic, data) => resolve(data),
         "quit-application");
   });
 
   Services.startup.quit(mode);
 
-  yield quitApplication
-      .then(cause => resp.body.cause = cause)
-      .then(() => resp.send());
+  resp.body.cause = await quitApplication;
+  resp.send();
 };
 
 GeckoDriver.prototype.installAddon = function(cmd, resp) {
   assert.firefox();
 
   let path = cmd.parameters.path;
   let temp = cmd.parameters.temporary || false;
   if (typeof path == "undefined" || typeof path != "string" ||
@@ -3463,68 +3463,68 @@ GeckoDriver.prototype.localizeProperty =
   }
 
   resp.body.value = l10n.localizeProperty(urls, id);
 };
 
 /**
  * Initialize the reftest mode
  */
-GeckoDriver.prototype.setupReftest = function* (cmd, resp) {
+GeckoDriver.prototype.setupReftest = async function(cmd, resp) {
   if (this._reftest) {
-    throw new UnsupportedOperationError("Called reftest:setup with a reftest session already active");
+    throw new UnsupportedOperationError(
+        "Called reftest:setup with a reftest session already active");
   }
 
   if (this.context !== Context.CHROME) {
-    throw new UnsupportedOperationError("Must set chrome context before running reftests");
+    throw new UnsupportedOperationError(
+        "Must set chrome context before running reftests");
   }
 
   let {urlCount = {}, screenshot = "unexpected"} = cmd.parameters;
   if (!["always", "fail", "unexpected"].includes(screenshot)) {
-    throw new InvalidArgumentError("Value of `screenshot` should be 'always', 'fail' or 'unexpected'");
+    throw new InvalidArgumentError(
+        "Value of `screenshot` should be 'always', 'fail' or 'unexpected'");
   }
 
   this._reftest = new reftest.Runner(this);
-
-  yield this._reftest.setup(urlCount, screenshot);
+  await this._reftest.setup(urlCount, screenshot);
 };
 
 
-/**
- * Run a reftest
- */
-GeckoDriver.prototype.runReftest = function* (cmd, resp) {
+/** Run a reftest. */
+GeckoDriver.prototype.runReftest = async function(cmd, resp) {
   let {test, references, expected, timeout} = cmd.parameters;
 
   if (!this._reftest) {
-    throw new UnsupportedOperationError("Called reftest:run before reftest:start");
+    throw new UnsupportedOperationError(
+        "Called reftest:run before reftest:start");
   }
 
   assert.string(test);
   assert.string(expected);
   assert.array(references);
 
-  let result = yield this._reftest.run(test, references, expected, timeout);
-
-  resp.body.value = result;
+  resp.body.value = await this._reftest.run(
+      test, references, expected, timeout);
 };
 
 /**
- * End a reftest run
+ * End a reftest run.
  *
  * Closes the reftest window (without changing the current window handle),
  * and removes cached canvases.
  */
-GeckoDriver.prototype.teardownReftest = function* (cmd, resp) {
+GeckoDriver.prototype.teardownReftest = function(cmd, resp) {
   if (!this._reftest) {
-    throw new UnsupportedOperationError("Called reftest:teardown before reftest:start");
+    throw new UnsupportedOperationError(
+        "Called reftest:teardown before reftest:start");
   }
 
   this._reftest.abort();
-
   this._reftest = null;
 };
 
 
 GeckoDriver.prototype.commands = {
   // Marionette service
   "Marionette:SetContext": GeckoDriver.prototype.setContext,
   "setContext": GeckoDriver.prototype.setContext,  // deprecated, remove in Firefox 60