From 2cf77cc7d299f7a05d8bce35b1d4c3855333674b Mon Sep 17 00:00:00 2001 From: Simon Stewart Date: Mon, 14 Dec 2020 12:22:02 +0000 Subject: [PATCH] Rework near relative locator to be easier to understand --- .../support/locators/RelativeLocator.java | 7 +-- .../selenium/support/locators/BUILD.bazel | 4 ++ .../support/locators/RelativeLocatorTest.java | 21 +++++++- javascript/atoms/locators/relative.js | 48 +++++++++++-------- 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/java/client/src/org/openqa/selenium/support/locators/RelativeLocator.java b/java/client/src/org/openqa/selenium/support/locators/RelativeLocator.java index dd0186b50ee21..04ac8ede7d64b 100644 --- a/java/client/src/org/openqa/selenium/support/locators/RelativeLocator.java +++ b/java/client/src/org/openqa/selenium/support/locators/RelativeLocator.java @@ -89,6 +89,7 @@ public class RelativeLocator { throw new UncheckedIOException(e); } } + private static final int CLOSE_IN_PIXELS = 100; /** * Start of a relative locator, finding elements by tag name. @@ -169,7 +170,7 @@ public RelativeBy toRightOf(By locator) { public RelativeBy near(WebElement element) { Require.nonNull("Element to search near", element); - return near(element, 50); + return near(element, CLOSE_IN_PIXELS); } public RelativeBy near(WebElement element, int atMostDistanceInPixels) { @@ -181,7 +182,7 @@ public RelativeBy near(WebElement element, int atMostDistanceInPixels) { public RelativeBy near(By locator) { Require.nonNull("Locator", locator); - return near((Object) locator, 50); + return near((Object) locator, CLOSE_IN_PIXELS); } public RelativeBy near(By locator, int atMostDistanceInPixels) { @@ -199,7 +200,7 @@ private RelativeBy near(Object locator, int atMostDistanceInPixels) { root, amend(ImmutableMap.of( "kind", "near", - "args", ImmutableList.of(asAtomLocatorParameter(locator), "distance", atMostDistanceInPixels)))); + "args", ImmutableList.of(asAtomLocatorParameter(locator), atMostDistanceInPixels)))); } @Override diff --git a/java/client/test/org/openqa/selenium/support/locators/BUILD.bazel b/java/client/test/org/openqa/selenium/support/locators/BUILD.bazel index 474443c902792..507a0f4cb88e1 100644 --- a/java/client/test/org/openqa/selenium/support/locators/BUILD.bazel +++ b/java/client/test/org/openqa/selenium/support/locators/BUILD.bazel @@ -6,6 +6,10 @@ java_selenium_test_suite( size = "medium", srcs = glob(["*Test.java"]), browsers = ["chrome"], + javacopts = [ + "--release", + "11", + ], deps = [ "//java/client/src/org/openqa/selenium:core", "//java/client/src/org/openqa/selenium/remote", diff --git a/java/client/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java b/java/client/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java index d786bd49d5e44..13c0c1adf4fe2 100644 --- a/java/client/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java +++ b/java/client/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java @@ -22,7 +22,6 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.testing.JUnit4TestBase; -import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -41,7 +40,7 @@ public void shouldBeAbleToFindElementsAboveAnother() { List elements = driver.findElements(withTagName("p").above(lowest)); List ids = elements.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList()); - assertThat(ids).isEqualTo(Arrays.asList("mid", "above")); + assertThat(ids).isEqualTo(List.of("mid", "above")); } @Test @@ -54,4 +53,22 @@ public void shouldBeAbleToCombineFilters() { assertThat(ids).isEqualTo(singletonList("third")); } + @Test + public void exerciseNearLocator() { + driver.get(appServer.whereIs("relative_locators.html")); + + List seen = driver.findElements(withTagName("td").near(By.id("center"))); + + // Elements are sorted by proximity and then DOM insertion order. + // Proximity is determined using distance from center points, so + // we expect the order to be: + // 1. Directly above (short vertical distance, first in DOM) + // 2. Directly below (short vertical distance, later in DOM) + // 3. Directly left (slight longer distance horizontally, first in DOM) + // 4. Directly right (slight longer distance horizontally, later in DOM) + // 5-8. Diagonally close (pythagorus sorting, with top row first + // because of DOM insertion order) + List ids = seen.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList()); + assertThat(ids).isEqualTo(List.of("second", "eighth", "fourth", "sixth", "first", "third", "seventh", "ninth")); + } } diff --git a/javascript/atoms/locators/relative.js b/javascript/atoms/locators/relative.js index 8cc3e4b1f8836..44e5cbe756b5a 100644 --- a/javascript/atoms/locators/relative.js +++ b/javascript/atoms/locators/relative.js @@ -145,11 +145,11 @@ bot.locators.relative.near_ = function (selector, opt_distance) { distance = opt_distance; } else if (goog.isNumber(selector['distance'])) { distance = /** @type {number} */ (selector['distance']); - delete selector['distance']; + // delete selector['distance']; } if (!distance) { - distance = 50; + distance = 100; } /** @@ -179,29 +179,39 @@ bot.locators.relative.near_ = function (selector, opt_distance) { // we would be comparing the right hand side of 2 to the left hand side // of 1. Similar logic happens for top and bottom. - var rhs1 = rect1.left + rect1.width; - var rhs2 = rect2.left + rect2.width; - var bottom1 = rect1.top - rect1.height; - var bottom2 = rect2.top - rect2.height; + // Distance from left edge to right edge + var leftDistance = Math.abs(rect1.left - (rect2.left + rect2.width)); - /** @type {function():boolean} */ - var verticalProximity = function () { - return Math.abs(bottom1 - rect2.top) <= distance || - Math.abs(bottom2 - rect1.top) <= distance; - }; + // Distance from right edge to left edge + var rightDistance = Math.abs((rect1.left + rect1.width) - rect2.left); - // Is 1 to the right of 2? - if (Math.abs(rhs1 - rect2.left) <= distance) { - return verticalProximity(); - } + // Distance from top to bottom + var topDistance = Math.abs(rect1.top - (rect2.top + rect2.height)); + + // Distance from bottom to top + var bottomDistance = Math.abs((rect1.top + rect1.height) - rect2.top); + + var horizontallyClose = leftDistance <= distance || rightDistance <= distance; + var verticallyClose = topDistance <= distance || bottomDistance <= distance; - // Is 1 to the left of 2? - if (Math.abs(rhs2 - rect1.left) <= distance) { - return verticalProximity(); + if (horizontallyClose && verticallyClose) { + return true; } - return false; + // Distance from centre points + var x1 = rect1.left + (rect1.width / 2); + var y1 = rect1.top + (rect1.height / 2); + + var x2 = rect2.left + (rect2.width / 2); + var y2 = rect2.top + (rect2.height / 2); + + var xDistance = Math.abs(x1 - x2); + var yDistance = Math.abs(y1 - y2); + + var dist = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2)); + return dist <= distance; }; + return func; };