Skip to content

Commit b72d78d

Browse files
committed
Increase timeout and polling constants for WebDriverWait
Use WebDriverWait to wait for the variable to exist (prevents race conditions)
1 parent 00b7aa0 commit b72d78d

File tree

3 files changed

+57
-30
lines changed

3 files changed

+57
-30
lines changed

uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/SessionControllerIntegrationTests.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.junit.jupiter.api.AfterEach;
88
import org.junit.jupiter.api.BeforeEach;
99
import org.junit.jupiter.api.Test;
10+
import org.openqa.selenium.support.ui.WebDriverWait;
1011
import org.springframework.beans.factory.annotation.Autowired;
1112
import org.springframework.beans.factory.annotation.Value;
1213
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@@ -41,22 +42,31 @@ void sessionPageHasTheFunction() {
4142
webDriver.get(baseUrl +
4243
"/session?clientId=admin&messageOrigin=http://localhost:8080");
4344

44-
Object r = webDriver.getJavascriptExecutor().executeScript(
45-
"return typeof(handleMessage);");
46-
assertThat(r).hasToString("function");
45+
WebDriverWait wait = webDriver.createWebDriverWait();
46+
Object type = wait.until(driver -> webDriver.getJavascriptExecutor().executeScript(
47+
"return typeof(handleMessage);"));
48+
49+
assertThat(type).hasToString("function");
4750
}
4851

4952
@Test
5053
void sessionManagementPageHasVariablesSet() {
5154
webDriver.get(baseUrl +
5255
"/session_management?clientId=admin&messageOrigin=http://localhost:8080");
5356

54-
Object clientId = webDriver.getJavascriptExecutor().executeScript(
55-
"return clientId;");
56-
assertThat(clientId).hasToString("admin");
57+
// Use WebDriverWait to wait for the variable to exist (prevents race conditions)
58+
// return null instead of crashing if undefined (better assertion handling)
59+
WebDriverWait wait = webDriver.createWebDriverWait();
60+
Object clientId = wait.until(driver -> webDriver.getJavascriptExecutor().executeScript(
61+
"return (typeof clientId !== 'undefined') ? clientId : null;"));
62+
63+
assertThat(clientId).as("Global variable 'clientId' should match URL param")
64+
.hasToString("admin");
65+
66+
Object origin = wait.until(driver -> webDriver.getJavascriptExecutor().executeScript(
67+
"return (typeof messageOrigin !== 'undefined') ? messageOrigin : null;"));
5768

58-
Object origin = webDriver.getJavascriptExecutor().executeScript(
59-
"return messageOrigin;");
60-
assertThat(origin).hasToString("http://localhost:8080");
69+
assertThat(origin).as("Global variable 'messageOrigin' should match URL param")
70+
.hasToString("http://localhost:8080");
6171
}
6272
}

uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/HomeIT.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333
import org.springframework.beans.factory.annotation.Value;
3434
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
3535

36-
import java.time.Duration;
37-
3836
import static org.assertj.core.api.Assertions.assertThat;
3937
import static org.assertj.core.api.Assumptions.assumeThat;
4038

@@ -110,12 +108,12 @@ void theHeaderDropdown() {
110108
.sendLoginCredentials(testAccounts.getUserName(), testAccounts.getPassword())
111109
.assertThatPageSource().contains("Where to?");
112110
try {
113-
WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(30));
111+
WebDriverWait wait = webDriver.createWebDriverWait();
114112
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("nav-dropdown-button"))).click();
115113
assertThat(wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("nav-dropdown-content-profile"))).isDisplayed()).isTrue();
116114
assertThat(wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("nav-dropdown-content-logout"))).isDisplayed()).isTrue();
117115
} catch (TimeoutException e) {
118-
// If the dropdown is not visible ignore
116+
// If the dropdown is not visible, ignore
119117
assumeThat(e.getMessage()).contains("waiting for visibility");
120118
}
121119

uaa/src/test/java/org/cloudfoundry/identity/uaa/test/UaaWebDriver.java

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package org.cloudfoundry.identity.uaa.test;
22

3-
import java.time.Duration;
4-
import java.util.List;
5-
import java.util.Set;
6-
73
import org.jspecify.annotations.Nullable;
84
import org.openqa.selenium.By;
95
import org.openqa.selenium.ElementNotInteractableException;
@@ -19,6 +15,10 @@
1915
import org.openqa.selenium.support.ui.FluentWait;
2016
import org.openqa.selenium.support.ui.WebDriverWait;
2117

