[java-idp-integration-tests] branch main updated: Attempt to fix Safari tests - retry stale element reference exceptions

Tom Zeller tzeller at dragonacea.biz
Sun Sep 15 01:13:06 UTC 2024


This is an automated email from the git hooks/post-receive script.

tzeller pushed a commit to branch main
in repository java-idp-integration-tests.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-integration-tests.git;a=commit;h=4bdeea5521e9bd1349d20705d45309ac7a9f260d

The following commit(s) were added to refs/heads/main by this push:
     new 4bdeea5  Attempt to fix Safari tests - retry stale element reference exceptions
4bdeea5 is described below

commit 4bdeea5521e9bd1349d20705d45309ac7a9f260d
Author: Tom Zeller <tzeller at dragonacea.biz>
AuthorDate: Sat Sep 14 20:12:55 2024 -0500

    Attempt to fix Safari tests - retry stale element reference exceptions
    
    Add a little sleep time when attempting to click.
    
    Decrease some Sauce Labs logging.
---
 .../idp/integration/tests/BaseIntegrationTest.java | 135 ++++++++++++++++-----
 .../tests/consent/UserPrefsRevokeConsentTest.java  |   2 +-
 2 files changed, 106 insertions(+), 31 deletions(-)

diff --git a/src/test/java/net/shibboleth/idp/integration/tests/BaseIntegrationTest.java b/src/test/java/net/shibboleth/idp/integration/tests/BaseIntegrationTest.java
index c7fac2f..d732627 100644
--- a/src/test/java/net/shibboleth/idp/integration/tests/BaseIntegrationTest.java
+++ b/src/test/java/net/shibboleth/idp/integration/tests/BaseIntegrationTest.java
@@ -1661,27 +1661,16 @@ public abstract class BaseIntegrationTest {
      */
     public DesiredCapabilities setUpDesiredCapabilities() {
 
-        log.trace("System property      SAUCE_ONDEMAND_BROWSERS  '{}'", System.getProperty("SAUCE_ONDEMAND_BROWSERS"));
-        log.trace("System property      SELENIUM_PLATFORM        '{}'", System.getProperty("SELENIUM_PLATFORM"));
-        log.trace("System property      SELENIUM_BROWSER         '{}'", System.getProperty("SELENIUM_BROWSER"));
-        log.trace("System property      SELENIUM_VERSION         '{}'", System.getProperty("SELENIUM_VERSION"));
-        log.trace("System property      SELENIUM_DEVICE          '{}'", System.getProperty("SELENIUM_DEVICE"));
-        log.trace("Environment variable SAUCE_ONDEMAND_BROWSERS  '{}'", System.getenv("SAUCE_ONDEMAND_BROWSERS"));
-        log.trace("Environment variable SELENIUM_PLATFORM        '{}'", System.getenv("SELENIUM_PLATFORM"));
-        log.trace("Environment variable SELENIUM_BROWSER         '{}'", System.getenv("SELENIUM_BROWSER"));
-        log.trace("Environment variable SELENIUM_VERSION         '{}'", System.getenv("SELENIUM_VERSION"));
-        log.trace("Environment variable SELENIUM_DEVICE          '{}'", System.getenv("SELENIUM_DEVICE"));
-
         // prefer system properties to environment variable
         final String platform = System.getProperty("SELENIUM_PLATFORM", System.getenv("SELENIUM_PLATFORM"));
-        final String browser = System.getProperty("SELENIUM_BROWSER", System.getenv("SELENIUM_BROWSER"));
-        final String version = System.getProperty("SELENIUM_VERSION", System.getenv("SELENIUM_VERSION"));
-        final String device = System.getProperty("SELENIUM_DEVICE", System.getenv("SELENIUM_DEVICE"));
+        final String browser  = System.getProperty("SELENIUM_BROWSER",  System.getenv("SELENIUM_BROWSER"));
+        final String version  = System.getProperty("SELENIUM_VERSION",  System.getenv("SELENIUM_VERSION"));
+        final String device   = System.getProperty("SELENIUM_DEVICE",   System.getenv("SELENIUM_DEVICE"));
 
-        log.debug("SELENIUM_PLATFORM '{}'", platform);
-        log.debug("SELENIUM_BROWSER  '{}'", browser);
-        log.debug("SELENIUM_VERSION  '{}'", version);
-        log.debug("SELENIUM_DEVICE   '{}'", device);
+        log.debug("SELENIUM_PLATFORM '{}' sys prop '{}' env var '{}'", platform, System.getProperty("SELENIUM_PLATFORM"), System.getenv("SELENIUM_PLATFORM"));
+        log.debug("SELENIUM_BROWSER  '{}' sys prop '{}' env var '{}'", browser,  System.getProperty("SELENIUM_BROWSER"),  System.getenv("SELENIUM_BROWSER"));
+        log.debug("SELENIUM_VERSION  '{}' sys prop '{}' env var '{}'", version,  System.getProperty("SELENIUM_VERSION"),  System.getenv("SELENIUM_VERSION"));
+        log.debug("SELENIUM_DEVICE   '{}' sys prop '{}' env var '{}'", device,   System.getProperty("SELENIUM_DEVICE"),   System.getenv("SELENIUM_DEVICE"));
 
         final DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
 
@@ -1848,12 +1837,25 @@ public abstract class BaseIntegrationTest {
     /**
      * Get the source of the last page loaded.
      * 
+     * Catches {@link StaleElementReferenceException} and retries 3 times.
+     * 
      * @return the source of the last page loaded or <code>null</code>
      */
     @Nullable
     public String getPageSource() {
-        final String pageSource = driver.findElement(By.tagName("body")).getText();
-        log.trace("get page source\n{}", pageSource);
+        String pageSource = null;
+        int retries = 0;
+        while (retries < 3) {
+            try {
+                pageSource = driver.findElement(By.tagName("body")).getText();
+                break;
+            } catch (final StaleElementReferenceException e) {
+                log.debug("Will retry attempt to get page source, caught stale element exception", e);
+                sleep(100);
+                retries++;
+            }
+        }
+        log.trace("Get page source :\n{}", pageSource);
         return pageSource;
     }
 
@@ -1972,7 +1974,7 @@ public abstract class BaseIntegrationTest {
     public void acceptTermsOfUse() {
         final WebElement element = driver.findElement(By.name(CONSENT_IDS_INPUT_NAME));
         if (!element.isSelected()) {
-            clickWorkaround(element);
+            clickWorkaroundWithRetry(element);
         }
     }
 
@@ -2099,22 +2101,22 @@ public abstract class BaseIntegrationTest {
     public void releaseEmailAttributeOnly() {
         final WebElement email = driver.findElement(By.id(EMAIL_ID));
         if (!email.isSelected()) {
-            clickWorkaround(email);
+            clickWorkaroundWithRetry(email);
         }
 
         final WebElement eduPersonAffiliation = driver.findElement(By.id(EDU_PERSON_AFFILIATION_ID));
         if (eduPersonAffiliation.isSelected()) {
-            clickWorkaround(eduPersonAffiliation);
+            clickWorkaroundWithRetry(eduPersonAffiliation);
         }
 
         final WebElement eduPersonPrincipalName = driver.findElement(By.id(EDU_PERSON_PRINCIPAL_NAME_ID));
         if (eduPersonPrincipalName.isSelected()) {
-            clickWorkaround(eduPersonPrincipalName);
+            clickWorkaroundWithRetry(eduPersonPrincipalName);
         }
 
         final WebElement uid = driver.findElement(By.id(UID_ID));
         if (uid.isSelected()) {
-            clickWorkaround(uid);
+            clickWorkaroundWithRetry(uid);
         }
     }
 
@@ -2124,7 +2126,7 @@ public abstract class BaseIntegrationTest {
     public void rememberConsent() {
         final WebElement element = driver.findElement(By.id(REMEMBER_CONSENT_ID));
         if (!element.isSelected()) {
-            clickWorkaround(element);
+            clickWorkaroundWithRetry(element);
         }
     }
 
@@ -2134,7 +2136,7 @@ public abstract class BaseIntegrationTest {
     public void doNotRememberConsent() {
         final WebElement element = driver.findElement(By.id(DO_NOT_REMEMBER_CONSENT_ID));
         if (!element.isSelected()) {
-            clickWorkaround(element);
+            clickWorkaroundWithRetry(element);
         }
     }
 
@@ -2144,7 +2146,7 @@ public abstract class BaseIntegrationTest {
     public void globalConsent() {
         final WebElement element = driver.findElement(By.id(GLOBAL_CONSENT_ID));
         if (!element.isSelected()) {
-            clickWorkaround(element);
+            clickWorkaroundWithRetry(element);
         }
     }
 
@@ -2231,7 +2233,7 @@ public abstract class BaseIntegrationTest {
      */
     public void clickWorkaround(final WebElement element) throws RuntimeException {
         boolean isSelected = element.isSelected();
-        log.trace("ClickWorkaround element '{}' isSelected '{}'", element, element.isSelected());
+        log.trace("Click workaround element '{}' isSelected '{}'", element, element.isSelected());
         try {
             // Try clicking element
             log.trace("Attempting to click element '{}'", element);
@@ -2242,6 +2244,7 @@ public abstract class BaseIntegrationTest {
             // Try moving to element and clicking, element must be in viewport
             try {
                 log.trace("Attempting to move to element and click '{}'", element);
+                sleep(100);
                 action.moveToElement(element).click().perform();
             } catch (org.openqa.selenium.interactions.MoveTargetOutOfBoundsException e1) {
                 log.trace("Unable to move to element '{}' out of bounds, will try JavaScript", element);
@@ -2251,11 +2254,12 @@ public abstract class BaseIntegrationTest {
             // If element is still not clicked, try JavaScript
             if ((isSelected && element.isSelected()) || (!isSelected && !element.isSelected())) {
                 log.trace("Attempting JavaScript to click element '{}'", element);
+                sleep(100);
                 final JavascriptExecutor js = (JavascriptExecutor) driver;
                 js.executeScript("arguments[0].click();", element);
             }
         }
-        log.trace("ClickWorkaround element '{}' isSelected '{}'", element, element.isSelected());
+        log.trace("Click workaround element '{}' isSelected '{}'", element, element.isSelected());
         // If element is not clicked, throw runtime exception
         if ((isSelected && element.isSelected()) || (!isSelected && !element.isSelected())) {
             log.error("Unable to click element '{}'", element);
@@ -2263,6 +2267,63 @@ public abstract class BaseIntegrationTest {
         }
     }
 
+    /**
+     * Call {@link #clickWorkaround()} twice if {@link StaleElementReferenceException} is thrown.
+     * 
+     * @param element
+     *            element to be clicked
+     * @throws RuntimeException
+     *             if element is not clicked
+     */
+    public void clickWorkaroundWithRetry(final WebElement element) throws RuntimeException {
+        try {
+            log.debug("Calling click workaround first for element '{}'", element);
+            clickWorkaround(element);
+        } catch (final StaleElementReferenceException e) {
+            log.debug("Caught stale element exception", e);
+            final By by = getByFromElement(element);
+            final WebElement refreshedElement = driver.findElement(by);
+            log.debug("Calling click workaround again for element '{}'", refreshedElement);
+            clickWorkaround(refreshedElement);
+        }
+    }
+
+    /**
+     * Get the {@link By} locator for the {@link WebElement}.
+     * 
+     * @param element
+     *            the {@link WebElement}
+     * @return the {@link By} locator
+     * @throws {@link
+     *             IllegalStateException} if locator can not be determined
+     */
+    @Nonnull
+    protected By getByFromElement(@Nonnull final WebElement element) {
+        // Pattern should match [[SafariDriver: Safari on mac (UUID)] -> id: uid]
+        final Pattern pattern = Pattern.compile(".*? -> (\\w+): (\\w+)]");
+
+        final Matcher matcher = pattern.matcher(element.toString());
+        Assert.assertTrue(matcher.find());
+
+        final String selector = matcher.group(1);
+        final String value = matcher.group(2);
+
+        By by = null;
+        switch (selector) {
+            case "id"              -> by = By.id(value);
+            case "className"       -> by = By.className(value);
+            case "tagName"         -> by = By.tagName(value);
+            case "xpath"           -> by = By.xpath(value);
+            case "cssSelector"     -> by = By.cssSelector(value);
+            case "linkText"        -> by = By.linkText(value);
+            case "name"            -> by = By.name(value);
+            case "partialLinkText" -> by = By.partialLinkText(value);
+            default -> throw new IllegalStateException("Unable to determine locator from element " + element);
+        }
+        log.debug("Get locator '{}' from element '{}'", by, element);
+        return by;
+    }
+
     /**
      * Log output of process.
      * 
@@ -3162,4 +3223,18 @@ public abstract class BaseIntegrationTest {
         return matcher.find() ? matcher.group(1) : null;
     }
 
+    /**
+     * Sleep and catch any {@link InterruptedException}.
+     * 
+     * @param millis
+     *            the length of time to sleep in milliseconds
+     */
+    public void sleep(@Nonnull final long millis) {
+        try {
+            Thread.sleep(millis);
+        } catch (final InterruptedException e) {
+            log.error("Unable to sleep", e);
+        }
+    }
+
 }
diff --git a/src/test/java/net/shibboleth/idp/integration/tests/consent/UserPrefsRevokeConsentTest.java b/src/test/java/net/shibboleth/idp/integration/tests/consent/UserPrefsRevokeConsentTest.java
index aa57fab..61da414 100644
--- a/src/test/java/net/shibboleth/idp/integration/tests/consent/UserPrefsRevokeConsentTest.java
+++ b/src/test/java/net/shibboleth/idp/integration/tests/consent/UserPrefsRevokeConsentTest.java
@@ -112,7 +112,7 @@ public class UserPrefsRevokeConsentTest extends AbstractSAML2IntegrationTest {
         // check the un-checked revoke consent checkbox
         WebElement revokeConsentCheckbox = driver.findElement(By.id(REVOKE_CONSENT_ID));
         Assert.assertFalse(revokeConsentCheckbox.isSelected());
-        clickWorkaround(revokeConsentCheckbox);
+        clickWorkaroundWithRetry(revokeConsentCheckbox);
 
         // start login flow again, should prompt for consent
 

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list