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.

+
- - - + + + - + - + - - - + + +
123123
44 56
789789
-
- 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.

+
- - - + + + - + - + - - - + + +
123123
44 56
789789
- -
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 +