18+
import java.time.Duration;
19+
import java.util.List;
20+
import java.util.Set;
21+
2222
/**
2323
* Thin wrapper around a "regular" webdriver, that allows you to "click-and-wait" until
2424
* an element has disappeared. This avoids explicit waits in test code.
@@ -28,24 +28,27 @@
2828
*/
2929
public class UaaWebDriver implements WebDriver {
3030

31+
public static final Duration WAIT_TIMEOUT = Duration.ofSeconds(30L);
32+
public static final Duration POLLING_TIME = Duration.ofMillis(100);
33+
3134
private final WebDriver delegate;
3235

3336
public UaaWebDriver(WebDriver delegate) {
3437
this.delegate = delegate;
3538
}
3639

3740
/**
38-
* Click on the element, and wait for a page reload. This is accomplished by waiting
39-
* for the reference to the clicked element to become "stale", ie not be in the current
40-
* DOM anymore, throwing {@link StaleElementReferenceException}. Sometimes, the Chrome driver
41-
* throws a 500 error, which body contains code -32000, so we use that as a signal as well.
41+
* Click on the element and wait for a page reload.
42+
* This is achieved by waiting for the reference to the clicked element to become "stale",
43+
* i.e., not be in the current DOM anymore, throwing {@link StaleElementReferenceException}.
44+
* Sometimes, the Chrome driver throws a 500 error, which body contains code -32000, so we use that as a signal as well.
4245
*/
4346
public void clickAndWait(By locator) {
4447
var clickableElement = this.delegate.findElement(locator);
4548
clickableElement.click();
4649

47-
new FluentWait<>(this.delegate).withTimeout(Duration.ofSeconds(5))
48-
.pollingEvery(Duration.ofMillis(100))
50+
new FluentWait<>(this.delegate).withTimeout(WAIT_TIMEOUT)
51+
.pollingEvery(POLLING_TIME)
4952
.withMessage(() -> "Waiting for navigation after clicking on [%s]. Current URL [%s].".formatted(locator, delegate.getCurrentUrl()))
5053
.until((d) -> {
5154
try {
@@ -60,19 +63,26 @@ public void clickAndWait(By locator) {
6063
}
6164

6265
/**
63-
* Press the UAA navigation element with the given id, and wait for the button with a given id
64-
* Example: After Login to UAA there is a menu in the top right corner with. A user can click on it and get
66+
* Press the UAA navigation element with the given id and wait for the button with a given id
67+
* Example: After Login to UAA, there is a menu in the top right corner that a user can click on and get
6568
* the profile page or perform a logout.
6669
*/
6770
public void pressUaaNavigation(String navigationElementId, String idButton) {
68-
WebDriverWait wait1 = new WebDriverWait(this.delegate, Duration.ofSeconds(10));
69-
WebElement elm1 = wait1.ignoreAll(List.of(StaleElementReferenceException.class, ElementNotInteractableException.class)).until(ExpectedConditions.visibilityOfElementLocated(By.id(navigationElementId)));
71+
WebDriverWait wait = createWebDriverWait();
72+
WebElement elm1 = wait.ignoreAll(List.of(StaleElementReferenceException.class, ElementNotInteractableException.class)).until(ExpectedConditions.visibilityOfElementLocated(By.id(navigationElementId)));
7073
elm1.click();
71-
WebDriverWait wait2 = new WebDriverWait(this.delegate, Duration.ofSeconds(30));
72-
WebElement elm2 = wait2.ignoreAll(List.of(StaleElementReferenceException.class, ElementNotInteractableException.class)).until(ExpectedConditions.visibilityOfElementLocated(By.id(idButton)));
74+
75+
WebElement elm2 = wait.ignoreAll(List.of(StaleElementReferenceException.class, ElementNotInteractableException.class)).until(ExpectedConditions.visibilityOfElementLocated(By.id(idButton)));
7376
elm2.click();
7477
}
7578

79+
/**
80+
* Provides a {@link WebDriverWait} instance configured with predefined timeout and polling settings.
81+
*/
82+
public WebDriverWait createWebDriverWait() {
83+
return new WebDriverWait(this.delegate, WAIT_TIMEOUT, POLLING_TIME);
84+
}
85+
7686
public JavascriptExecutor getJavascriptExecutor() {
7787
return (JavascriptExecutor) this.delegate;
7888
}
@@ -143,7 +153,16 @@ public Options manage() {
143153
}
144154

145155
public SessionId getSessionId() {
146-
return ((RemoteWebDriver) this.delegate).getSessionId();
156+
if (!(this.delegate instanceof RemoteWebDriver)) {
157+
return null;
158+
}
159+
try {
160+
return ((RemoteWebDriver) this.delegate).getSessionId();
161+
} catch (Exception e) {
162+
// If the WebDriver has been quit or closed, getSessionId() may throw an exception
163+
// Return null to indicate the session is no longer available
164+
return null;
165+
}
147166
}
148167

149168
public TakesScreenshot getTakesScreenShot() {

0 commit comments

Comments
 (0)