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/dotnet/test/common/RelativeLocatorTest.cs b/dotnet/test/common/RelativeLocatorTest.cs index 1f2cf15d525b5..5d5dfd98fe772 100644 --- a/dotnet/test/common/RelativeLocatorTest.cs +++ b/dotnet/test/common/RelativeLocatorTest.cs @@ -47,12 +47,12 @@ public void ShouldBeAbleToFindElementsAboveAnotherWithXpath() { driver.Url = (EnvironmentManager.Instance.UrlBuilder.WhereIs("relative_locators.html")); - IWebElement lowest = driver.FindElement(By.Id("seventh")); + IWebElement lowest = driver.FindElement(By.Id("bottomLeft")); var elements = driver.FindElements(RelativeBy.WithLocator(By.XPath("//td[1]")).Above(lowest)); var values = elements.Select(element => element.GetDomAttribute("id")); - Assert.That(values, Is.EquivalentTo(new List { "fourth", "first" })); + Assert.That(values, Is.EquivalentTo(new List { "left", "topLeft" })); } [Test] @@ -73,10 +73,10 @@ public void ShouldBeAbleToCombineFilters() { driver.Url = (EnvironmentManager.Instance.UrlBuilder.WhereIs("relative_locators.html")); - ReadOnlyCollection seen = driver.FindElements(RelativeBy.WithLocator(By.TagName("td")).Above(By.Id("center")).RightOf(By.Id("second"))); + ReadOnlyCollection seen = driver.FindElements(RelativeBy.WithLocator(By.TagName("td")).Above(By.Id("center")).RightOf(By.Id("top"))); var elementIds = seen.Select(element => element.GetDomAttribute("id")); - Assert.That(elementIds, Is.EquivalentTo(new List() { "third" })); + Assert.That(elementIds, Is.EquivalentTo(new List() { "topRight" })); } @@ -85,10 +85,10 @@ public void ShouldBeAbleToCombineFiltersWithXpath() { driver.Url = (EnvironmentManager.Instance.UrlBuilder.WhereIs("relative_locators.html")); - ReadOnlyCollection seen = driver.FindElements(RelativeBy.WithLocator(By.XPath("//td[1]")).Below(By.Id("second")).Above(By.Id("seventh"))); + ReadOnlyCollection seen = driver.FindElements(RelativeBy.WithLocator(By.XPath("//td[1]")).Below(By.Id("top")).Above(By.Id("bottomLeft"))); var values = seen.Select(element => element.GetDomAttribute("id")); - Assert.That(values, Is.EquivalentTo(new List { "fourth" })); + Assert.That(values, Is.EquivalentTo(new List { "left" })); } [Test] @@ -97,10 +97,10 @@ public void ShouldBeAbleToCombineFiltersWithCssSelector() driver.Url = (EnvironmentManager.Instance.UrlBuilder.WhereIs("relative_locators.html")); ReadOnlyCollection seen = driver.FindElements( - RelativeBy.WithLocator(By.CssSelector("td")).Above(By.Id("center")).RightOf(By.Id("second"))); + RelativeBy.WithLocator(By.CssSelector("td")).Above(By.Id("center")).RightOf(By.Id("top"))); var values = seen.Select(element => element.GetDomAttribute("id")); - Assert.That(values, Is.EquivalentTo(new List { "third" })); + Assert.That(values, Is.EquivalentTo(new List { "topRight" })); } [Test] @@ -120,7 +120,7 @@ public void ExerciseNearLocatorWithTagName() // 5-8. Diagonally close (pythagoras sorting, with top row first // because of DOM insertion order) var values = seen.Select(element => element.GetDomAttribute("id")); - Assert.That(values, Is.EquivalentTo(new List { "second", "eighth", "fourth", "sixth", "first", "third", "seventh", "ninth" })); + Assert.That(values, Is.EquivalentTo(new List { "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight" })); } [Test] @@ -140,7 +140,7 @@ public void ExerciseNearLocatorWithXpath() // 5-8. Diagonally close (pythagoras sorting, with top row first // because of DOM insertion order) var values = seen.Select(element => element.GetDomAttribute("id")); - Assert.That(values, Is.EquivalentTo(new List { "second", "eighth", "fourth", "sixth", "first", "third", "seventh", "ninth" })); + Assert.That(values, Is.EquivalentTo(new List { "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight" })); } [Test] @@ -160,7 +160,7 @@ public void ExerciseNearLocatorWithCssSelector() // 5-8. Diagonally close (pythagoras sorting, with top row first // because of DOM insertion order) var values = seen.Select(element => element.GetDomAttribute("id")); - Assert.That(values, Is.EquivalentTo(new List { "second", "eighth", "fourth", "sixth", "first", "third", "seventh", "ninth" })); + Assert.That(values, Is.EquivalentTo(new List { "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight" })); } [Test] @@ -218,11 +218,11 @@ public void NearLocatorShouldNotFindFarElements() { driver.Url = (EnvironmentManager.Instance.UrlBuilder.WhereIs("relative_locators.html")); - var rect3 = driver.FindElement(By.Id("rect3")); + var rect = driver.FindElement(By.Id("rect1")); Assert.That(() => { - var rect2 = driver.FindElement(RelativeBy.WithLocator(By.Id("rect4")).Near(rect3)); + var rect2 = driver.FindElement(RelativeBy.WithLocator(By.Id("rect4")).Near(rect)); }, Throws.TypeOf().With.Message.EqualTo("Unable to find element; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#no-such-element-exception")); } diff --git a/java/src/org/openqa/selenium/support/locators/RelativeLocator.java b/java/src/org/openqa/selenium/support/locators/RelativeLocator.java index 4ad1f58b8d4c8..f977874be1a25 100644 --- a/java/src/org/openqa/selenium/support/locators/RelativeLocator.java +++ b/java/src/org/openqa/selenium/support/locators/RelativeLocator.java @@ -147,6 +147,50 @@ public RelativeBy toRightOf(By locator) { return simpleDirection("right", locator); } + public RelativeBy straightAbove(WebElement element) { + Require.nonNull("Element to search straight above of", element); + return simpleDirection("straightAbove", element); + } + + public RelativeBy straightAbove(By locator) { + Require.nonNull("Locator", locator); + assertLocatorCanBeSerialized(locator); + return simpleDirection("straightAbove", locator); + } + + public RelativeBy straightBelow(WebElement element) { + Require.nonNull("Element to search straight below of", element); + return simpleDirection("straightBelow", element); + } + + public RelativeBy straightBelow(By locator) { + Require.nonNull("Locator", locator); + assertLocatorCanBeSerialized(locator); + return simpleDirection("straightBelow", locator); + } + + public RelativeBy straightLeftOf(WebElement element) { + Require.nonNull("Element to search straight to the left of", element); + return simpleDirection("straightLeft", element); + } + + public RelativeBy straightLeftOf(By locator) { + Require.nonNull("Locator", locator); + assertLocatorCanBeSerialized(locator); + return simpleDirection("straightLeft", locator); + } + + public RelativeBy straightRightOf(WebElement element) { + Require.nonNull("Element to search straight to the right of", element); + return simpleDirection("straightRight", element); + } + + public RelativeBy straightRightOf(By locator) { + Require.nonNull("Locator", locator); + assertLocatorCanBeSerialized(locator); + return simpleDirection("straightRight", locator); + } + public RelativeBy near(WebElement element) { Require.nonNull("Element to search near", element); return near(element, CLOSE_IN_PIXELS); diff --git a/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java b/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java index 2f9d3b448b8ca..edd383fa04555 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,132 @@ 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")).toLeftOf(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")).toRightOf(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")).straightLeftOf(right)); + List ids = + elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList()); + + assertThat(ids).containsExactly("center", "left"); + } + + @Test + void shouldBeAbleToFindElementsStraightRightOfAnother() { + driver.get(appServer.whereIs("relative_locators.html")); + + WebElement left = driver.findElement(By.id("left")); + + List elements = driver.findElements(with(tagName("td")).straightRightOf(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 +207,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 @@ -103,12 +219,11 @@ void shouldBeAbleToCombineFiltersWithCssSelector() { driver.get(appServer.whereIs("relative_locators.html")); List seen = - driver.findElements( - with(cssSelector("td")).above(By.id("center")).toRightOf(By.id("second"))); + driver.findElements(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 +242,29 @@ 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( + "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight"); + assertThat(ids) .containsExactly( - "second", "eighth", "fourth", "sixth", "first", "third", "seventh", "ninth"); + "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")) + .straightRightOf(By.id("bottomLeft"))); + + List ids = seen.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList()); + + assertThat(ids).containsExactly("bottomRight"); } @Test @@ -151,7 +286,7 @@ void exerciseNearLocatorWithXpath() { assertThat(ids) .containsExactly( - "second", "eighth", "fourth", "sixth", "first", "third", "seventh", "ninth"); + "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight"); } @Test @@ -170,9 +305,10 @@ 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"); + "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight"); } @Test @@ -197,7 +333,6 @@ void ensureNoRepeatedElements() { + "
El-E
\n" + "
El-F
\n" + " ")); - driver.get(url); WebElement base = driver.findElement(By.id("e")); @@ -217,7 +352,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"); @@ -227,10 +361,10 @@ void nearLocatorShouldFindNearElements() { void nearLocatorShouldNotFindFarElements() { driver.get(appServer.whereIs("relative_locators.html")); - WebElement rect3 = driver.findElement(By.id("rect3")); + WebElement rect = driver.findElement(By.id("rect1")); assertThatExceptionOfType(NoSuchElementException.class) - .isThrownBy(() -> driver.findElement(with(By.id("rect4")).near(rect3))) + .isThrownBy(() -> driver.findElement(with(By.id("rect4")).near(rect))) .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/javascript/node/selenium-webdriver/test/element_finding_test.js b/javascript/node/selenium-webdriver/test/element_finding_test.js index a13c58b1a4134..278236be526e4 100644 --- a/javascript/node/selenium-webdriver/test/element_finding_test.js +++ b/javascript/node/selenium-webdriver/test/element_finding_test.js @@ -389,12 +389,12 @@ suite(function (env) { it('should combine filters', async function () { await driver.get(Pages.relativeLocators) - let elements = await driver.findElements(withTagName('td').above(By.id('center')).toRightOf(By.id('second'))) + let elements = await driver.findElements(withTagName('td').above(By.id('center')).toRightOf(By.id('top'))) let ids = [] for (let i = 0; i < elements.length; i++) { ids.push(await elements[i].getAttribute('id')) } - assert.notDeepStrictEqual(ids.indexOf('third'), -1, `Elements are ${ids}`) + assert.notDeepStrictEqual(ids.indexOf('topRight'), -1, `Elements are ${ids}`) }) }) @@ -408,8 +408,8 @@ suite(function (env) { it('should combine filters', async function () { await driver.get(Pages.relativeLocators) - let element = await driver.findElement(withTagName('td').above(By.id('center')).toRightOf(By.id('second'))) - assert.deepStrictEqual(await element.getAttribute('id'), `third`) + let element = await driver.findElement(withTagName('td').above(By.id('center')).toRightOf(By.id('top'))) + assert.deepStrictEqual(await element.getAttribute('id'), `topRight`) }) it('should search by passing in a by object', async function () { diff --git a/py/selenium/webdriver/support/relative_locator.py b/py/selenium/webdriver/support/relative_locator.py index d1ccbc257ac3f..3225190fb1fda 100644 --- a/py/selenium/webdriver/support/relative_locator.py +++ b/py/selenium/webdriver/support/relative_locator.py @@ -61,7 +61,7 @@ def locate_with(by: ByType, using: str) -> "RelativeBy": class RelativeBy: """Gives the opportunity to find elements based on their relative location - on the page from a root elelemt. It is recommended that you use the helper + on the page from a root element. It is recommended that you use the helper function to create it. Example: @@ -160,6 +160,78 @@ def to_right_of(self, element_or_locator: Union[WebElement, Dict, None] = None) self.filters.append({"kind": "right", "args": [element_or_locator]}) return self + @overload + def straight_above(self, element_or_locator: Union[WebElement, LocatorType]) -> "RelativeBy": ... + + @overload + def straight_above(self, element_or_locator: None = None) -> "NoReturn": ... + + def straight_above(self, element_or_locator: Union[WebElement, LocatorType, None] = None) -> "RelativeBy": + """Add a filter to look for elements above. + + :Args: + - element_or_locator: Element to look above + """ + if not element_or_locator: + raise WebDriverException("Element or locator must be given when calling above method") + + self.filters.append({"kind": "straightAbove", "args": [element_or_locator]}) + return self + + @overload + def straight_below(self, element_or_locator: Union[WebElement, LocatorType]) -> "RelativeBy": ... + + @overload + def straight_below(self, element_or_locator: None = None) -> "NoReturn": ... + + def straight_below(self, element_or_locator: Union[WebElement, Dict, None] = None) -> "RelativeBy": + """Add a filter to look for elements below. + + :Args: + - element_or_locator: Element to look below + """ + if not element_or_locator: + raise WebDriverException("Element or locator must be given when calling below method") + + self.filters.append({"kind": "straightBelow", "args": [element_or_locator]}) + return self + + @overload + def straight_left_of(self, element_or_locator: Union[WebElement, LocatorType]) -> "RelativeBy": ... + + @overload + def straight_left_of(self, element_or_locator: None = None) -> "NoReturn": ... + + def straight_left_of(self, element_or_locator: Union[WebElement, Dict, None] = None) -> "RelativeBy": + """Add a filter to look for elements to the left of. + + :Args: + - element_or_locator: Element to look to the left of + """ + if not element_or_locator: + raise WebDriverException("Element or locator must be given when calling to_left_of method") + + self.filters.append({"kind": "straightLeft", "args": [element_or_locator]}) + return self + + @overload + def straight_right_of(self, element_or_locator: Union[WebElement, LocatorType]) -> "RelativeBy": ... + + @overload + def straight_right_of(self, element_or_locator: None = None) -> "NoReturn": ... + + def straight_right_of(self, element_or_locator: Union[WebElement, Dict, None] = None) -> "RelativeBy": + """Add a filter to look for elements right of. + + :Args: + - element_or_locator: Element to look right of + """ + if not element_or_locator: + raise WebDriverException("Element or locator must be given when calling to_right_of method") + + self.filters.append({"kind": "straightRight", "args": [element_or_locator]}) + return self + @overload def near(self, element_or_locator: Union[WebElement, LocatorType], distance: int = 50) -> "RelativeBy": ... diff --git a/py/test/selenium/webdriver/support/relative_by_tests.py b/py/test/selenium/webdriver/support/relative_by_tests.py index d90d3fedae1d4..8159330441211 100644 --- a/py/test/selenium/webdriver/support/relative_by_tests.py +++ b/py/test/selenium/webdriver/support/relative_by_tests.py @@ -64,22 +64,20 @@ def test_should_be_able_to_combine_filters(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements( - with_tag_name("td") - .above(driver.find_element(By.ID, "center")) - .to_right_of(driver.find_element(By.ID, "second")) + with_tag_name("td").above(driver.find_element(By.ID, "center")).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): @@ -88,22 +86,22 @@ def test_should_be_able_to_use_css_selectors(driver, pages): 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): @@ -111,27 +109,41 @@ def test_should_be_able_to_use_xpath(driver, pages): elements = driver.find_elements( locate_with(By.XPATH, "//td[1]") - .below(driver.find_element(By.ID, "second")) - .above(driver.find_element(By.ID, "seventh")) + .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") + .straight_below(driver.find_element(By.ID, "topRight")) + .straight_right_of(driver.find_element(By.ID, "bottomLeft")) + ) + + ids = [el.get_attribute("id") for el in elements] + assert len(ids) == 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,15 +151,15 @@ 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 def test_near_locator_should_find_near_elements(driver, pages): pages.load("relative_locators.html") - rect1 = driver.find_element(By.ID, "rect1") + rect = driver.find_element(By.ID, "rect1") - el = driver.find_element(locate_with(By.ID, "rect2").near(rect1)) + el = driver.find_element(locate_with(By.ID, "rect2").near(rect)) assert el.get_attribute("id") == "rect2" @@ -162,10 +174,10 @@ def test_near_locator_should_find_near_elements_by_locator(driver, pages): def test_near_locator_should_not_find_far_elements(driver, pages): pages.load("relative_locators.html") - rect3 = driver.find_element(By.ID, "rect3") + rect = driver.find_element(By.ID, "rect2") with pytest.raises(NoSuchElementException) as exc: - driver.find_element(locate_with(By.ID, "rect4").near(rect3)) + driver.find_element(locate_with(By.ID, "rect4").near(rect)) assert "Cannot locate relative element with: {'id': 'rect4'}" in exc.value.msg @@ -174,16 +186,16 @@ def test_near_locator_should_not_find_far_elements_by_locator(driver, pages): pages.load("relative_locators.html") with pytest.raises(NoSuchElementException) as exc: - driver.find_element(locate_with(By.ID, "rect4").near({By.ID: "rect3"})) + driver.find_element(locate_with(By.ID, "rect4").near({By.ID: "rect2"})) assert "Cannot locate relative element with: {'id': 'rect4'}" in exc.value.msg def test_near_locator_should_find_far_elements(driver, pages): pages.load("relative_locators.html") - rect3 = driver.find_element(By.ID, "rect3") + rect = driver.find_element(By.ID, "rect2") - el = driver.find_element(locate_with(By.ID, "rect4").near(rect3, 100)) + el = driver.find_element(locate_with(By.ID, "rect4").near(rect, 100)) assert el.get_attribute("id") == "rect4" @@ -191,6 +203,98 @@ def test_near_locator_should_find_far_elements(driver, pages): def test_near_locator_should_find_far_elements_by_locator(driver, pages): pages.load("relative_locators.html") - el = driver.find_element(locate_with(By.ID, "rect4").near({By.ID: "rect3"}, 100)) + el = driver.find_element(locate_with(By.ID, "rect4").near({By.ID: "rect2"}, 100)) assert el.get_attribute("id") == "rect4" + + +def test_should_find_elements_above_another(driver, pages): + pages.load("relative_locators.html") + + elements = driver.find_elements(with_tag_name("td").above({By.ID: "center"})) + + ids = [el.get_attribute("id") for el in elements] + assert len(ids) == 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") + + elements = driver.find_elements(with_tag_name("td").below({By.ID: "center"})) + + ids = [el.get_attribute("id") for el in elements] + assert len(ids) == 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") + + elements = driver.find_elements(with_tag_name("td").to_left_of({By.ID: "center"})) + + ids = [el.get_attribute("id") for el in elements] + assert len(ids) == 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") + + elements = driver.find_elements(with_tag_name("td").to_right_of({By.ID: "center"})) + + ids = [el.get_attribute("id") for el in elements] + assert len(ids) == 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") + + elements = driver.find_elements(with_tag_name("td").straight_above({By.ID: "bottom"})) + + ids = [el.get_attribute("id") for el in elements] + assert len(ids) == 2 + assert "top" in ids + assert "center" in ids + + +def test_should_find_elements_straight_below_another(driver, pages): + pages.load("relative_locators.html") + + elements = driver.find_elements(with_tag_name("td").straight_below({By.ID: "top"})) + + ids = [el.get_attribute("id") for el in elements] + assert len(ids) == 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") + + elements = driver.find_elements(with_tag_name("td").straight_left_of({By.ID: "right"})) + + ids = [el.get_attribute("id") for el in elements] + assert len(ids) == 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") + + elements = driver.find_elements(with_tag_name("td").straight_right_of({By.ID: "left"})) + + ids = [el.get_attribute("id") for el in elements] + assert len(ids) == 2 + assert "right" in ids + assert "center" in ids diff --git a/rb/spec/integration/selenium/webdriver/driver_spec.rb b/rb/spec/integration/selenium/webdriver/driver_spec.rb index b5b03c662b0d5..a9f301d310b4e 100644 --- a/rb/spec/integration/selenium/webdriver/driver_spec.rb +++ b/rb/spec/integration/selenium/webdriver/driver_spec.rb @@ -115,7 +115,7 @@ module WebDriver driver.navigate.to url_for('relative_locators.html') above = driver.find_element(relative: {tag_name: 'td', above: {id: 'center'}}) - expect(above.attribute('id')).to eq('second') + expect(above.attribute('id')).to eq('top') end it 'finds child element' do @@ -182,7 +182,7 @@ module WebDriver driver.navigate.to url_for('relative_locators.html') above = driver.find_elements(relative: {css: 'td', above: {id: 'center'}}) - expect(above.map { |e| e.attribute('id') }).to eq(%w[second first third]) + expect(above.map { |e| e.attribute('id') }).to eq(%w[top topLeft topRight]) end it 'finds below element' do @@ -196,36 +196,36 @@ module WebDriver it 'finds near another within default distance' do driver.navigate.to url_for('relative_locators.html') - near = driver.find_elements(relative: {tag_name: 'td', near: {id: 'sixth'}}) - expect(near.map { |e| e.attribute('id') }).to eq(%w[third ninth center second eighth]) + near = driver.find_elements(relative: {tag_name: 'td', near: {id: 'right'}}) + expect(near.map { |e| e.attribute('id') }).to eq(%w[topRight bottomRight center top bottom]) end it 'finds near another within custom distance', except: {browser: %i[safari safari_preview]} do driver.navigate.to url_for('relative_locators.html') - near = driver.find_elements(relative: {tag_name: 'td', near: {id: 'sixth', distance: 100}}) - expect(near.map { |e| e.attribute('id') }).to eq(%w[third ninth center second eighth]) + near = driver.find_elements(relative: {tag_name: 'td', near: {id: 'right', distance: 100}}) + expect(near.map { |e| e.attribute('id') }).to eq(%w[topRight bottomRight center top bottom]) end it 'finds to the left of another' do driver.navigate.to url_for('relative_locators.html') left = driver.find_elements(relative: {tag_name: 'td', left: {id: 'center'}}) - expect(left.map { |e| e.attribute('id') }).to eq(%w[fourth first seventh]) + expect(left.map { |e| e.attribute('id') }).to eq(%w[left topLeft bottomLeft]) end it 'finds to the right of another' do driver.navigate.to url_for('relative_locators.html') right = driver.find_elements(relative: {tag_name: 'td', right: {id: 'center'}}) - expect(right.map { |e| e.attribute('id') }).to eq(%w[sixth third ninth]) + expect(right.map { |e| e.attribute('id') }).to eq(%w[right topRight bottomRight]) end it 'finds by combined relative locators' do driver.navigate.to url_for('relative_locators.html') - found = driver.find_elements(relative: {tag_name: 'td', right: {id: 'second'}, above: {id: 'center'}}) - expect(found.map { |e| e.attribute('id') }).to eq(['third']) + found = driver.find_elements(relative: {tag_name: 'td', right: {id: 'top'}, above: {id: 'center'}}) + expect(found.map { |e| e.attribute('id') }).to eq(['topRight']) end it 'finds all by empty relative locator' do