Skip to content

Commit 3d2a826

Browse files
browser: nearby filter (#1543)
1 parent e7c5593 commit 3d2a826

23 files changed

Lines changed: 332 additions & 39 deletions

File tree

webtau-browser/src/main/java/org/testingisdocumenting/webtau/browser/AdditionalBrowserInteractions.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,7 @@ public interface AdditionalBrowserInteractions {
3232

3333
List<WebElement> filterByRegexp(List<WebElement> webElements, String regexp);
3434

35+
List<WebElement> filterByNearby(List<WebElement> webElements, WebElement target);
36+
3537
WebElement parentByCss(SearchContext element, String css);
3638
}

webtau-browser/src/main/java/org/testingisdocumenting/webtau/browser/BrowserInjectedJavaScript.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ public List<WebElement> filterByRegexp(List<WebElement> webElements, String rege
7777
webElements, regexp);
7878
}
7979

80+
@Override
81+
@SuppressWarnings("unchecked")
82+
public List<WebElement> filterByNearby(List<WebElement> webElements, WebElement target) {
83+
injectScript();
84+
return (List<WebElement>) javascriptExecutor.executeScript(returnTwoArgFunc("filterByNearby"),
85+
webElements, target);
86+
}
87+
8088
@Override
8189
public WebElement parentByCss(SearchContext element, String css) {
8290
injectScript();

webtau-browser/src/main/java/org/testingisdocumenting/webtau/browser/page/PageElement.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@
3232
import org.testingisdocumenting.webtau.browser.page.path.filter.ByNumberPageElementsFilter;
3333
import org.testingisdocumenting.webtau.browser.page.path.filter.ByRegexpPageElementsFilter;
3434
import org.testingisdocumenting.webtau.browser.page.path.filter.ByTextPageElementsFilter;
35-
import org.testingisdocumenting.webtau.browser.page.path.finder.ByCssPageElementFinder;
36-
import org.testingisdocumenting.webtau.browser.page.path.finder.ParentByCssPageElementFinder;
37-
import org.testingisdocumenting.webtau.browser.page.path.finder.ParentPageElementFinder;
35+
import org.testingisdocumenting.webtau.browser.page.path.filter.NearbyPageElementFilter;
36+
import org.testingisdocumenting.webtau.browser.page.path.finder.*;
3837
import org.testingisdocumenting.webtau.data.ValuePath;
3938
import org.testingisdocumenting.webtau.data.render.PrettyPrintable;
4039
import org.testingisdocumenting.webtau.data.render.PrettyPrinter;
@@ -265,6 +264,10 @@ public PageElement parent(String css) {
265264
return withFinder(new ParentByCssPageElementFinder(additionalBrowserInteractions, css));
266265
}
267266

267+
public PageElement nearby(PageElement target) {
268+
return withFilter(new NearbyPageElementFilter(additionalBrowserInteractions, target));
269+
}
270+
268271
public PageElement get(String text) {
269272
return withFilter(new ByTextPageElementsFilter(additionalBrowserInteractions, text));
270273
}

webtau-browser/src/main/java/org/testingisdocumenting/webtau/browser/page/path/PageElementFinder.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,12 @@
1818
package org.testingisdocumenting.webtau.browser.page.path;
1919

2020
import org.testingisdocumenting.webtau.reporter.TokenizedMessage;
21-
import org.openqa.selenium.SearchContext;
2221
import org.openqa.selenium.WebElement;
2322

2423
import java.util.List;
2524

2625
public interface PageElementFinder {
27-
List<WebElement> find(SearchContext parent);
26+
List<WebElement> find(PageElementPathSearchContext parent);
2827

2928
/**
3029
* @param isFirst isFirst is this the first entry in the path

webtau-browser/src/main/java/org/testingisdocumenting/webtau/browser/page/path/PageElementPath.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,16 @@
1717

1818
package org.testingisdocumenting.webtau.browser.page.path;
1919

20-
import org.testingisdocumenting.webtau.browser.page.path.finder.ByCssPageElementFinder;
21-
import org.testingisdocumenting.webtau.reporter.TokenizedMessage;
22-
import org.openqa.selenium.SearchContext;
2320
import org.openqa.selenium.WebDriver;
2421
import org.openqa.selenium.WebElement;
22+
import org.testingisdocumenting.webtau.browser.page.path.finder.ByCssPageElementFinder;
23+
import org.testingisdocumenting.webtau.reporter.TokenizedMessage;
2524

2625
import java.util.ArrayList;
2726
import java.util.Collections;
2827
import java.util.List;
2928

30-
import static java.util.stream.Collectors.toList;
29+
import static java.util.stream.Collectors.*;
3130

3231
public class PageElementPath {
3332
private List<PageElementPathEntry> entries;
@@ -64,16 +63,16 @@ public static PageElementPath css(String cssSelector) {
6463
}
6564

6665
public List<WebElement> find(WebDriver driver) {
67-
SearchContext root = driver;
66+
var context = new PageElementPathSearchContext(driver, null);
6867

6968
List<WebElement> webElements = Collections.emptyList();
7069
for (PageElementPathEntry entry : entries) {
71-
webElements = entry.find(root);
70+
webElements = entry.find(context);
7271
if (webElements.isEmpty()) {
7372
return webElements;
7473
}
7574

76-
root = webElements.get(0);
75+
context = PageElementPathSearchContext.fromElement(webElements.get(0));
7776
}
7877

7978
return webElements;

webtau-browser/src/main/java/org/testingisdocumenting/webtau/browser/page/path/PageElementPathEntry.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
package org.testingisdocumenting.webtau.browser.page.path;
1919

2020
import org.testingisdocumenting.webtau.reporter.TokenizedMessage;
21-
import org.openqa.selenium.SearchContext;
2221
import org.openqa.selenium.WebElement;
2322

2423
import java.util.ArrayList;
@@ -44,8 +43,8 @@ PageElementPathEntry copy() {
4443
return copy;
4544
}
4645

47-
List<WebElement> find(SearchContext parent) {
48-
List<WebElement> elements = finder.find(parent);
46+
List<WebElement> find(PageElementPathSearchContext searchContext) {
47+
List<WebElement> elements = finder.find(searchContext);
4948
if (elements.isEmpty()) {
5049
return elements;
5150
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2023 webtau maintainers
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.testingisdocumenting.webtau.browser.page.path;
18+
19+
import org.openqa.selenium.SearchContext;
20+
import org.openqa.selenium.WebElement;
21+
22+
public record PageElementPathSearchContext(SearchContext searchContext, WebElement parent) {
23+
static PageElementPathSearchContext fromElement(WebElement element) {
24+
return new PageElementPathSearchContext(element, element);
25+
}
26+
27+
public boolean hasParent() {
28+
return parent != null;
29+
}
30+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2023 webtau maintainers
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.testingisdocumenting.webtau.browser.page.path.filter;
18+
19+
import org.openqa.selenium.WebElement;
20+
import org.testingisdocumenting.webtau.browser.AdditionalBrowserInteractions;
21+
import org.testingisdocumenting.webtau.browser.page.NullWebElement;
22+
import org.testingisdocumenting.webtau.browser.page.PageElement;
23+
import org.testingisdocumenting.webtau.browser.page.path.PageElementsFilter;
24+
import org.testingisdocumenting.webtau.reporter.TokenizedMessage;
25+
26+
import java.util.Collections;
27+
import java.util.List;
28+
29+
import static org.testingisdocumenting.webtau.WebTauCore.*;
30+
31+
public class NearbyPageElementFilter implements PageElementsFilter {
32+
private final AdditionalBrowserInteractions additionalBrowserInteractions;
33+
private final PageElement target;
34+
35+
public NearbyPageElementFilter(AdditionalBrowserInteractions additionalBrowserInteractions, PageElement target) {
36+
this.additionalBrowserInteractions = additionalBrowserInteractions;
37+
this.target = target;
38+
}
39+
40+
@Override
41+
public List<WebElement> filter(List<WebElement> original) {
42+
WebElement targetElement = target.findElement();
43+
if (targetElement instanceof NullWebElement) {
44+
return Collections.emptyList();
45+
}
46+
47+
return additionalBrowserInteractions.filterByNearby(original, targetElement);
48+
}
49+
50+
@Override
51+
public TokenizedMessage description() {
52+
return tokenizedMessage().classifier("nearby").add(target.describe());
53+
}
54+
}

webtau-browser/src/main/java/org/testingisdocumenting/webtau/browser/page/path/finder/ByCssPageElementFinder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
package org.testingisdocumenting.webtau.browser.page.path.finder;
1919

2020
import org.testingisdocumenting.webtau.browser.page.path.PageElementFinder;
21+
import org.testingisdocumenting.webtau.browser.page.path.PageElementPathSearchContext;
2122
import org.testingisdocumenting.webtau.reporter.TokenizedMessage;
2223
import org.openqa.selenium.By;
23-
import org.openqa.selenium.SearchContext;
2424
import org.openqa.selenium.WebElement;
2525

2626
import java.util.List;
@@ -35,8 +35,8 @@ public ByCssPageElementFinder(String css) {
3535
}
3636

3737
@Override
38-
public List<WebElement> find(SearchContext parent) {
39-
return parent.findElements(By.cssSelector(css));
38+
public List<WebElement> find(PageElementPathSearchContext parent) {
39+
return parent.searchContext().findElements(By.cssSelector(css));
4040
}
4141

4242
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2021 webtau maintainers
3+
* Copyright 2019 TWO SIGMA OPEN SOURCE, LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.testingisdocumenting.webtau.browser.page.path.finder;
19+
20+
import org.openqa.selenium.WebElement;
21+
import org.openqa.selenium.support.locators.RelativeLocator;
22+
import org.testingisdocumenting.webtau.browser.page.PageElement;
23+
24+
import java.util.function.Function;
25+
26+
public class ByRelativeAbovePageElementFinder extends ByRelativePageElementFinder {
27+
public ByRelativeAbovePageElementFinder(PageElement target) {
28+
super(target, "above");
29+
}
30+
31+
protected Function<WebElement, RelativeLocator.RelativeBy> direction(RelativeLocator.RelativeBy chainStart) {
32+
return chainStart::above;
33+
}
34+
}

0 commit comments

Comments
 (0)