Bug 1409040 - Add element.isDOMElement. r?whimboo draft
authorAndreas Tolfsen <ato@sny.no>
Fri, 13 Oct 2017 19:20:26 +0100
changeset 680900 1fc6669a88b7357048728784de964b6abf3a7569
parent 680899 dfdf1e6ed474e772e55b8fc62d4b40903fb6139e
child 680901 0bdbac98f19cdb5d494971575025792ead7aa3ea
push id84670
push userbmo:ato@sny.no
push dateMon, 16 Oct 2017 14:55:19 +0000
reviewerswhimboo
bugs1409040
milestone58.0a1
Bug 1409040 - Add element.isDOMElement. r?whimboo MozReview-Commit-ID: 6Mlo33vu5LG
testing/marionette/element.js
testing/marionette/evaluate.js
testing/marionette/test_element.js
--- a/testing/marionette/element.js
+++ b/testing/marionette/element.js
@@ -15,17 +15,17 @@ const {
   StaleElementReferenceError,
 } = Cu.import("chrome://marionette/content/error.js", {});
 const {pprint} = Cu.import("chrome://marionette/content/format.js", {});
 const {PollPromise} = Cu.import("chrome://marionette/content/sync.js", {});
 
 this.EXPORTED_SYMBOLS = ["element"];
 
 const XBLNS = "http://www.mozilla.org/xbl";
-const XMLNS = "http://www.w3.org/1999/xhtml";
+const XHTMLNS = "http://www.w3.org/1999/xhtml";
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 /** XUL elements that support checked property. */
 const XUL_CHECKED_ELS = new Set([
   "button",
   "checkbox",
   "listitem",
   "toolbarbutton",
@@ -709,20 +709,17 @@ element.isSelected = function(el) {
 
   if (element.isXULElement(el)) {
     if (XUL_CHECKED_ELS.has(el.tagName)) {
       return el.checked;
     } else if (XUL_SELECTED_ELS.has(el.tagName)) {
       return el.selected;
     }
 
-  // TODO(ato): Use element.isDOMElement when bug 1400256 lands
-  } else if (typeof el == "object" &&
-      "nodeType" in el &&
-      el.nodeType == el.ELEMENT_NODE) {
+  } else if (element.isDOMElement(el)) {
     if (el.localName == "input" && ["checkbox", "radio"].includes(el.type)) {
       return el.checked;
     } else if (el.localName == "option") {
       return el.selected;
     }
   }
 
   return false;
@@ -1018,17 +1015,33 @@ element.isKeyboardInteractable = () => t
  */
 element.scrollIntoView = function(el) {
   if (el.scrollIntoView) {
     el.scrollIntoView({block: "end", inline: "nearest", behavior: "instant"});
   }
 };
 
 /**
- * Ascertains whether <var>el</var> is a XUL- or XBL element.
+ * Ascertains whether <var>node</var> is a DOM element.
+ *
+ * @param {*} node
+ *     Element thought to be an <code>Element</code>.
+ *
+ * @return {boolean}
+ *     True if <var>node</var> is a DOM element, false otherwise.
+ */
+element.isDOMElement = function(node) {
+  return typeof node == "object" &&
+      node !== null &&
+      node.nodeType === node.ELEMENT_NODE &&
+      node.namespaceURI === XHTMLNS;
+};
+
+/**
+ * Ascertains whether <var>node</var> is a XUL- or XBL element.
  *
  * @param {*} node
  *     Element thought to be a XUL- or XBL element.
  *
  * @return {boolean}
  *     True if <var>node</var> is a XULElement or XBLElement,
  *     false otherwise.
  */
@@ -1077,17 +1090,17 @@ const boolEls = {
  *     Element to test if |attr| is a boolean attribute on.
  * @param {string} attr
  *     Attribute to test is a boolean attribute.
  *
  * @return {boolean}
  *     True if the attribute is boolean, false otherwise.
  */
 element.isBooleanAttribute = function(el, attr) {
-  if (el.namespaceURI !== XMLNS) {
+  if (!element.isDOMElement(el)) {
     return false;
   }
 
   // global boolean attributes that apply to all HTML elements,
   // except for custom elements
   const customElement = !el.localName.includes("-");
   if ((attr == "hidden" || attr == "itemscope") && customElement) {
     return true;
--- a/testing/marionette/evaluate.js
+++ b/testing/marionette/evaluate.js
@@ -265,17 +265,17 @@ evaluate.toJSON = function(obj, seenEls)
       t == "[object String]") {
     return obj;
 
   // Array, NodeList, HTMLCollection, et al.
   } else if (element.isCollection(obj)) {
     return [...obj].map(el => evaluate.toJSON(el, seenEls));
 
   // HTMLElement
-  } else if ("nodeType" in obj && obj.nodeType == obj.ELEMENT_NODE) {
+  } else if (element.isDOMElement(obj)) {
     let uuid = seenEls.add(obj);
     return element.makeWebElement(uuid);
 
   // custom JSON representation
   } else if (typeof obj.toJSON == "function") {
     let unsafeJSON = obj.toJSON();
     return evaluate.toJSON(unsafeJSON, seenEls);
   }
--- a/testing/marionette/test_element.js
+++ b/testing/marionette/test_element.js
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {utils: Cu} = Components;
 
 Cu.import("chrome://marionette/content/element.js");
 
 const XBLNS = "http://www.mozilla.org/xbl";
+const XHTMLNS = "http://www.w3.org/1999/xhtml";
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 class Element {
   constructor(tagName, attrs = {}) {
     this.tagName = tagName;
     this.localName = tagName;
 
     for (let attr in attrs) {
@@ -22,16 +23,18 @@ class Element {
   get nodeType() { return 1; }
   get ELEMENT_NODE() { return 1; }
 }
 
 class DOMElement extends Element {
   constructor(tagName, attrs = {}) {
     super(tagName, attrs);
 
+    this.namespaceURI = XHTMLNS;
+
     if (this.localName == "option") {
       this.selected = false;
     }
 
     if (this.localName == "input" && ["checkbox", "radio"].includes(this.type)) {
       this.checked = false;
     }
   }
@@ -88,19 +91,30 @@ add_test(function test_isSelected() {
   // anything else should not be selected
   for (let typ of [domEl, undefined, null, "foo", true, [], {}]) {
     ok(!element.isSelected(typ));
   }
 
   run_next_test();
 });
 
+add_test(function test_isDOMElement() {
+  ok(element.isDOMElement(domEl));
+  ok(!element.isDOMElement(xulEl));
+  for (let typ of [true, 42, {}, [], undefined, null]) {
+    ok(!element.isDOMElement(typ));
+  }
+
+  run_next_test();
+});
+
 add_test(function test_isXULElement() {
   ok(element.isXULElement(xulEl));
   ok(element.isXULElement(xblEl));
+  ok(!element.isXULElement(domEl));
   for (let typ of [true, 42, {}, [], undefined, null]) {
     ok(!element.isXULElement(typ));
   }
 
   run_next_test();
 });
 
 add_test(function test_coordinates() {