Skip to content

Commit d776f36

Browse files
committed
Refactor Selenium tests
1 parent 0e87e7e commit d776f36

9 files changed

Lines changed: 136 additions & 112 deletions

File tree

msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenInteractiveIT.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ void acquireTokenInteractive_ManagedUser() {
4444

4545
LabResponse labResponse = LabUserHelper.getDefaultUser();
4646
LabUser user = labResponse.getUser();
47-
assertAcquireTokenCommon(user, labResponse.getApp().getAppId(), cfg.commonAuthority(), cfg.graphDefaultScope());
47+
48+
assertAcquireTokenCommon(user, labResponse.getApp().getAppId(), labResponse.getLab().getAuthority()+ "common", cfg.graphDefaultScope());
4849
}
4950

5051
//TODO: need to sort out ADFS 2022 configuration

msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/DeviceCodeIT.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ private void runAutomatedDeviceCodeFlow(DeviceCode deviceCode, LabUser user) {
9393
seleniumDriver.findElement(new By.ById(deviceCodeFormId)).sendKeys(deviceCode.userCode());
9494

9595
LOG.info("Loggin in ... click continue");
96-
WebElement continueBtn = SeleniumExtensions.waitForElementToBeVisibleAndEnable(
97-
seleniumDriver,
98-
new By.ById(continueButtonId));
99-
continueBtn.click();
96+
// WebElement continueBtn = SeleniumExtensions.waitForElementToBeVisibleAndEnable(
97+
// seleniumDriver,
98+
// new By.ById(continueButtonId));
99+
// continueBtn.click();
100100

101101
SeleniumExtensions.performADOrCiamLogin(seleniumDriver, user);
102102
} catch (Exception e) {

msal4j-sdk/src/integrationtest/java/com.microsoft.aad.msal4j/SeleniumTest.java

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,29 @@
66
import com.microsoft.aad.msal4j.labapi2.LabUser;
77
import infrastructure.SeleniumExtensions;
88
import org.openqa.selenium.WebDriver;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
911

1012
abstract class SeleniumTest {
13+
private static final Logger LOG = LoggerFactory.getLogger(SeleniumTest.class);
1114

1215
WebDriver seleniumDriver;
1316
HttpListener httpListener;
1417

1518
public void cleanUp() {
16-
seleniumDriver.quit();
19+
if (seleniumDriver != null) {
20+
try {
21+
seleniumDriver.quit();
22+
} catch (Exception e) {
23+
LOG.error("Error closing WebDriver: {}", e.getMessage());
24+
}
25+
}
1726
if (httpListener != null) {
18-
httpListener.stopListener();
27+
try {
28+
httpListener.stopListener();
29+
} catch (Exception e) {
30+
LOG.error("Error stopping HttpListener: {}", e.getMessage());
31+
}
1932
}
2033
}
2134

@@ -26,14 +39,27 @@ public void startUpBrowser() {
2639
void runSeleniumAutomatedLogin(LabUser user, AbstractClientApplicationBase app) {
2740
AuthorityType authorityType = app.authenticationAuthority.authorityType;
2841

29-
if (authorityType == AuthorityType.B2C) {
30-
SeleniumExtensions.performLocalLogin(seleniumDriver, user);
31-
} else if (authorityType == AuthorityType.AAD) {
32-
SeleniumExtensions.performADOrCiamLogin(seleniumDriver, user);
33-
} else if (authorityType == AuthorityType.ADFS) {
34-
SeleniumExtensions.performADFSLogin(seleniumDriver, user);
35-
} else if (authorityType == AuthorityType.CIAM || authorityType == AuthorityType.OIDC) {
36-
SeleniumExtensions.performADOrCiamLogin(seleniumDriver, user);
42+
try {
43+
switch (authorityType) {
44+
case B2C:
45+
SeleniumExtensions.performLocalLogin(seleniumDriver, user);
46+
break;
47+
case AAD:
48+
SeleniumExtensions.performADOrCiamLogin(seleniumDriver, user);
49+
break;
50+
case ADFS:
51+
SeleniumExtensions.performADFSLogin(seleniumDriver, user);
52+
break;
53+
case CIAM:
54+
case OIDC:
55+
SeleniumExtensions.performADOrCiamLogin(seleniumDriver, user);
56+
break;
57+
default:
58+
throw new IllegalArgumentException("Unsupported authority type: " + authorityType);
59+
}
60+
} catch (Exception e) {
61+
LOG.error("Selenium automation failed for authority type {}: {}", authorityType, e.getMessage());
62+
throw new RuntimeException("Selenium automation failed", e);
3763
}
3864
}
3965
}

msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/labapi2/Lab.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ public String getTenantId() {
7474
return this.tenantId;
7575
}
7676

77+
public String getAuthority() {
78+
return this.authority;
79+
}
80+
7781
public String getFederationProvider() {
7882
return this.federationProvider;
7983
}

msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/labapi2/LabServiceParameters.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ public class LabServiceParameters {
77

88
public enum FederationProvider {
99
NONE, // No federation
10-
ADFS_V4,
11-
@Deprecated // ADFSv3 is out of support, do not use. The Arlington lab is federated to ADFSv3, so this value is needed
12-
ADFS_V3,
13-
ADFSv2022,
1410
CIAM, // CIAM
1511
CIAMCUD, // CIAM CUD
1612
}

msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/labapi2/LabUser.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
111111
jsonWriter.writeStringField("lastUpdatedBy", lastUpdatedBy);
112112
jsonWriter.writeStringField("lastUpdatedDate", lastUpdatedDate);
113113
jsonWriter.writeStringField("tenantId", tenantId);
114+
jsonWriter.writeStringField("federationProvider", federationProvider);
114115

115116
jsonWriter.writeEndObject();
116117

msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/labapi2/LabUserHelper.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public static LabResponse getLabUserData(UserQuery query) {
6868
*/
6969
private static Object getKVLabData(String secret) {
7070
try {
71-
log.debug("Retrieving Key Vault secret: {}", secret);
71+
log.info("Retrieving Key Vault secret: {}", secret);
7272
// Use MSAL Team vault for configuration
7373
KeyVaultSecret keyVaultSecret = keyVaultSecretsProviderMsal.getSecretByName(secret);
7474
String labData = keyVaultSecret.getValue();
@@ -198,6 +198,8 @@ public static LabResponse mergeKVLabData(String... secrets) {
198198
log.info("Merged secrets [{}]: {}", String.join(", ", secrets),
199199
mergedResponse.getUser() != null ? mergedResponse.getUser().getUpn() : "N/A");
200200

201+
System.out.println(mergedResponse.toJsonString());
202+
201203
return mergedResponse;
202204
} catch (Exception e) {
203205
log.error("Failed to merge secrets [{}]: {}", String.join(", ", secrets), e.getMessage());

msal4j-sdk/src/integrationtest/java/infrastructure/SeleniumExtensions.java

Lines changed: 86 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -5,165 +5,164 @@
55

66
import com.microsoft.aad.msal4j.TestConstants;
77
import com.microsoft.aad.msal4j.labapi2.LabUser;
8-
import org.apache.commons.io.FileUtils;
98
import org.openqa.selenium.By;
10-
import org.openqa.selenium.OutputType;
119
import org.openqa.selenium.StaleElementReferenceException;
12-
import org.openqa.selenium.TakesScreenshot;
1310
import org.openqa.selenium.TimeoutException;
1411
import org.openqa.selenium.WebDriver;
1512
import org.openqa.selenium.WebElement;
1613
import org.openqa.selenium.chrome.ChromeDriver;
1714
import org.openqa.selenium.chrome.ChromeOptions;
18-
import org.openqa.selenium.support.ui.ExpectedCondition;
15+
import org.openqa.selenium.support.ui.ExpectedConditions;
1916
import org.openqa.selenium.support.ui.WebDriverWait;
2017
import org.slf4j.Logger;
2118
import org.slf4j.LoggerFactory;
2219

23-
import java.io.File;
24-
import java.util.concurrent.TimeUnit;
20+
import java.time.Duration;
2521

2622
public class SeleniumExtensions {
2723

2824
private static final Logger LOG = LoggerFactory.getLogger(SeleniumExtensions.class);
2925

30-
//These timeout values define how long Selenium will wait for elements to be visible and enabled
31-
private static final int DEFAULT_TIMEOUT_IN_SEC = 15;
32-
private static final int COMMON_ELEMENT_TIMEOUT_IN_SEC = 5; //Used for most elements in a sign-in flow
26+
private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(15);
27+
private static final Duration COMMON_ELEMENT_TIMEOUT = Duration.ofSeconds(5);
3328

3429
private SeleniumExtensions() {
3530
}
3631

3732
public static WebDriver createDefaultWebDriver() {
3833
ChromeOptions options = new ChromeOptions();
39-
40-
//No visual rendering, remove to see browser window when debugging
41-
// options.addArguments("--headless");
42-
//Add to avoid issues if your real browser's history/cookies are affecting tests, should not be needed in ADO pipelines
34+
options.addArguments("--headless");
4335
options.addArguments("--incognito");
4436

4537
System.setProperty("webdriver.chrome.driver", "C:/Windows/chromedriver.exe");
46-
ChromeDriver driver = new ChromeDriver(options);
47-
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
48-
49-
return driver;
38+
return new ChromeDriver(options);
5039
}
5140

52-
public static WebElement waitForElementToBeVisibleAndEnable(WebDriver driver, By by, int timeOutInSeconds) {
53-
WebDriverWait webDriverWait = new WebDriverWait(driver, timeOutInSeconds);
54-
return webDriverWait.until(dr ->
55-
{
41+
public static WebElement waitForElementToBeVisibleAndEnabled(WebDriver driver, By by, Duration timeout) {
42+
WebDriverWait wait = new WebDriverWait(driver, timeout.getSeconds());
43+
return wait.until(dr -> {
5644
try {
57-
WebElement elementToBeDisplayed = driver.findElement(by);
58-
if (elementToBeDisplayed.isDisplayed() && elementToBeDisplayed.isEnabled()) {
59-
return elementToBeDisplayed;
45+
WebElement element = driver.findElement(by);
46+
if (element.isDisplayed() && element.isEnabled()) {
47+
return element;
6048
}
6149
return null;
6250
} catch (StaleElementReferenceException e) {
63-
LOG.info("Stale element waitForElementToBeVisibleAndEnable: " + e.getMessage());
51+
LOG.debug("Stale element in waitForElementToBeVisibleAndEnabled: {}", e.getMessage());
6452
return null;
6553
}
6654
});
6755
}
6856

69-
public static WebElement waitForElementToBeVisibleAndEnable(WebDriver driver, By by) {
70-
return waitForElementToBeVisibleAndEnable(driver, by, DEFAULT_TIMEOUT_IN_SEC);
57+
public static WebElement waitForElementToBeVisibleAndEnabled(WebDriver driver, By by) {
58+
return waitForElementToBeVisibleAndEnabled(driver, by, DEFAULT_TIMEOUT);
7159
}
7260

7361
public static void performADOrCiamLogin(WebDriver driver, LabUser user) {
74-
LOG.info("performADOrCiamLogin");
62+
LOG.info("performADOrCiamLogin for user: {}", user.getUpn());
7563

7664
UserInformationFields fields = new UserInformationFields(user);
7765

78-
LOG.info("Loggin in ... Entering username");
79-
driver.findElement(new By.ById(fields.getAadUserNameInputId())).sendKeys(user.getUpn());
66+
LOG.info("Entering username");
67+
waitForElementToBeVisibleAndEnabled(driver, By.id(fields.getAadUserNameInputId()))
68+
.sendKeys(user.getUpn());
8069

81-
LOG.info("Loggin in ... Clicking <Next> after username");
82-
driver.findElement(new By.ById(fields.getAadSignInButtonId())).click();
70+
LOG.info("Clicking Next after username");
71+
waitForElementToBeVisibleAndEnabled(driver, By.id(fields.getAadSignInButtonId()))
72+
.click();
8373

84-
LOG.info("Loggin in ... Entering password");
85-
By by = new By.ById(fields.getPasswordInputId());
86-
waitForElementToBeVisibleAndEnable(driver, by).sendKeys(user.getPassword());
74+
LOG.info("Entering password");
75+
System.out.println("Using password ID: " + fields.getPasswordInputId());
76+
waitForElementToBeVisibleAndEnabled(driver, By.id(fields.getPasswordInputId()));
77+
System.out.println(By.id(fields.getPasswordInputId()));
78+
waitForElementToBeVisibleAndEnabled(driver, By.id(fields.getPasswordInputId()))
79+
.sendKeys(user.getPassword());
8780

88-
LOG.info("Loggin in ... click submit");
89-
waitForElementToBeVisibleAndEnable(driver, new By.ById(fields.getPasswordSigInButtonId())).
90-
click();
81+
LOG.info("Clicking submit");
82+
waitForElementToBeVisibleAndEnabled(driver, By.id(fields.getPasswordSigInButtonId()))
83+
.click();
9184

92-
try {
93-
checkAuthenticationCompletePage(driver);
85+
if (checkAuthenticationCompletePage(driver)) {
9486
return;
95-
} catch (TimeoutException ex) {
96-
LOG.error("Timeout Exception while checking authentication complete page: " + ex.getMessage());
9787
}
9888

99-
LOG.info("Checking optional questions");
89+
handleOptionalPrompts(driver);
90+
}
10091

92+
private static boolean checkAuthenticationCompletePage(WebDriver driver) {
10193
try {
102-
LOG.info("Are you trying to sign in to ... ? checking");
103-
waitForElementToBeVisibleAndEnable(driver, new By.ById(SeleniumConstants.ARE_YOU_TRYING_TO_SIGN_IN_TO), COMMON_ELEMENT_TIMEOUT_IN_SEC).
104-
click();
105-
LOG.info("Are you trying to sign in to ... ? click Continue");
106-
94+
WebDriverWait wait = new WebDriverWait(driver, COMMON_ELEMENT_TIMEOUT.getSeconds());
95+
wait.until(ExpectedConditions.textToBePresentInElementLocated(
96+
By.tagName("body"), "Authentication complete"));
97+
return true;
10798
} catch (TimeoutException ex) {
108-
LOG.error("Timeout Exception while checking sign in prompt: " + ex.getMessage());
99+
LOG.debug("Authentication complete page not found: {}", ex.getMessage());
100+
return false;
109101
}
102+
}
110103

104+
private static void handleOptionalPrompts(WebDriver driver) {
105+
// Handle "Are you trying to sign in to..." prompt
111106
try {
112-
LOG.info("Stay signed in? checking");
113-
waitForElementToBeVisibleAndEnable(driver, new By.ById(SeleniumConstants.STAY_SIGN_IN_NO_BUTTON_ID), COMMON_ELEMENT_TIMEOUT_IN_SEC).
114-
click();
115-
LOG.info("Stay signed in? click NO");
107+
LOG.info("Checking for 'Are you trying to sign in' prompt");
108+
waitForElementToBeVisibleAndEnabled(
109+
driver,
110+
By.id(SeleniumConstants.ARE_YOU_TRYING_TO_SIGN_IN_TO),
111+
COMMON_ELEMENT_TIMEOUT)
112+
.click();
113+
LOG.info("Clicked Continue on sign-in prompt");
116114
} catch (TimeoutException ex) {
117-
LOG.error("Timeout Exception while checking stay signed in prompt: " + ex.getMessage());
115+
LOG.debug("No 'Are you trying to sign in' prompt found");
118116
}
119-
}
120117

121-
private static void checkAuthenticationCompletePage(WebDriver driver) {
122-
new WebDriverWait(driver, COMMON_ELEMENT_TIMEOUT_IN_SEC).until((ExpectedCondition<Boolean>) d -> {
123-
WebElement we = d.findElement(new By.ByTagName("body"));
124-
try {
125-
if (we != null && we.getText().contains("Authentication complete"))
126-
//The authentication is complete and the WebDriverWait can end
127-
return true;
128-
} catch (StaleElementReferenceException e) {
129-
//It is possible for this method to begin executing before the redirect happens, in which case the WebElement
130-
// will reference something on the previous page and cause a StaleElementReferenceException
131-
return false;
132-
}
133-
return false;
134-
});
118+
// Handle "Stay signed in?" prompt
119+
try {
120+
LOG.info("Checking for 'Stay signed in' prompt");
121+
waitForElementToBeVisibleAndEnabled(
122+
driver,
123+
By.id(SeleniumConstants.STAY_SIGN_IN_NO_BUTTON_ID),
124+
COMMON_ELEMENT_TIMEOUT)
125+
.click();
126+
LOG.info("Clicked No on 'Stay signed in' prompt");
127+
} catch (TimeoutException ex) {
128+
LOG.debug("No 'Stay signed in' prompt found");
129+
}
135130
}
136131

137132
public static void performADFSLogin(WebDriver driver, LabUser user) {
138-
LOG.info("PerformADFSLogin");
133+
LOG.info("performADFSLogin for user: {}", user.getUpn());
139134

140135
UserInformationFields fields = new UserInformationFields(user);
141136

142-
LOG.info("Loggin in ... Entering username");
143-
driver.findElement(new By.ById(fields.getADFSUserNameInputId())).sendKeys(user.getUpn());
137+
LOG.info("Entering username");
138+
waitForElementToBeVisibleAndEnabled(driver, By.id(fields.getADFSUserNameInputId()))
139+
.sendKeys(user.getUpn());
144140

145-
LOG.info("Loggin in ... Entering password");
146-
By by = new By.ById(fields.getPasswordInputId());
147-
waitForElementToBeVisibleAndEnable(driver, by).sendKeys(user.getPassword());
141+
LOG.info("Entering password");
142+
waitForElementToBeVisibleAndEnabled(driver, By.id(fields.getPasswordInputId()))
143+
.sendKeys(user.getPassword());
148144

149-
LOG.info("Loggin in ... click submit");
150-
waitForElementToBeVisibleAndEnable(driver, new By.ById(fields.getPasswordSigInButtonId())).
151-
click();
145+
LOG.info("Clicking submit");
146+
waitForElementToBeVisibleAndEnabled(driver, By.id(fields.getPasswordSigInButtonId()))
147+
.click();
152148
}
153149

154150
public static void performLocalLogin(WebDriver driver, LabUser user) {
155-
LOG.info("PerformLocalLogin");
151+
LOG.info("performLocalLogin");
156152

157-
driver.findElement(new By.ById(SeleniumConstants.B2C_LOCAL_ACCOUNT_ID)).click();
153+
waitForElementToBeVisibleAndEnabled(driver, By.id(SeleniumConstants.B2C_LOCAL_ACCOUNT_ID))
154+
.click();
158155

159-
LOG.info("Loggin in ... Entering username");
160-
driver.findElement(new By.ById(SeleniumConstants.B2C_LOCAL_USERNAME_ID)).sendKeys(TestConstants.B2C_UPN);
156+
LOG.info("Entering username");
157+
waitForElementToBeVisibleAndEnabled(driver, By.id(SeleniumConstants.B2C_LOCAL_USERNAME_ID))
158+
.sendKeys(TestConstants.B2C_UPN);
161159

162-
LOG.info("Loggin in ... Entering password");
163-
By by = new By.ById(SeleniumConstants.B2C_LOCAL_PASSWORD_ID);
164-
waitForElementToBeVisibleAndEnable(driver, by).sendKeys(user.getPassword());
160+
LOG.info("Entering password");
161+
waitForElementToBeVisibleAndEnabled(driver, By.id(SeleniumConstants.B2C_LOCAL_PASSWORD_ID))
162+
.sendKeys(user.getPassword());
165163

166-
waitForElementToBeVisibleAndEnable(driver, new By.ById(SeleniumConstants.B2C_LOCAL_SIGN_IN_BUTTON_ID)).
167-
click();
164+
LOG.info("Clicking sign in");
165+
waitForElementToBeVisibleAndEnabled(driver, By.id(SeleniumConstants.B2C_LOCAL_SIGN_IN_BUTTON_ID))
166+
.click();
168167
}
169168
}

0 commit comments

Comments
 (0)