Bug 1283999 - Fix lookup of hyperlinks in XHTML documents; r=automatedtester a=test-only
authorAndreas Tolfsen <ato@mozilla.com>
Sat, 02 Jul 2016 21:38:48 +0100
changeset 341936 42fc9e1652199459ddb667b1fb0b541602550393
parent 341935 86b1691ed273fa8de4373b35e374a8be087b8214
child 341937 fa4681fe062f30712caef3b2724bd3ac71862468
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersautomatedtester, test-only
bugs1283999
milestone49.0a2
Bug 1283999 - Fix lookup of hyperlinks in XHTML documents; r=automatedtester a=test-only Lower-case "a" matches hyperlinks in XHTML documents as well as HTML documents. Upper-case "A" only matches HTML documents. The patch also refactors link text- and partial link text lookup into distinct functions, so that there is no more worry about variable scoping in match blocks. MozReview-Commit-ID: FB7MAmosBoR
testing/marionette/element.js
--- a/testing/marionette/element.js
+++ b/testing/marionette/element.js
@@ -334,16 +334,68 @@ function findByXPathAll(root, value, nod
   while (element) {
     elements.push(element);
     element = values.iterateNext();
   }
   return elements;
 }
 
 /**
+ * Find all hyperlinks dscendant of |node| which link text is |s|.
+ *
+ * @param {DOMElement} node
+ *     Where in the DOM hierarchy to being searching.
+ * @param {string} s
+ *     Link text to search for.
+ *
+ * @return {Array.<DOMAnchorElement>}
+ *     Sequence of link elements which text is |s|.
+ */
+element.findByLinkText = function(node, s) {
+  return filterLinks(node, link => link.text === s);
+};
+
+/**
+ * Find all hyperlinks descendant of |node| which link text contains |s|.
+ *
+ * @param {DOMElement} node
+ *     Where in the DOM hierachy to begin searching.
+ * @param {string} s
+ *     Link text to search for.
+ *
+ * @return {Array.<DOMAnchorElement>}
+ *     Sequence of link elements which text containins |s|.
+ */
+element.findByPartialLinkText = function(node, s) {
+  return filterLinks(node, link => link.text.indexOf(s) != -1);
+};
+
+/**
+ * Filters all hyperlinks that are descendant of |node| by |predicate|.
+ *
+ * @param {DOMElement} node
+ *     Where in the DOM hierarchy to begin searching.
+ * @param {function(DOMAnchorElement): boolean} predicate
+ *     Function that determines if given link should be included in
+ *     return value or filtered away.
+ *
+ * @return {Array.<DOMAnchorElement>}
+ *     Sequence of link elements matching |predicate|.
+ */
+function filterLinks(node, predicate) {
+  let rv = [];
+  for (let link of node.getElementsByTagName("a")) {
+    if (predicate(link)) {
+      rv.push(link);
+    }
+  }
+  return rv;
+}
+
+/**
  * Finds a single element.
  *
  * @param {element.Strategy} using
  *     Selector strategy to use.
  * @param {string} value
  *     Selector expression.
  * @param {DOMElement} rootNode
  *     Document root.
@@ -378,32 +430,31 @@ function findElement(using, value, rootN
 
     case element.Strategy.TagName:
       // works for all elements
       return startNode.getElementsByTagName(value)[0];
 
     case element.Strategy.XPath:
       return  findByXPath(rootNode, value, startNode);
 
-    // TODO(ato): Rewrite this, it's hairy:
     case element.Strategy.LinkText:
-    case element.Strategy.PartialLinkText:
-      let el;
-      let allLinks = startNode.getElementsByTagName("A");
-      for (let i = 0; i < allLinks.length && !el; i++) {
-        let text = allLinks[i].text;
-        if (using == element.Strategy.PartialLinkText) {
-          if (text.indexOf(value) != -1) {
-            el = allLinks[i];
-          }
-        } else if (text == value) {
-          el = allLinks[i];
+      for (let link of startNode.getElementsByTagName("a")) {
+        if (link.text === value) {
+          return link;
         }
       }
-      return el;
+      break;
+
+    case element.Strategy.PartialLinkText:
+      for (let link of startNode.getElementsByTagName("a")) {
+        if (link.text.indexOf(value) != -1) {
+          return link;
+        }
+      }
+      break;
 
     case element.Strategy.Selector:
       try {
         return startNode.querySelector(value);
       } catch (e) {
         throw new InvalidSelectorError(`${e.message}: "${value}"`);
       }
 
@@ -456,30 +507,20 @@ function findElements(using, value, root
 
     case element.Strategy.ClassName:
       return startNode.getElementsByClassName(value);
 
     case element.Strategy.TagName:
       return startNode.getElementsByTagName(value);
 
     case element.Strategy.LinkText:
+      return element.findByLinkText(startNode, value);
+
     case element.Strategy.PartialLinkText:
-      let els = [];
-      let allLinks = startNode.getElementsByTagName("A");
-      for (let i = 0; i < allLinks.length; i++) {
-        let text = allLinks[i].text;
-        if (using == element.Strategy.PartialLinkText) {
-          if (text.indexOf(value) != -1) {
-            els.push(allLinks[i]);
-          }
-        } else if (text == value) {
-          els.push(allLinks[i]);
-        }
-      }
-      return els;
+      return element.findByPartialLinkText(startNode, value);
 
     case element.Strategy.Selector:
       return startNode.querySelectorAll(value);
 
     case element.Strategy.Anon:
       return rootNode.getAnonymousNodes(startNode);
 
     case element.Strategy.AnonAttribute: