diff --git a/.github/workflows/e2eTests.yml b/.github/workflows/e2eTests.yml index fd2991e86b8..cb552f309d9 100644 --- a/.github/workflows/e2eTests.yml +++ b/.github/workflows/e2eTests.yml @@ -296,7 +296,7 @@ jobs: maven-version: 3.9.5 - name: Run tests continue-on-error: true - run: mvn -e test "-DretryMaximumNumberOfAttempts=1" "-DexecutionAddress=local" "-DtargetOperatingSystem=MAC" "-DtargetBrowserName=SAFARI" "-DgenerateAllureReportArchive=true" "-Dtest=${GLOBAL_TESTING_SCOPE}" + run: mvn -e test "-DsetThreadCount=1" "-DretryMaximumNumberOfAttempts=1" "-DexecutionAddress=local" "-DtargetOperatingSystem=MAC" "-DtargetBrowserName=SAFARI" "-DgenerateAllureReportArchive=true" "-Dtest=${GLOBAL_TESTING_SCOPE}" - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: @@ -336,7 +336,7 @@ jobs: chrome-version: stable - name: Run tests continue-on-error: true - run: mvn -e test "-DretryMaximumNumberOfAttempts=1" "-DexecutionAddress=local" "-DtargetOperatingSystem=MAC" "-DtargetBrowserName=chrome" "-DheadlessExecution=true" "-DgenerateAllureReportArchive=true" "-Dtest=${GLOBAL_TESTING_SCOPE}" + run: mvn -e test "-DsetThreadCount=1" "-DretryMaximumNumberOfAttempts=1" "-DexecutionAddress=local" "-DtargetOperatingSystem=MAC" "-DtargetBrowserName=chrome" "-DheadlessExecution=true" "-DgenerateAllureReportArchive=true" "-Dtest=${GLOBAL_TESTING_SCOPE}" - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: @@ -516,7 +516,7 @@ jobs: maven-version: 3.9.5 - name: Run tests continue-on-error: true - run: mvn -e test "-DretryMaximumNumberOfAttempts=1" "-DexecutionAddress=browserstack" "-DtargetOperatingSystem=MAC" "-DtargetBrowserName=Safari" "-DbrowserStack.os=OS X" "-DbrowserStack.osVersion=Sonoma" "-DbrowserStack.browserVersion=17.0" "-DgenerateAllureReportArchive=true" "-Dtest=%regex[.*BrowserActionsTests.*], %regex[.*BigPageActionsTest.*]" + run: mvn -e test "-DsetThreadCount=1" "-DretryMaximumNumberOfAttempts=1" "-DexecutionAddress=browserstack" "-DtargetOperatingSystem=MAC" "-DtargetBrowserName=Safari" "-DbrowserStack.os=OS X" "-DbrowserStack.osVersion=Sonoma" "-DbrowserStack.browserVersion=17.0" "-DgenerateAllureReportArchive=true" "-Dtest=%regex[.*BrowserActionsTests.*], %regex[.*BigPageActionsTest.*]" - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: @@ -649,7 +649,7 @@ jobs: maven-version: 3.9.5 - name: Run tests continue-on-error: true - run: mvn -e test "-DretryMaximumNumberOfAttempts=1" "-DexecutionAddress=browserstack" "-DtargetOperatingSystem=MAC" "-DtargetBrowserName=Safari" "-DmaximumPerformanceMode=1" "-DbrowserStack.os=OS X" "-DbrowserStack.osVersion=Sonoma" "-DbrowserStack.browserVersion=17.0" -DgenerateAllureReportArchive="true" -Dtest="%regex[.*CucumberTests.*]" + run: mvn -e test "-DsetThreadCount=1" "-DretryMaximumNumberOfAttempts=1" "-DexecutionAddress=browserstack" "-DtargetOperatingSystem=MAC" "-DtargetBrowserName=Safari" "-DmaximumPerformanceMode=1" "-DbrowserStack.os=OS X" "-DbrowserStack.osVersion=Sonoma" "-DbrowserStack.browserVersion=17.0" -DgenerateAllureReportArchive="true" -Dtest="%regex[.*CucumberTests.*]" - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: diff --git a/src/main/java/com/shaft/driver/internal/DriverFactory/DriverFactoryHelper.java b/src/main/java/com/shaft/driver/internal/DriverFactory/DriverFactoryHelper.java index dff560abca3..181852e3bfa 100644 --- a/src/main/java/com/shaft/driver/internal/DriverFactory/DriverFactoryHelper.java +++ b/src/main/java/com/shaft/driver/internal/DriverFactory/DriverFactoryHelper.java @@ -308,12 +308,23 @@ private void createNewLocalDriverInstance(DriverType driverType, int retryAttemp } ReportManager.log(initialLog.replace("Attempting to run locally on", "Successfully Opened") + "."); } catch (Exception exception) { - if (exception.getMessage().contains("cannot create default profile directory")) { + String message = exception.getMessage(); + if (message.contains("cannot create default profile directory")) { // this exception happens when the profile directory is not correct, very specific case // should fail immediately failAction("Failed to create new Browser Session", exception); - } - if (exception.getMessage().contains("Failed to initialize BiDi Mapper")) { + } else if (message.contains("DevToolsActivePort file doesn't exist")) { + // this exception was observed with `Windows_Edge_Local` pipeline to happen randomly + // suggested fix as per titus fortner: https://bugs.chromium.org/p/chromedriver/issues/detail?id=4403#c35 + + var chOptions = optionsManager.getChOptions(); + chOptions.addArguments("--remote-debugging-pipe"); + optionsManager.setChOptions(chOptions); + + var edOptions = optionsManager.getEdOptions(); + edOptions.addArguments("--remote-debugging-pipe"); + optionsManager.setEdOptions(edOptions); + } else if (message.contains("Failed to initialize BiDi Mapper")) { // this exception happens in some corner cases where the capabilities are not compatible with BiDi mode // should force disable BiDi and try again SHAFT.Properties.platform.set().enableBiDi(false); @@ -326,11 +337,10 @@ private void createNewLocalDriverInstance(DriverType driverType, int retryAttemp chOptions.setCapability("webSocketUrl", SHAFT.Properties.platform.enableBiDi()); optionsManager.setChOptions(chOptions); - var EdOptions = optionsManager.getEdOptions(); - EdOptions.setCapability("webSocketUrl", SHAFT.Properties.platform.enableBiDi()); - optionsManager.setEdOptions(EdOptions); - } - if (driverType.equals(DriverType.SAFARI) && Throwables.getRootCause(exception).getMessage().toLowerCase().contains("safari instance is already paired with another webdriver session")) { + var edOptions = optionsManager.getEdOptions(); + edOptions.setCapability("webSocketUrl", SHAFT.Properties.platform.enableBiDi()); + optionsManager.setEdOptions(edOptions); + } else if (driverType.equals(DriverType.SAFARI) && Throwables.getRootCause(exception).getMessage().toLowerCase().contains("safari instance is already paired with another webdriver session")) { //this issue happens when running locally via safari/mac platform // sample failure can be found here: https://github.com/ShaftHQ/SHAFT_ENGINE/actions/runs/4527911969/jobs/7974202314#step:4:46621 // attempting blind fix by trying to quit existing safari instances if any @@ -339,16 +349,7 @@ private void createNewLocalDriverInstance(DriverType driverType, int retryAttemp } catch (Throwable throwable) { // ignore } - } - // attempting blind fix by trying to quit existing driver if any - try { - driver.quit(); - } catch (Throwable throwable) { - // ignore - } finally { - setDriver(null); - } - if (exception.getMessage().contains("java.util.concurrent.TimeoutException")) { + } else if (exception.getMessage().contains("java.util.concurrent.TimeoutException")) { // this happens in case an auto closable BiDi session was left hanging // the default timeout is 30 seconds, so this wait will waste 26 and the following will waste 5 more // the desired effect will be to wait for the bidi session to timeout @@ -358,6 +359,15 @@ private void createNewLocalDriverInstance(DriverType driverType, int retryAttemp //do nothing } } + // attempting blind fix by trying to quit existing driver if any + try { + driver.quit(); + } catch (Throwable throwable) { + // ignore + } finally { + setDriver(null); + } + // evaluating retry attempts if (retryAttempts > 0) { try { Thread.sleep(5000); diff --git a/src/main/java/com/shaft/gui/browser/BrowserActions.java b/src/main/java/com/shaft/gui/browser/BrowserActions.java index 0de2a2dbfef..833b25f2b1f 100644 --- a/src/main/java/com/shaft/gui/browser/BrowserActions.java +++ b/src/main/java/com/shaft/gui/browser/BrowserActions.java @@ -259,8 +259,8 @@ public BrowserActions navigateToURL(String targetUrl, WindowType windowType) { */ public BrowserActions navigateToURL(String targetUrl, String targetUrlAfterRedirection) { //reset scope in case user was stuck inside an iFrame - LocatorBuilder.setIFrameLocator(null); - ShadowLocatorBuilder.shadowDomLocator = null; + LocatorBuilder.getIFrameLocator().remove(); + ShadowLocatorBuilder.shadowDomLocator.remove(); String modifiedTargetUrl = targetUrl; var baseUrl = SHAFT.Properties.web.baseURL(); diff --git a/src/main/java/com/shaft/gui/browser/internal/JavaScriptWaitManager.java b/src/main/java/com/shaft/gui/browser/internal/JavaScriptWaitManager.java index 6070cf8686b..af734272426 100644 --- a/src/main/java/com/shaft/gui/browser/internal/JavaScriptWaitManager.java +++ b/src/main/java/com/shaft/gui/browser/internal/JavaScriptWaitManager.java @@ -2,23 +2,17 @@ import com.shaft.driver.SHAFT; import com.shaft.driver.internal.DriverFactory.DriverFactoryHelper; +import com.shaft.driver.internal.DriverFactory.SynchronizationManager; import com.shaft.tools.internal.support.JavaScriptHelper; -import com.shaft.tools.io.internal.ReportManagerHelper; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; -import org.openqa.selenium.support.ui.ExpectedCondition; -import org.openqa.selenium.support.ui.WebDriverWait; -import java.time.Duration; import java.util.ArrayList; -import java.util.Objects; +import java.util.Arrays; public class JavaScriptWaitManager { - private static final String TARGET_DOCUMENT_READY_STATE = "complete"; private static final ThreadLocal jsWaitDriver = new ThreadLocal<>(); - private static final int delayBetweenPolls = 20; // milliseconds - private static int WAIT_DURATION_INTEGER; - private static JavascriptExecutor jsExec; + private static final ThreadLocal jsExec = new ThreadLocal<>(); private JavaScriptWaitManager() { throw new IllegalStateException("Utility class"); @@ -26,8 +20,7 @@ private JavaScriptWaitManager() { private static void setDriver(WebDriver driver) { jsWaitDriver.set(driver); - jsExec = (JavascriptExecutor) jsWaitDriver.get(); - WAIT_DURATION_INTEGER = SHAFT.Properties.timeouts.lazyLoadingTimeout(); + jsExec.set((JavascriptExecutor) jsWaitDriver.get()); } /** @@ -38,9 +31,9 @@ public static void waitForLazyLoading(WebDriver driver) { if (SHAFT.Properties.timeouts.waitForLazyLoading() && !DriverFactoryHelper.isMobileNativeExecution()) { ArrayList lazyLoadingThreads = new ArrayList<>(); - lazyLoadingThreads.add(Thread.ofVirtual().start(JavaScriptWaitManager::waitForJQueryLoadIfDefined)); - lazyLoadingThreads.add(Thread.ofVirtual().start(JavaScriptWaitManager::waitForAngularIfDefined)); - lazyLoadingThreads.add(Thread.ofVirtual().start(JavaScriptWaitManager::waitForJSLoadIfDefined)); + lazyLoadingThreads.add(Thread.ofVirtual().start(JavaScriptWaitManager::waitForJQuery)); + lazyLoadingThreads.add(Thread.ofVirtual().start(JavaScriptWaitManager::waitForAngular)); + lazyLoadingThreads.add(Thread.ofVirtual().start(JavaScriptWaitManager::waitForDocumentReadyState)); lazyLoadingThreads.forEach(thread -> { try { thread.join(); @@ -51,129 +44,39 @@ public static void waitForLazyLoading(WebDriver driver) { } } - private static void waitForJQueryLoadIfDefined() { - try { - Boolean jQueryDefined = (Boolean) jsExec.executeScript("return typeof jQuery != 'undefined'"); - if (Boolean.TRUE.equals(jQueryDefined)) { - ExpectedCondition jQueryLoad = null; + private static void waitForDocumentReadyState() { + new SynchronizationManager(jsWaitDriver.get()).fluentWait().until(f -> { try { - // Wait for jQuery to load - jQueryLoad = driver -> ((Long) ((JavascriptExecutor) jsWaitDriver.get()) - .executeScript("return jQuery.active") == 0); - } catch (NullPointerException e) { - // do nothing + var ready = Arrays.asList("loaded", "complete"); + return ready.contains(jsExec.get().executeScript(JavaScriptHelper.DOCUMENT_READY_STATE.getValue()).toString()); + } catch (Exception exception) { + // force return in case of unexpected exception + return true; } - // Get JQuery is Ready - boolean jqueryReady = (Boolean) jsExec.executeScript("return jQuery.active==0"); - - if (!jqueryReady) { - // Wait JQuery until it is Ready! - int tryCounter = 0; - while ((!jqueryReady) && (tryCounter < 5)) { - try { - // Wait for jQuery to load - (new WebDriverWait(jsWaitDriver.get(), Duration.ofSeconds(WAIT_DURATION_INTEGER))).until(jQueryLoad); - } catch (NullPointerException e) { - // do nothing - } - sleep(); - tryCounter++; - jqueryReady = (Boolean) jsExec.executeScript("return jQuery.active == 0"); - } - } - } - } catch (Throwable throwable) { - // do nothing - } + }); } - private static void waitForAngularLoad() { - JavascriptExecutor jsExec = (JavascriptExecutor) jsWaitDriver.get(); - - String angularReadyScript = "return angular.element(document).injector().get('$http').pendingRequests.length === 0"; - - // Wait for ANGULAR to load - ExpectedCondition angularLoad = driver -> Boolean - .valueOf(((JavascriptExecutor) Objects.requireNonNull(driver)).executeScript(angularReadyScript).toString()); - - // Get Angular is Ready - boolean angularReady = Boolean.parseBoolean(jsExec.executeScript(angularReadyScript).toString()); - - if (!angularReady) { - // Wait ANGULAR until it is Ready! - int tryCounter = 0; - while ((!angularReady) && (tryCounter < 5)) { - // Wait for Angular to load - (new WebDriverWait(jsWaitDriver.get(), Duration.ofSeconds(WAIT_DURATION_INTEGER))).until(angularLoad); -// ExpectedCondition finalAngularLoad = angularLoad; -// (new WebDriverWait(jsWaitDriver.get(), WAIT_DURATION)).until(waitDriver-> finalAngularLoad); - // More Wait for stability (Optional) - sleep(); - tryCounter++; - angularReady = Boolean.parseBoolean(jsExec.executeScript(angularReadyScript).toString()); - } - } - } - - private static void waitForJSLoadIfDefined() { - try { - JavascriptExecutor jsExec = (JavascriptExecutor) jsWaitDriver.get(); - - // Wait for Javascript to load - ExpectedCondition jsLoad = driver -> ((JavascriptExecutor) jsWaitDriver.get()) - .executeScript(JavaScriptHelper.DOCUMENT_READYSTATE.getValue()).toString().trim() - .equalsIgnoreCase(TARGET_DOCUMENT_READY_STATE); - - // Get JS is Ready - boolean jsReady = jsExec.executeScript(JavaScriptHelper.DOCUMENT_READYSTATE.getValue()).toString().trim() - .equalsIgnoreCase(TARGET_DOCUMENT_READY_STATE); - - // Wait Javascript until it is Ready! - if (!jsReady) { - // Wait JS until it is Ready! - int tryCounter = 0; - while ((!jsReady) && (tryCounter < 5)) { - // Wait for Javascript to load - try { - (new WebDriverWait(jsWaitDriver.get(), Duration.ofSeconds(WAIT_DURATION_INTEGER))).until(jsLoad); - } catch (org.openqa.selenium.TimeoutException e) { - //do nothing - //TODO: confirm that this fixed the timeout issue on the grid - } - // More Wait for stability (Optional) - sleep(); - tryCounter++; - jsReady = jsExec.executeScript(JavaScriptHelper.DOCUMENT_READYSTATE.getValue()).toString().trim() - .equalsIgnoreCase(TARGET_DOCUMENT_READY_STATE); + private static void waitForJQuery() { + new SynchronizationManager(jsWaitDriver.get()).fluentWait().until(f -> { + try { + return Long.parseLong(jsExec.get().executeScript(JavaScriptHelper.JQUERY_ACTIVE_STATE.getValue()).toString()) == 0; + } catch (Exception exception) { + // force return in case of unexpected exception + // org.openqa.selenium.JavascriptException: javascript error: jQuery is not defined + return true; } - } - } catch (Throwable throwable) { - // do nothing - } + }); } - private static void waitForAngularIfDefined() { - try { - Boolean angularDefined = !((Boolean) jsExec.executeScript("return window.angular === undefined")); - if (Boolean.TRUE.equals(angularDefined)) { - Boolean angularInjectorDefined = !((Boolean) jsExec - .executeScript("return angular.element(document).injector() === undefined")); - - if (Boolean.TRUE.equals(angularInjectorDefined)) { - waitForAngularLoad(); - } + private static void waitForAngular() { + new SynchronizationManager(jsWaitDriver.get()).fluentWait().until(f -> { + try { + return Long.parseLong(jsExec.get().executeScript(JavaScriptHelper.ANGULAR_READY_STATE.getValue()).toString()) == 0; + } catch (Exception exception) { + // force return in case of unexpected exception + // org.openqa.selenium.JavascriptException: javascript error: angular is not defined + return true; } - } catch (Throwable throwable) { - // do nothing - } - } - - private static void sleep() { - try { - Thread.sleep(JavaScriptWaitManager.delayBetweenPolls); - } catch (Exception e) { - ReportManagerHelper.logDiscrete(e); - // InterruptedException - } + }); } } \ No newline at end of file diff --git a/src/main/java/com/shaft/gui/element/ElementActions.java b/src/main/java/com/shaft/gui/element/ElementActions.java index 549dcbd0f08..7a662d10dbb 100755 --- a/src/main/java/com/shaft/gui/element/ElementActions.java +++ b/src/main/java/com/shaft/gui/element/ElementActions.java @@ -668,7 +668,7 @@ public ElementActions submitFormUsingJavaScript(By elementLocator) { public ElementActions switchToIframe(By elementLocator) { try { var elementInformation = ElementInformation.fromList(ElementActionsHelper.identifyUniqueElement(driver, elementLocator)); - LocatorBuilder.setIFrameLocator(elementInformation.getLocator()); + LocatorBuilder.getIFrameLocator().set(elementInformation.getLocator()); // note to self: remove elementLocator in case of bug in screenshot manager driver.switchTo().frame(elementInformation.getFirstElement()); boolean discreetLoggingState = ReportManagerHelper.getDiscreteLogging(); @@ -693,7 +693,7 @@ public ElementActions switchToIframe(By elementLocator) { public ElementActions switchToDefaultContent() { try { driver.switchTo().defaultContent(); - LocatorBuilder.setIFrameLocator(null); + LocatorBuilder.getIFrameLocator().remove(); boolean discreetLoggingState = ReportManagerHelper.getDiscreteLogging(); ReportManagerHelper.setDiscreteLogging(true); ElementActionsHelper.passAction(driver, null, Thread.currentThread().getStackTrace()[1].getMethodName(), null, null, null); diff --git a/src/main/java/com/shaft/gui/element/internal/ElementActionsHelper.java b/src/main/java/com/shaft/gui/element/internal/ElementActionsHelper.java index 45a78efb272..4b8ba37fdb6 100644 --- a/src/main/java/com/shaft/gui/element/internal/ElementActionsHelper.java +++ b/src/main/java/com/shaft/gui/element/internal/ElementActionsHelper.java @@ -132,11 +132,15 @@ public static List waitForElementPresence(WebDriver driver, By elementLo final WebElement[] targetElement = new WebElement[1]; ElementInformation elementInformation = new ElementInformation(); // BLOCK #1 :: GETTING THE ELEMENT - if (ShadowLocatorBuilder.shadowDomLocator != null && ShadowLocatorBuilder.cssSelector == elementLocator) { - targetElement[0] = driver.findElement(ShadowLocatorBuilder.shadowDomLocator).getShadowRoot().findElement(ShadowLocatorBuilder.cssSelector); - } else if (LocatorBuilder.getIFrameLocator() != null) { + By shadowDomLocator = ShadowLocatorBuilder.shadowDomLocator.get(); + By cssSelector = ShadowLocatorBuilder.cssSelector.get(); + if (shadowDomLocator != null && cssSelector == elementLocator) { + targetElement[0] = driver.findElement(shadowDomLocator) + .getShadowRoot() + .findElement(cssSelector); + } else if (LocatorBuilder.getIFrameLocator().get() != null) { try { - targetElement[0] = driver.switchTo().frame(driver.findElement(LocatorBuilder.getIFrameLocator())).findElement(elementLocator); + targetElement[0] = driver.switchTo().frame(driver.findElement(LocatorBuilder.getIFrameLocator().get())).findElement(elementLocator); } catch (NoSuchElementException exception) { targetElement[0] = driver.findElement(elementLocator); } @@ -181,8 +185,11 @@ public static List waitForElementPresence(WebDriver driver, By elementLo }); var threadCount = myExecutor.submit(() -> { // BLOCK #4 :: GETTING THE NUMBER OF FOUND ELEMENTS - if (ShadowLocatorBuilder.shadowDomLocator != null && ShadowLocatorBuilder.cssSelector == elementLocator) { - elementInformation.setNumberOfFoundElements(driver.findElement(ShadowLocatorBuilder.shadowDomLocator).getShadowRoot().findElements(ShadowLocatorBuilder.cssSelector).size()); + if (shadowDomLocator != null && cssSelector == elementLocator) { + elementInformation.setNumberOfFoundElements(driver.findElement(shadowDomLocator) + .getShadowRoot() + .findElements(cssSelector) + .size()); } else { elementInformation.setNumberOfFoundElements(driver.findElements(elementLocator).size()); } @@ -280,6 +287,7 @@ private static String performAction(WebDriver driver, ElementInformation element } catch (Throwable throwable) { //ignored } + //perform click try { elementInformation.getFirstElement().click(); } catch (Throwable throwable) { diff --git a/src/main/java/com/shaft/gui/internal/locator/LocatorBuilder.java b/src/main/java/com/shaft/gui/internal/locator/LocatorBuilder.java index dd0bc2da6c4..58718155565 100644 --- a/src/main/java/com/shaft/gui/internal/locator/LocatorBuilder.java +++ b/src/main/java/com/shaft/gui/internal/locator/LocatorBuilder.java @@ -1,21 +1,18 @@ package com.shaft.gui.internal.locator; import lombok.Getter; -import lombok.Setter; import org.openqa.selenium.By; import org.openqa.selenium.support.locators.RelativeLocator; import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; public class LocatorBuilder { - @Setter @Getter - static By iFrameLocator; - + static ThreadLocal iFrameLocator = new ThreadLocal<>(); @Getter - static By shadowDomLocator; - @Setter - private static Locators mode = Locators.XPATH; + static ThreadLocal shadowDomLocator = new ThreadLocal<>(); + private static final ThreadLocal mode = new ThreadLocal<>(); String partialXpath; private String tagName = "*"; private ArrayList parameters = new ArrayList<>(); @@ -27,6 +24,7 @@ private LocatorBuilder() { } private LocatorBuilder(String tagName, ArrayList parameters, @SuppressWarnings("SameParameterValue") String order) { + mode.set(Locators.XPATH); this.tagName = tagName; this.parameters = parameters; this.order = order; @@ -110,13 +108,15 @@ public RelativeLocator.RelativeBy relativeBy() { } public XpathAxis axisBy() { - mode = Locators.XPATH; + mode.set(Locators.XPATH); partialXpath = buildXpathExpression(); return new XpathAxis(this); } public By build() { - if (mode == Locators.CSS) { + AtomicBoolean isShadowElement = new AtomicBoolean(false); + parameters.forEach(parameter -> isShadowElement.set(parameter.toLowerCase().contains("shadow"))); + if (mode.get() == Locators.CSS || isShadowElement.get()) { return By.cssSelector(buildSelectorExpression()); } return By.xpath(buildXpathExpression()); @@ -158,6 +158,7 @@ String buildSelectorExpression() { } public ShadowLocatorBuilder insideShadowDom(By shadowDomLocator) { + mode.set(Locators.CSS); return new ShadowLocatorBuilder(shadowDomLocator, By.cssSelector(buildSelectorExpression())); } } diff --git a/src/main/java/com/shaft/gui/internal/locator/ShadowLocatorBuilder.java b/src/main/java/com/shaft/gui/internal/locator/ShadowLocatorBuilder.java index 80ce0bd5d94..9b4fc0977e6 100644 --- a/src/main/java/com/shaft/gui/internal/locator/ShadowLocatorBuilder.java +++ b/src/main/java/com/shaft/gui/internal/locator/ShadowLocatorBuilder.java @@ -3,16 +3,16 @@ import org.openqa.selenium.By; public class ShadowLocatorBuilder { - public static By shadowDomLocator; - public static By cssSelector; + public static ThreadLocal shadowDomLocator = new ThreadLocal<>(); + public static ThreadLocal cssSelector = new ThreadLocal<>(); public ShadowLocatorBuilder(By shadowDomLocator, By cssSelector) { - ShadowLocatorBuilder.shadowDomLocator = shadowDomLocator; - ShadowLocatorBuilder.cssSelector = cssSelector; + ShadowLocatorBuilder.shadowDomLocator.set(shadowDomLocator); + ShadowLocatorBuilder.cssSelector.set(cssSelector); } public By build() { // this is returned as a placeholder, the real locator is built when the action is being performed and currently supports a limited set of element actions - return cssSelector; + return cssSelector.get(); } } \ No newline at end of file diff --git a/src/main/java/com/shaft/properties/internal/Timeouts.java b/src/main/java/com/shaft/properties/internal/Timeouts.java index da06756ac8c..a8cbcf95d99 100644 --- a/src/main/java/com/shaft/properties/internal/Timeouts.java +++ b/src/main/java/com/shaft/properties/internal/Timeouts.java @@ -20,10 +20,6 @@ private static void setProperty(String key, String value) { @DefaultValue("true") Boolean waitForLazyLoading(); - @Key("lazyLoadingTimeout") - @DefaultValue("30") - int lazyLoadingTimeout(); - @Key("browserNavigationTimeout") @DefaultValue("60") int browserNavigationTimeout(); diff --git a/src/main/java/com/shaft/tools/internal/support/JavaScriptHelper.java b/src/main/java/com/shaft/tools/internal/support/JavaScriptHelper.java index a7115273372..b4e0755e2ca 100644 --- a/src/main/java/com/shaft/tools/internal/support/JavaScriptHelper.java +++ b/src/main/java/com/shaft/tools/internal/support/JavaScriptHelper.java @@ -290,7 +290,9 @@ function getXPath(element) { "(function(){'use strict';var api;api=function(x,y){var elm,scrollX,scrollY,newX,newY;scrollX=window.pageXOffset;scrollY=window.pageYOffset;window.scrollTo(x,y);newX=x-window.pageXOffset;newY=y-window.pageYOffset;elm=this.elementFromPoint(newX,newY);window.scrollTo(scrollX,scrollY);return elm;};this.document.elementFromAbsolutePoint=api;}).call(this);return document.elementFromAbsolutePoint(arguments[0], arguments[1]);"), WINDOW_FOCUS("window.focus();"), WINDOW_RESET_LOCATION("window.moveTo(0,0);"), WINDOW_RESIZE("window.resizeTo($WIDTH,$HEIGHT);"), - DOCUMENT_READYSTATE("return document.readyState"); + DOCUMENT_READY_STATE("return document.readyState;"), + JQUERY_ACTIVE_STATE("return jQuery.active;"), + ANGULAR_READY_STATE("return angular.element(document).injector().get('$http').pendingRequests.length;"); private final String value; diff --git a/src/test/java/testPackage/locator/ShadowDomTest.java b/src/test/java/testPackage/locator/ShadowDomTest.java index 9107e0f8346..bc5fa6b5327 100644 --- a/src/test/java/testPackage/locator/ShadowDomTest.java +++ b/src/test/java/testPackage/locator/ShadowDomTest.java @@ -1,8 +1,6 @@ package testPackage.locator; import com.shaft.driver.SHAFT; -import com.shaft.gui.internal.locator.LocatorBuilder; -import com.shaft.gui.internal.locator.Locators; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.Browser; @@ -37,7 +35,6 @@ public void shaftLocator() { public void beforeMethod() { if (SHAFT.Properties.web.targetBrowserName().equalsIgnoreCase(Browser.CHROME.browserName()) || SHAFT.Properties.web.targetBrowserName().equalsIgnoreCase(Browser.EDGE.browserName())) { - LocatorBuilder.setMode(Locators.CSS); driver.set(new SHAFT.GUI.WebDriver()); } } @@ -46,7 +43,6 @@ public void beforeMethod() { public void afterMethod() { if (SHAFT.Properties.web.targetBrowserName().equalsIgnoreCase(Browser.CHROME.browserName()) || SHAFT.Properties.web.targetBrowserName().equalsIgnoreCase(Browser.EDGE.browserName())) { - LocatorBuilder.setMode(Locators.XPATH); driver.get().quit(); } } @@ -55,7 +51,6 @@ public void afterMethod() { public void shaftLocator_2() { if (SHAFT.Properties.web.targetBrowserName().equalsIgnoreCase(Browser.CHROME.browserName()) || SHAFT.Properties.web.targetBrowserName().equalsIgnoreCase(Browser.EDGE.browserName())) { - LocatorBuilder.setMode(Locators.CSS); driver.get().browser().navigateToURL("https://usercentrics.com"); By shadowDom = By.id("usercentrics-root"); By shadowElement = SHAFT.GUI.Locator.hasTagName("button") diff --git a/src/test/java/testPackage/properties/TimeoutsTests.java b/src/test/java/testPackage/properties/TimeoutsTests.java index c3a365772bf..79c24bd8bb4 100644 --- a/src/test/java/testPackage/properties/TimeoutsTests.java +++ b/src/test/java/testPackage/properties/TimeoutsTests.java @@ -6,7 +6,6 @@ public class TimeoutsTests { Boolean waitForLazyLoading; - int lazyLoadingTimeout; int browserNavigationTimeout; int pageLoadTimeout; int scriptExecutionTimeout; @@ -27,7 +26,6 @@ public class TimeoutsTests { @BeforeClass public void beforeClass() { waitForLazyLoading = SHAFT.Properties.timeouts.waitForLazyLoading(); - lazyLoadingTimeout = SHAFT.Properties.timeouts.lazyLoadingTimeout(); browserNavigationTimeout = SHAFT.Properties.timeouts.browserNavigationTimeout(); pageLoadTimeout = SHAFT.Properties.timeouts.pageLoadTimeout(); scriptExecutionTimeout = SHAFT.Properties.timeouts.scriptExecutionTimeout(); @@ -49,7 +47,6 @@ public void beforeClass() { @Test public void test() { SHAFT.Properties.timeouts.set().waitForLazyLoading(waitForLazyLoading); - SHAFT.Properties.timeouts.set().lazyLoadingTimeout(lazyLoadingTimeout); SHAFT.Properties.timeouts.set().browserNavigationTimeout(browserNavigationTimeout); SHAFT.Properties.timeouts.set().pageLoadTimeout(pageLoadTimeout); SHAFT.Properties.timeouts.set().scriptExecutionTimeout(scriptExecutionTimeout);