diff --git a/common/src/web/relative_locators.html b/common/src/web/relative_locators.html
index 7857a367bb0a8..02f0172a21e7f 100644
--- a/common/src/web/relative_locators.html
+++ b/common/src/web/relative_locators.html
@@ -1,5 +1,4 @@
-
-
+
Relative Locators
Relative Locator Tests
-This text is above.
-
This is a paragraph of text in the middle.
-
This text is below.
-
+
+ This text is above.
+ This is a paragraph of text in the middle.
+ This text is below.
+
- 1 |
- 2 |
- 3 |
+ 1 |
+ 2 |
+ 3 |
- 4 |
+ 4 |
5 |
- 6 |
+ 6 |
- 7 |
- 8 |
- 9 |
+ 7 |
+ 8 |
+ 9 |
-
- Rectangle 1
-
-
- Rectangle 2, which is near Rectangle 1
-
+
+ El-A
+ El-B
+ El-C
+ El-D
+ El-E
+ El-F
+
-
- Rectangle 3
-
-
- Rectangle 4, which is not near Rectangle 2 because it is more than 50 px away
-
+
+ Rectangle 1
+ Rectangle 2, which is near Rectangle 1
+ Rectangle 3
+
+ Rectangle 4, which is not near Rectangle 2 because it is more than 50 px away
+
+
diff --git a/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java b/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java
index 2f9d3b448b8ca..2bc5f99e8b945 100644
--- a/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java
+++ b/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java
@@ -52,13 +52,13 @@ void shouldBeAbleToFindElementsAboveAnotherWithTagName() {
void shouldBeAbleToFindElementsAboveAnotherWithXpath() {
driver.get(appServer.whereIs("relative_locators.html"));
- WebElement lowest = driver.findElement(By.id("seventh"));
+ WebElement lowest = driver.findElement(By.id("bottomLeft"));
List seen = driver.findElements(with(xpath("//td[1]")).above(lowest));
List ids = seen.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
- assertThat(ids).containsExactly("fourth", "first");
+ assertThat(ids).containsExactly("left", "topLeft");
}
@Test
@@ -74,16 +74,133 @@ void shouldBeAbleToFindElementsAboveAnotherWithCssSelector() {
assertThat(ids).containsExactly("mid", "above");
}
+ @Test
+ void shouldBeAbleToFindElementsBelowAnother() {
+ driver.get(appServer.whereIs("relative_locators.html"));
+
+ WebElement midpoint = driver.findElement(By.id("mid"));
+
+ List elements = driver.findElements(with(tagName("p")).below(midpoint));
+ List ids =
+ elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
+
+ assertThat(ids).containsExactly("below");
+ }
+
+ @Test
+ void shouldFindElementsAboveAnother() {
+ driver.get(appServer.whereIs("relative_locators.html"));
+
+ WebElement midpoint = driver.findElement(By.id("center"));
+
+ List elements = driver.findElements(with(tagName("td")).above(midpoint));
+ List ids =
+ elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
+
+ assertThat(ids).containsExactly("top", "topLeft", "topRight");
+ }
+
+ @Test
+ void shouldFindElementsBelowAnother() {
+ driver.get(appServer.whereIs("relative_locators.html"));
+
+ WebElement midpoint = driver.findElement(By.id("center"));
+
+ List elements = driver.findElements(with(tagName("td")).below(midpoint));
+ List ids =
+ elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
+
+ assertThat(ids).containsExactly("bottom", "bottomLeft", "bottomRight");
+ }
+
+ @Test
+ void shouldFindElementsLeftOfAnother() {
+ driver.get(appServer.whereIs("relative_locators.html"));
+
+ WebElement midpoint = driver.findElement(By.id("center"));
+
+ List elements = driver.findElements(with(tagName("td")).left(midpoint));
+ List ids =
+ elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
+
+ assertThat(ids).containsExactly("left", "topLeft", "bottomLeft");
+ }
+
+ @Test
+ void shouldFindElementsRightOfAnother() {
+ driver.get(appServer.whereIs("relative_locators.html"));
+
+ WebElement midpoint = driver.findElement(By.id("center"));
+
+ List elements = driver.findElements(with(tagName("td")).right(midpoint));
+ List ids =
+ elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
+
+ assertThat(ids).containsExactly("right", "topRight", "bottomRight");
+ }
+
+ @Test
+ void shouldBeAbleToFindElementsStraightAboveAnother() {
+ driver.get(appServer.whereIs("relative_locators.html"));
+
+ WebElement bottom = driver.findElement(By.id("bottom"));
+
+ List elements = driver.findElements(with(tagName("td")).straightAbove(bottom));
+ List ids =
+ elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
+
+ assertThat(ids).containsExactly("center", "top");
+ }
+
+ @Test
+ void shouldBeAbleToFindElementsStraightBelowAnother() {
+ driver.get(appServer.whereIs("relative_locators.html"));
+
+ WebElement top = driver.findElement(By.id("top"));
+
+ List elements = driver.findElements(with(tagName("td")).straightBelow(top));
+ List ids =
+ elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
+
+ assertThat(ids).containsExactly("center", "bottom");
+ }
+
+ @Test
+ void shouldBeAbleToFindElementsStraightLeftOfAnother() {
+ driver.get(appServer.whereIs("relative_locators.html"));
+
+ WebElement right = driver.findElement(By.id("right"));
+
+ List elements = driver.findElements(with(tagName("td")).straightLeft(right));
+ List ids =
+ elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
+
+ assertThat(ids).containsExactly("left", "center");
+ }
+
+ @Test
+ void shouldBeAbleToFindElementsStraightRightOfAnother() {
+ driver.get(appServer.whereIs("relative_locators.html"));
+
+ WebElement left = driver.findElement(By.id("left"));
+
+ List elements = driver.findElements(with(tagName("td")).straightAbove(left));
+ List ids =
+ elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
+
+ assertThat(ids).containsExactly("center", "right");
+ }
+
@Test
void shouldBeAbleToCombineFilters() {
driver.get(appServer.whereIs("relative_locators.html"));
List seen =
- driver.findElements(with(tagName("td")).above(By.id("center")).toRightOf(By.id("second")));
+ driver.findElements(with(tagName("td")).above(By.id("center")).toRightOf(By.id("top")));
List ids = seen.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
- assertThat(ids).containsExactly("third");
+ assertThat(ids).containsExactly("topRight");
}
@Test
@@ -91,11 +208,11 @@ void shouldBeAbleToCombineFiltersWithXpath() {
driver.get(appServer.whereIs("relative_locators.html"));
List seen =
- driver.findElements(with(xpath("//td[1]")).below(By.id("second")).above(By.id("seventh")));
+ driver.findElements(with(xpath("//td[1]")).below(By.id("top")).above(By.id("bottomLeft")));
List ids = seen.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
- assertThat(ids).containsExactly("fourth");
+ assertThat(ids).containsExactly("left");
}
@Test
@@ -104,11 +221,11 @@ void shouldBeAbleToCombineFiltersWithCssSelector() {
List seen =
driver.findElements(
- with(cssSelector("td")).above(By.id("center")).toRightOf(By.id("second")));
+ with(cssSelector("td")).above(By.id("center")).toRightOf(By.id("top")));
List ids = seen.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
- assertThat(ids).containsExactly("third");
+ assertThat(ids).containsExactly("topRight");
}
@Test
@@ -127,9 +244,23 @@ void exerciseNearLocatorWithTagName() {
// 5-8. Diagonally close (pythagoras sorting, with top row first
// because of DOM insertion order)
List ids = seen.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
- assertThat(ids)
- .containsExactly(
- "second", "eighth", "fourth", "sixth", "first", "third", "seventh", "ninth");
+ assertThat(ids).containsExactly(
+ "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight"
+ );
+ }
+
+ @Test
+ void shouldBeAbleToCombineStraightFilters() {
+ driver.get(appServer.whereIs("relative_locators.html"));
+
+ List seen = driver.findElements(with(tagName("td"))
+ .straightBelow(By.id("topRight"))
+ .straightRight(By.id("bottomLeft"))
+ );
+
+ List ids = seen.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
+
+ assertThat(ids).containsExactly("bottomRight");
}
@Test
@@ -149,9 +280,9 @@ void exerciseNearLocatorWithXpath() {
// because of DOM insertion order)
List ids = seen.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
- assertThat(ids)
- .containsExactly(
- "second", "eighth", "fourth", "sixth", "first", "third", "seventh", "ninth");
+ assertThat(ids).containsExactly(
+ "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight"
+ );
}
@Test
@@ -170,35 +301,14 @@ void exerciseNearLocatorWithCssSelector() {
// 5-8. Diagonally close (pythagoras sorting, with top row first
// because of DOM insertion order)
List ids = seen.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
- assertThat(ids)
- .containsExactly(
- "second", "eighth", "fourth", "sixth", "first", "third", "seventh", "ninth");
+ assertThat(ids).containsExactly(
+ "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight"
+ );
}
@Test
void ensureNoRepeatedElements() {
- String url =
- appServer.create(
- new Page()
- .withTitle("Repeated Elements")
- .withStyles(
- " .c {\n"
- + " \tposition: absolute;\n"
- + " \tborder: 1px solid black;\n"
- + " \theight: 50px;\n"
- + " \twidth: 50px;\n"
- + " }")
- .withBody(
- "\n"
- + " El-A
\n"
- + " El-B
\n"
- + " El-C
\n"
- + " El-D
\n"
- + " El-E
\n"
- + " El-F
\n"
- + " "));
-
- driver.get(url);
+ driver.get(appServer.whereIs("relative_locators.html"));
WebElement base = driver.findElement(By.id("e"));
List cells = driver.findElements(with(tagName("div")).above(base));
@@ -206,10 +316,9 @@ void ensureNoRepeatedElements() {
WebElement a = driver.findElement(By.id("a"));
WebElement b = driver.findElement(By.id("b"));
- assertThat(cells)
- .describedAs(
- cells.stream().map(e -> e.getAttribute("id")).collect(Collectors.joining(", ")))
- .isEqualTo(List.of(b, a));
+ assertThat(cells).describedAs(
+ cells.stream().map(e -> e.getAttribute("id")).collect(Collectors.joining(", "))
+ ).isEqualTo(List.of(b, a));
}
@Test
@@ -217,7 +326,6 @@ void nearLocatorShouldFindNearElements() {
driver.get(appServer.whereIs("relative_locators.html"));
WebElement rect1 = driver.findElement(By.id("rect1"));
-
WebElement rect2 = driver.findElement(with(By.id("rect2")).near(rect1));
assertThat(rect2.getAttribute("id")).isEqualTo("rect2");
@@ -230,7 +338,7 @@ void nearLocatorShouldNotFindFarElements() {
WebElement rect3 = driver.findElement(By.id("rect3"));
assertThatExceptionOfType(NoSuchElementException.class)
- .isThrownBy(() -> driver.findElement(with(By.id("rect4")).near(rect3)))
- .withMessageContaining("Cannot locate an element using");
+ .isThrownBy(() -> driver.findElement(with(By.id("rect4")).near(rect3)))
+ .withMessageContaining("Cannot locate an element using");
}
}
diff --git a/javascript/atoms/locators/relative.js b/javascript/atoms/locators/relative.js
index 4a0175f46b0e6..8540f6fc4cb3f 100644
--- a/javascript/atoms/locators/relative.js
+++ b/javascript/atoms/locators/relative.js
@@ -70,10 +70,8 @@ bot.locators.relative.proximity_ = function (selector, proximity) {
bot.locators.relative.above_ = function (selector) {
return bot.locators.relative.proximity_(
selector,
- function (rect1, rect2) {
- // "rect1" is the element we're comparing against. "rect2" is the variable element
- var top = rect2.top + rect2.height;
- return top < rect1.top;
+ function (expected, toFind) {
+ return toFind.top + toFind.height <= expected.top;
});
};
@@ -90,9 +88,8 @@ bot.locators.relative.above_ = function (selector) {
bot.locators.relative.below_ = function (selector) {
return bot.locators.relative.proximity_(
selector,
- function (rect1, rect2) {
- var bottom = rect1.top + rect1.height;
- return bottom < rect2.top;
+ function (expected, toFind) {
+ return toFind.top >= expected.top + expected.height;
});
};
@@ -107,9 +104,82 @@ bot.locators.relative.below_ = function (selector) {
bot.locators.relative.leftOf_ = function (selector) {
return bot.locators.relative.proximity_(
selector,
- function (rect1, rect2) {
- var left = rect2.left + rect2.width;
- return left < rect1.left;
+ function (expected, toFind) {
+ return toFind.left + toFind.width <= expected.left;
+ });
+};
+
+
+/**
+* Relative locator to find elements that are to the left of the expected one.
+*
+* @param {!Element|function():!Element|!Object} selector Mechanism to be used to find the element.
+* @return {!Filter} A function that determines whether the selector is right of the given element.
+* @private
+*/
+bot.locators.relative.rightOf_ = function (selector) {
+ return bot.locators.relative.proximity_(
+ selector,
+ function (expected, toFind) {
+ return toFind.left >= expected.left + expected.width;
+ });
+};
+
+
+/**
+ * Relative locator to find elements that are above the expected one. "Above"
+ * is defined as where the bottom of the element found by `selector` is above
+ * the top of an element we're comparing to.
+ *
+ * @param {!Element|function():!Element|!Object} selector Mechanism to be used to find the element.
+ * @return {!Filter} A function that determines whether the selector is above the given element.
+ * @private
+ */
+bot.locators.relative.straightAbove_ = function (selector) {
+ return bot.locators.relative.proximity_(
+ selector,
+ function (expected, toFind) {
+ return toFind.left < expected.left + expected.width
+ && toFind.left + toFind.width > expected.left
+ && toFind.top + toFind.height <= expected.top;
+ });
+};
+
+
+/**
+ * Relative locator to find elements that are below the expected one. "Below"
+ * is defined as where the top of the element found by `selector` is below the
+ * bottom of an element we're comparing to.
+ *
+ * @param {!Element|function():!Element|!Object} selector Mechanism to be used to find the element.
+ * @return {!Filter} A function that determines whether the selector is below the given element.
+ * @private
+ */
+bot.locators.relative.straightBelow_ = function (selector) {
+ return bot.locators.relative.proximity_(
+ selector,
+ function (expected, toFind) {
+ return toFind.left < expected.left + expected.width
+ && toFind.left + toFind.width > expected.left
+ && toFind.top >= expected.top + expected.height;
+ });
+};
+
+
+/**
+ * Relative locator to find elements that are to the left of the expected one.
+ *
+ * @param {!Element|function():!Element|!Object} selector Mechanism to be used to find the element.
+ * @return {!Filter} A function that determines whether the selector is left of the given element.
+ * @private
+ */
+bot.locators.relative.straightLeftOf_ = function (selector) {
+ return bot.locators.relative.proximity_(
+ selector,
+ function (expected, toFind) {
+ return toFind.top < expected.top + expected.height
+ && toFind.top + toFind.height > expected.top
+ && toFind.left + toFind.width <= expected.left;
});
};
@@ -121,12 +191,13 @@ bot.locators.relative.leftOf_ = function (selector) {
* @return {!Filter} A function that determines whether the selector is right of the given element.
* @private
*/
-bot.locators.relative.rightOf_ = function (selector) {
+bot.locators.relative.straightRightOf_ = function (selector) {
return bot.locators.relative.proximity_(
selector,
- function (rect1, rect2) {
- var right = rect1.left + rect1.width;
- return right < rect2.left;
+ function (expected, toFind) {
+ return toFind.top < expected.top + expected.height
+ && toFind.top + toFind.height > expected.top
+ && toFind.left >= expected.left + expected.width;
});
};
@@ -167,7 +238,12 @@ bot.locators.relative.near_ = function (selector, opt_distance) {
var rect1 = bot.dom.getClientRect(element);
var rect2 = bot.dom.getClientRect(compareTo);
- var rect1_bigger = new goog.math.Rect(rect1.left-distance,rect1.top-distance,rect1.width+distance*2,rect1.height+distance*2);
+ var rect1_bigger = new goog.math.Rect(
+ rect1.left-distance,
+ rect1.top-distance,
+ rect1.width+distance*2,
+ rect1.height+distance*2
+ );
return rect1_bigger.intersects(rect2);
};
@@ -213,19 +289,27 @@ bot.locators.relative.resolve_ = function (selector) {
* @const
*/
bot.locators.relative.STRATEGIES_ = {
- 'left': bot.locators.relative.leftOf_,
- 'right': bot.locators.relative.rightOf_,
'above': bot.locators.relative.above_,
'below': bot.locators.relative.below_,
+ 'left': bot.locators.relative.leftOf_,
'near': bot.locators.relative.near_,
+ 'right': bot.locators.relative.rightOf_,
+ 'straightAbove': bot.locators.relative.straightAbove_,
+ 'straightBelow': bot.locators.relative.straightBelow_,
+ 'straightLeft': bot.locators.relative.straightLeftOf_,
+ 'straightRight': bot.locators.relative.straightRightOf_,
};
bot.locators.relative.RESOLVERS_ = {
- 'left': bot.locators.relative.resolve_,
- 'right': bot.locators.relative.resolve_,
'above': bot.locators.relative.resolve_,
'below': bot.locators.relative.resolve_,
+ 'left': bot.locators.relative.resolve_,
'near': bot.locators.relative.resolve_,
+ 'right': bot.locators.relative.resolve_,
+ 'straightAbove': bot.locators.relative.resolve_,
+ 'straightBelow': bot.locators.relative.resolve_,
+ 'straightLeft': bot.locators.relative.resolve_,
+ 'straightRight': bot.locators.relative.resolve_,
};
/**
diff --git a/javascript/atoms/test/deps.js b/javascript/atoms/test/deps.js
new file mode 100644
index 0000000000000..1ace12463b23d
--- /dev/null
+++ b/javascript/atoms/test/deps.js
@@ -0,0 +1,62 @@
+// This file was autogenerated by calcdeps.py
+const dirAtoms = '../../../javascript/atoms/'
+const dirLocators = dirAtoms + 'locators/'
+const dirWgxpath = '../../../third_party/js/wgxpath/'
+goog.addDependency(dirWgxpath + 'wgxpath.js', ['wgxpath'], []);
+goog.addDependency(dirWgxpath + 'context.js', ['wgxpath.Context'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'ieAttrWrapper.js', ['wgxpath.IEAttrWrapper'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'lexer.js', ['wgxpath.Lexer'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'userAgent.js', ['wgxpath.userAgent'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'nodeset.js', ['wgxpath.NodeSet'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'node.js', ['wgxpath.Node'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'parser.js', ['wgxpath.Parser'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'nsResolver.js', ['wgxpath.nsResolver'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'dataType.js', ['wgxpath.DataType'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'expr.js', ['wgxpath.Expr'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'binaryExpr.js', ['wgxpath.BinaryExpr'], ['wgxpath', 'wgxpath.Expr', 'wgxpath.DataType']);
+goog.addDependency(dirWgxpath + 'filterExpr.js', ['wgxpath.FilterExpr'], ['wgxpath', 'wgxpath.Expr']);
+goog.addDependency(dirWgxpath + 'pathExpr.js', ['wgxpath.PathExpr'], ['wgxpath', 'wgxpath.Expr']);
+goog.addDependency(dirWgxpath + 'unaryExpr.js', ['wgxpath.UnaryExpr'], ['wgxpath', 'wgxpath.Expr']);
+goog.addDependency(dirWgxpath + 'unionExpr.js', ['wgxpath.UnionExpr'], ['wgxpath', 'wgxpath.Expr']);
+goog.addDependency(dirWgxpath + 'step.js', ['wgxpath.Step'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'literal.js', ['wgxpath.Literal'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'predicates.js', ['wgxpath.Predicates'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'number.js', ['wgxpath.Number'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'functionCall.js', ['wgxpath.FunctionCall'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'kindTest.js', ['wgxpath.KindTest'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'nodeTest.js', ['wgxpath.NodeTest'], ['wgxpath']);
+goog.addDependency(dirWgxpath + 'nameTest.js', ['wgxpath.NameTest'], ['wgxpath']);
+goog.addDependency(dirAtoms + 'bot.js', ['bot'], []);
+goog.addDependency(dirAtoms + 'userAgent.js', ['bot.userAgent'], ['goog.userAgent', 'goog.userAgent.product']);
+goog.addDependency(dirAtoms + 'action.js', ['bot.action'], ['bot.Error', 'bot.ErrorCode', 'bot.dom', 'bot.events', 'goog.array', 'goog.dom', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.events.EventType', 'goog.userAgent', 'goog.Uri']);
+goog.addDependency(dirAtoms + 'color.js', ['bot.color'], []);
+goog.addDependency('color/color.js', ['goog.color', 'goog.color.Hsl', 'goog.color.Hsv', 'goog.color.Rgb'], ['goog.color.names', 'goog.math'], {});
+goog.addDependency(dirLocators + 'xpath.js', ['bot.locators.xpath'], ['goog.array', 'goog.dom', 'goog.dom.xml']);
+goog.addDependency(dirAtoms + 'domcore.js', ['bot.dom.core'], []);
+goog.addDependency(dirAtoms + 'dom.js', ['bot.dom'], ['bot', 'bot.color', 'bot.dom.core', 'bot.locators.xpath', 'goog.array', 'goog.dom.NodeIterator', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.math.Size', 'goog.string', 'goog.style']);
+goog.addDependency(dirAtoms + 'error.js', ['bot.Error', 'bot.ErrorCode'], ['goog.debug.Error', 'goog.object']);
+goog.addDependency(dirAtoms + 'events.js', ['bot.events'], ['bot.dom', 'goog.dom', 'goog.events.EventType', 'goog.userAgent']);
+goog.addDependency(dirAtoms + 'inject.js', ['bot.inject', 'bot.inject.cache'], ['bot.Error', 'bot.ErrorCode', 'goog.array', 'goog.dom', 'goog.dom.NodeType', 'goog.json', 'goog.object']);
+goog.addDependency(dirAtoms + 'keys.js', ['bot.keys'], ['bot.Error', 'bot.ErrorCode', 'bot.action', 'bot.events', 'goog.dom.selection', 'goog.events.EventType', 'goog.events.KeyCodes', 'goog.userAgent']);
+goog.addDependency(dirAtoms + 'script.js', ['bot.script'], ['bot.Error', 'bot.ErrorCode', 'goog.events', 'goog.events.EventType']);
+goog.addDependency(dirLocators + 'classname.js', ['bot.locators.className'], ['goog.array', 'goog.dom', 'goog.dom.DomHelper', 'goog.string']);
+goog.addDependency(dirLocators + 'css.js', ['bot.locators.css'], ['goog.array', 'goog.dom', 'goog.dom.NodeType', 'goog.object', 'goog.string', 'bot.userAgent']);
+goog.addDependency(dirLocators + 'id.js', ['bot.locators.id'], ['bot.dom', 'goog.array', 'goog.dom']);
+goog.addDependency(dirLocators + 'link_text.js', ['bot.locators.linkText', 'bot.locators.partialLinkText'], ['bot', 'bot.dom', 'goog.array', 'goog.dom', 'goog.dom.DomHelper']);
+goog.addDependency(dirLocators + 'locators.js', ['bot.locators'], ['bot', 'bot.locators.className', 'bot.locators.css', 'bot.locators.id', 'bot.locators.linkText', 'bot.locators.name', 'bot.locators.partialLinkText', 'bot.locators.relative', 'bot.locators.tagName', 'bot.locators.xpath', 'goog.array', 'goog.object']);
+goog.addDependency(dirLocators + 'name.js', ['bot.locators.name'], ['bot.dom', 'goog.array', 'goog.dom']);
+goog.addDependency(dirLocators + 'relative.js', ['bot.locators.relative'], ['goog.array', 'goog.dom', 'goog.dom.DomHelper']);
+goog.addDependency(dirLocators + 'tag_name.js', ['bot.locators.tagName'], ['goog.array', 'goog.dom', 'goog.dom.DomHelper']);
+goog.addDependency(dirAtoms + "test/window_focus.js", [], []);
+goog.addDependency("../../../javascript/selenium-atoms/browserbot.js", ['core.browserbot'], ['bot.locators', 'bot.dom', 'core.locators', 'core.patternMatcher']);
+goog.addDependency("../../../javascript/selenium-atoms/core.js", ['core.Error'], []);
+goog.addDependency("../../../javascript/selenium-atoms/filters.js", ['core.filters'], ['bot.dom', 'core.Error', 'goog.array']);
+goog.addDependency("../../../javascript/selenium-atoms/locator_strategies.js", ['core.LocatorStrategies'], ['bot.inject.cache', 'bot.locators', 'core.Error', 'core.filters', 'goog.string']);
+goog.addDependency("../../../javascript/selenium-atoms/pattern_matcher.js", ['core.patternMatcher'], []);
+goog.addDependency("../../../javascript/selenium-atoms/script.js", ['core.script'], ['bot.script']);
+goog.addDependency("../../../javascript/selenium-atoms/se_element.js", ['core.element'], ['bot.dom', 'core.Error', 'core.locators']);
+goog.addDependency("../../../javascript/selenium-atoms/se_locators.js", ['core.locators', 'core.locators.Locator'], ['core.Error', 'core.LocatorStrategies', 'goog.dom.NodeType', 'goog.string']);
+goog.addDependency("../../../javascript/selenium-atoms/testbase.js", [], []);
+goog.addDependency("../../../javascript/selenium-atoms/text.js", ['core.text'], ['bot.dom', 'core.locators', 'core.patternMatcher', 'goog.dom.NodeType', 'goog.string', 'goog.userAgent']);
+goog.addDependency("../../../javascript/webdriver-atoms/logging.js", ['webdriver.debug.Console'], ['goog.debug.LogManager', 'goog.debug.Logger.Level', 'goog.debug.TextFormatter']);
+goog.addDependency("../../../javascript/webdriver-atoms/web_element.js", ['webdriver.element'], ['bot.dom', 'goog.dom', 'goog.dom.TagName', 'goog.math', 'goog.string', 'goog.style']);
diff --git a/javascript/atoms/test/relative_locator_test.html b/javascript/atoms/test/relative_locator_test.html
index 9f34328207ae4..bd35c18bcbc39 100644
--- a/javascript/atoms/test/relative_locator_test.html
+++ b/javascript/atoms/test/relative_locator_test.html
@@ -1,7 +1,7 @@
-
+
- relative_locator_test.html
-
-
-
-
-
-
+
+
+
Relative Locator Tests
-
-This text is above.
-
This is a paragraph of text in the middle.
-
This text is below.
+
+ This text is above.
+ This is a paragraph of text in the middle.
+ This text is below.
+
- 1 |
- 2 |
- 3 |
+ 1 |
+ 2 |
+ 3 |
- 4 |
+ 4 |
5 |
- 6 |
+ 6 |
- 7 |
- 8 |
- 9 |
+ 7 |
+ 8 |
+ 9 |
-
- El-A
- El-B
- El-C
- El-D
- El-E
- El-F
-
+
+ El-A
+ El-B
+ El-C
+ El-D
+ El-E
+ El-F
+
+
diff --git a/javascript/atoms/test/test_bootstrap.js b/javascript/atoms/test/test_bootstrap.js
index 22a3458341737..84186cec89325 100644
--- a/javascript/atoms/test/test_bootstrap.js
+++ b/javascript/atoms/test/test_bootstrap.js
@@ -55,11 +55,11 @@
}
}
- // All of the files to load. Files are specified in the order they must be
+ // All the files to load. Files are specified in the order they must be
// loaded, NOT alphabetical order.
var files = [
'../../../third_party/closure/goog/base.js',
- '../../deps.js'
+ 'deps.js'
];
if (location.pathname.lastIndexOf('/filez/_main/javascript/', 0) === 0) {
diff --git a/javascript/node/selenium-webdriver/lib/by.js b/javascript/node/selenium-webdriver/lib/by.js
index 712b1c74335aa..f97b4bf0dcc0b 100644
--- a/javascript/node/selenium-webdriver/lib/by.js
+++ b/javascript/node/selenium-webdriver/lib/by.js
@@ -261,7 +261,7 @@ class By {
*
* Note: this method will likely be removed in the future please use
* `locateWith`.
- * @param {By} The value returned from calling By.tagName()
+ * @param {By} tagName The value returned from calling By.tagName()
* @returns
*/
function withTagName(tagName) {
@@ -270,7 +270,7 @@ function withTagName(tagName) {
/**
* Start searching for relative objects using search criteria with By.
- * @param {string} A By map that shows how to find the initial element
+ * @param {string} by A By map that shows how to find the initial element
* @returns {RelativeBy}
*/
function locateWith(by) {
@@ -354,6 +354,58 @@ class RelativeBy {
return this
}
+ /**
+ * Look for elements above the root element passed in
+ * @param {string|WebElement} locatorOrElement
+ * @return {!RelativeBy} Return this object
+ */
+ straightAbove(locatorOrElement) {
+ this.filters.push({
+ kind: 'straightAbove',
+ args: [getLocator(locatorOrElement)],
+ })
+ return this
+ }
+
+ /**
+ * Look for elements below the root element passed in
+ * @param {string|WebElement} locatorOrElement
+ * @return {!RelativeBy} Return this object
+ */
+ straightBelow(locatorOrElement) {
+ this.filters.push({
+ kind: 'straightBelow',
+ args: [getLocator(locatorOrElement)],
+ })
+ return this
+ }
+
+ /**
+ * Look for elements left the root element passed in
+ * @param {string|WebElement} locatorOrElement
+ * @return {!RelativeBy} Return this object
+ */
+ straightToLeftOf(locatorOrElement) {
+ this.filters.push({
+ kind: 'straightLeft',
+ args: [getLocator(locatorOrElement)],
+ })
+ return this
+ }
+
+ /**
+ * Look for elements right the root element passed in
+ * @param {string|WebElement} locatorOrElement
+ * @return {!RelativeBy} Return this object
+ */
+ straightToRightOf(locatorOrElement) {
+ this.filters.push({
+ kind: 'straightRight',
+ args: [getLocator(locatorOrElement)],
+ })
+ return this
+ }
+
/**
* Look for elements near the root element passed in
* @param {string|WebElement} locatorOrElement
diff --git a/py/test/selenium/webdriver/support/relative_by_tests.py b/py/test/selenium/webdriver/support/relative_by_tests.py
index d90d3fedae1d4..54ba5370a0c2f 100644
--- a/py/test/selenium/webdriver/support/relative_by_tests.py
+++ b/py/test/selenium/webdriver/support/relative_by_tests.py
@@ -63,75 +63,85 @@ def test_should_be_able_to_find_elements_above_another_by_locator(driver, pages)
def test_should_be_able_to_combine_filters(driver, pages):
pages.load("relative_locators.html")
- elements = driver.find_elements(
- with_tag_name("td")
+ elements = driver.find_elements(with_tag_name("td")
.above(driver.find_element(By.ID, "center"))
- .to_right_of(driver.find_element(By.ID, "second"))
+ .to_right_of(driver.find_element(By.ID, "top"))
)
ids = [el.get_attribute("id") for el in elements]
- assert "third" in ids
+ assert "topRight" in ids
def test_should_be_able_to_combine_filters_by_locator(driver, pages):
pages.load("relative_locators.html")
- elements = driver.find_elements(with_tag_name("td").above({By.ID: "center"}).to_right_of({By.ID: "second"}))
+ elements = driver.find_elements(with_tag_name("td").above({By.ID: "center"}).to_right_of({By.ID: "top"}))
ids = [el.get_attribute("id") for el in elements]
- assert "third" in ids
+ assert "topRight" in ids
def test_should_be_able_to_use_css_selectors(driver, pages):
pages.load("relative_locators.html")
- elements = driver.find_elements(
- locate_with(By.CSS_SELECTOR, "td")
+ elements = driver.find_elements(locate_with(By.CSS_SELECTOR, "td")
.above(driver.find_element(By.ID, "center"))
- .to_right_of(driver.find_element(By.ID, "second"))
+ .to_right_of(driver.find_element(By.ID, "top"))
)
ids = [el.get_attribute("id") for el in elements]
- assert "third" in ids
+ assert "topRight" in ids
def test_should_be_able_to_use_css_selectors_by_locator(driver, pages):
pages.load("relative_locators.html")
elements = driver.find_elements(
- locate_with(By.CSS_SELECTOR, "td").above({By.ID: "center"}).to_right_of({By.ID: "second"})
+ locate_with(By.CSS_SELECTOR, "td").above({By.ID: "center"}).to_right_of({By.ID: "top"})
)
ids = [el.get_attribute("id") for el in elements]
- assert "third" in ids
+ assert "topRight" in ids
def test_should_be_able_to_use_xpath(driver, pages):
pages.load("relative_locators.html")
- elements = driver.find_elements(
- locate_with(By.XPATH, "//td[1]")
- .below(driver.find_element(By.ID, "second"))
- .above(driver.find_element(By.ID, "seventh"))
+ elements = driver.find_elements(locate_with(By.XPATH, "//td[1]")
+ .below(driver.find_element(By.ID, "top"))
+ .above(driver.find_element(By.ID, "bottomLeft"))
)
ids = [el.get_attribute("id") for el in elements]
- assert "fourth" in ids
+ assert "left" in ids
def test_should_be_able_to_use_xpath_by_locator(driver, pages):
pages.load("relative_locators.html")
- elements = driver.find_elements(locate_with(By.XPATH, "//td[1]").below({By.ID: "second"}).above({By.ID: "seventh"}))
+ elements = driver.find_elements(locate_with(By.XPATH, "//td[1]").below({By.ID: "top"}).above({By.ID: "bottomLeft"}))
ids = [el.get_attribute("id") for el in elements]
- assert "fourth" in ids
+ assert "left" in ids
+
+
+def test_should_be_able_to_combine_straight_filters(driver, pages):
+ pages.load("relative_locators.html")
+
+ elements = driver.find_elements(with_tag_name("td")
+ .straightBelow(driver.find_element(By.ID, "topRight"))
+ .straight_to_right_of(driver.find_element(By.ID, "bottomLeft"))
+ )
+
+ ids = [el.get_attribute("id") for el in elements]
+ assert ids.count() == 1
+ assert "bottomRight" in ids
def test_no_such_element_is_raised_rather_than_index_error(driver, pages):
pages.load("relative_locators.html")
with pytest.raises(NoSuchElementException) as exc:
- anchor = driver.find_element(By.ID, "second")
+ anchor = driver.find_element(By.ID, "top")
driver.find_element(locate_with(By.ID, "nonexistentid").above(anchor))
assert "Cannot locate relative element with: {'id': 'nonexistentid'}" in exc.value.msg
@@ -139,7 +149,7 @@ def test_no_such_element_is_raised_rather_than_index_error(driver, pages):
def test_no_such_element_is_raised_rather_than_index_error_by_locator(driver, pages):
pages.load("relative_locators.html")
with pytest.raises(NoSuchElementException) as exc:
- driver.find_element(locate_with(By.ID, "nonexistentid").above({By.ID: "second"}))
+ driver.find_element(locate_with(By.ID, "nonexistentid").above({By.ID: "top"}))
assert "Cannot locate relative element with: {'id': 'nonexistentid'}" in exc.value.msg
@@ -194,3 +204,96 @@ def test_near_locator_should_find_far_elements_by_locator(driver, pages):
el = driver.find_element(locate_with(By.ID, "rect4").near({By.ID: "rect3"}, 100))
assert el.get_attribute("id") == "rect4"
+
+
+def test_should_find_elements_above_another(driver, pages):
+ pages.load("relative_locators.html")
+
+ el = driver.find_elements(with_tag_name("td").above({By.ID: "center"}))
+
+ ids = [el.get_attribute("id") for el in elements]
+ assert ids.count() == 3
+ assert "top" in ids
+ assert "topLeft" in ids
+ assert "topRight" in ids
+
+
+def test_should_find_elements_below_another(driver, pages):
+ pages.load("relative_locators.html")
+
+ el = driver.find_elements(with_tag_name("td").below({By.ID: "center"}))
+
+ ids = [el.get_attribute("id") for el in elements]
+ assert ids.count() == 3
+ assert "bottom" in ids
+ assert "bottomLeft" in ids
+ assert "bottomRight" in ids
+
+
+def test_should_find_elements_left_of_another(driver, pages):
+ pages.load("relative_locators.html")
+
+ el = driver.find_elements(with_tag_name("td").to_left_of({By.ID: "center"}))
+
+ ids = [el.get_attribute("id") for el in elements]
+ assert ids.count() == 3
+ assert "left" in ids
+ assert "topLeft" in ids
+ assert "bottomLeft" in ids
+
+
+def test_should_find_elements_right_of_another(driver, pages):
+ pages.load("relative_locators.html")
+
+ el = driver.find_elements(with_tag_name("td").to_right_of({By.ID: "center"}))
+
+ ids = [el.get_attribute("id") for el in elements]
+ assert ids.count() == 3
+ assert "right" in ids
+ assert "topRight" in ids
+ assert "bottomRight" in ids
+
+
+def test_should_find_elements_straight_above_another(driver, pages):
+ pages.load("relative_locators.html")
+
+ el = driver.find_elements(with_tag_name("td").above({By.ID: "bottom"}))
+
+ ids = [el.get_attribute("id") for el in elements]
+ assert ids.count() == 2
+ assert "top" in ids
+ assert "center" in ids
+
+
+def test_should_find_elements_straight_below_another(driver, pages):
+ pages.load("relative_locators.html")
+
+ el = driver.find_elements(with_tag_name("td").below({By.ID: "top"}))
+
+ ids = [el.get_attribute("id") for el in elements]
+ assert ids.count() == 2
+ assert "bottom" in ids
+ assert "center" in ids
+
+
+def test_should_find_elements_straight_left_of_another(driver, pages):
+ pages.load("relative_locators.html")
+
+ el = driver.find_elements(with_tag_name("td").to_left_of({By.ID: "right"}))
+
+ ids = [el.get_attribute("id") for el in elements]
+ assert ids.count() == 2
+ assert "left" in ids
+ assert "center" in ids
+
+
+def test_should_find_elements_straight_right_of_another(driver, pages):
+ pages.load("relative_locators.html")
+
+ el = driver.find_elements(with_tag_name("td").to_right_of({By.ID: "left"}))
+
+ ids = [el.get_attribute("id") for el in elements]
+ assert ids.count() == 2
+ assert "right" in ids
+ assert "center" in ids
+