From f940e117318d1d43a6cb6436d1dea54c0dead030 Mon Sep 17 00:00:00 2001 From: "a.y.perov" Date: Tue, 18 Jan 2022 10:04:33 +0300 Subject: [PATCH] added WebElements searching --- .../searching/FindElementsBuilder.java | 92 ++++++++++++++++ .../functions/searching/FindWebElements.java | 104 +++++++++++++++++- .../functions/searching/FindWidgets.java | 9 +- .../searching/MultipleSearchSupplier.java | 36 +++++- .../functions/searching/SearchSupplier.java | 36 +++++- 5 files changed, 264 insertions(+), 13 deletions(-) create mode 100644 selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindElementsBuilder.java diff --git a/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindElementsBuilder.java b/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindElementsBuilder.java new file mode 100644 index 0000000000..97ea42435d --- /dev/null +++ b/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindElementsBuilder.java @@ -0,0 +1,92 @@ +package ru.tinkoff.qa.neptune.selenium.functions.searching; + +import org.openqa.selenium.SearchContext; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.WrapsElement; +import ru.tinkoff.qa.neptune.core.api.steps.annotations.StepParameter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public abstract class FindElementsBuilder> implements Function { + @StepParameter("Above") + private List above = new ArrayList<>(); + @StepParameter("Below") + private List below = new ArrayList<>(); + @StepParameter("Left of") + private List toLeftOf = new ArrayList<>(); + @StepParameter("Right of") + private List toRightOf = new ArrayList<>(); + @StepParameter("Near") + private List near = new ArrayList<>(); + @StepParameter("Near with distance") + private Map nearWithDistance = new HashMap<>(); + + abstract void buildLocator(SearchContext searchContext); + + WebElement performFind(SearchContext searchContext, SearchSupplier find) { + var found = find.get().apply(searchContext); + if (found instanceof WrapsElement) { + return ((WrapsElement) found).getWrappedElement(); + } + return (WebElement) found; + } + + public FindElementsBuilder above(Object above) { + this.above.add(above); + return this; + } + + public FindElementsBuilder below(Object below) { + this.below.add(below); + return this; + } + + public FindElementsBuilder toLeftOf(Object toLeftOf) { + this.toLeftOf.add(toLeftOf); + return this; + } + + public FindElementsBuilder toRightOf(Object toRightOf) { + this.toRightOf.add(toRightOf); + return this; + } + + public FindElementsBuilder near(Object near) { + this.near.add(near); + return this; + } + + public FindElementsBuilder near(Object near, Integer distance) { + this.nearWithDistance.put(near, distance); + return this; + } + + + public List getAbove() { + return above; + } + + public List getBelow() { + return below; + } + + public List getToLeftOf() { + return toLeftOf; + } + + public List getToRightOf() { + return toRightOf; + } + + public List getNear() { + return near; + } + + public Map getNearWithDistance() { + return nearWithDistance; + } +} diff --git a/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindWebElements.java b/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindWebElements.java index 9593e02a7b..b9c9fff032 100644 --- a/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindWebElements.java +++ b/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindWebElements.java @@ -11,12 +11,14 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.nonNull; import static java.util.stream.Collectors.toList; +import static org.openqa.selenium.support.locators.RelativeLocator.with; import static ru.tinkoff.qa.neptune.selenium.functions.searching.CGLibProxyBuilder.createProxy; import static ru.tinkoff.qa.neptune.selenium.functions.searching.ToStringFormer.getMultipleToString; -final class FindWebElements implements Function> { - - private final By by; +final class FindWebElements extends FindElementsBuilder> { + private By by; + private By fullBy; + private boolean isBuildStarted; private FindWebElements(By by) { checkArgument(nonNull(by), "Locator by-strategy should be defined."); @@ -27,11 +29,101 @@ static FindWebElements webElements(By by) { return new FindWebElements(by); } + + @Override + protected void buildLocator(SearchContext searchContext) { + isBuildStarted = true; + var relativeLocator = with(by); + + var aboveList = getAbove(); + var belowList = getBelow(); + var toLeftOfList = getToLeftOf(); + var toRightOfList = getToRightOf(); + var nearList = getNear(); + var nearWithDistance = getNearWithDistance(); + + if (!aboveList.isEmpty()) { + for (var element : aboveList) { + if (element instanceof By) { + relativeLocator = relativeLocator.above((By) element); + } else if (element instanceof WebElement) { + relativeLocator = relativeLocator.above((WebElement) element); + } else if (element instanceof SearchSupplier) { + relativeLocator = relativeLocator.above(performFind(searchContext, (SearchSupplier) element)); + } + } + } + + if (!belowList.isEmpty()) { + for (var element : belowList) { + if (element instanceof By) { + relativeLocator = relativeLocator.below((By) element); + } else if (element instanceof WebElement) { + relativeLocator = relativeLocator.below((WebElement) element); + } else if (element instanceof SearchSupplier) { + relativeLocator = relativeLocator.below(performFind(searchContext, (SearchSupplier) element)); + } + } + } + + if (!toLeftOfList.isEmpty()) { + for (var element : toLeftOfList) { + if (element instanceof By) { + relativeLocator = relativeLocator.toLeftOf((By) element); + } else if (element instanceof WebElement) { + relativeLocator = relativeLocator.toLeftOf((WebElement) element); + } else if (element instanceof SearchSupplier) { + relativeLocator = relativeLocator.toLeftOf(performFind(searchContext, (SearchSupplier) element)); + } + } + } + + if (!toRightOfList.isEmpty()) { + for (var element : toRightOfList) { + if (element instanceof By) { + relativeLocator = relativeLocator.toRightOf((By) element); + } else if (element instanceof WebElement) { + relativeLocator = relativeLocator.toRightOf((WebElement) element); + } else if (element instanceof SearchSupplier) { + relativeLocator = relativeLocator.toRightOf(performFind(searchContext, (SearchSupplier) element)); + } + } + } + + if (!nearList.isEmpty()) { + for (var element : nearList) { + if (element instanceof By) { + relativeLocator = relativeLocator.near((By) element); + } else if (element instanceof WebElement) { + relativeLocator = relativeLocator.near((WebElement) element); + } else if (element instanceof SearchSupplier) { + relativeLocator = relativeLocator.near(performFind(searchContext, (SearchSupplier) element)); + } + } + } + + if (!nearWithDistance.isEmpty()) { + for (var element : nearWithDistance.entrySet()) { + if (element.getKey() instanceof By) { + relativeLocator = relativeLocator.near((By) element.getKey(), element.getValue()); + } else if (element.getKey() instanceof WebElement) { + relativeLocator = relativeLocator.near((WebElement) element.getKey(), element.getValue()); + } else if (element.getKey() instanceof SearchSupplier) { + relativeLocator = relativeLocator.near(performFind(searchContext, (SearchSupplier) element.getKey()), element.getValue()); + } + } + } + + fullBy = relativeLocator; + } + @Override public List apply(SearchContext searchContext) { - return new ArrayList<>(searchContext.findElements(by) - .stream().map(webElement -> createProxy(webElement.getClass(), new WebElementInterceptor(webElement, by))) - .collect(toList())) { + if (!isBuildStarted) { + buildLocator(searchContext); + } + return new ArrayList<>(searchContext.findElements(fullBy).stream() + .map(webElement -> createProxy(webElement.getClass(), new WebElementInterceptor(webElement, fullBy))).collect(toList())) { public String toString() { if (size() == 0) { diff --git a/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindWidgets.java b/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindWidgets.java index 9875cbb3a2..9268954eb0 100644 --- a/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindWidgets.java +++ b/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/FindWidgets.java @@ -8,7 +8,6 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; -import java.util.function.Function; import java.util.function.Predicate; import static com.google.common.base.Preconditions.checkArgument; @@ -21,7 +20,7 @@ import static ru.tinkoff.qa.neptune.selenium.functions.searching.ToStringFormer.getMultipleToString; import static ru.tinkoff.qa.neptune.selenium.functions.searching.WidgetPriorityComparator.widgetPriorityComparator; -class FindWidgets implements Function> { +class FindWidgets extends FindElementsBuilder> { private static final FindByBuilder BUILDER = new FindByBuilder(); private static final List> SCAN_RESULT = new ArrayList<>(new ClassGraph() @@ -95,7 +94,7 @@ public String toString() { return getMultipleToString(this); } }; - + //TODO информация о классах и их By должна инициализироваться до момента выполнения функции classesToInstantiate.forEach(clazz -> { var by = BUILDER.buildIt(clazz); result.addAll(searchContext.findElements(by).stream() @@ -104,4 +103,8 @@ public String toString() { }); return result; } + + @Override + protected void buildLocator(SearchContext searchContext) { + } } diff --git a/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/MultipleSearchSupplier.java b/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/MultipleSearchSupplier.java index f01cae8c67..a6865aac91 100644 --- a/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/MultipleSearchSupplier.java +++ b/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/MultipleSearchSupplier.java @@ -18,7 +18,6 @@ import java.time.Duration; import java.util.List; -import java.util.function.Function; import static ru.tinkoff.qa.neptune.core.api.steps.Criteria.OR; import static ru.tinkoff.qa.neptune.selenium.functions.searching.CommonElementCriteria.*; @@ -37,8 +36,11 @@ public final class MultipleSearchSupplier extends SequentialGetStepSupplier.GetListChainedStepSupplier, SearchContext, R, MultipleSearchSupplier> { - private MultipleSearchSupplier(Function> originalFunction) { + private final FindElementsBuilder findBuilder; + + private MultipleSearchSupplier(FindElementsBuilder> originalFunction) { super(originalFunction); + findBuilder = originalFunction; from(new SearchingInitialFunction()); timeOut(ELEMENT_WAITING_DURATION.get()); addIgnored(StaleElementReferenceException.class); @@ -686,6 +688,36 @@ public MultipleSearchSupplier timeOut(Duration timeOut) { return super.timeOut(timeOut); } + public MultipleSearchSupplier above(Object by) { + findBuilder.above(by); + return this; + } + + public MultipleSearchSupplier below(Object by) { + findBuilder.below(by); + return this; + } + + public MultipleSearchSupplier toLeftOf(Object by) { + findBuilder.toLeftOf(by); + return this; + } + + public MultipleSearchSupplier toRightOf(Object by) { + findBuilder.toRightOf(by); + return this; + } + + public MultipleSearchSupplier near(Object by) { + findBuilder.near(by); + return this; + } + + public MultipleSearchSupplier near(Object by, Integer distance) { + findBuilder.near(by, distance); + return this; + } + @Override public MultipleSearchSupplier clone() { return super.clone(); diff --git a/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/SearchSupplier.java b/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/SearchSupplier.java index afc265f4d8..7169fb2e06 100644 --- a/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/SearchSupplier.java +++ b/selenium/src/main/java/ru/tinkoff/qa/neptune/selenium/functions/searching/SearchSupplier.java @@ -14,7 +14,6 @@ import ru.tinkoff.qa.neptune.selenium.captors.WebElementImageCaptor; import java.time.Duration; -import java.util.function.Function; import static ru.tinkoff.qa.neptune.core.api.steps.Criteria.OR; import static ru.tinkoff.qa.neptune.selenium.functions.searching.CommonElementCriteria.*; @@ -36,8 +35,11 @@ public final class SearchSupplier extends SequentialGetStepSupplier.GetObjectFromIterableChainedStepSupplier> { - private > SearchSupplier(Function originalFunction) { + private final FindElementsBuilder findBuilder; + + private > SearchSupplier(FindElementsBuilder originalFunction) { super(originalFunction); + findBuilder = originalFunction; from(new SearchingInitialFunction()); timeOut(ELEMENT_WAITING_DURATION.get()); addIgnored(StaleElementReferenceException.class); @@ -681,6 +683,36 @@ public SearchSupplier timeOut(Duration timeOut) { return super.timeOut(timeOut); } + public SearchSupplier above(Object by) { + findBuilder.above(by); + return this; + } + + public SearchSupplier below(Object by) { + findBuilder.below(by); + return this; + } + + public SearchSupplier toLeftOf(Object by) { + findBuilder.toLeftOf(by); + return this; + } + + public SearchSupplier toRightOf(Object by) { + findBuilder.toRightOf(by); + return this; + } + + public SearchSupplier near(Object by) { + findBuilder.near(by); + return this; + } + + public SearchSupplier near(Object by, Integer distance) { + findBuilder.near(by, distance); + return this; + } + @Override public SearchSupplier clone() { return super.clone();