Run tests with keycloak.v2 login theme

The fixes (mostly selectors) are needed for tests.

In the future, to switch the keycloak.v2 to the default theme, do
the following:

- Update `ThemeSelectorProvider`: Uncomment relevant lines
- Update `testsuite/integration-arquillian/tests/pom.xml`: Revert the change in `<login.theme.default>` property
- Update `ThemeSelectorTest` per comment

Signed-off-by: Hynek Mlnarik <hmlnarik@redhat.com>
This commit is contained in:
Hynek Mlnarik 2024-07-17 10:17:25 +02:00 committed by Hynek Mlnařík
parent c3019fb2d3
commit 183cd6c957
43 changed files with 289 additions and 400 deletions

View file

@ -35,7 +35,7 @@ public class DeleteAccountActionConfirmPage extends RequiredActions {
}
public boolean isErrorMessageDisplayed() {
return driver.findElements(By.cssSelector(".alert-error")).size() == 1;
return driver.findElements(By.cssSelector(".pf-v5-c-alert")).size() == 1;
}
public String getErrorMessageText() {

View file

@ -33,12 +33,19 @@ import static org.keycloak.testsuite.util.UIUtils.getTextFromElement;
*/
public class FeedbackMessage {
private final String SUCCESS = "success";
private final String WARNING = "warning";
private final String ERROR = "error";
private final String INFO = "info";
private final static String SUCCESS = "success";
private final static String WARNING = "warning";
private final static String ERROR = "danger";
private final static String INFO = "info";
@FindBy(css = "div[class^='alert']")
private static final Pattern ALERT_TYPE_CLASS_PATTERN = Pattern.compile("(pf-m|alert)-("
+ SUCCESS + "|"
+ WARNING + "|"
+ ERROR + "|"
+ INFO
+ ")");
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert']")
private WebElement alertRoot;
@FindBy(css = "span[id^='input-error']")
@ -71,7 +78,7 @@ public class FeedbackMessage {
public String getType() {
try {
String cssClass = alertRoot.getAttribute("class");
Matcher classMatcher = Pattern.compile("alert-(.+)").matcher(cssClass);
Matcher classMatcher = ALERT_TYPE_CLASS_PATTERN.matcher(cssClass);
if (!classMatcher.find()) {
throw new RuntimeException("Failed to identify feedback message type");
}

View file

@ -34,7 +34,7 @@ public class OneTimeCode extends Authenticate {
@FindBy(xpath = ".//label[@for='otp']")
private WebElement otpInputLabel;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement loginErrorMessage;
@FindBy(id = "input-error-otp-code")

View file

@ -43,7 +43,7 @@ public class LoginPasswordUpdatePage {
@FindBy(css = "input[type=\"submit\"]")
private WebElement submitButton;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement loginErrorMessage;
public void changePassword(String newPassword, String passwordConfirm) {

View file

@ -31,7 +31,7 @@ public class IdpConfirmLinkPage extends LanguageComboboxAwarePage {
@FindBy(id = "linkAccount")
private WebElement linkAccountButton;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement message;
@Override

View file

@ -25,7 +25,7 @@ public class IdpConfirmOverrideLinkPage extends LanguageComboboxAwarePage {
@FindBy(id = "confirmOverride")
private WebElement confirmOverrideButton;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement message;
@Override

View file

@ -44,7 +44,7 @@ public class InstalledAppRedirectPage extends AbstractPage {
@FindBy(id = "kc-page-title")
private WebElement pageTitle;
@FindBy(className = "alert-error")
@FindBy(className = "pf-v5-c-alert")
private WebElement errorBox;
@Override

View file

@ -20,6 +20,10 @@ package org.keycloak.testsuite.pages;
import org.junit.Assert;
import org.keycloak.testsuite.util.DroneUtils;
import org.keycloak.testsuite.util.WaitUtils;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
@ -33,12 +37,18 @@ import org.openqa.selenium.support.FindBy;
*/
public abstract class LanguageComboboxAwarePage extends AbstractPage {
@FindBy(id = "kc-current-locale-link")
@FindBy(xpath = "//select[@aria-label='languages']/option[@selected]")
private WebElement languageText;
@FindBy(id = "kc-locale-dropdown")
@FindBy(xpath = "//select[@aria-label='languages']")
private WebElement localeDropdown;
@FindBy(id = "kc-current-locale-link")
private WebElement languageTextBase; // base theme
@FindBy(id = "kc-locale-dropdown")
private WebElement localeDropdownBase; // base theme
@FindBy(id = "try-another-way")
private WebElement tryAnotherWayLink;
@ -52,13 +62,26 @@ public abstract class LanguageComboboxAwarePage extends AbstractPage {
private WebElement accountLink;
public String getLanguageDropdownText() {
return languageText.getText();
try {
final String text = languageText.getText();
return text == null ? text : text.trim();
} catch (NoSuchElementException ex) {
return languageTextBase.getText();
}
}
public void openLanguage(String language){
WebElement langLink = localeDropdown.findElement(By.xpath("//a[text()[contains(.,'" + language + "')]]"));
String url = langLink.getAttribute("href");
DroneUtils.getCurrentDriver().navigate().to(url);
try {
WebElement langLink = localeDropdown.findElement(By.xpath("//option[text()[contains(.,'" + language + "')]]"));
String url = langLink.getAttribute("value");
DroneUtils.getCurrentDriver().navigate().to(new URI(DroneUtils.getCurrentDriver().getCurrentUrl()).resolve(url).toString());
} catch (NoSuchElementException ex) {
WebElement langLink = localeDropdownBase.findElement(By.xpath("//a[text()[contains(.,'" + language + "')]]"));
String url = langLink.getAttribute("href");
DroneUtils.getCurrentDriver().navigate().to(url);
} catch (URISyntaxException ex) {
Assert.fail(ex.getMessage());
}
WaitUtils.waitForPageToLoad();
}

View file

@ -48,7 +48,7 @@ public class LoginConfigTotpPage extends LogoutSessionsPage {
@FindBy(id = "mode-manual")
private WebElement manualLink;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement loginAlertErrorMessage;
@FindBy(id = "input-error-otp-code")

View file

@ -65,13 +65,13 @@ public class LoginPage extends LanguageComboboxAwarePage {
@FindBy(linkText = "Forgot Password?")
private WebElement resetPasswordLink;
@FindBy(className = "alert-error")
@FindBy(className = "pf-m-danger")
private WebElement loginErrorMessage;
@FindBy(className = "alert-success")
@FindBy(className = "pf-m-success")
private WebElement loginSuccessMessage;
@FindBy(className = "alert-info")
@FindBy(className = "pf-m-info")
private WebElement loginInfoMessage;
@FindBy(className = "instruction")

View file

@ -35,10 +35,10 @@ public class LoginPasswordResetPage extends LanguageComboboxAwarePage {
@FindBy(css = "input[type=\"submit\"]")
private WebElement submitButton;
@FindBy(className = "alert-success")
@FindBy(className = "pf-v5-c-success")
private WebElement emailSuccessMessage;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement emailErrorMessage;
@FindBy(partialLinkText = "Back to Login")

View file

@ -35,7 +35,7 @@ public class LoginPasswordUpdatePage extends LogoutSessionsPage {
@FindBy(css = "input[type=\"submit\"]")
private WebElement submitButton;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement loginErrorMessage;
@FindBy(className = "kc-feedback-text")

View file

@ -41,7 +41,7 @@ public class LoginTotpPage extends LanguageComboboxAwarePage {
@FindBy(css = "input[type=\"submit\"]")
private WebElement submitButton;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement loginErrorMessage;
@FindBy(id = "input-error-otp-code")

View file

@ -40,16 +40,16 @@ public class LoginUpdateProfilePage extends AbstractPage {
@Page
private UpdateProfileErrors errorsPage;
@FindBy(id = "firstName")
@FindBy(name = "firstName")
private WebElement firstNameInput;
@FindBy(id = "lastName")
@FindBy(name = "lastName")
private WebElement lastNameInput;
@FindBy(id = "email")
@FindBy(name = "email")
private WebElement emailInput;
@FindBy(id = "department")
@FindBy(name = "department")
private WebElement departmentInput;
@FindBy(css = "input[type=\"submit\"]")
@ -58,7 +58,7 @@ public class LoginUpdateProfilePage extends AbstractPage {
@FindBy(name = "cancel-aia")
private WebElement cancelAIAButton;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement loginAlertErrorMessage;
public void update(String firstName, String lastName) {

View file

@ -34,7 +34,7 @@ public class OAuth2DeviceVerificationPage extends LanguageComboboxAwarePage {
@FindBy(css = "input[type=\"submit\"]")
private WebElement submitButton;
@FindBy(className = "alert-error")
@FindBy(className = "pf-v5-c-alert")
private WebElement verifyErrorMessage;
public void submit(String userCode) {
@ -108,7 +108,7 @@ public class OAuth2DeviceVerificationPage extends LanguageComboboxAwarePage {
try {
driver.findElement(By.id("device-user-code"));
return driver.findElement(By.id("kc-page-title")).getText().equals("Device Login")
&& driver.findElement(By.className("kc-feedback-text")).getText().equals("Invalid code, please try again.");
&& driver.findElement(By.className("pf-m-danger")).getText().equals("Invalid code, please try again.");
} catch (Throwable t) {
}
}
@ -120,7 +120,7 @@ public class OAuth2DeviceVerificationPage extends LanguageComboboxAwarePage {
try {
driver.findElement(By.id("device-user-code"));
return driver.findElement(By.id("kc-page-title")).getText().equals("Device Login")
&& driver.findElement(By.className("kc-feedback-text")).getText().equals("The code has expired. Please go back to your device and try connecting again.");
&& driver.findElement(By.className("pf-m-danger")).getText().equals("The code has expired. Please go back to your device and try connecting again.");
} catch (Throwable t) {
}
}

View file

@ -27,7 +27,7 @@ public class PasswordPage extends LanguageComboboxAwarePage {
@FindBy(name = "login")
private WebElement submitButton;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement loginErrorMessage;
@FindBy(linkText = "Forgot Password?")

View file

@ -44,34 +44,34 @@ public class RegisterPage extends AbstractPage {
@Page
private PasswordFields.PasswordErrors passwordErrors;
@FindBy(id = "firstName")
@FindBy(name = "firstName")
private WebElement firstNameInput;
@FindBy(id = "lastName")
@FindBy(name = "lastName")
private WebElement lastNameInput;
@FindBy(id = "email")
@FindBy(name = "email")
private WebElement emailInput;
@FindBy(id = "username")
@FindBy(name = "username")
private WebElement usernameInput;
@FindBy(id = "password")
@FindBy(name = "password")
private WebElement passwordInput;
@FindBy(id = "password-confirm")
@FindBy(name = "password-confirm")
private WebElement passwordConfirmInput;
@FindBy(id = "department")
@FindBy(name = "department")
private WebElement departmentInput;
@FindBy(id = "termsAccepted")
@FindBy(name = "termsAccepted")
private WebElement termsAcceptedInput;
@FindBy(css = "input[type=\"submit\"]")
private WebElement submitButton;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement loginAlertErrorMessage;
@FindBy(className = "instruction")
@ -136,7 +136,7 @@ public class RegisterPage extends AbstractPage {
if (attributes != null) {
for (Entry<String, String> attribute : attributes.entrySet()) {
driver.findElement(By.id(Constants.USER_ATTRIBUTES_PREFIX + attribute.getKey())).sendKeys(attribute.getValue());
driver.findElement(By.name(Constants.USER_ATTRIBUTES_PREFIX + attribute.getKey())).sendKeys(attribute.getValue());
}
}
@ -238,7 +238,7 @@ public class RegisterPage extends AbstractPage {
public boolean isDepartmentPresent() {
try {
return driver.findElement(By.id("department")).isDisplayed();
return driver.findElement(By.name("department")).isDisplayed();
} catch (NoSuchElementException nse) {
return false;
}

View file

@ -9,19 +9,19 @@ import static org.keycloak.testsuite.util.UIUtils.clickLink;
public class UpdateAccountInformationPage extends LanguageComboboxAwarePage {
@FindBy(id = "username")
@FindBy(name = "username")
private WebElement usernameInput;
@FindBy(id = "email")
@FindBy(name = "email")
private WebElement emailInput;
@FindBy(id = "firstName")
@FindBy(name = "firstName")
private WebElement firstNameInput;
@FindBy(id = "lastName")
@FindBy(name = "lastName")
private WebElement lastNameInput;
@FindBy(id = "department")
@FindBy(name = "department")
private WebElement departmentInput;
@FindBy(css = "input[type=\"submit\"]")
@ -106,7 +106,7 @@ public class UpdateAccountInformationPage extends LanguageComboboxAwarePage {
public boolean isDepartmentPresent() {
try {
return driver.findElement(By.id("department")).isDisplayed();
return driver.findElement(By.name("department")).isDisplayed();
} catch (NoSuchElementException nse) {
return false;
}

View file

@ -33,23 +33,23 @@ public class VerifyProfilePage extends AbstractPage {
@Page
private AccountFields.AccountErrors accountErrors;
@FindBy(id = "firstName")
@FindBy(name = "firstName")
private WebElement firstNameInput;
@FindBy(id = "lastName")
@FindBy(name = "lastName")
private WebElement lastNameInput;
@FindBy(id = "email")
@FindBy(name = "email")
private WebElement emailInput;
@FindBy(id = "department")
@FindBy(name = "department")
private WebElement departmentInput;
@FindBy(css = "input[type=\"submit\"]")
private WebElement submitButton;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement loginAlertErrorMessage;

View file

@ -44,10 +44,10 @@ public class X509IdentityConfirmationPage extends LanguageComboboxAwarePage {
@FindBy(name = "cancel")
private WebElement ignoreButton;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement loginErrorMessage;
@FindBy(className = "alert-warning")
@FindBy(className = "pf-v5-c-warning")
private WebElement loginWarningMessage;
@FindBy(className = "alert-success")

View file

@ -345,19 +345,19 @@ public class OAuthClient {
public void linkUsers(String username, String password) {
WaitUtils.waitForPageToLoad();
WebElement linkAccountButton = driver.findElement(By.id("linkAccount"));
WebElement linkAccountButton = driver.findElement(By.name("linkAccount"));
waitUntilElement(linkAccountButton).is().clickable();
linkAccountButton.click();
WaitUtils.waitForPageToLoad();
WebElement usernameInput = driver.findElement(By.id("username"));
WebElement usernameInput = driver.findElement(By.name("username"));
usernameInput.clear();
usernameInput.sendKeys(username);
WebElement passwordInput = driver.findElement(By.id("password"));
WebElement passwordInput = driver.findElement(By.name("password"));
passwordInput.clear();
passwordInput.sendKeys(password);
WebElement loginButton = driver.findElement(By.id("kc-login"));
WebElement loginButton = driver.findElement(By.name("kc-login"));
waitUntilElement(loginButton).is().clickable();
loginButton.click();
}
@ -382,8 +382,8 @@ public class OAuthClient {
WaitUtils.waitForPageToLoad();
String src = driver.getPageSource();
try {
driver.findElement(By.id("username")).sendKeys(username);
driver.findElement(By.id("password")).sendKeys(password);
driver.findElement(By.name("username")).sendKeys(username);
driver.findElement(By.name("password")).sendKeys(password);
if (rememberMe) {
driver.findElement(By.id("rememberMe")).click();
}
@ -396,19 +396,19 @@ public class OAuthClient {
private void updateAccountInformation(String username, String email, String firstName, String lastName) {
WebElement usernameInput = driver.findElement(By.id("username"));
WebElement usernameInput = driver.findElement(By.name("username"));
usernameInput.clear();
usernameInput.sendKeys(username);
WebElement emailInput = driver.findElement(By.id("email"));
WebElement emailInput = driver.findElement(By.name("email"));
emailInput.clear();
emailInput.sendKeys(email);
WebElement firstNameInput = driver.findElement(By.id("firstName"));
WebElement firstNameInput = driver.findElement(By.name("firstName"));
firstNameInput.clear();
firstNameInput.sendKeys(firstName);
WebElement lastNameInput = driver.findElement(By.id("lastName"));
WebElement lastNameInput = driver.findElement(By.name("lastName"));
lastNameInput.clear();
lastNameInput.sendKeys(lastName);

View file

@ -19,6 +19,7 @@ import java.time.Duration;
import java.util.Optional;
import java.util.function.Supplier;
import org.openqa.selenium.chrome.ChromeDriver;
import static org.keycloak.testsuite.util.DroneUtils.getCurrentDriver;
import static org.keycloak.testsuite.util.WaitUtils.log;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
@ -230,7 +231,7 @@ public final class UIUtils {
}
public static String getRawPageSource(WebDriver driver) {
if (driver instanceof FirefoxDriver) {
if ((driver instanceof FirefoxDriver) || (driver instanceof ChromeDriver)) {
// firefox has some weird "bug" it wraps xml in html
return driver.findElement(By.tagName("body")).getText();
}

View file

@ -26,7 +26,7 @@ public class WebAuthnErrorPage extends LanguageComboboxAwarePage {
@FindBy(id = "cancelWebAuthnAIA")
private WebElement cancelRegistrationAIA;
@FindBy(className = "alert-error")
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement errorMessage;
public void clickTryAgain() {

View file

@ -159,7 +159,9 @@ public abstract class AbstractKeycloakTest {
private boolean resetTimeOffset;
private static String PREFERRED_DEFAULT_LOGIN_THEME = System.getProperty("login.theme.default");
public static final String PROPERTY_LOGIN_THEME_DEFAULT = "login.theme.default";
public static final String PREFERRED_DEFAULT_LOGIN_THEME = System.getProperty(PROPERTY_LOGIN_THEME_DEFAULT);
@Before
public void beforeAbstractKeycloakTest() throws Exception {

View file

@ -173,7 +173,7 @@ public class AppInitiatedActionUpdateEmailWithVerificationTest extends AbstractA
assertEquals(String.format("The account email has been successfully updated to %s.", "new@localhost"), infoPage.getInfo());
//Issue #15136
final WebElement backToApplicationLink = driver.findElement(By.linkText("« Back to Application"));
assertThat(backToApplicationLink.toString(), Matchers.containsString("/auth/realms/master/app/auth"));
assertThat(backToApplicationLink.getDomAttribute("href"), Matchers.containsString("/auth/realms/master/app/auth"));
events.expect(EventType.UPDATE_EMAIL)
.detail(Details.PREVIOUS_EMAIL, "test-user@localhost")

View file

@ -16,10 +16,8 @@
*/
package org.keycloak.testsuite.actions;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.keycloak.userprofile.config.UPConfigUtils.ROLE_ADMIN;
import static org.keycloak.userprofile.config.UPConfigUtils.ROLE_USER;
@ -60,7 +58,10 @@ import org.keycloak.testsuite.pages.LoginUpdateProfileEditUsernameAllowedPage;
import org.keycloak.testsuite.util.UserBuilder;
import org.keycloak.userprofile.UserProfileContext;
import org.keycloak.utils.StringUtil;
import java.util.HashSet;
import org.openqa.selenium.ElementClickInterceptedException;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -457,6 +458,7 @@ public class RequiredActionUpdateProfileTest extends AbstractTestRealmKeycloakTe
UPConfig testUpConfig = configuration.clone();
List<String> attributes = List.of("foo", "bar", "zar");
List<String> values = IntStream.range(0, 5).mapToObj(Integer::toString).collect(Collectors.toList());
Set<String> valuesSet = new HashSet<>(values);
for (String attribute : attributes) {
testUpConfig.addOrReplaceAttribute(
@ -487,17 +489,24 @@ public class RequiredActionUpdateProfileTest extends AbstractTestRealmKeycloakTe
userRep.setRequiredActions(List.of(UserModel.RequiredAction.UPDATE_PROFILE.name()));
testRealm().users().get(userRep.getId()).update(userRep);
loginPage.open();
for (String value : values) {
assertEquals(value, updateProfilePage.getAttribute(attribute + "-" + value));
}
assertThat(IntStream.range(0, 5).mapToObj(value -> updateProfilePage.getAttribute(attribute + "-" + value)).collect(Collectors.toSet()), Matchers.equalTo(valuesSet));
final String lastValue = values.get(values.size() - 1);
// remove multiple values, only the last value should be kept as you can't remove the last one
for (String value : values) {
updateProfilePage.clickRemoveAttributeValue(attribute + "-0");
try {
updateProfilePage.clickRemoveAttributeValue(attribute + "-0");
} catch (ElementClickInterceptedException e) {
if (! lastValue.equals(value)) { // Ignore that the last value cannot be clicked / removed - this is by design
throw e;
}
}
}
updateProfilePage.update("f", "l", "e@keycloak.org");
userRep = ActionUtil.findUserWithAdminClient(adminClient, "john-doh@localhost");
assertThat(userRep.getAttributes().get(attribute), Matchers.containsInAnyOrder(values.get(values.size() - 1)));
assertThat(userRep.getAttributes().get(attribute), Matchers.hasSize(1));
assertThat(userRep.getAttributes().get(attribute).get(0), Matchers.in(values));
// make sure adding/removing within the same context works
userRep.setRequiredActions(List.of(UserModel.RequiredAction.UPDATE_PROFILE.name()));
@ -508,19 +517,26 @@ public class RequiredActionUpdateProfileTest extends AbstractTestRealmKeycloakTe
updateProfilePage.setAttribute(elementId, value);
updateProfilePage.clickAddAttributeValue(elementId);
}
assertThat(IntStream.range(0, 5).mapToObj(value -> updateProfilePage.getAttribute(attribute + "-" + value)).collect(Collectors.toSet()), Matchers.equalTo(valuesSet));
for (String value : values) {
assertEquals(value, updateProfilePage.getAttribute(attribute + "-" + value));
}
for (String value : values) {
updateProfilePage.clickRemoveAttributeValue(attribute + "-0");
try {
updateProfilePage.clickRemoveAttributeValue(attribute + "-0");
} catch (ElementClickInterceptedException e) {
if (! lastValue.equals(value)) { // Ignore that the last value cannot be clicked / removed - this is by design
throw e;
}
}
}
// make sure the last attribute is set with a value
if (StringUtil.isBlank(updateProfilePage.getAttribute(attribute + "-0"))) {
updateProfilePage.setAttribute(attribute + "-0", values.get(values.size() - 1));
updateProfilePage.setAttribute(attribute + "-0", lastValue);
}
updateProfilePage.update("f", "l", "e@keycloak.org");
userRep = ActionUtil.findUserWithAdminClient(adminClient, "john-doh@localhost");
assertThat(userRep.getAttributes().get(attribute), Matchers.containsInAnyOrder(values.get(values.size() - 1)));
assertThat(userRep.getAttributes().get(attribute), Matchers.hasSize(1));
assertThat(userRep.getAttributes().get(attribute).get(0), Matchers.in(values));
// at the end the attribute is set with multiple values
userRep.setRequiredActions(List.of(UserModel.RequiredAction.UPDATE_PROFILE.name()));

View file

@ -33,6 +33,7 @@ import static org.keycloak.testsuite.forms.VerifyProfileTest.CONFIGURATION_FOR_U
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.jboss.arquillian.graphene.page.Page;
@ -61,6 +62,7 @@ import org.keycloak.testsuite.util.ClientScopeBuilder;
import org.keycloak.testsuite.util.KeycloakModelUtils;
import org.keycloak.testsuite.util.UserBuilder;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
/**
* Test update-profile required action with custom user profile configurations
@ -107,7 +109,7 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
@Before
public void beforeTest() {
VerifyProfileTest.setUserProfileConfiguration(testRealm(),null);
VerifyProfileTest.setUserProfileConfiguration(testRealm(), null);
ApiUtil.removeUserByUsername(testRealm(), "test-user@localhost");
UserRepresentation user = UserBuilder.create().enabled(true)
@ -146,11 +148,11 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
//assert field names
// i18n replaced
Assert.assertEquals("First name",updateProfilePage.getLabelForField("firstName"));
Assert.assertEquals("First name", updateProfilePage.getLabelForField("firstName"));
// attribute name used if no display name set
Assert.assertEquals("lastName",updateProfilePage.getLabelForField("lastName"));
Assert.assertEquals("lastName", updateProfilePage.getLabelForField("lastName"));
// direct value in display name
Assert.assertEquals("Department",updateProfilePage.getLabelForField("department"));
Assert.assertEquals("Department", updateProfilePage.getLabelForField("department"));
}
@ -172,49 +174,22 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
loginPage.login(USERNAME1, PASSWORD);
updateProfilePage.assertCurrent();
String htmlFormId="kc-update-profile-form";
//assert fields and groups location in form, attributes without a group appear first
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(1) > div:nth-child(2) > input#lastName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(2) > div:nth-child(2) > input#username")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(3) > div:nth-child(2) > input#firstName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(4) > div:nth-child(1) > label#header-company")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(4) > div:nth-child(2) > label#description-company")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(5) > div:nth-child(2) > input#department")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(6) > div:nth-child(1) > label#header-contact")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(7) > div:nth-child(2) > input#email")
).isDisplayed()
);
List<WebElement> element = driver.findElements(By.cssSelector("form#kc-update-profile-form label"));
String[] labelOrder = new String[]{"lastName", "username", "firstName", "header-company", "description-company", "department", "header-contact", "email"};
for (int i = 0; i < element.size(); i++) {
WebElement webElement = element.get(i);
String id;
if (webElement.getAttribute("for") != null) {
id = webElement.getAttribute("for");
// see that the label has an element it belongs to
assertThat("Label with id: " + id + " should have component it belongs to", driver.findElement(By.id(id)).isDisplayed(), is(true));
} else {
id = webElement.getAttribute("id");
}
assertThat("Label at index: " + i + " with id: " + id + " was not in found in the same order in the dom", id, is(labelOrder[i]));
}
}
@ -235,31 +210,14 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
updateProfilePage.assertCurrent();
//assert fields location in form
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-update-profile-form > div:nth-child(1) > div:nth-child(2) > input#lastName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-update-profile-form > div:nth-child(2) > div:nth-child(2) > input#department")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-update-profile-form > div:nth-child(3) > div:nth-child(2) > input#username")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-update-profile-form > div:nth-child(4) > div:nth-child(2) > input#firstName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-update-profile-form > div:nth-child(5) > div:nth-child(2) > input#email")
).isDisplayed()
);
//assert fields and groups location in form, attributes without a group appear first
List<WebElement> element = driver.findElements(By.cssSelector("form#kc-update-profile-form input"));
String[] labelOrder = new String[]{"lastName", "department", "username", "firstName", "email"};
for (int i = 0; i < labelOrder.length; i++) {
WebElement webElement = element.get(i);
String id = webElement.getAttribute("id");
assertThat("Field at index: " + i + " with id: " + id + " was not in found in the same order in the dom", id, is(labelOrder[i]));
}
}
@Test
@ -343,7 +301,7 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
setUserProfileConfiguration("{\"attributes\": ["
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL +","+VALIDATIONS_LENGTH + "},"
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "," + VALIDATIONS_LENGTH + "},"
+ "{\"name\": \"department\"," + PERMISSIONS_ADMIN_ONLY + "}"
+ "]}");
@ -436,7 +394,7 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
updateProfilePage.assertCurrent();
Assert.assertEquals("Brady", updateProfilePage.getLastName());
Assert.assertFalse("'department' field is visible" , updateProfilePage.isDepartmentPresent());
Assert.assertFalse("'department' field is visible", updateProfilePage.isDepartmentPresent());
//update of the other attributes must be successful in this case
updateProfilePage.prepareUpdate().username(USERNAME1).firstName("First").lastName("Last").email(USERNAME1).submit();
@ -494,7 +452,7 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
setUserProfileConfiguration("{\"attributes\": ["
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\"" + SCOPE_DEPARTMENT + "\"]}}"
+ "]}");
oauth.scope(SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
@ -534,7 +492,7 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
setUserProfileConfiguration("{\"attributes\": ["
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\"" + SCOPE_DEPARTMENT + "\"]}}"
+ "]}");
oauth.clientId(client_scope_default.getClientId()).openLoginForm();
@ -568,7 +526,7 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
setUserProfileConfiguration("{\"attributes\": ["
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\"" + SCOPE_DEPARTMENT + "\"]}}"
+ "]}");
oauth.scope(SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
@ -602,7 +560,7 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
setUserProfileConfiguration("{\"attributes\": ["
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\"" + SCOPE_DEPARTMENT + "\"]}}"
+ "]}");
oauth.scope(SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
@ -631,7 +589,7 @@ public class RequiredActionUpdateProfileWithUserProfileTest extends AbstractTest
setUserProfileConfiguration("{\"attributes\": ["
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\"" + SCOPE_DEPARTMENT + "\"]}}"
+ "]}");
oauth.clientId(client_scope_optional.getClientId()).openLoginForm();

View file

@ -1897,7 +1897,7 @@ public class SAMLServletAdapterTest extends AbstractSAMLServletAdapterTest {
waitForPageToLoad();
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage); // we are still in login
Assert.assertEquals("Your login attempt timed out. Login will start from the beginning.",
UIUtils.getTextFromElement(driver.findElement(By.className("alert-error"))));
UIUtils.getTextFromElement(driver.findElement(By.cssSelector("div[class^='pf-v5-c-alert'], div[class^='alert-error']"))));
// login successfully in tab2 after the error
loginPage.form().login(bburkeUser);

View file

@ -30,6 +30,7 @@ import org.keycloak.testsuite.util.AdminClientUtil;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.UserBuilder;
import static org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID;
public class AdminConsoleWhoAmILocaleTest extends AbstractKeycloakTest {
@ -52,6 +53,10 @@ public class AdminConsoleWhoAmILocaleTest extends AbstractKeycloakTest {
@Before
public void createHttpClient() throws Exception {
client = HttpClientBuilder.create().build();
getCleanup().addCleanup(ClientAttributeUpdater.forClient(adminClient, "master", ADMIN_CLI_CLIENT_ID).setAttribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, "true").update());
getCleanup().addCleanup(ClientAttributeUpdater.forClient(adminClient, REALM_I18N_OFF, ADMIN_CLI_CLIENT_ID).setAttribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, "true").update());
getCleanup().addCleanup(ClientAttributeUpdater.forClient(adminClient, REALM_I18N_ON, ADMIN_CLI_CLIENT_ID).setAttribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, "true").update());
}
@After
@ -101,17 +106,7 @@ public class AdminConsoleWhoAmILocaleTest extends AbstractKeycloakTest {
}
private OAuthClient.AccessTokenResponse accessToken(String realmName, String username, String password) throws Exception {
String codeVerifier = PkceUtils.generateCodeVerifier();
oauth.realm(realmName)
.codeVerifier(codeVerifier)
.codeChallenge(PkceUtils.generateS256CodeChallenge(codeVerifier))
.codeChallengeMethod(OAuth2Constants.PKCE_METHOD_S256)
.clientId(Constants.ADMIN_CONSOLE_CLIENT_ID)
.redirectUri(adminConsole.createUriBuilder().build(realmName).toASCIIString());
oauth.doLogin(username, password);
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, null);
return response;
return oauth.doGrantAccessTokenRequest(realmName, username, password, null, ADMIN_CLI_CLIENT_ID, null);
}
private String whoAmiUrl(String realmName) {
@ -139,7 +134,7 @@ public class AdminConsoleWhoAmILocaleTest extends AbstractKeycloakTest {
@Test
public void testLocaleRealmI18nDisabledUserWithoutLocale() throws Exception {
OAuthClient.AccessTokenResponse response = accessToken(REALM_I18N_OFF, USER_WITHOUT_LOCALE, PASSWORD);
OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest(REALM_I18N_OFF, USER_WITHOUT_LOCALE, PASSWORD, null, ADMIN_CLI_CLIENT_ID, null);
JsonNode whoAmI = SimpleHttpDefault
.doGet(whoAmiUrl(REALM_I18N_OFF), client)
.header("Accept", "application/json")
@ -276,7 +271,8 @@ public class AdminConsoleWhoAmILocaleTest extends AbstractKeycloakTest {
@Test
public void testLocaleRealmTokenForOtherClient() throws Exception {
try (Keycloak adminCliClient = AdminClientUtil.createAdminClient(true, REALM_I18N_ON,
try (var c = ClientAttributeUpdater.forClient(adminClient, REALM_I18N_ON, ADMIN_CLI_CLIENT_ID).setAttribute(Constants.SECURITY_ADMIN_CONSOLE_ATTR, null).update();
Keycloak adminCliClient = AdminClientUtil.createAdminClient(true, REALM_I18N_ON,
USER_WITH_LOCALE, PASSWORD, Constants.ADMIN_CLI_CLIENT_ID, null)) {
AccessTokenResponse accessToken = adminCliClient.tokenManager().getAccessToken();
Assert.assertNotNull(accessToken);

View file

@ -120,7 +120,7 @@ public abstract class AbstractDefaultIdpTest extends AbstractInitializedBaseBrok
waitForPage(driver, "sign in to", true);
WebElement errorElement = driver.findElement(By.className("alert-error"));
WebElement errorElement = driver.findElement(By.className("pf-v5-c-alert"));
assertNotNull("Page should show an error message but it's missing", errorElement);
// Login to IDP failed due consent denied. Error message is displayed on the username/password screen of the consumer realm

View file

@ -1,6 +1,7 @@
package org.keycloak.testsuite.broker;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.CoreMatchers;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Test;
import org.keycloak.admin.client.resource.IdentityProviderResource;
@ -27,6 +28,7 @@ import org.keycloak.testsuite.util.ClientScopeBuilder;
import org.keycloak.util.JsonSerialization;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@ -391,7 +393,7 @@ public class KcOidcFirstBrokerLoginTest extends AbstractFirstBrokerLoginTest {
updateAccountInformationPage.assertCurrent();
assertEquals("Please specify username.", loginUpdateProfilePage.getInputErrors().getUsernameError());
updateAccountInformationPage.updateAccountInformation("new-username", "no-first-name@localhost.com", "First Name", "Last Name");
UserRepresentation userRepresentation = AccountHelper.getUserRepresentation(adminClient.realm(bc.consumerRealmName()), "new-username");
@ -498,46 +500,20 @@ public class KcOidcFirstBrokerLoginTest extends AbstractFirstBrokerLoginTest {
String htmlFormId = "kc-idp-review-profile-form";
//assert fields and groups location in form, attributes without a group appear first
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(1) > div:nth-child(2) > input#lastName")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(2) > div:nth-child(2) > input#username")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(3) > div:nth-child(2) > input#firstName")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(4) > div:nth-child(1) > label#header-company")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(4) > div:nth-child(2) > label#description-company")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(5) > div:nth-child(2) > input#department")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(6) > div:nth-child(1) > label#header-contact")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(7) > div:nth-child(2) > input#email")
).isDisplayed()
);
List<WebElement> element = driver.findElements(By.cssSelector("form#kc-idp-review-profile-form label"));
String[] labelOrder = new String[]{"lastName", "username", "firstName", "header-company", "description-company", "department", "header-contact", "email"};
for (int i = 0; i < element.size(); i++) {
WebElement webElement = element.get(i);
String id;
if (webElement.getAttribute("for") != null) {
id = webElement.getAttribute("for");
// see that the label has an element it belongs to
assertThat("Label with id: " + id + " should have component it belongs to", driver.findElement(By.id(id)).isDisplayed(), is(true));
} else {
id = webElement.getAttribute("id");
}
assertThat("Label at index: " + i + " with id: " + id + " was not in found in the same order in the dom", labelOrder[i], is(id));
}
}
@Test
@ -562,32 +538,13 @@ public class KcOidcFirstBrokerLoginTest extends AbstractFirstBrokerLoginTest {
updateAccountInformationPage.assertCurrent();
//assert fields location in form
String htmlFormId = "kc-idp-review-profile-form";
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(1) > div:nth-child(2) > input#lastName")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(2) > div:nth-child(2) > input#department")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(3) > div:nth-child(2) > input#username")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(4) > div:nth-child(2) > input#firstName")
).isDisplayed()
);
org.junit.Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(5) > div:nth-child(2) > input#email")
).isDisplayed()
);
List<WebElement> element = driver.findElements(By.cssSelector("form#kc-idp-review-profile-form input"));
String[] labelOrder = new String[]{"lastName", "department", "username", "firstName", "email"};
for (int i = 0; i < labelOrder.length; i++) {
WebElement webElement = element.get(i);
String id = webElement.getAttribute("id");
assertThat("Field at index: " + i + " with id: " + id + " was not in found in the same order in the dom", id, is(labelOrder[i]));
}
}
@Test

View file

@ -36,7 +36,9 @@ import org.keycloak.testsuite.util.BrowserTabUtil;
import org.keycloak.testsuite.util.InfinispanTestTimeServiceRule;
import org.keycloak.testsuite.util.OAuthClient;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
import static org.keycloak.testsuite.AssertEvents.DEFAULT_REDIRECT_URI;
import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
@ -62,6 +64,7 @@ public class KcOidcMultipleTabsBrokerTest extends AbstractInitializedBaseBroker
// Similar to MultipleTabsLoginTest.multipleTabsParallelLogin but with IDP brokering test involved
@Test
public void testAuthenticationExpiredWithMoreBrowserTabs_clickIdpLoginInTab1AfterExpiration() {
assumeTrue("Since the JS engine in real browser does check the expiration regularly in all tabs, this test only works with HtmlUnit", driver instanceof HtmlUnitDriver);
try (BrowserTabUtil tabUtil = BrowserTabUtil.getInstanceAndSetEnv(driver)) {
oauth.clientId("broker-app");
loginPage.open(bc.consumerRealmName());
@ -100,6 +103,7 @@ public class KcOidcMultipleTabsBrokerTest extends AbstractInitializedBaseBroker
// Similar to MultipleTabsLoginTest.multipleTabsParallelLogin but with IDP brokering test involved
@Test
public void testAuthenticationExpiredWithMoreBrowserTabs_loginExpiredInBothConsumerAndProvider() {
assumeTrue("Since the JS engine in real browser does check the expiration regularly in all tabs, this test only works with HtmlUnit", driver instanceof HtmlUnitDriver);
try (BrowserTabUtil tabUtil = BrowserTabUtil.getInstanceAndSetEnv(driver)) {
// Open login page in tab1 and click "login with IDP"
oauth.clientId("broker-app");
@ -166,6 +170,7 @@ public class KcOidcMultipleTabsBrokerTest extends AbstractInitializedBaseBroker
@Test
public void testAuthenticationExpiredWithMoreBrowserTabs_loginExpiredInProvider() throws Exception {
assumeTrue("Since the JS engine in real browser does check the expiration regularly in all tabs, this test only works with HtmlUnit", driver instanceof HtmlUnitDriver);
// Testing the scenario when authenticationSession expired only in "provider" realm and "consumer" is able to handle it at IDP.
// So need to increase authSession timeout on "consumer"
try (BrowserTabUtil tabUtil = BrowserTabUtil.getInstanceAndSetEnv(driver);

View file

@ -32,7 +32,9 @@ import org.keycloak.testsuite.util.BrowserTabUtil;
import org.keycloak.testsuite.util.InfinispanTestTimeServiceRule;
import org.keycloak.testsuite.util.OAuthClient;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
/**
@ -58,6 +60,7 @@ public class KcSamlMultipleTabsBrokerTest extends AbstractInitializedBaseBrokerT
// Similar to MultipleTabsLoginTest.multipleTabsParallelLogin but with IDP brokering test involved
@Test
public void testAuthenticationExpiredWithMoreBrowserTabs_loginExpiredInBothConsumerAndProvider() {
assumeTrue("Since the JS engine in real browser does check the expiration regularly in all tabs, this test only works with HtmlUnit", driver instanceof HtmlUnitDriver);
try (BrowserTabUtil tabUtil = BrowserTabUtil.getInstanceAndSetEnv(driver)) {
// Open login page in tab1 and click "login with IDP"
oauth.clientId("broker-app");
@ -120,6 +123,7 @@ public class KcSamlMultipleTabsBrokerTest extends AbstractInitializedBaseBrokerT
@Test
public void testAuthenticationExpiredWithMoreBrowserTabs_loginExpiredInProvider() throws Exception {
assumeTrue("Since the JS engine in real browser does check the expiration regularly in all tabs, this test only works with HtmlUnit", driver instanceof HtmlUnitDriver);
// Testing the scenario when authenticationSession expired only in "provider" realm and "consumer" is able to handle it at IDP.
// So need to increase authSession timeout on "consumer"
try (BrowserTabUtil tabUtil = BrowserTabUtil.getInstanceAndSetEnv(driver);

View file

@ -151,7 +151,7 @@ public abstract class AbstractFailoverClusterTest extends AbstractClusterTest {
protected Cookie verifyLoggedIn(Cookie sessionCookieForVerification) {
// verify on realm path
URLUtils.navigateToUri(AUTH_SERVER_ROOT + "/realms/test");
URLUtils.navigateToUri(AUTH_SERVER_ROOT + "/realms/test/");
Cookie sessionCookieOnRealmPath = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE);
assertNotNull(sessionCookieOnRealmPath);
assertEquals(sessionCookieOnRealmPath.getValue(), sessionCookieForVerification.getValue());

View file

@ -223,6 +223,8 @@ public class UncaughtErrorPageTest extends AbstractKeycloakTest {
try {
checkPageNotFound("/auth/realms/master/nosuch");
// Once keycloak.v2 would be the default login theme, uncomment the following line and remove the one below:
// String url = driver.findElement(By.xpath("//option[text()[contains(.,'Deutsch')]]")).getAttribute("value");
String url = driver.findElement(By.xpath("//a[text()[contains(.,'Deutsch')]]")).getAttribute("href");
driver.navigate().to(url);
errorPage.assertCurrent();

View file

@ -55,6 +55,7 @@ import org.keycloak.testsuite.util.GreenMailRule;
import org.keycloak.testsuite.util.KeycloakModelUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
/**
* Test user registration with customized user-profile configurations
@ -288,41 +289,13 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
registerPage.assertCurrent();
//assert fields location in form
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-register-form > div:nth-child(1) > div:nth-child(2) > input#lastName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-register-form > div:nth-child(2) > div:nth-child(2) > input#department")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-register-form > div:nth-child(3) > div:nth-child(2) > input#username")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("#password")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("#password-confirm")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-register-form > div:nth-child(6) > div:nth-child(2) > input#firstName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-register-form > div:nth-child(7) > div:nth-child(2) > input#email")
).isDisplayed()
);
List<WebElement> element = driver.findElements(By.cssSelector("form#kc-register-form input"));
String[] labelOrder = new String[]{"lastName", "department", "username", "password", "password-confirm", "firstName", "email"};
for (int i = 0; i < labelOrder.length; i++) {
WebElement webElement = element.get(i);
String id = webElement.getAttribute("id");
assertThat("Field at index: " + i + " with id: " + id + " was not in found in the same order in the dom", id, is(labelOrder[i]));
}
}
public static final String UP_CONFIG_PART_INPUT_TYPES = "{\"name\": \"defaultType\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
@ -440,50 +413,22 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
loginPage.clickRegister();
registerPage.assertCurrent();
String htmlFormId="kc-register-form";
//assert fields and groups location in form, attributes without a group appear first
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(1) > div:nth-child(2) > input#lastName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(2) > div:nth-child(2) > input#username")
).isDisplayed()
);
// password and password confirmation fields appear after the username field, in positions 3 and 4
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(5) > div:nth-child(2) > input#firstName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(6) > div:nth-child(1) > label#header-company")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(6) > div:nth-child(2) > label#description-company")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(7) > div:nth-child(2) > input#department")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(8) > div:nth-child(1) > label#header-contact")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(9) > div:nth-child(2) > input#email")
).isDisplayed()
);
List<WebElement> element = driver.findElements(By.cssSelector("form#kc-register-form label"));
String[] labelOrder = new String[]{"lastName", "username", "password", "password-confirm", "firstName", "header-company", "description-company", "department", "header-contact", "email"};
for (int i = 0; i < element.size(); i++) {
WebElement webElement = element.get(i);
String id;
if (webElement.getAttribute("for") != null) {
id = webElement.getAttribute("for");
// see that the label has an element it belongs to
assertThat("Label with id: " + id + " should have component it belongs to", driver.findElement(By.id(id)).isDisplayed(), is(true));
} else {
id = webElement.getAttribute("id");
}
assertThat("Label at index: " + i + " with id: " + id + " was not in found in the same order in the dom", id, is(labelOrder[i]));
}
}
@Test
@ -702,4 +647,4 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
private UserRepresentation getUser(String userId) {
return testRealm().users().get(userId).toRepresentation();
}
}
}

View file

@ -7,10 +7,15 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.theme.ThemeSelectorProvider;
import static org.junit.Assert.assertEquals;
public class ThemeSelectorTest extends AbstractTestRealmKeycloakTest {
// At this moment, the default login theme as defined in ThemeSelectorProvider is "keycloak".
// Once the ThemeSelectorProvider.DEFAULT_V2 becomes default, this needs to be reflected in this constant.
private static final String SYSTEM_DEFAULT_LOGIN_THEME = ThemeSelectorProvider.DEFAULT;
@Page
protected LoginPage loginPage;
@ -21,7 +26,7 @@ public class ThemeSelectorTest extends AbstractTestRealmKeycloakTest {
@Test
public void clientOverride() {
loginPage.open();
assertEquals("keycloak", detectTheme());
assertEquals(System.getProperty(PROPERTY_LOGIN_THEME_DEFAULT, SYSTEM_DEFAULT_LOGIN_THEME), detectTheme());
ClientRepresentation rep = testRealm().clients().findByClientId("test-app").get(0);
@ -37,7 +42,7 @@ public class ThemeSelectorTest extends AbstractTestRealmKeycloakTest {
testRealm().clients().get(rep.getId()).update(rep);
loginPage.open();
assertEquals("keycloak", detectTheme());
assertEquals(SYSTEM_DEFAULT_LOGIN_THEME, detectTheme());
} finally {
rep.getAttributes().put("login_theme", "");
testRealm().clients().get(rep.getId()).update(rep);
@ -48,6 +53,8 @@ public class ThemeSelectorTest extends AbstractTestRealmKeycloakTest {
// for the purpose of the test does not matter which profile is used (product or community)
if(driver.getPageSource().contains("/login/keycloak/css/login.css") || driver.getPageSource().contains("/login/rh-sso/css/login.css")) {
return "keycloak";
} else if (driver.getPageSource().contains("/login/keycloak.v2/css/styles.css") || driver.getPageSource().contains("/login/rh-sso/css/styles.css")) {
return "keycloak.v2";
} else {
return "base";
}

View file

@ -73,6 +73,7 @@ import org.keycloak.testsuite.util.UserBuilder;
import org.keycloak.userprofile.UserProfileContext;
import org.keycloak.util.JsonSerialization;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
/**
* @author Vlastimil Elias <velias@redhat.com>
@ -218,49 +219,22 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
loginPage.login("login-test5", "password");
verifyProfilePage.assertCurrent();
String htmlFormId="kc-update-profile-form";
//assert fields and groups location in form, attributes without a group appear first
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(1) > div:nth-child(2) > input#lastName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(2) > div:nth-child(2) > input#username")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(3) > div:nth-child(2) > input#firstName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(4) > div:nth-child(1) > label#header-company")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(4) > div:nth-child(2) > label#description-company")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(5) > div:nth-child(2) > input#department")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(6) > div:nth-child(1) > label#header-contact")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#"+htmlFormId+" > div:nth-child(7) > div:nth-child(2) > input#email")
).isDisplayed()
);
List<WebElement> element = driver.findElements(By.cssSelector("form#kc-update-profile-form label"));
String[] labelOrder = new String[]{"lastName", "username", "firstName", "header-company", "description-company", "department", "header-contact", "email"};
for (int i = 0; i < element.size(); i++) {
WebElement webElement = element.get(i);
String id;
if (webElement.getAttribute("for") != null) {
id = webElement.getAttribute("for");
// see that the label has an element it belongs to
assertThat("Label with id: " + id + " should have component it belongs to", driver.findElement(By.id(id)).isDisplayed(), is(true));
} else {
id = webElement.getAttribute("id");
}
assertThat("Label at index: " + i + " with id: " + id + " was not in found in the same order in the dom", id, is(labelOrder[i]));
}
}
@Test
@ -287,31 +261,13 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
verifyProfilePage.assertCurrent();
//assert fields location in form
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-update-profile-form > div:nth-child(1) > div:nth-child(2) > input#lastName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-update-profile-form > div:nth-child(2) > div:nth-child(2) > input#department")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-update-profile-form > div:nth-child(3) > div:nth-child(2) > input#username")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-update-profile-form > div:nth-child(4) > div:nth-child(2) > input#firstName")
).isDisplayed()
);
Assert.assertTrue(
driver.findElement(
By.cssSelector("form#kc-update-profile-form > div:nth-child(5) > div:nth-child(2) > input#email")
).isDisplayed()
);
List<WebElement> element = driver.findElements(By.cssSelector("form#kc-update-profile-form input"));
String[] labelOrder = new String[]{"lastName", "department", "username", "firstName", "email"};
for (int i = 0; i < labelOrder.length; i++) {
WebElement webElement = element.get(i);
String id = webElement.getAttribute("id");
assertThat("Field at index: " + i + " with id: " + id + " was not in found in the same order in the dom", id, is(labelOrder[i]));
}
}
@Test

View file

@ -167,7 +167,7 @@ public class LoginPageTest extends AbstractI18NTest {
@Test
public void testIdentityProviderCapitalization(){
loginPage.open();
assertEquals("GitHub", loginPage.findSocialButton("github").getText());
assertEquals("", loginPage.findSocialButton("github").getText()); // github is only displayed as an icon in keycloak.v2 theme
assertEquals("mysaml", loginPage.findSocialButton("mysaml").getText());
assertEquals("MyOIDC", loginPage.findSocialButton("myoidc").getText());
}

View file

@ -118,6 +118,7 @@ import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT;
import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT_LINKS;
import static org.keycloak.models.AccountRoles.VIEW_GROUPS;
import static org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
import static org.keycloak.testsuite.AbstractKeycloakTest.PREFERRED_DEFAULT_LOGIN_THEME;
import static org.keycloak.testsuite.Assert.assertNames;
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.UP_COMPONENT_CONFIG_KEY;
@ -174,7 +175,7 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
protected void testRhssoThemes(RealmResource realm) {
// check themes are removed
RealmRepresentation rep = realm.toRepresentation();
Assert.assertNull("Login theme was not modified", rep.getLoginTheme());
assertThat("Login theme modified for test purposes", rep.getLoginTheme(), anyOf(nullValue(), equalTo(PREFERRED_DEFAULT_LOGIN_THEME)));
Assert.assertNull("Email theme was not modified", rep.getEmailTheme());
// there should be either new default or left null if not set
assertThat("Account theme was not modified", rep.getAccountTheme(), anyOf(equalTo("keycloak.v2"), nullValue()));

View file

@ -460,8 +460,9 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
oauth.fillLoginForm("alice", "alice");
String aliceCode = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
WebClient webClient = DroneHtmlUnitDriver.class.cast(driver).getWebClient();
webClient.getCookieManager().clearCookies();
// WebClient webClient = DroneHtmlUnitDriver.class.cast(driver).getWebClient();
// webClient.getCookieManager().clearCookies();
driver.manage().deleteAllCookies();
oauth.openLoginForm();
driver.manage().addCookie(authSessionCookie);
oauth.fillLoginForm("bob", "bob");

View file

@ -50,6 +50,7 @@ import org.keycloak.broker.saml.SAMLIdentityProviderConfig;
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
import org.keycloak.testsuite.updaters.IdentityProviderCreator;
import org.keycloak.testsuite.util.IdentityProviderBuilder;
import static org.hamcrest.Matchers.anyOf;
import static org.keycloak.testsuite.util.Matchers.bodyHC;
import static org.keycloak.testsuite.util.Matchers.statusCodeIsHC;
@ -197,9 +198,12 @@ public class IdpInitiatedLoginTest extends AbstractSamlTest {
.execute(r -> {
assertThat(r, statusCodeIsHC(Response.Status.OK));
assertThat(r, bodyHC(allOf(
containsString("Redirecting, please wait."),
anyOf(
containsString("Redirecting, please wait."),
containsString("Authentication Redirect")
),
containsString("<input type=\"hidden\" name=\"SAMLResponse\""),
containsString("<h1 id=\"kc-page-title\">")
containsString(" id=\"kc-page-title\"")
)));
});
}
@ -219,9 +223,13 @@ public class IdpInitiatedLoginTest extends AbstractSamlTest {
.execute(r -> {
assertThat(r, statusCodeIsHC(Response.Status.OK));
assertThat(r, bodyHC(allOf(
anyOf(
containsString("Redirecting, please wait."),
containsString("Authentication Redirect")
),
containsString("Redirecting, please wait."),
containsString("<input type=\"hidden\" name=\"SAMLRequest\""),
containsString("<h1 id=\"kc-page-title\">")
containsString(" id=\"kc-page-title\"")
)));
});
}

View file

@ -210,7 +210,7 @@
<browser.strict.cookies>false</browser.strict.cookies>
<webdriverDownloadBinaries>true</webdriverDownloadBinaries>
<droneInstantiationTimeoutInSeconds>60</droneInstantiationTimeoutInSeconds>
<login.theme.default/>
<login.theme.default>keycloak.v2</login.theme.default>
<github.username/>
<github.secretToken/>
<ieDriverArch>Win32</ieDriverArch>