Bug 1274274 - Disassociate convertWrappedArguments from element store; r=automatedtester
authorAndreas Tolfsen <ato@mozilla.com>
Fri, 20 May 2016 16:16:56 +0100
changeset 337935 e848faf4bb29bc0195b11ba682cfe9322d841b53
parent 337934 aa348e14ae8202828b821328eb48ca24f8454948
child 337936 dd338221d47080318113d6a908ac7651d11b5ce3
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersautomatedtester
bugs1274274
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1274274 - Disassociate convertWrappedArguments from element store; r=automatedtester Moved ElementManager#convertWrappedArguments to the testing/marionette/element.js module scope and renamed it to fromJson. MozReview-Commit-ID: JMTZcG0JSUE
testing/marionette/action.js
testing/marionette/driver.js
testing/marionette/element.js
testing/marionette/listener.js
--- a/testing/marionette/action.js
+++ b/testing/marionette/action.js
@@ -53,18 +53,19 @@ action.Chain.prototype.dispatchActions =
     touchProvider) {
   // Some touch events code in the listener needs to do ipc, so we can't
   // share this code across chrome/content.
   if (touchProvider) {
     this.touchProvider = touchProvider;
   }
 
   this.elementManager = elementManager;
-  let commandArray = elementManager.convertWrappedArguments(args, container);
   this.container = container;
+  let commandArray = element.fromJson(
+      args, elementManager, container.frame, container.shadowRoot);
 
   if (touchId == null) {
     touchId = this.nextTouchId++;
   }
 
   if (!container.frame.document.createTouch) {
     this.mouseEventsOnly = true;
   }
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -874,17 +874,17 @@ GeckoDriver.prototype.execute_ = functio
       let sb = this.sandboxes.get(opts.sandboxName, opts.newSandbox);
       if (opts.sandboxName) {
         sb = sandbox.augment(sb, new logging.Adapter(this.marionetteLog));
         sb = sandbox.augment(sb, {global: sb});
       }
 
       opts.timeout = timeout;
       script = this.importedScripts.for(Context.CHROME).concat(script);
-      let wargs = this.curBrowser.elementManager.convertWrappedArguments(args, {frame: sb.window});
+      let wargs = element.fromJson(args, this.curBrowser.elementManager, sb.window);
       let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
       return evaluatePromise.then(res => this.curBrowser.elementManager.wrapValue(res));
   }
 };
 
 /**
  * Execute pure JavaScript.  Used to execute simpletest harness tests,
  * which are like mochitests only injected using Marionette.
@@ -899,17 +899,17 @@ GeckoDriver.prototype.executeJSScript = 
     filename: cmd.parameters.filename,
     line: cmd.parameters.line,
     async: cmd.parameters.async,
   };
 
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
-      let wargs = this.curBrowser.elementManager.convertWrappedArguments(args, {frame: win});
+      let wargs = element.fromJson(args, this.curBrowser.elementManager, win);
       let harness = new simpletest.Harness(
           win,
           Context.CHROME,
           this.marionetteLog,
           scriptTimeout,
           function() {},
           this.testName);
 
--- a/testing/marionette/element.js
+++ b/testing/marionette/element.js
@@ -245,66 +245,16 @@ element.Store = class {
             }
           }
         }
         break;
     }
 
     return result;
   }
-
-  /**
-   * Convert any ELEMENT references in 'args' to the actual elements
-   *
-   * @param object args
-   *        Arguments passed in by client
-   * @param nsIDOMWindow, ShadowRoot container
-   *        The window and an optional shadow root that contains the element
-   *
-   * @returns object
-   *        Returns the objects passed in by the client, with the
-   *        reference IDs replaced by the actual elements.
-   */
-  convertWrappedArguments(args, container) {
-    let converted;
-    switch (typeof(args)) {
-      case 'number':
-      case 'string':
-      case 'boolean':
-        converted = args;
-        break;
-      case 'object':
-        if (args == null) {
-          converted = null;
-        }
-        else if (Object.prototype.toString.call(args) == '[object Array]') {
-          converted = [];
-          for (let i in args) {
-            converted.push(this.convertWrappedArguments(args[i], container));
-          }
-        }
-        else if (((typeof(args[element.LegacyKey]) === 'string') && args.hasOwnProperty(element.LegacyKey)) ||
-                 ((typeof(args[element.Key]) === 'string') &&
-                     args.hasOwnProperty(element.Key))) {
-          let elementUniqueIdentifier = args[element.Key] ? args[element.Key] : args[element.LegacyKey];
-          converted = this.get(elementUniqueIdentifier, container);
-          if (converted == null) {
-            throw new WebDriverError(`Unknown element: ${elementUniqueIdentifier}`);
-          }
-        }
-        else {
-          converted = {};
-          for (let prop in args) {
-            converted[prop] = this.convertWrappedArguments(args[prop], container);
-          }
-        }
-        break;
-    }
-    return converted;
-  }
 };
 
 /**
  * Find a single element or a collection of elements starting at the
  * document root or a given node.
  *
  * If |timeout| is above 0, an implicit search technique is used.
  * This will wait for the duration of |timeout| for the element
@@ -701,16 +651,73 @@ element.makeWebElement = function(uuid) 
 };
 
 element.generateUUID = function() {
   let uuid = uuidGen.generateUUID().toString();
   return uuid.substring(1, uuid.length - 1);
 };
 
 /**
+ * Convert any web elements in arbitrary objects to DOM elements by
+ * looking them up in the seen element store.
+ *
+ * @param {?} obj
+ *     Arbitrary object containing web elements.
+ * @param {element.Store} seenEls
+ *     Element store to use for lookup of web element references.
+ * @param {Window} win
+ *     Window.
+ * @param {ShadowRoot} shadowRoot
+ *     Shadow root.
+ *
+ * @return {?}
+ *     Same object as provided by |obj| with the web elements replaced
+ *     by DOM elements.
+ */
+element.fromJson = function(
+    obj, seenEls, win, shadowRoot = undefined) {
+  switch (typeof(obj)) {
+    case "boolean":
+    case "number":
+    case "string":
+      return obj;
+
+    case "object":
+      if (obj === null) {
+        return obj;
+      }
+
+      // arrays
+      else if (Array.isArray(obj)) {
+        return obj.map(e => element.fromJson(e, seenEls, win, shadowRoot));
+      }
+
+      // web elements
+      else if (Object.keys(obj).includes(element.Key) ||
+          Object.keys(obj).includes(element.LegacyKey)) {
+        let uuid = obj[element.Key] || obj[element.LegacyKey];
+        let el = seenEls.get(uuid, {frame: win, shadowRoot: shadowRoot});
+        if (!el) {
+          throw new WebDriverError(`Unknown element: ${uuid}`);
+        }
+        return el;
+      }
+
+      // arbitrary objects
+      else {
+        let rv = {};
+        for (let prop in obj) {
+          rv[prop] = element.fromJson(obj[prop], seenEls, win, shadowRoot);
+        }
+        return rv;
+      }
+  }
+};
+
+/**
  * Check if the element is detached from the current frame as well as
  * the optional shadow root (when inside a Shadow DOM context).
  *
  * @param {nsIDOMElement} el
  *     Element to be checked.
  * @param nsIDOMWindow frame
  *     Window object that contains the element or the current host
  *     of the shadow root.
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -520,33 +520,35 @@ function checkForInterrupted() {
     }
 }
 
 function* execute(script, args, timeout, opts) {
   opts.timeout = timeout;
   script = importedScripts.for("content").concat(script);
 
   let sb = sandbox.createMutable(curContainer.frame);
-  let wargs = elementManager.convertWrappedArguments(args, curContainer);
+  let wargs = element.fromJson(
+      args, elementManager, curContainer.frame, curContainer.shadowRoot);
   let res = yield evaluate.sandbox(sb, script, wargs, opts);
 
   return elementManager.wrapValue(res);
 }
 
 function* executeInSandbox(script, args, timeout, opts) {
   opts.timeout = timeout;
   script = importedScripts.for("content").concat(script);
 
   let sb = sandboxes.get(opts.sandboxName, opts.newSandbox);
   if (opts.sandboxName) {
     sb = sandbox.augment(sb, {global: sb});
     sb = sandbox.augment(sb, new logging.Adapter(contentLog));
   }
 
-  let wargs = elementManager.convertWrappedArguments(args, curContainer);
+  let wargs = element.fromJson(
+      args, elementManager, curContainer.frame, curContainer.shadowRoot);
   let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
 
   let res = yield evaluatePromise;
   sendSyncMessage("Marionette:shareData", {log: elementManager.wrapValue(contentLog.get())});
   return elementManager.wrapValue(res);
 }
 
 function* executeSimpleTest(script, args, timeout, opts) {
@@ -559,17 +561,18 @@ function* executeSimpleTest(script, args
       "content",
       contentLog,
       timeout,
       marionetteTestName);
   let sb = sandbox.createSimpleTest(curContainer.frame, harness);
   // TODO(ato): Not sure this is needed:
   sb = sandbox.augment(sb, new logging.Adapter(contentLog));
 
-  let wargs = elementManager.convertWrappedArguments(args, curContainer);
+  let wargs = element.fromJson(
+      args, elementManager, curContainer.frame, curContainer.shadowRoot);
   let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
 
   let res = yield evaluatePromise;
   sendSyncMessage("Marionette:shareData", {log: elementManager.wrapValue(contentLog.get())});
   return elementManager.wrapValue(res);
 }
 
 /**
@@ -837,17 +840,18 @@ function setDispatch(batches, touches, b
 /**
  * Start multi-action.
  *
  * @param {Number} maxLen
  *     Longest action chain for one finger.
  */
 function multiAction(args, maxLen) {
   // unwrap the original nested array
-  let commandArray = elementManager.convertWrappedArguments(args, curContainer);
+  let commandArray = element.fromJson(
+      args, elementManager, curContainer.frame, curContainer.shadowRoot);
   let concurrentEvent = [];
   let temp;
   for (let i = 0; i < maxLen; i++) {
     let row = [];
     for (let j = 0; j < commandArray.length; j++) {
       if (typeof commandArray[j][i] != "undefined") {
         // add finger id to the front of each action, i.e. [finger_id, action, element]
         temp = commandArray[j][i];