From 9928b802db156fa2fe1a46bda15d59350360a205 Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Mon, 7 Aug 2023 13:10:40 +0300 Subject: [PATCH] EPMHLM-340 Support explicitly waits --- pom.xml | 10 +-- .../epam/healenium/SelfHealingDriverWait.java | 61 +++++++++++++++++++ .../com/epam/healenium/SelfHealingEngine.java | 16 ++--- .../healenium/handlers/proxy/BaseHandler.java | 6 ++ .../proxy/WebElementProxyHandler.java | 6 ++ .../healenium/model/ReferenceElementsDto.java | 2 + .../epam/healenium/model/SessionContext.java | 2 + .../processor/FindChildElementProcessor.java | 3 + .../processor/FindElementProcessor.java | 3 + .../GetReferenceElementsProcessor.java | 3 + .../processor/HealingElementsProcessor.java | 2 +- .../epam/healenium/service/NodeService.java | 12 ++-- .../epam/healenium/utils/ProxyFactory.java | 9 +-- src/main/resources/itemsWithAttributes.js | 5 +- 14 files changed, 117 insertions(+), 23 deletions(-) create mode 100644 src/main/java/com/epam/healenium/SelfHealingDriverWait.java diff --git a/pom.xml b/pom.xml index 769be1f..d276762 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ 4.0.0 com.epam.healenium healenium-web - 3.4.3 + 3.4.4 jar healenium-web healenium web client @@ -57,9 +57,9 @@ UTF-8 3.8.4 1.4.2 - 0.4.11 - 4.5.0 - 2.13.4.1 + 0.4.12 + 4.10.0 + 2.15.2 3.12.0 1.15 4.9.3 @@ -67,7 +67,7 @@ 1.4.2.Final 1.18.22 0.8.1 - 10.0.10 + 11.0.15 2.2 6.1.1 1.16.3 diff --git a/src/main/java/com/epam/healenium/SelfHealingDriverWait.java b/src/main/java/com/epam/healenium/SelfHealingDriverWait.java new file mode 100644 index 0000000..f54bc99 --- /dev/null +++ b/src/main/java/com/epam/healenium/SelfHealingDriverWait.java @@ -0,0 +1,61 @@ +package com.epam.healenium; + +import org.openqa.selenium.TimeoutException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.ui.Sleeper; +import org.openqa.selenium.support.ui.WebDriverWait; + +import java.time.Clock; +import java.time.Duration; +import java.util.function.Function; + +public class SelfHealingDriverWait extends WebDriverWait { + + private final WebDriver webDriver; + + public SelfHealingDriverWait(WebDriver driver, Duration timeout) { + super(driver, timeout); + this.webDriver = driver; + } + + public SelfHealingDriverWait(WebDriver driver, Duration timeout, Duration sleep) { + super(driver, timeout, sleep); + this.webDriver = driver; + } + + public SelfHealingDriverWait(WebDriver driver, Duration timeout, Duration sleep, Clock clock, Sleeper sleeper) { + super(driver, timeout, sleep, clock, sleeper); + this.webDriver = driver; + } + + @Override + public V until(Function isTrue) { + if (webDriver instanceof SelfHealingDriver) { + SelfHealingDriver hlmDriver = (SelfHealingDriver) webDriver; + try { + hlmDriver.getCurrentEngine().getSessionContext().setWaitCommand(true); + V until = super.until(isTrue); + hlmDriver.getCurrentEngine().getSessionContext().setWaitCommand(false); + return until; + } catch (TimeoutException timeoutException) { + if (hlmDriver.getCurrentEngine().getSessionContext().isFindElementWaitCommand()) { + hlmDriver.getCurrentEngine().getSessionContext().setWaitCommand(false); + hlmDriver.getCurrentEngine().getSessionContext().setFindElementWaitCommand(false); + V value = isTrue.apply(webDriver); + if (value != null && (Boolean.class != value.getClass() || Boolean.TRUE.equals(value))) { + return value; + } + } + throw timeoutException; + } catch (Exception ex) { + hlmDriver.getCurrentEngine().getSessionContext().setWaitCommand(false); + throw ex; + } + } else { + return super.until(isTrue); + } + } +} + + + diff --git a/src/main/java/com/epam/healenium/SelfHealingEngine.java b/src/main/java/com/epam/healenium/SelfHealingEngine.java index 83b9732..1cbc332 100644 --- a/src/main/java/com/epam/healenium/SelfHealingEngine.java +++ b/src/main/java/com/epam/healenium/SelfHealingEngine.java @@ -101,13 +101,13 @@ public void saveElements(Context context, List webElements) { List storedIds = sessionSelectors.get(by); if (storedIds == null || (!storedIds.containsAll(ids) && storedIds.size() != ids.size())) { sessionSelectors.put(by, ids); - RequestDto requestDto = client.getMapper().buildDto(context.getBy(), context.getAction(), null); - requestDto.setElementIds(ids); + List> nodePath = getNodePath(webElements, context); + if (context.getCurrentUrl() == null) { + context.setCurrentUrl(getCurrentUrl()); + } + RequestDto requestDto = client.getMapper().buildDto(context.getBy(), context.getAction(), context.getCurrentUrl()); requestDto.setSessionId(((RemoteWebDriver) webDriver).getSessionId().toString()); - requestDto.setNodePath(getNodePath(webElements)); - String currentUrl = getCurrentUrl(); - context.setCurrentUrl(currentUrl); - requestDto.setUrl(currentUrl); + requestDto.setNodePath(nodePath); client.saveElements(requestDto); } } catch (Exception e) { @@ -116,9 +116,9 @@ public void saveElements(Context context, List webElements) { } } - public List> getNodePath(List webElements) { + public List> getNodePath(List webElements, Context context) { return webElements.stream() - .map(e -> nodeService.getNodePath(webDriver, e)) + .map(e -> nodeService.getNodePath(webDriver, e, context)) .collect(Collectors.toList()); } diff --git a/src/main/java/com/epam/healenium/handlers/proxy/BaseHandler.java b/src/main/java/com/epam/healenium/handlers/proxy/BaseHandler.java index c99a78d..eccea1b 100644 --- a/src/main/java/com/epam/healenium/handlers/proxy/BaseHandler.java +++ b/src/main/java/com/epam/healenium/handlers/proxy/BaseHandler.java @@ -51,6 +51,9 @@ public BaseHandler(SelfHealingEngine engine) { @Override public WebElement findElement(By by) { try { + if (engine.getSessionContext().isWaitCommand()) { + engine.getSessionContext().setFindElementWaitCommand(true); + } if (engine.isHealingEnabled()) { Context context = new Context() .setBy(by) @@ -82,6 +85,9 @@ public WebElement findElement(By by) { @Override public List findElements(By by) { try { + if (engine.getSessionContext().isWaitCommand()) { + engine.getSessionContext().setFindElementWaitCommand(true); + } if (engine.isHealingEnabled()) { Context context = new Context() .setBy(by) diff --git a/src/main/java/com/epam/healenium/handlers/proxy/WebElementProxyHandler.java b/src/main/java/com/epam/healenium/handlers/proxy/WebElementProxyHandler.java index 38a54b2..ff8c309 100644 --- a/src/main/java/com/epam/healenium/handlers/proxy/WebElementProxyHandler.java +++ b/src/main/java/com/epam/healenium/handlers/proxy/WebElementProxyHandler.java @@ -74,6 +74,9 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl @Override public WebElement findElement(By by) { try { + if (engine.getSessionContext().isWaitCommand()) { + engine.getSessionContext().setFindElementWaitCommand(true); + } PageAwareBy pageBy = awareBy(by); if (engine.isHealingEnabled()) { Context context = new Context() @@ -96,6 +99,9 @@ public WebElement findElement(By by) { @Override public List findElements(By by) { try { + if (engine.getSessionContext().isWaitCommand()) { + engine.getSessionContext().setFindElementWaitCommand(true); + } PageAwareBy pageBy = awareBy(by); By inner = pageBy.getBy(); if (engine.isHealingEnabled()) { diff --git a/src/main/java/com/epam/healenium/model/ReferenceElementsDto.java b/src/main/java/com/epam/healenium/model/ReferenceElementsDto.java index 895c85d..6f5f391 100644 --- a/src/main/java/com/epam/healenium/model/ReferenceElementsDto.java +++ b/src/main/java/com/epam/healenium/model/ReferenceElementsDto.java @@ -2,6 +2,7 @@ import com.epam.healenium.treecomparing.Node; import lombok.Data; +import lombok.ToString; import lombok.experimental.Accessors; import java.util.List; @@ -11,6 +12,7 @@ public class ReferenceElementsDto { private String pageContent; + @ToString.Exclude private List> paths; private List unsuccessfulLocators; } diff --git a/src/main/java/com/epam/healenium/model/SessionContext.java b/src/main/java/com/epam/healenium/model/SessionContext.java index 1b3544c..a548e52 100644 --- a/src/main/java/com/epam/healenium/model/SessionContext.java +++ b/src/main/java/com/epam/healenium/model/SessionContext.java @@ -19,5 +19,7 @@ public class SessionContext { private Map disableHealingElement = new HashMap<>(); private Map> sessionSelectors = new HashMap<>(); private BiFunction functionUrl; + private boolean waitCommand = false; + private boolean findElementWaitCommand = false; } diff --git a/src/main/java/com/epam/healenium/processor/FindChildElementProcessor.java b/src/main/java/com/epam/healenium/processor/FindChildElementProcessor.java index a70ef40..e9fed3a 100644 --- a/src/main/java/com/epam/healenium/processor/FindChildElementProcessor.java +++ b/src/main/java/com/epam/healenium/processor/FindChildElementProcessor.java @@ -25,6 +25,9 @@ public void execute() { engine.saveElements(context, Collections.singletonList(element)); context.getElements().add(element); } catch (NoSuchElementException e) { + if (engine.getSessionContext().isWaitCommand()) { + throw e; + } context.setNoSuchElementException(e); } } diff --git a/src/main/java/com/epam/healenium/processor/FindElementProcessor.java b/src/main/java/com/epam/healenium/processor/FindElementProcessor.java index 03791b8..0bf7732 100644 --- a/src/main/java/com/epam/healenium/processor/FindElementProcessor.java +++ b/src/main/java/com/epam/healenium/processor/FindElementProcessor.java @@ -25,6 +25,9 @@ public void execute() { engine.saveElements(context, Collections.singletonList(element)); context.getElements().add(element); } catch (NoSuchElementException e) { + if (engine.getSessionContext().isWaitCommand()) { + throw e; + } context.setNoSuchElementException(e); } } diff --git a/src/main/java/com/epam/healenium/processor/GetReferenceElementsProcessor.java b/src/main/java/com/epam/healenium/processor/GetReferenceElementsProcessor.java index 2ce34bd..d725605 100644 --- a/src/main/java/com/epam/healenium/processor/GetReferenceElementsProcessor.java +++ b/src/main/java/com/epam/healenium/processor/GetReferenceElementsProcessor.java @@ -20,6 +20,9 @@ public GetReferenceElementsProcessor(BaseProcessor nextProcessor) { @Override public boolean validate() { + if (engine.getSessionContext().isWaitCommand()) { + return false; + } Locator locator = engine.getClient().getMapper().byToLocator(context.getBy()); Map enableHealingSelectors = engine.getSessionContext().getEnableHealingElements(); Map disableHealingSelector = engine.getSessionContext().getDisableHealingElement(); diff --git a/src/main/java/com/epam/healenium/processor/HealingElementsProcessor.java b/src/main/java/com/epam/healenium/processor/HealingElementsProcessor.java index f00e0cc..710186d 100644 --- a/src/main/java/com/epam/healenium/processor/HealingElementsProcessor.java +++ b/src/main/java/com/epam/healenium/processor/HealingElementsProcessor.java @@ -49,7 +49,7 @@ public void execute() { private void splitDbNodes(List> nodesFromDb) { for (WebElement webElement : context.getElements()) { - List nodePath = engine.getNodeService().getNodePath(driver, webElement); + List nodePath = engine.getNodeService().getNodePath(driver, webElement, context); if (!nodesFromDb.contains(nodePath)) { context.getNewElementsToNodes().put(webElement, nodePath); } else { diff --git a/src/main/java/com/epam/healenium/service/NodeService.java b/src/main/java/com/epam/healenium/service/NodeService.java index b02425b..919c55f 100644 --- a/src/main/java/com/epam/healenium/service/NodeService.java +++ b/src/main/java/com/epam/healenium/service/NodeService.java @@ -1,6 +1,7 @@ package com.epam.healenium.service; import com.epam.healenium.FieldName; +import com.epam.healenium.model.Context; import com.epam.healenium.treecomparing.Node; import com.epam.healenium.treecomparing.NodeBuilder; import com.epam.healenium.utils.ResourceReader; @@ -33,11 +34,12 @@ public class NodeService { /** * build list nodes by source webElement * + * @param driver - web driver * @param webElement - source element - * @param driver - web driver + * @param context - find element context dto * @return - list path nodes */ - public List getNodePath(WebDriver driver, WebElement webElement) { + public List getNodePath(WebDriver driver, WebElement webElement, Context context) { JavascriptExecutor executor = (JavascriptExecutor) driver; String data = (String) executor.executeScript(SCRIPT, webElement); List path = new LinkedList<>(); @@ -45,8 +47,10 @@ public List getNodePath(WebDriver driver, WebElement webElement) { try { ObjectMapper mapper = new ObjectMapper(); JsonNode treeNode = mapper.readTree(data); - if (treeNode.isArray()) { - for (final JsonNode jsonNode : treeNode) { + context.setCurrentUrl(treeNode.get("url").textValue()); + JsonNode items = treeNode.get("items"); + if (items.isArray()) { + for (final JsonNode jsonNode : items) { Node node = toNode(mapper.treeAsTokens(jsonNode)); path.add(node); } diff --git a/src/main/java/com/epam/healenium/utils/ProxyFactory.java b/src/main/java/com/epam/healenium/utils/ProxyFactory.java index c5dc6a9..9411178 100644 --- a/src/main/java/com/epam/healenium/utils/ProxyFactory.java +++ b/src/main/java/com/epam/healenium/utils/ProxyFactory.java @@ -13,10 +13,6 @@ package com.epam.healenium.utils; import com.epam.healenium.SelfHealingDriver; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.util.Arrays; -import java.util.stream.Stream; import lombok.experimental.UtilityClass; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; @@ -25,6 +21,11 @@ import org.openqa.selenium.interactions.Interactive; import org.openqa.selenium.interactions.Locatable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.stream.Stream; + @UtilityClass @SuppressWarnings("unchecked") public class ProxyFactory { diff --git a/src/main/resources/itemsWithAttributes.js b/src/main/resources/itemsWithAttributes.js index 5b30fce..9cca1ef 100644 --- a/src/main/resources/itemsWithAttributes.js +++ b/src/main/resources/itemsWithAttributes.js @@ -1,5 +1,6 @@ var items = []; +var result = {items: null, url: null}; var a = arguments[0]; while (a != document) { var child = a; @@ -25,4 +26,6 @@ while (a != document) { items.unshift(node); a = a.parentNode; } -return JSON.stringify(items); \ No newline at end of file +result.items = items; +result.url = window.location.href; +return JSON.stringify(result); \ No newline at end of file