Bug 1388082 - Convert content script to async/await. r?automatedtester draft
authorAndreas Tolfsen <ato@sny.no>
Mon, 07 Aug 2017 18:59:45 +0100
changeset 645938 e769a5e05d4308ee3067bcabbce2f57fad3d8938
parent 645937 e2a8f9318c99904a4fedf9717d9b1a895eaf4acd
child 645939 33bb0813c29dcaceb2f17f74455fe3343fb4d476
push id73947
push userbmo:ato@sny.no
push dateMon, 14 Aug 2017 16:03:22 +0000
reviewersautomatedtester
bugs1388082
milestone57.0a1
Bug 1388082 - Convert content script to async/await. r?automatedtester MozReview-Commit-ID: GHyhwa91L73
testing/marionette/listener.js
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -14,18 +14,16 @@ var uuidGen = Cc["@mozilla.org/uuid-gene
 
 var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
     .getService(Ci.mozIJSSubScriptLoader);
 
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 Cu.import("chrome://marionette/content/accessibility.js");
 Cu.import("chrome://marionette/content/action.js");
 Cu.import("chrome://marionette/content/atom.js");
 Cu.import("chrome://marionette/content/capture.js");
 Cu.import("chrome://marionette/content/element.js");
 const {
   ElementNotInteractableError,
@@ -443,20 +441,20 @@ var loadListener = {
         (capabilities.get("pageLoadStrategy") !==
         session.PageLoadStrategy.None);
 
     if (loadEventExpected) {
       let startTime = new Date().getTime();
       this.start(command_id, timeout, startTime, true);
     }
 
-    return Task.spawn(function* () {
-      yield trigger();
+    return (async () => {
+      await trigger();
 
-    }).then(val => {
+    })().then(val => {
       if (!loadEventExpected) {
         sendOk(command_id);
         return;
       }
 
       // If requested setup a timer to detect a possible page load
       if (useUnloadTimer) {
         this.timerPageUnload = Cc["@mozilla.org/timer;1"]
@@ -466,17 +464,16 @@ var loadListener = {
       }
 
     }).catch(err => {
       if (loadEventExpected) {
         this.stop();
       }
 
       sendError(err, command_id);
-
     });
   },
 };
 
 /**
  * Called when listener is first started up.  The listener sends its
  * unique window ID and its current URI to the actor.  If the actor returns
  * an ID, we start the listeners. Otherwise, nothing happens.
@@ -507,22 +504,22 @@ function registerSelf() {
 function dispatch(fn) {
   if (typeof fn != "function") {
     throw new TypeError("Provided dispatch handler is not a function");
   }
 
   return function(msg) {
     let id = msg.json.command_id;
 
-    let req = Task.spawn(function* () {
+    let req = (async () => {
       if (typeof msg.json == "undefined" || msg.json instanceof Array) {
-        return yield fn.apply(null, msg.json);
+        return fn.apply(null, msg.json);
       }
-      return yield fn(msg.json);
-    });
+      return fn(msg.json);
+    })();
 
     let okOrValueResponse = rv => {
       if (typeof rv == "undefined") {
         sendOk(id);
       } else {
         sendResponse(rv, id);
       }
     };
@@ -798,36 +795,35 @@ function checkForInterrupted() {
     // OOP frame
     } else {
       sendSyncMessage("Marionette:switchToModalOrigin");
     }
     sendSyncMessage("Marionette:switchedToFrame", {restorePrevious: true});
   }
 }
 
-function* execute(script, args, timeout, opts) {
+async function execute(script, args, timeout, opts) {
   opts.timeout = timeout;
 
   let sb = sandbox.createMutable(curContainer.frame);
   let wargs = evaluate.fromJSON(
       args, seenEls, curContainer.frame, curContainer.shadowRoot);
-  let res = yield evaluate.sandbox(sb, script, wargs, opts);
+  let res = await evaluate.sandbox(sb, script, wargs, opts);
 
   return evaluate.toJSON(res, seenEls);
 }
 
-function* executeInSandbox(script, args, timeout, opts) {
+async function executeInSandbox(script, args, timeout, opts) {
   opts.timeout = timeout;
 
   let sb = sandboxes.get(opts.sandboxName, opts.newSandbox);
   let wargs = evaluate.fromJSON(
       args, seenEls, curContainer.frame, curContainer.shadowRoot);
-  let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
 
-  let res = yield evaluatePromise;
+  let res = await evaluate.sandbox(sb, script, wargs, opts);
   return evaluate.toJSON(res, seenEls);
 }
 
 function emitTouchEvent(type, touch) {
   if (!wasInterrupted()) {
     logger.info(`Emitting Touch event of type ${type} ` +
         `to element with id: ${touch.target.id} ` +
         `and tag name: ${touch.target.tagName} ` +
@@ -879,41 +875,40 @@ function emitTouchEvent(type, touch) {
         1,
         0);
   }
 }
 
 /**
  * Function that perform a single tap
  */
-function singleTap(id, corx, cory) {
+async function singleTap(id, corx, cory) {
   let el = seenEls.get(id, curContainer);
   // after this block, the element will be scrolled into view
   let visible = element.isVisible(el, corx, cory);
   if (!visible) {
     throw new ElementNotInteractableError(
         "Element is not currently visible and may not be manipulated");
   }
 
   let a11y = accessibility.get(capabilities.get("moz:accessibilityChecks"));
-  return a11y.getAccessible(el, true).then(acc => {
-    a11y.assertVisible(acc, el, visible);
-    a11y.assertActionable(acc, el);
-    if (!curContainer.frame.document.createTouch) {
-      legacyactions.mouseEventsOnly = true;
-    }
-    let c = element.coordinates(el, corx, cory);
-    if (!legacyactions.mouseEventsOnly) {
-      let touchId = legacyactions.nextTouchId++;
-      let touch = createATouch(el, c.x, c.y, touchId);
-      emitTouchEvent("touchstart", touch);
-      emitTouchEvent("touchend", touch);
-    }
-    legacyactions.mouseTap(el.ownerDocument, c.x, c.y);
-  });
+  let acc = await a11y.getAccessible(el, true);
+  a11y.assertVisible(acc, el, visible);
+  a11y.assertActionable(acc, el);
+  if (!curContainer.frame.document.createTouch) {
+    legacyactions.mouseEventsOnly = true;
+  }
+  let c = element.coordinates(el, corx, cory);
+  if (!legacyactions.mouseEventsOnly) {
+    let touchId = legacyactions.nextTouchId++;
+    let touch = createATouch(el, c.x, c.y, touchId);
+    emitTouchEvent("touchstart", touch);
+    emitTouchEvent("touchend", touch);
+  }
+  legacyactions.mouseTap(el.ownerDocument, c.x, c.y);
 }
 
 /**
  * Function to create a touch based on the element
  * corx and cory are relative to the viewport, id is the touchId
  */
 function createATouch(el, corx, cory, touchId) {
   let doc = el.ownerDocument;
@@ -935,29 +930,29 @@ function createATouch(el, corx, cory, to
 
 /**
  * Perform a series of grouped actions at the specified points in time.
  *
  * @param {obj} msg
  *      Object with an |actions| attribute that is an Array of objects
  *      each of which represents an action sequence.
  */
-function* performActions(msg) {
+async function performActions(msg) {
   let chain = action.Chain.fromJson(msg.actions);
-  yield action.dispatch(chain, seenEls, curContainer);
+  await action.dispatch(chain, seenEls, curContainer);
 }
 
 /**
- * The Release Actions command is used to release all the keys and pointer
+ * The release actions command is used to release all the keys and pointer
  * buttons that are currently depressed. This causes events to be fired
  * as if the state was released by an explicit series of actions. It also
  * clears all the internal state of the virtual devices.
  */
-function* releaseActions() {
-  yield action.dispatchTickActions(
+async function releaseActions() {
+  await action.dispatchTickActions(
       action.inputsToCancel.reverse(), 0, seenEls, curContainer);
   action.inputsToCancel.length = 0;
   action.inputStateMap.clear();
 }
 
 /**
  * Start action chain on one finger.
  */
@@ -1297,47 +1292,47 @@ function refresh(msg) {
 function getPageSource() {
   return curContainer.frame.document.documentElement.outerHTML;
 }
 
 /**
  * Find an element in the current browsing context's document using the
  * given search strategy.
  */
-function* findElementContent(strategy, selector, opts = {}) {
+async function findElementContent(strategy, selector, opts = {}) {
   if (!SUPPORTED_STRATEGIES.has(strategy)) {
     throw new InvalidSelectorError("Strategy not supported: " + strategy);
   }
 
   opts.all = false;
   if (opts.startNode) {
     opts.startNode = seenEls.get(opts.startNode, curContainer);
   }
 
-  let el = yield element.find(curContainer, strategy, selector, opts);
+  let el = await element.find(curContainer, strategy, selector, opts);
   let elRef = seenEls.add(el);
   let webEl = element.makeWebElement(elRef);
   return webEl;
 }
 
 /**
  * Find elements in the current browsing context's document using the
  * given search strategy.
  */
-function* findElementsContent(strategy, selector, opts = {}) {
+async function findElementsContent(strategy, selector, opts = {}) {
   if (!SUPPORTED_STRATEGIES.has(strategy)) {
     throw new InvalidSelectorError("Strategy not supported: " + strategy);
   }
 
   opts.all = true;
   if (opts.startNode) {
     opts.startNode = seenEls.get(opts.startNode, curContainer);
   }
 
-  let els = yield element.find(curContainer, strategy, selector, opts);
+  let els = await element.find(curContainer, strategy, selector, opts);
   let elRefs = seenEls.addAll(els);
   let webEls = elRefs.map(element.makeWebElement);
   return webEls;
 }
 
 /** Find and return the active element on the page. */
 function getActiveElement() {
   let el = curContainer.frame.document.activeElement;
@@ -1497,32 +1492,30 @@ function isElementEnabled(id) {
  * and Radio Button states, or option elements.
  */
 function isElementSelected(id) {
   let el = seenEls.get(id, curContainer);
   return interaction.isElementSelected(
       el, capabilities.get("moz:accessibilityChecks"));
 }
 
-function* sendKeysToElement(id, val) {
+async function sendKeysToElement(id, val) {
   let el = seenEls.get(id, curContainer);
   if (el.type == "file") {
-    yield interaction.uploadFile(el, val);
+    await interaction.uploadFile(el, val);
   } else if ((el.type == "date" || el.type == "time") &&
       Preferences.get("dom.forms.datetime")) {
-    yield interaction.setFormControlValue(el, val);
+    interaction.setFormControlValue(el, val);
   } else {
-    yield interaction.sendKeysToElement(
+    await interaction.sendKeysToElement(
         el, val, false, capabilities.get("moz:accessibilityChecks"));
   }
 }
 
-/**
- * Clear the text of an element.
- */
+/** Clear the text of an element. */
 function clearElement(id) {
   try {
     let el = seenEls.get(id, curContainer);
     if (el.type == "file") {
       el.value = null;
     } else {
       atom.clearElement(el, curContainer.frame);
     }
@@ -1837,68 +1830,68 @@ function flushRendering() {
       !windowUtils.isMozAfterPaintPending) {
     logger.error("Internal error: descendant frame generated a MozAfterPaint event, but the root document doesn't have one!");
   }
 
   logger.debug(`flushRendering ${windowUtils.isMozAfterPaintPending}`);
   return windowUtils.isMozAfterPaintPending;
 }
 
-function* reftestWait(url, remote) {
+async function reftestWait(url, remote) {
   let win = curContainer.frame;
   let document = curContainer.frame.document;
 
   let windowUtils = content.QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIDOMWindowUtils);
 
 
   let reftestWait = false;
 
   if (document.location.href !== url || document.readyState != "complete") {
     logger.debug(`Waiting for page load of ${url}`);
-    yield new Promise(resolve => {
-      let maybeResolve = (event) => {
+    await new Promise(resolve => {
+      let maybeResolve = event => {
         if (event.target === curContainer.frame.document &&
             event.target.location.href === url) {
           win = curContainer.frame;
           document = curContainer.frame.document;
           reftestWait = document.documentElement.classList.contains("reftest-wait");
           removeEventListener("load", maybeResolve, {once: true});
           win.setTimeout(resolve, 0);
         }
       };
       addEventListener("load", maybeResolve, true);
     });
   } else {
     // Ensure that the event loop has spun at least once since load,
     // so that setTimeout(fn, 0) in the load event has run
     reftestWait = document.documentElement.classList.contains("reftest-wait");
-    yield new Promise(resolve => win.setTimeout(resolve, 0));
+    await new Promise(resolve => win.setTimeout(resolve, 0));
   }
 
   let root = document.documentElement;
   if (reftestWait) {
     // Check again in case reftest-wait was removed since the load event
     if (root.classList.contains("reftest-wait")) {
       logger.debug("Waiting for reftest-wait removal");
-      yield new Promise(resolve => {
+      await new Promise(resolve => {
         let observer = new win.MutationObserver(() => {
           if (!root.classList.contains("reftest-wait")) {
             observer.disconnect();
             logger.debug("reftest-wait removed");
             win.setTimeout(resolve, 0);
           }
         });
         observer.observe(root, {attributes: true});
       });
     }
 
     logger.debug("Waiting for rendering");
 
-    yield new Promise(resolve => {
+    await new Promise(resolve => {
       let maybeResolve = () => {
         if (flushRendering()) {
           win.addEventListener("MozAfterPaint", maybeResolve, {once: true});
         } else {
           win.setTimeout(resolve, 0);
         }
       };
       maybeResolve();