Skip to content

Commit d10f8c2

Browse files
alpatrondiemol
andauthored
improve "near" relative locator behaviour (#11290)
* improve "near" relative locator behaviour Changes the behaviour of the "near" relative locator to use the distance between the two rectangles' boundaries for determining closeness. The relative_locators.html file is changed so that the center cell and cell number two's centers are far away but their boundaries are near each other. Fixes #11272 * Fix default distance in relative locator * Add Python tests * [java] Adding test in Java and setting default to 50px * [py] Fixing linter --------- Co-authored-by: Diego Molina <[email protected]> Co-authored-by: Diego Molina <[email protected]>
1 parent 0dd9e34 commit d10f8c2

File tree

5 files changed

+73
-44
lines changed

5 files changed

+73
-44
lines changed

common/src/web/relative_locators.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@
1010
td {
1111
border: solid;
1212
}
13+
.small-rectangle {
14+
border: 1px solid black;
15+
width: 100px;
16+
height: 50px;
17+
margin: 5px 25px;
18+
}
19+
.big-rectangle {
20+
border: 1px solid black;
21+
width: 150px;
22+
height: 400px;
23+
}
1324
</style>
1425
</head>
1526
<body>
@@ -37,5 +48,19 @@ <h1>Relative Locator Tests</h1>
3748
</tr>
3849
</table>
3950

51+
<div class="small-rectangle" id="rect1">
52+
Rectangle 1
53+
</div>
54+
<div class="big-rectangle" id="rect2">
55+
Rectangle 2, which is near Rectangle 1
56+
</div>
57+
58+
<div class="small-rectangle" style="margin:60px 25px" id="rect3">
59+
Rectangle 3
60+
</div>
61+
<div class="big-rectangle" id="rect4">
62+
Rectangle 4, which is not near Rectangle 2 because it is more than 50 px away
63+
</div>
64+
4065
</body>
4166
</html>

java/src/org/openqa/selenium/support/locators/RelativeLocator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public class RelativeLocator {
6969

7070
private static final Json JSON = new Json();
7171

72-
private static final int CLOSE_IN_PIXELS = 100;
72+
private static final int CLOSE_IN_PIXELS = 50;
7373

7474
/** Start of a relative locator, finding elements by tag name. */
7575
public static RelativeBy with(By by) {

java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.openqa.selenium.support.locators;
1919

2020
import static org.assertj.core.api.Assertions.assertThat;
21+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
2122
import static org.openqa.selenium.By.cssSelector;
2223
import static org.openqa.selenium.By.tagName;
2324
import static org.openqa.selenium.By.xpath;
@@ -27,6 +28,7 @@
2728
import java.util.stream.Collectors;
2829
import org.junit.jupiter.api.Test;
2930
import org.openqa.selenium.By;
31+
import org.openqa.selenium.NoSuchElementException;
3032
import org.openqa.selenium.WebElement;
3133
import org.openqa.selenium.environment.webserver.Page;
3234
import org.openqa.selenium.testing.JupiterTestBase;
@@ -209,4 +211,26 @@ void ensureNoRepeatedElements() {
209211
cells.stream().map(e -> e.getAttribute("id")).collect(Collectors.joining(", ")))
210212
.isEqualTo(List.of(b, a));
211213
}
214+
215+
@Test
216+
void nearLocatorShouldFindNearElements() {
217+
driver.get(appServer.whereIs("relative_locators.html"));
218+
219+
WebElement rect1 = driver.findElement(By.id("rect1"));
220+
221+
WebElement rect2 = driver.findElement(with(By.id("rect2")).near(rect1));
222+
223+
assertThat(rect2.getAttribute("id")).isEqualTo("rect2");
224+
}
225+
226+
@Test
227+
void nearLocatorShouldNotFindFarElements() {
228+
driver.get(appServer.whereIs("relative_locators.html"));
229+
230+
WebElement rect3 = driver.findElement(By.id("rect3"));
231+
232+
assertThatExceptionOfType(NoSuchElementException.class)
233+
.isThrownBy(() -> driver.findElement(with(By.id("rect4")).near(rect3)))
234+
.withMessageContaining("Cannot locate an element using");
235+
}
212236
}

javascript/atoms/locators/relative.js

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ goog.require('bot.dom');
2222
goog.require('bot.locators');
2323
goog.require('goog.array');
2424
goog.require('goog.dom');
25+
goog.require('goog.math.Rect');
2526

2627

2728
/**
@@ -149,7 +150,7 @@ bot.locators.relative.near_ = function (selector, opt_distance) {
149150
}
150151

151152
if (!distance) {
152-
distance = 100;
153+
distance = 50;
153154
}
154155

155156
/**
@@ -166,49 +167,9 @@ bot.locators.relative.near_ = function (selector, opt_distance) {
166167
var rect1 = bot.dom.getClientRect(element);
167168
var rect2 = bot.dom.getClientRect(compareTo);
168169

169-
// Ascii art time!
170-
//
171-
// +---+
172-
// | 1 |
173-
// +---+ +---+
174-
// | 2 |
175-
// +---+
176-
//
177-
// As you can see, the right hand side of 1 is "left of" the left-most
178-
// edge of 2. The top edge of 2 is at the same level as the bottom
179-
// edge of 1. This means that 1 is "above" 2, and 2 is "below" one.
170+
var rect1_bigger = new goog.math.Rect(rect1.left-distance,rect1.top-distance,rect1.width+distance*2,rect1.height+distance*2);
180171

181-
// Distance from left edge to right edge
182-
var leftDistance = Math.abs(rect1.left - (rect2.left + rect2.width));
183-
184-
// Distance from right edge to left edge
185-
var rightDistance = Math.abs((rect1.left + rect1.width) - rect2.left);
186-
187-
// Distance from top to bottom
188-
var topDistance = Math.abs(rect1.top - (rect2.top + rect2.height));
189-
190-
// Distance from bottom to top
191-
var bottomDistance = Math.abs((rect1.top + rect1.height) - rect2.top);
192-
193-
var horizontallyClose = leftDistance <= distance || rightDistance <= distance;
194-
var verticallyClose = topDistance <= distance || bottomDistance <= distance;
195-
196-
if (horizontallyClose && verticallyClose) {
197-
return true;
198-
}
199-
200-
// Distance from centre points
201-
var x1 = rect1.left + (rect1.width / 2);
202-
var y1 = rect1.top + (rect1.height / 2);
203-
204-
var x2 = rect2.left + (rect2.width / 2);
205-
var y2 = rect2.top + (rect2.height / 2);
206-
207-
var xDistance = Math.abs(x1 - x2);
208-
var yDistance = Math.abs(y1 - y2);
209-
210-
var dist = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
211-
return dist <= distance;
172+
return rect1_bigger.intersects(rect2);
212173
};
213174

214175
return func;

py/test/selenium/webdriver/support/relative_by_tests.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,22 @@ def test_no_such_element_is_raised_rather_than_index_error(driver, pages):
8787
anchor = driver.find_element(By.ID, "second")
8888
driver.find_element(locate_with(By.ID, "nonexistentid").above(anchor))
8989
assert exc.value.msg == "Cannot locate relative element with: {'id': 'nonexistentid'}"
90+
91+
92+
def test_near_locator_should_find_near_elements(driver, pages):
93+
pages.load("relative_locators.html")
94+
rect1 = driver.find_element(By.ID, "rect1")
95+
96+
el = driver.find_element(locate_with(By.ID, "rect2").near(rect1))
97+
98+
assert el.get_attribute("id") == "rect2"
99+
100+
101+
def test_near_locator_should_not_find_far_elements(driver, pages):
102+
pages.load("relative_locators.html")
103+
rect3 = driver.find_element(By.ID, "rect3")
104+
105+
with pytest.raises(NoSuchElementException) as exc:
106+
driver.find_element(locate_with(By.ID, "rect4").near(rect3))
107+
108+
assert exc.value.msg == "Cannot locate relative element with: {'id': 'rect4'}"

0 commit comments

Comments
 (0)