KEYCLOAK-3212 Improve Console UI tests stability in FF, Chrome and IE
This commit is contained in:
parent
f97d0846ed
commit
7dbdb023a0
39 changed files with 382 additions and 221 deletions
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
<!--component versions-->
|
<!--component versions-->
|
||||||
<arquillian-core.version>1.1.11.Final</arquillian-core.version>
|
<arquillian-core.version>1.1.11.Final</arquillian-core.version>
|
||||||
<selenium.version>2.52.0</selenium.version>
|
<selenium.version>2.53.0</selenium.version>
|
||||||
<arquillian-drone.version>2.0.0.Beta1</arquillian-drone.version>
|
<arquillian-drone.version>2.0.0.Beta1</arquillian-drone.version>
|
||||||
<arquillian-graphene.version>2.1.0.Alpha3</arquillian-graphene.version>
|
<arquillian-graphene.version>2.1.0.Alpha3</arquillian-graphene.version>
|
||||||
<arquillian-wildfly-container.version>2.0.0.Final</arquillian-wildfly-container.version>
|
<arquillian-wildfly-container.version>2.0.0.Final</arquillian-wildfly-container.version>
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.keycloak.testsuite.auth.page.account;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.testsuite.page.Form;
|
import org.keycloak.testsuite.page.Form;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElementIsNotPresent;
|
||||||
|
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
@ -69,7 +71,7 @@ public class AccountFields extends Form {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForUsernameInputNotPresent() {
|
public void waitForUsernameInputNotPresent() {
|
||||||
waitUntilElement(usernameInput).is().not().present();
|
waitUntilElementIsNotPresent(driver, usernameInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.keycloak.testsuite.page.AbstractAlert;
|
||||||
public class AccountManagementAlert extends AbstractAlert {
|
public class AccountManagementAlert extends AbstractAlert {
|
||||||
|
|
||||||
public boolean isError() {
|
public boolean isError() {
|
||||||
return getAttributeClass().contains("alert-error");
|
return checkAlertType("error");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import static org.keycloak.testsuite.admin.Users.getPasswordOf;
|
||||||
import org.keycloak.testsuite.auth.page.account.AccountFields;
|
import org.keycloak.testsuite.auth.page.account.AccountFields;
|
||||||
import org.keycloak.testsuite.auth.page.account.PasswordFields;
|
import org.keycloak.testsuite.auth.page.account.PasswordFields;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.*;
|
import static org.keycloak.testsuite.util.WaitUtils.*;
|
||||||
|
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
@ -51,6 +52,9 @@ public class LoginForm extends Form {
|
||||||
@FindBy(id = "rememberMe")
|
@FindBy(id = "rememberMe")
|
||||||
private WebElement rememberMe;
|
private WebElement rememberMe;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//label[@for='password']")
|
||||||
|
private WebElement labelPassword;
|
||||||
|
|
||||||
public void setUsername(String username) {
|
public void setUsername(String username) {
|
||||||
accountFields.setUsername(username);
|
accountFields.setUsername(username);
|
||||||
}
|
}
|
||||||
|
@ -70,26 +74,28 @@ public class LoginForm extends Form {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void register() {
|
public void register() {
|
||||||
waitForUsernameInputPresent();
|
|
||||||
waitUntilElement(registerLink).is().present();
|
|
||||||
registerLink.click();
|
registerLink.click();
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void login() {
|
public void login() {
|
||||||
waitUntilElement(loginButton).is().present();
|
labelPassword.click(); // This is a nasty trick for IE; As IE was "moving the cursor" towards the login button
|
||||||
|
// it opened the internationalization menu (when present) and then clicked
|
||||||
|
// one of the languages instead of the Login button
|
||||||
loginButton.click();
|
loginButton.click();
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forgotPassword() {
|
public void forgotPassword() {
|
||||||
waitUntilElement(forgottenPassword).is().present();
|
|
||||||
forgottenPassword.click();
|
forgottenPassword.click();
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rememberMe(boolean value) {
|
public void rememberMe(boolean value) {
|
||||||
waitForRememberMePresent();
|
|
||||||
boolean selected = rememberMe.isSelected();
|
boolean selected = rememberMe.isSelected();
|
||||||
if ((value && !selected) || !value && selected) {
|
if ((value && !selected) || !value && selected) {
|
||||||
rememberMe.click();
|
rememberMe.click();
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +109,7 @@ public class LoginForm extends Form {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForRegisterLinkNotPresent() {
|
public void waitForRegisterLinkNotPresent() {
|
||||||
waitUntilElement(registerLink).is().not().present();
|
waitUntilElementIsNotPresent(driver, registerLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForResetPasswordLinkNotPresent() {
|
public void waitForResetPasswordLinkNotPresent() {
|
||||||
|
@ -115,7 +121,7 @@ public class LoginForm extends Form {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForRememberMeNotPresent() {
|
public void waitForRememberMeNotPresent() {
|
||||||
waitUntilElement(rememberMe).is().not().present();
|
waitUntilElementIsNotPresent(driver, rememberMe);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForLoginButtonPresent() {
|
public void waitForLoginButtonPresent() {
|
||||||
|
@ -150,6 +156,7 @@ public class LoginForm extends Form {
|
||||||
|
|
||||||
public void submit() {
|
public void submit() {
|
||||||
submit.click();
|
submit.click();
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.auth.page.login;
|
package org.keycloak.testsuite.auth.page.login;
|
||||||
|
|
||||||
|
import org.keycloak.testsuite.util.UIUtils;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ public class TermsAndConditions extends LoginActions {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCurrent() {
|
public boolean isCurrent() {
|
||||||
return driver.getTitle().equals("Terms and Conditions");
|
return UIUtils.currentTitleEquals(driver, "Terms and Conditions");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void acceptTerms() {
|
public void acceptTerms() {
|
||||||
|
|
|
@ -50,17 +50,14 @@ public class AdminEvents extends Events {
|
||||||
private AdminEventsTableFilterForm filterForm;
|
private AdminEventsTableFilterForm filterForm;
|
||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
waitForBody();
|
|
||||||
clickHeaderButton("Update");
|
clickHeaderButton("Update");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
waitForBody();
|
|
||||||
clickHeaderButton("Reset");
|
clickHeaderButton("Reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void filter() {
|
public void filter() {
|
||||||
waitForBody();
|
|
||||||
filterButton.click();
|
filterButton.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,17 +50,14 @@ public class LoginEvents extends Events {
|
||||||
private LoginEventsTableFilterForm filterForm;
|
private LoginEventsTableFilterForm filterForm;
|
||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
waitForBody();
|
|
||||||
clickHeaderButton("Update");
|
clickHeaderButton("Update");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
waitForBody();
|
|
||||||
clickHeaderButton("Reset");
|
clickHeaderButton("Reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void filter() {
|
public void filter() {
|
||||||
waitForBody();
|
|
||||||
filterButton.click();
|
filterButton.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,19 +27,19 @@ import org.openqa.selenium.support.FindBy;
|
||||||
*/
|
*/
|
||||||
public class AdminConsoleAlert extends AbstractAlert {
|
public class AdminConsoleAlert extends AbstractAlert {
|
||||||
|
|
||||||
@FindBy(xpath = "//button[@class='close']")
|
@FindBy(xpath = ".//button[@class='close']")
|
||||||
protected WebElement closeButton;
|
protected WebElement closeButton;
|
||||||
|
|
||||||
public boolean isInfo() {
|
public boolean isInfo() {
|
||||||
return getAttributeClass().contains("alert-info");
|
return checkAlertType("info");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isWarning() {
|
public boolean isWarning() {
|
||||||
return getAttributeClass().contains("alert-warning");
|
return checkAlertType("waring");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDanger() {
|
public boolean isDanger() {
|
||||||
return getAttributeClass().contains("alert-danger");
|
return checkAlertType("danger");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
|
|
@ -17,12 +17,14 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.console.page.fragment;
|
package org.keycloak.testsuite.console.page.fragment;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||||
import org.openqa.selenium.By;
|
import org.openqa.selenium.By;
|
||||||
import static org.openqa.selenium.By.xpath;
|
import static org.openqa.selenium.By.xpath;
|
||||||
|
@ -33,6 +35,9 @@ import static org.openqa.selenium.By.xpath;
|
||||||
*/
|
*/
|
||||||
public class DataTable {
|
public class DataTable {
|
||||||
|
|
||||||
|
@Drone
|
||||||
|
protected WebDriver driver;
|
||||||
|
|
||||||
@FindBy(css = "input[class*='search']")
|
@FindBy(css = "input[class*='search']")
|
||||||
private WebElement searchInput;
|
private WebElement searchInput;
|
||||||
@FindBy(css = "div[class='input-group-addon'] i")
|
@FindBy(css = "div[class='input-group-addon'] i")
|
||||||
|
@ -49,38 +54,30 @@ public class DataTable {
|
||||||
private WebElement infoRow;
|
private WebElement infoRow;
|
||||||
|
|
||||||
public void search(String pattern) {
|
public void search(String pattern) {
|
||||||
waitForBody();
|
|
||||||
searchInput.sendKeys(pattern);
|
searchInput.sendKeys(pattern);
|
||||||
searchButton.click();
|
searchButton.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clickHeaderButton(String buttonText) {
|
public void clickHeaderButton(String buttonText) {
|
||||||
waitForBody();
|
|
||||||
header.findElement(By.xpath(".//button[text()='" + buttonText + "']")).click();
|
header.findElement(By.xpath(".//button[text()='" + buttonText + "']")).click();
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clickHeaderLink(String linkText) {
|
public void clickHeaderLink(String linkText) {
|
||||||
waitForBody();
|
|
||||||
header.findElement(By.linkText(linkText)).click();
|
header.findElement(By.linkText(linkText)).click();
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebElement body() {
|
public WebElement body() {
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForBody() {
|
|
||||||
waitUntilElement(body).is().present();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<WebElement> rows() {
|
public List<WebElement> rows() {
|
||||||
waitForBody();
|
|
||||||
pause(250);
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebElement getRowByLinkText(String text) {
|
public WebElement getRowByLinkText(String text) {
|
||||||
WebElement row = body.findElement(By.xpath(".//tr[./td/a[text()='" + text + "']]"));
|
WebElement row = body.findElement(By.xpath(".//tr[./td/a[text()='" + text + "']]"));
|
||||||
waitUntilElement(row).is().present();
|
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,12 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.console.page.fragment;
|
package org.keycloak.testsuite.console.page.fragment;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
|
|
||||||
import org.jboss.arquillian.graphene.fragment.Root;
|
import org.jboss.arquillian.graphene.fragment.Root;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -33,6 +33,9 @@ public class ModalDialog {
|
||||||
@Root
|
@Root
|
||||||
private WebElement root;
|
private WebElement root;
|
||||||
|
|
||||||
|
@Drone
|
||||||
|
private WebDriver driver;
|
||||||
|
|
||||||
@FindBy(xpath = ".//button[text()='Cancel']")
|
@FindBy(xpath = ".//button[text()='Cancel']")
|
||||||
private WebElement cancelButton;
|
private WebElement cancelButton;
|
||||||
@FindBy(xpath = ".//button[text()='Delete']")
|
@FindBy(xpath = ".//button[text()='Delete']")
|
||||||
|
@ -44,26 +47,24 @@ public class ModalDialog {
|
||||||
private WebElement nameInput;
|
private WebElement nameInput;
|
||||||
|
|
||||||
public void ok() {
|
public void ok() {
|
||||||
waitUntilElement(okButton).is().present();
|
waitForModalFadeIn(driver);
|
||||||
okButton.click();
|
okButton.click();
|
||||||
waitUntilElement(root).is().not().present();
|
waitForModalFadeOut(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void confirmDeletion() {
|
public void confirmDeletion() {
|
||||||
waitUntilElement(deleteButton).is().present();
|
waitForModalFadeIn(driver);
|
||||||
deleteButton.click();
|
deleteButton.click();
|
||||||
waitUntilElement(root).is().not().present();
|
waitForModalFadeOut(driver);
|
||||||
pause(200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
waitUntilElement(cancelButton).is().present();
|
waitForModalFadeIn(driver);
|
||||||
cancelButton.click();
|
cancelButton.click();
|
||||||
waitUntilElement(root).is().not().present();
|
waitForModalFadeOut(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
waitUntilElement(nameInput).is().present();
|
|
||||||
nameInput.clear();
|
nameInput.clear();
|
||||||
nameInput.sendKeys(name);
|
nameInput.sendKeys(name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,16 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.page;
|
package org.keycloak.testsuite.page;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
import java.util.Arrays;
|
|
||||||
import static org.jboss.arquillian.graphene.Graphene.waitModel;
|
|
||||||
import org.jboss.arquillian.graphene.fragment.Root;
|
import org.jboss.arquillian.graphene.fragment.Root;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
|
||||||
|
import org.keycloak.testsuite.util.WaitUtils;
|
||||||
|
import org.openqa.selenium.TimeoutException;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||||
|
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -37,33 +39,27 @@ public abstract class AbstractAlert {
|
||||||
@Root
|
@Root
|
||||||
protected WebElement root;
|
protected WebElement root;
|
||||||
|
|
||||||
public void waitUntilPresent() {
|
@Drone
|
||||||
waitUntilElement(root, "Flash message should be present.").is().present();
|
protected WebDriver driver;
|
||||||
}
|
|
||||||
|
|
||||||
public void waitUntilPresentAndClassSet() {
|
|
||||||
waitUntilPresent();
|
|
||||||
waitModel().until(new Predicate<WebDriver>() {
|
|
||||||
@Override
|
|
||||||
public boolean apply(WebDriver input) {
|
|
||||||
return !Arrays.asList(getAttributeClass().split(" ")).contains("alert-");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return root.getText();
|
return root.getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAttributeClass() {
|
|
||||||
String attrClass = root.getAttribute("class");
|
|
||||||
log.debug("Alert @class = '" + attrClass + "'");
|
|
||||||
return attrClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSuccess() {
|
public boolean isSuccess() {
|
||||||
log.debug("Alert.isSuccess()");
|
log.debug("Alert.isSuccess()");
|
||||||
return getAttributeClass().contains("alert-success");
|
return checkAlertType("success");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean checkAlertType(String type) {
|
||||||
|
WaitUtils.waitForPageToLoad(driver);
|
||||||
|
try {
|
||||||
|
(new WebDriverWait(driver, 1)).until(ExpectedConditions.attributeContains(root, "class", "alert-" + type));
|
||||||
|
}
|
||||||
|
catch (TimeoutException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,8 @@ import java.util.Map;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
|
||||||
|
|
||||||
import org.openqa.selenium.By;
|
import org.keycloak.testsuite.util.URLUtils;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,17 +86,15 @@ public abstract class AbstractPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void navigateTo() {
|
public void navigateTo() {
|
||||||
String uri = buildUri().toASCIIString();
|
navigateTo(true);
|
||||||
log.debug("current URL: " + driver.getCurrentUrl());
|
}
|
||||||
log.info("navigating to " + uri);
|
|
||||||
driver.navigate().to(uri);
|
public void navigateTo(boolean waitForMatch) {
|
||||||
pause(300); // this is needed for FF for some reason
|
URLUtils.navigateToUri(driver, buildUri().toASCIIString(), waitForMatch);
|
||||||
waitUntilElement(By.tagName("body")).is().visible();
|
|
||||||
log.info("current URL: " + driver.getCurrentUrl());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCurrent() {
|
public boolean isCurrent() {
|
||||||
return driver.getCurrentUrl().equals(toString());
|
return URLUtils.currentUrlEqual(driver, toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
import static org.jboss.arquillian.graphene.Graphene.guardAjax;
|
import static org.jboss.arquillian.graphene.Graphene.guardAjax;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||||
|
|
||||||
|
import org.keycloak.testsuite.util.WaitUtils;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
@ -45,8 +47,8 @@ public class Form {
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
// guardAjax(save).click();
|
// guardAjax(save).click();
|
||||||
waitUntilElement(save).is().present();
|
|
||||||
save.click();
|
save.click();
|
||||||
|
WaitUtils.waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
|
@ -54,14 +56,12 @@ public class Form {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getInputValue(WebElement input) {
|
public static String getInputValue(WebElement input) {
|
||||||
waitUntilElement(input).is().present();
|
|
||||||
return input.getAttribute(VALUE);
|
return input.getAttribute(VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String VALUE = "value";
|
public static final String VALUE = "value";
|
||||||
|
|
||||||
public static void setInputValue(WebElement input, String value) {
|
public static void setInputValue(WebElement input, String value) {
|
||||||
waitUntilElement(input).is().present();
|
|
||||||
if (input.isEnabled()) {
|
if (input.isEnabled()) {
|
||||||
input.clear();
|
input.clear();
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package org.keycloak.testsuite.util;
|
||||||
|
|
||||||
|
import org.openqa.selenium.TimeoutException;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||||
|
import org.openqa.selenium.support.ui.Select;
|
||||||
|
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||||
|
*/
|
||||||
|
public final class UIUtils {
|
||||||
|
|
||||||
|
public static boolean selectContainsOption(Select select, String optionText) {
|
||||||
|
for (WebElement option : select.getOptions()) {
|
||||||
|
if (option.getText().equals(optionText)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean currentTitleEquals(WebDriver driver, String url) {
|
||||||
|
try {
|
||||||
|
(new WebDriverWait(driver, 5)).until(ExpectedConditions.titleIs(url));
|
||||||
|
}
|
||||||
|
catch (TimeoutException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
package org.keycloak.testsuite.util;
|
||||||
|
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.openqa.selenium.TimeoutException;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.ie.InternetExplorerDriver;
|
||||||
|
import org.openqa.selenium.support.ui.ExpectedCondition;
|
||||||
|
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static org.openqa.selenium.support.ui.ExpectedConditions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||||
|
*/
|
||||||
|
public final class URLUtils {
|
||||||
|
|
||||||
|
public static void navigateToUri(WebDriver driver, String uri, boolean waitForMatch) {
|
||||||
|
navigateToUri(driver, uri, waitForMatch, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void navigateToUri(WebDriver driver, String uri, boolean waitForMatch, boolean enableIEWorkaround) {
|
||||||
|
Logger log = Logger.getLogger(URLUtils.class);
|
||||||
|
|
||||||
|
log.info("starting navigation");
|
||||||
|
|
||||||
|
// In IE, sometime the current URL is not correct; one of the indicators is that the target URL
|
||||||
|
// equals the current URL
|
||||||
|
if (driver instanceof InternetExplorerDriver && driver.getCurrentUrl().equals(uri)) {
|
||||||
|
log.info("IE workaround: target URL equals current URL - refreshing the page");
|
||||||
|
driver.navigate().refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitUtils.waitForPageToLoad(driver);
|
||||||
|
|
||||||
|
log.info("current URL: " + driver.getCurrentUrl());
|
||||||
|
log.info("navigating to " + uri);
|
||||||
|
driver.navigate().to(uri);
|
||||||
|
|
||||||
|
if (waitForMatch) {
|
||||||
|
try {
|
||||||
|
(new WebDriverWait(driver, 3)).until(urlMatches("^" + Pattern.quote(uri) + ".*$"));
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
log.info("new current URL doesn't start with desired URL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitUtils.waitForPageToLoad(driver);
|
||||||
|
|
||||||
|
log.info("new current URL: " + driver.getCurrentUrl());
|
||||||
|
|
||||||
|
// In IE, after deleting the cookies for test realm, the first loaded page in master's admin console
|
||||||
|
// contains invalid URL (misses #/realms/[realm] or contains state and code fragments), although the
|
||||||
|
// address bar states the correct URL; seemingly this is another bug in IE WebDriver)
|
||||||
|
if (enableIEWorkaround && driver instanceof InternetExplorerDriver
|
||||||
|
&& (driver.getCurrentUrl().matches("^[^#]+/#state=[^#/&]+&code=[^#/&]+$")
|
||||||
|
|| driver.getCurrentUrl().matches("^.+/auth/admin/[^/]+/console/$"))) {
|
||||||
|
log.info("IE workaround: reloading the page after deleting the cookies...");
|
||||||
|
navigateToUri(driver, uri, waitForMatch, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.info("navigation complete");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean currentUrlEqual(WebDriver driver, String url) {
|
||||||
|
return urlCheck(driver, urlToBe(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean currentUrlDoesntEqual(WebDriver driver, String url) {
|
||||||
|
return urlCheck(driver, not(urlToBe(url)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean currentUrlStartWith(WebDriver driver, String url) {
|
||||||
|
return urlCheck(driver, urlMatches("^" + Pattern.quote(url) + ".*$"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean currentUrlDoesntStartWith(WebDriver driver, String url) {
|
||||||
|
return urlCheck(driver, urlMatches("^(?!" + Pattern.quote(url) + ").+$"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean urlCheck(WebDriver driver, ExpectedCondition condition) {
|
||||||
|
return urlCheck(driver, condition, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean urlCheck(WebDriver driver, ExpectedCondition condition, boolean secondTry) {
|
||||||
|
Logger log = Logger.getLogger(URLUtils.class);
|
||||||
|
|
||||||
|
try {
|
||||||
|
(new WebDriverWait(driver, 1, 100)).until(condition);
|
||||||
|
}
|
||||||
|
catch (TimeoutException e) {
|
||||||
|
if (driver instanceof InternetExplorerDriver && !secondTry) {
|
||||||
|
// IE WebDriver has sometimes invalid current URL
|
||||||
|
log.info("IE workaround: checking URL failed at first attempt - refreshing the page and trying one more time...");
|
||||||
|
driver.navigate().refresh();
|
||||||
|
urlCheck(driver, condition, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,36 +16,60 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.util;
|
package org.keycloak.testsuite.util;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import static org.jboss.arquillian.graphene.Graphene.waitGui;
|
import static org.jboss.arquillian.graphene.Graphene.waitGui;
|
||||||
import org.jboss.arquillian.graphene.wait.ElementBuilder;
|
import org.jboss.arquillian.graphene.wait.ElementBuilder;
|
||||||
import org.openqa.selenium.By;
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.TimeoutException;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||||
|
|
||||||
|
import static org.jboss.arquillian.graphene.Graphene.waitModel;
|
||||||
|
import static org.openqa.selenium.support.ui.ExpectedConditions.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Petr Mensik
|
* @author Petr Mensik
|
||||||
* @author tkyjovsk
|
* @author tkyjovsk
|
||||||
|
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||||
*/
|
*/
|
||||||
public final class WaitUtils {
|
public final class WaitUtils {
|
||||||
|
|
||||||
|
protected final static org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(WaitUtils.class);
|
||||||
|
|
||||||
public static final String PAGELOAD_TIMEOUT_PROP = "pageload.timeout";
|
public static final String PAGELOAD_TIMEOUT_PROP = "pageload.timeout";
|
||||||
|
|
||||||
public static final Integer PAGELOAD_TIMEOUT = Integer.parseInt(System.getProperty(PAGELOAD_TIMEOUT_PROP, "60000"));
|
public static final Integer PAGELOAD_TIMEOUT_MILLIS = Integer.parseInt(System.getProperty(PAGELOAD_TIMEOUT_PROP, "10000"));
|
||||||
|
|
||||||
|
public static final int IMPLICIT_ELEMENT_WAIT_MILLIS = 750;
|
||||||
|
|
||||||
|
// Should be no longer necessary for finding elements since we have implicit wait
|
||||||
public static ElementBuilder<Void> waitUntilElement(By by) {
|
public static ElementBuilder<Void> waitUntilElement(By by) {
|
||||||
return waitGui().until().element(by);
|
return waitGui().until().element(by);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should be no longer necessary for finding elements since we have implicit wait
|
||||||
public static ElementBuilder<Void> waitUntilElement(WebElement element) {
|
public static ElementBuilder<Void> waitUntilElement(WebElement element) {
|
||||||
return waitGui().until().element(element);
|
return waitGui().until().element(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should be no longer necessary for finding elements since we have implicit wait
|
||||||
public static ElementBuilder<Void> waitUntilElement(WebElement element, String failMessage) {
|
public static ElementBuilder<Void> waitUntilElement(WebElement element, String failMessage) {
|
||||||
return waitGui().until(failMessage).element(element);
|
return waitGui().until(failMessage).element(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void waitUntilElementIsNotPresent(WebDriver driver, By locator) {
|
||||||
|
waitUntilElementIsNotPresent(driver, driver.findElement(locator));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void waitUntilElementIsNotPresent(WebDriver driver, WebElement element) {
|
||||||
|
(new WebDriverWait(driver, IMPLICIT_ELEMENT_WAIT_MILLIS))
|
||||||
|
.until(invisibilityOfAllElements(Collections.singletonList(element)));
|
||||||
|
}
|
||||||
|
|
||||||
public static void pause(long millis) {
|
public static void pause(long millis) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(millis);
|
Thread.sleep(millis);
|
||||||
|
@ -55,4 +79,40 @@ public final class WaitUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for page to finish any pending redirects, REST API requests etc.
|
||||||
|
* Because Keycloak's Admin Console is a single-page application, we need to take extra steps to ensure
|
||||||
|
* the page is fully loaded
|
||||||
|
*
|
||||||
|
* @param driver
|
||||||
|
*/
|
||||||
|
public static void waitForPageToLoad(WebDriver driver) {
|
||||||
|
WebDriverWait wait = new WebDriverWait(driver, PAGELOAD_TIMEOUT_MILLIS / 1000);
|
||||||
|
|
||||||
|
try {
|
||||||
|
wait.until(not(urlContains("redirect_fragment")));
|
||||||
|
|
||||||
|
// Checks if the document is ready and asks AngularJS, if present, whether there are any REST API requests
|
||||||
|
// in progress
|
||||||
|
wait.until(javaScriptThrowsNoExceptions(
|
||||||
|
"if (document.readyState !== 'complete' " +
|
||||||
|
"|| (typeof angular !== 'undefined' && angular.element(document.body).injector().get('$http').pendingRequests.length !== 0)) {" +
|
||||||
|
"throw \"Not ready\";" +
|
||||||
|
"}"));
|
||||||
|
}
|
||||||
|
catch (TimeoutException e) {
|
||||||
|
// Sometimes, for no obvious reason, the browser/JS doesn't set document.readyState to 'complete' correctly
|
||||||
|
// but that's no reason to let the test fail; after the timeout the page is surely fully loaded
|
||||||
|
log.warn("waitForPageToLoad time exceeded!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void waitForModalFadeIn(WebDriver driver) {
|
||||||
|
pause(500); // TODO: Find out how to do in more 'elegant' way, e.g. like in the waitForModalFadeOut
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void waitForModalFadeOut(WebDriver driver) {
|
||||||
|
waitUntilElementIsNotPresent(driver, By.className("modal-backdrop"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.testsuite.auth.page.AuthRealm;
|
import org.keycloak.testsuite.auth.page.AuthRealm;
|
||||||
|
import org.keycloak.testsuite.auth.page.account.Account;
|
||||||
import org.keycloak.testsuite.auth.page.login.OIDCLogin;
|
import org.keycloak.testsuite.auth.page.login.OIDCLogin;
|
||||||
import org.keycloak.testsuite.auth.page.login.SAMLPostLogin;
|
import org.keycloak.testsuite.auth.page.login.SAMLPostLogin;
|
||||||
import org.keycloak.testsuite.auth.page.login.SAMLRedirectLogin;
|
import org.keycloak.testsuite.auth.page.login.SAMLRedirectLogin;
|
||||||
|
@ -46,6 +47,8 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest {
|
||||||
protected AuthRealm testRealmPage;
|
protected AuthRealm testRealmPage;
|
||||||
@Page
|
@Page
|
||||||
protected OIDCLogin testRealmLoginPage;
|
protected OIDCLogin testRealmLoginPage;
|
||||||
|
@Page
|
||||||
|
protected Account testRealmAccountPage;
|
||||||
|
|
||||||
@Page
|
@Page
|
||||||
protected SAMLPostLogin testRealmSAMLPostLoginPage;
|
protected SAMLPostLogin testRealmSAMLPostLoginPage;
|
||||||
|
@ -68,6 +71,7 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest {
|
||||||
@Before
|
@Before
|
||||||
public void beforeAuthTest() {
|
public void beforeAuthTest() {
|
||||||
testRealmLoginPage.setAuthRealm(testRealmPage);
|
testRealmLoginPage.setAuthRealm(testRealmPage);
|
||||||
|
testRealmAccountPage.setAuthRealm(testRealmPage);
|
||||||
|
|
||||||
testUser = createUserRepresentation("test", "test@email.test", "test", "user", true);
|
testUser = createUserRepresentation("test", "test@email.test", "test", "user", true);
|
||||||
setPasswordFor(testUser, PASSWORD);
|
setPasswordFor(testUser, PASSWORD);
|
||||||
|
@ -97,7 +101,8 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteAllCookiesForTestRealm() {
|
public void deleteAllCookiesForTestRealm() {
|
||||||
testRealmPage.navigateTo();
|
// testRealmPage.navigateTo();
|
||||||
|
testRealmAccountPage.navigateTo(); // Because IE webdriver freezes when loading a JSON page (realm page), we need to use this alternative
|
||||||
log.debug("deleting cookies in test realm");
|
log.debug("deleting cookies in test realm");
|
||||||
driver.manage().deleteAllCookies();
|
driver.manage().deleteAllCookies();
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,13 +169,15 @@ public abstract class AbstractKeycloakTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteAllCookiesForMasterRealm() {
|
public void deleteAllCookiesForMasterRealm() {
|
||||||
masterRealmPage.navigateTo();
|
// masterRealmPage.navigateTo();
|
||||||
|
accountPage.navigateTo(); // Because IE webdriver freezes when loading a JSON page (realm page), we need to use this alternative
|
||||||
log.debug("deleting cookies in master realm");
|
log.debug("deleting cookies in master realm");
|
||||||
driver.manage().deleteAllCookies();
|
driver.manage().deleteAllCookies();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void driverSettings() {
|
protected void driverSettings() {
|
||||||
driver.manage().timeouts().pageLoadTimeout(WaitUtils.PAGELOAD_TIMEOUT, TimeUnit.MILLISECONDS);
|
driver.manage().timeouts().implicitlyWait(WaitUtils.IMPLICIT_ELEMENT_WAIT_MILLIS, TimeUnit.MILLISECONDS);
|
||||||
|
driver.manage().timeouts().pageLoadTimeout(WaitUtils.PAGELOAD_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
||||||
driver.manage().window().maximize();
|
driver.manage().window().maximize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,12 +52,10 @@ public abstract class AbstractAccountManagementTest extends AbstractAuthTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertAlertSuccess() {
|
public void assertAlertSuccess() {
|
||||||
alert.waitUntilPresentAndClassSet();
|
|
||||||
assertTrue(alert.isSuccess());
|
assertTrue(alert.isSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertAlertError() {
|
public void assertAlertError() {
|
||||||
alert.waitUntilPresentAndClassSet();
|
|
||||||
assertTrue(alert.isError());
|
assertTrue(alert.isError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.util;
|
package org.keycloak.testsuite.util;
|
||||||
|
|
||||||
import javax.ws.rs.core.UriBuilder;
|
|
||||||
|
|
||||||
import org.apache.http.Header;
|
import org.apache.http.Header;
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
@ -27,12 +25,12 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.keycloak.testsuite.page.AbstractPage;
|
import org.keycloak.testsuite.page.AbstractPage;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import org.keycloak.testsuite.auth.page.login.PageWithLoginUrl;
|
import org.keycloak.testsuite.auth.page.login.PageWithLoginUrl;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.util.URLUtils.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
@ -51,16 +49,9 @@ public class URLAssert {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertCurrentUrlEquals(WebDriver driver, final AbstractPage page) {
|
public static void assertCurrentUrlEquals(WebDriver driver, final AbstractPage page) {
|
||||||
// WebDriverWait wait = new WebDriverWait(driver, 1);
|
String expected = page.toString();
|
||||||
// ExpectedCondition<Boolean> urlStartsWith = new ExpectedCondition<Boolean>() {
|
assertTrue("Expected URL: " + expected + "; actual: " + driver.getCurrentUrl(),
|
||||||
//
|
currentUrlEqual(driver, page.toString()));
|
||||||
// @Override
|
|
||||||
// public Boolean apply(WebDriver wd) {
|
|
||||||
// return startsWithNormalized(wd.getCurrentUrl(), page.toString());
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// wait.until(urlStartsWith);
|
|
||||||
assertEqualsNormalized(page.toString(), driver.getCurrentUrl());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertCurrentUrlStartsWith(AbstractPage page) {
|
public static void assertCurrentUrlStartsWith(AbstractPage page) {
|
||||||
|
@ -68,16 +59,8 @@ public class URLAssert {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertCurrentUrlStartsWith(WebDriver driver, final String url) {
|
public static void assertCurrentUrlStartsWith(WebDriver driver, final String url) {
|
||||||
// WebDriverWait wait = new WebDriverWait(driver, 1);
|
assertTrue("URL expected to begin with:" + url + "; actual URL: " + driver.getCurrentUrl(),
|
||||||
// ExpectedCondition<Boolean> urlStartsWith = new ExpectedCondition<Boolean>() {
|
currentUrlStartWith(driver, url));
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public Boolean apply(WebDriver wd) {
|
|
||||||
// return startsWithNormalized(wd.getCurrentUrl(), url);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// wait.until(urlStartsWith);
|
|
||||||
assertTrue("'" + driver.getCurrentUrl() + " does not start with '" + url + "'", startsWithNormalized(driver.getCurrentUrl(), url));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertCurrentUrlDoesntStartWith(AbstractPage page) {
|
public static void assertCurrentUrlDoesntStartWith(AbstractPage page) {
|
||||||
|
@ -85,35 +68,10 @@ public class URLAssert {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertCurrentUrlDoesntStartWith(WebDriver driver, final String url) {
|
public static void assertCurrentUrlDoesntStartWith(WebDriver driver, final String url) {
|
||||||
// WebDriverWait wait = new WebDriverWait(driver, 1, 250);
|
assertTrue("URL expected NOT to begin with:" + url + "; actual URL: " + driver.getCurrentUrl(),
|
||||||
// ExpectedCondition<Boolean> urlDoesntStartWith = new ExpectedCondition<Boolean>() {
|
currentUrlDoesntStartWith(driver, url));
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public Boolean apply(WebDriver wd) {
|
|
||||||
// return !startsWithNormalized(wd.getCurrentUrl(), url);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// wait.until(urlDoesntStartWith);
|
|
||||||
assertFalse(startsWithNormalized(driver.getCurrentUrl(), url));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this normalization is needed because of slash-encoding in uri fragment (the part after #)
|
|
||||||
public static String normalizeUri(String uri) {
|
|
||||||
return UriBuilder.fromUri(uri).build().toASCIIString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean startsWithNormalized(String str1, String str2) {
|
|
||||||
String uri1 = normalizeUri(str1);
|
|
||||||
String uri2 = normalizeUri(str2);
|
|
||||||
return uri1.startsWith(uri2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void assertEqualsNormalized(String str1, String str2) {
|
|
||||||
assertEquals(normalizeUri(str1), normalizeUri(str2));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void assertCurrentUrlStartsWithLoginUrlOf(PageWithLoginUrl page) {
|
public static void assertCurrentUrlStartsWithLoginUrlOf(PageWithLoginUrl page) {
|
||||||
assertCurrentUrlStartsWithLoginUrlOf(page.getDriver(), page);
|
assertCurrentUrlStartsWithLoginUrlOf(page.getDriver(), page);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,10 @@
|
||||||
|
|
||||||
<name>Admin Console UI Tests</name>
|
<name>Admin Console UI Tests</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<keycloak.theme.dir>${auth.server.home}/themes</keycloak.theme.dir>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<pluginManagement>
|
<pluginManagement>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
@ -54,6 +58,14 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<systemProperties>
|
||||||
|
<keycloak.theme.dir>${keycloak.theme.dir}</keycloak.theme.dir>
|
||||||
|
</systemProperties>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
</build>
|
</build>
|
||||||
|
|
|
@ -52,8 +52,10 @@ public class PasswordPolicy extends Authentication {
|
||||||
|
|
||||||
public void removePolicy(Type policy) {
|
public void removePolicy(Type policy) {
|
||||||
getPolicyRow(policy).findElement(By.cssSelector("td.kc-action-cell")).click();
|
getPolicyRow(policy).findElement(By.cssSelector("td.kc-action-cell")).click();
|
||||||
|
if (!primaryButton.isDisplayed()) {
|
||||||
primaryButton.click();
|
primaryButton.click();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void editPolicy(Type policy, int value) {
|
public void editPolicy(Type policy, int value) {
|
||||||
editPolicy(policy, String.valueOf(value));
|
editPolicy(policy, String.valueOf(value));
|
||||||
|
|
|
@ -62,32 +62,26 @@ public class Clients extends AdminConsoleRealm {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createClient() {
|
public void createClient() {
|
||||||
waitForBody();
|
|
||||||
clickHeaderLink(CREATE);
|
clickHeaderLink(CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importClient() {
|
public void importClient() {
|
||||||
waitForBody();
|
|
||||||
clickHeaderLink(IMPORT);
|
clickHeaderLink(IMPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clickClient(ClientRepresentation client) {
|
public void clickClient(ClientRepresentation client) {
|
||||||
waitForBody();
|
|
||||||
clickClient(client.getClientId());
|
clickClient(client.getClientId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clickClient(String clientId) {
|
public void clickClient(String clientId) {
|
||||||
waitForBody();
|
|
||||||
body().findElement(linkText(clientId)).click();
|
body().findElement(linkText(clientId)).click();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void editClient(String clientId) {
|
public void editClient(String clientId) {
|
||||||
waitForBody();
|
|
||||||
clickRowActionButton(getRowByLinkText(clientId), EDIT);
|
clickRowActionButton(getRowByLinkText(clientId), EDIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteClient(String clientId) {
|
public void deleteClient(String clientId) {
|
||||||
waitForBody();
|
|
||||||
clickRowActionButton(getRowByLinkText(clientId), DELETE);
|
clickRowActionButton(getRowByLinkText(clientId), DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,15 +56,18 @@ public class ClientCredentialsForm extends Form {
|
||||||
public void regenerateSecret() {
|
public void regenerateSecret() {
|
||||||
waitUntilElement(regenerateSecretButton).is().visible();
|
waitUntilElement(regenerateSecretButton).is().visible();
|
||||||
regenerateSecretButton.click();
|
regenerateSecretButton.click();
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void regenerateRegistrationAccessToken() {
|
public void regenerateRegistrationAccessToken() {
|
||||||
waitUntilElement(regenerateRegistrationAccessTokenButton).is().visible();
|
waitUntilElement(regenerateRegistrationAccessTokenButton).is().visible();
|
||||||
regenerateRegistrationAccessTokenButton.click();
|
regenerateRegistrationAccessTokenButton.click();
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generateNewKeysAndCert() {
|
public void generateNewKeysAndCert() {
|
||||||
waitUntilElement(generateNewKeysAndCert).is().visible();
|
waitUntilElement(generateNewKeysAndCert).is().visible();
|
||||||
generateNewKeysAndCert.click();
|
generateNewKeysAndCert.click();
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
package org.keycloak.testsuite.console.page.clients.installation;
|
package org.keycloak.testsuite.console.page.clients.installation;
|
||||||
|
|
||||||
import org.keycloak.testsuite.page.Form;
|
import org.keycloak.testsuite.page.Form;
|
||||||
|
import org.keycloak.testsuite.util.WaitUtils;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
import org.openqa.selenium.support.ui.Select;
|
import org.openqa.selenium.support.ui.Select;
|
||||||
|
@ -40,6 +41,7 @@ public class ClientInstallationForm extends Form {
|
||||||
|
|
||||||
public void setConfigFormat(String value) {
|
public void setConfigFormat(String value) {
|
||||||
configFormatsSelect.selectByVisibleText(value);
|
configFormatsSelect.selectByVisibleText(value);
|
||||||
|
WaitUtils.waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTextareaContent() {
|
public String getTextareaContent() {
|
||||||
|
|
|
@ -42,17 +42,14 @@ public class ClientMappers extends Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createMapper() {
|
public void createMapper() {
|
||||||
waitForBody();
|
|
||||||
clickHeaderLink(CREATE);
|
clickHeaderLink(CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addBuiltin() {
|
public void addBuiltin() {
|
||||||
waitForBody();
|
|
||||||
clickHeaderLink(ADD_BUILTIN);
|
clickHeaderLink(ADD_BUILTIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clickMapper(String mapperName) {
|
public void clickMapper(String mapperName) {
|
||||||
waitForBody();
|
|
||||||
body().findElement(By.linkText(mapperName)).click();
|
body().findElement(By.linkText(mapperName)).click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +58,6 @@ public class ClientMappers extends Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clickMapperActionButton(String mapperName, String buttonText) {
|
private void clickMapperActionButton(String mapperName, String buttonText) {
|
||||||
waitForBody();
|
|
||||||
clickRowActionButton(getRowByLinkText(mapperName), buttonText);
|
clickRowActionButton(getRowByLinkText(mapperName), buttonText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package org.keycloak.testsuite.console.page.clients.mappers;
|
package org.keycloak.testsuite.console.page.clients.mappers;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
|
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
|
||||||
import org.keycloak.testsuite.page.Form;
|
import org.keycloak.testsuite.page.Form;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
|
||||||
|
import org.keycloak.testsuite.util.WaitUtils;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
import org.openqa.selenium.support.ui.Select;
|
import org.openqa.selenium.support.ui.Select;
|
||||||
|
@ -44,40 +47,40 @@ public class CreateClientMappersForm extends Form {
|
||||||
@FindBy(id = "mapperTypeCreate")
|
@FindBy(id = "mapperTypeCreate")
|
||||||
private Select mapperTypeSelect;
|
private Select mapperTypeSelect;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Property']//following-sibling::node()//input[@type='text']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Property')]//following-sibling::node()//input[@type='text']")
|
||||||
private WebElement propertyInput;
|
private WebElement propertyInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='User Attribute']//following-sibling::node()//input[@type='text']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'User Attribute')]//following-sibling::node()//input[@type='text']")
|
||||||
private WebElement userAttributeInput;
|
private WebElement userAttributeInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='User Session Note']//following-sibling::node()//input[@type='text']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'User Session Note')]//following-sibling::node()//input[@type='text']")
|
||||||
private WebElement userSessionNoteInput;
|
private WebElement userSessionNoteInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Multivalued']//following-sibling::node()//div[@class='onoffswitch']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Multivalued')]//following-sibling::node()//div[@class='onoffswitch']")
|
||||||
private OnOffSwitch multivaluedInput;
|
private OnOffSwitch multivaluedInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//button[text() = 'Select Role']/../..//input")
|
@FindBy(xpath = ".//button[text() = 'Select Role']/../..//input")
|
||||||
private WebElement roleInput;
|
private WebElement roleInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='New Role Name']//following-sibling::node()//input[@type='text']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'New Role Name')]//following-sibling::node()//input[@type='text']")
|
||||||
private WebElement newRoleInput;
|
private WebElement newRoleInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Token Claim Name']//following-sibling::node()//input[@type='text']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Token Claim Name')]//following-sibling::node()//input[@type='text']")
|
||||||
private WebElement tokenClaimNameInput;
|
private WebElement tokenClaimNameInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Claim value']//following-sibling::node()//input[@type='text']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Claim value')]//following-sibling::node()//input[@type='text']")
|
||||||
private WebElement tokenClaimValueInput;
|
private WebElement tokenClaimValueInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Claim JSON Type']//following-sibling::node()//select")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Claim JSON Type')]//following-sibling::node()//select")
|
||||||
private Select claimJSONTypeInput;
|
private Select claimJSONTypeInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Add to ID token']//following-sibling::node()//div[@class='onoffswitch']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Add to ID token')]//following-sibling::node()//div[@class='onoffswitch']")
|
||||||
private OnOffSwitch addToIDTokenInput;
|
private OnOffSwitch addToIDTokenInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Add to access token']//following-sibling::node()//div[@class='onoffswitch']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Add to access token')]//following-sibling::node()//div[@class='onoffswitch']")
|
||||||
private OnOffSwitch addToAccessTokenInput;
|
private OnOffSwitch addToAccessTokenInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Full group path']//following-sibling::node()//div[@class='onoffswitch']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Full group path')]//following-sibling::node()//div[@class='onoffswitch']")
|
||||||
private OnOffSwitch fullGroupPath;
|
private OnOffSwitch fullGroupPath;
|
||||||
|
|
||||||
@FindBy(xpath = ".//button[text() = 'Select Role']")
|
@FindBy(xpath = ".//button[text() = 'Select Role']")
|
||||||
|
@ -87,16 +90,19 @@ public class CreateClientMappersForm extends Form {
|
||||||
private RoleSelectorModalDialog roleSelectorModalDialog;
|
private RoleSelectorModalDialog roleSelectorModalDialog;
|
||||||
|
|
||||||
public class RoleSelectorModalDialog {
|
public class RoleSelectorModalDialog {
|
||||||
|
@Drone
|
||||||
|
private WebDriver driver;
|
||||||
|
|
||||||
@FindBy(id = "available")
|
@FindBy(id = "available")
|
||||||
private Select realmAvailable;
|
private Select realmAvailable;
|
||||||
@FindBy(xpath = ".//button[@tooltip='Select realm role']")
|
@FindBy(xpath = ".//button[@tooltip='Select realm role' and not(@disabled)]")
|
||||||
private WebElement selectRealmRoleButton;
|
private WebElement selectRealmRoleButton;
|
||||||
|
|
||||||
@FindBy(id = "available-client")
|
@FindBy(id = "available-client")
|
||||||
private Select clientAvailable;
|
private Select clientAvailable;
|
||||||
@FindBy(id = "clients")
|
@FindBy(id = "clients")
|
||||||
private Select clientSelect;
|
private Select clientSelect;
|
||||||
@FindBy(xpath = ".//button[@tooltip='Select client role']")
|
@FindBy(xpath = ".//button[@tooltip='Select client role' and not(@disabled)]")
|
||||||
private WebElement selectClientRoleButton;
|
private WebElement selectClientRoleButton;
|
||||||
@FindBy(xpath = ".//button[@class='close']")
|
@FindBy(xpath = ".//button[@class='close']")
|
||||||
private WebElement closeButton;
|
private WebElement closeButton;
|
||||||
|
@ -109,8 +115,9 @@ public class CreateClientMappersForm extends Form {
|
||||||
if (roleName != null) {
|
if (roleName != null) {
|
||||||
realmAvailable.selectByVisibleText(roleName);
|
realmAvailable.selectByVisibleText(roleName);
|
||||||
}
|
}
|
||||||
|
WaitUtils.pause(1000);
|
||||||
selectRealmRoleButton.click();
|
selectRealmRoleButton.click();
|
||||||
pause(500); // wait for the modal dialog to fade out
|
WaitUtils.waitForModalFadeOut(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectClientRole(String clientName, String roleName) {
|
public void selectClientRole(String clientName, String roleName) {
|
||||||
|
@ -118,8 +125,9 @@ public class CreateClientMappersForm extends Form {
|
||||||
clientSelect.selectByVisibleText(clientName);
|
clientSelect.selectByVisibleText(clientName);
|
||||||
clientAvailable.selectByVisibleText(roleName);
|
clientAvailable.selectByVisibleText(roleName);
|
||||||
}
|
}
|
||||||
|
WaitUtils.pause(1000);
|
||||||
selectClientRoleButton.click();
|
selectClientRoleButton.click();
|
||||||
pause(500); // wait for the modal dialog to fade out
|
WaitUtils.waitForModalFadeOut(driver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,25 +271,25 @@ public class CreateClientMappersForm extends Form {
|
||||||
}
|
}
|
||||||
|
|
||||||
//SAML
|
//SAML
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Role attribute name']//following-sibling::node()//input[@type='text']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Role attribute name')]//following-sibling::node()//input[@type='text']")
|
||||||
private WebElement roleAttributeNameInput;
|
private WebElement roleAttributeNameInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Friendly Name']//following-sibling::node()//input[@type='text']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Friendly Name')]//following-sibling::node()//input[@type='text']")
|
||||||
private WebElement friendlyNameInput;
|
private WebElement friendlyNameInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='SAML Attribute NameFormat']//following-sibling::node()//select")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'SAML Attribute NameFormat')]//following-sibling::node()//select")
|
||||||
private Select samlAttributeNameFormatSelect;
|
private Select samlAttributeNameFormatSelect;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Single Role Attribute']//following-sibling::node()//div[@class='onoffswitch']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Single Role Attribute')]//following-sibling::node()//div[@class='onoffswitch']")
|
||||||
private OnOffSwitch singleRoleAttributeSwitch;
|
private OnOffSwitch singleRoleAttributeSwitch;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Attribute value']//following-sibling::node()//input[@type='text']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Attribute value')]//following-sibling::node()//input[@type='text']")
|
||||||
private WebElement attributeValueInput;
|
private WebElement attributeValueInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Group attribute name']//following-sibling::node()//input[@type='text']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Group attribute name')]//following-sibling::node()//input[@type='text']")
|
||||||
private WebElement groupAttributeNameInput;
|
private WebElement groupAttributeNameInput;
|
||||||
|
|
||||||
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Single Group Attribute']//following-sibling::node()//div[@class='onoffswitch']")
|
@FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Single Group Attribute')]//following-sibling::node()//div[@class='onoffswitch']")
|
||||||
private OnOffSwitch singleGroupAttributeSwitch;
|
private OnOffSwitch singleGroupAttributeSwitch;
|
||||||
|
|
||||||
public void setRoleAttributeName(String value) {
|
public void setRoleAttributeName(String value) {
|
||||||
|
|
|
@ -51,7 +51,6 @@ public class ThemeSettings extends RealmSettings {
|
||||||
private OnOffSwitch internatEnabledSwitch;
|
private OnOffSwitch internatEnabledSwitch;
|
||||||
|
|
||||||
public void changeLoginTheme(String themeName) {
|
public void changeLoginTheme(String themeName) {
|
||||||
waitUntilElement(By.id("loginTheme")).is().present();
|
|
||||||
loginThemeSelect.selectByVisibleText(themeName);
|
loginThemeSelect.selectByVisibleText(themeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package org.keycloak.testsuite.console.page.roles;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -11,12 +10,12 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation.Composites;
|
import org.keycloak.representations.idm.RoleRepresentation.Composites;
|
||||||
import org.keycloak.testsuite.page.Form;
|
import org.keycloak.testsuite.page.Form;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||||
|
|
||||||
|
import org.keycloak.testsuite.util.UIUtils;
|
||||||
import org.openqa.selenium.By;
|
import org.openqa.selenium.By;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.logging.LogEntries;
|
|
||||||
import org.openqa.selenium.logging.LogEntry;
|
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
import org.openqa.selenium.support.ui.Select;
|
import org.openqa.selenium.support.ui.Select;
|
||||||
|
|
||||||
|
@ -156,22 +155,12 @@ public class RoleCompositeRoles extends Form {
|
||||||
|
|
||||||
public boolean isAssignedRole(String role) {
|
public boolean isAssignedRole(String role) {
|
||||||
waitUntilElement(By.id("assigned")).is().present();
|
waitUntilElement(By.id("assigned")).is().present();
|
||||||
try {
|
return UIUtils.selectContainsOption(assignedRealmRolesSelect, role);
|
||||||
assignedRealmRolesSelect.selectByVisibleText(role);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAssignedClientRole(String role) {
|
public boolean isAssignedClientRole(String role) {
|
||||||
waitUntilElement(By.id("assigned")).is().present();
|
waitUntilElement(By.id("assigned")).is().present();
|
||||||
try {
|
return UIUtils.selectContainsOption(assignedClientRolesSelect, role);
|
||||||
assignedClientRolesSelect.selectByVisibleText(role);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectClientRole(String client) {
|
public void selectClientRole(String client) {
|
||||||
|
|
|
@ -28,7 +28,6 @@ public class RolesTable extends DataTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clickRole(String name) {
|
public void clickRole(String name) {
|
||||||
waitForBody();
|
|
||||||
clickRowByLinkText(name);
|
clickRowByLinkText(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,6 @@ public class UserCredentials extends User {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clickResetPasswordAndConfirm() {
|
public void clickResetPasswordAndConfirm() {
|
||||||
waitUntilElement(resetPasswordButton);
|
|
||||||
resetPasswordButton.click();
|
resetPasswordButton.click();
|
||||||
modalDialog.ok();
|
modalDialog.ok();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,10 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.console.page.users;
|
package org.keycloak.testsuite.console.page.users;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
|
import org.keycloak.testsuite.util.URLUtils;
|
||||||
import org.openqa.selenium.By;
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
@ -27,6 +30,8 @@ import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
|
||||||
import org.keycloak.testsuite.console.page.AdminConsoleRealm;
|
import org.keycloak.testsuite.console.page.AdminConsoleRealm;
|
||||||
import org.keycloak.testsuite.console.page.fragment.DataTable;
|
import org.keycloak.testsuite.console.page.fragment.DataTable;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||||
import static org.openqa.selenium.By.*;
|
import static org.openqa.selenium.By.*;
|
||||||
|
|
||||||
|
@ -59,6 +64,9 @@ public class Users extends AdminConsoleRealm {
|
||||||
|
|
||||||
public class UsersTable extends DataTable {
|
public class UsersTable extends DataTable {
|
||||||
|
|
||||||
|
@Drone
|
||||||
|
private WebDriver driver;
|
||||||
|
|
||||||
public List<UserRepresentation> searchUsers(String searchPattern) {
|
public List<UserRepresentation> searchUsers(String searchPattern) {
|
||||||
search(searchPattern);
|
search(searchPattern);
|
||||||
return getUsersFromTableRows();
|
return getUsersFromTableRows();
|
||||||
|
@ -73,19 +81,18 @@ public class Users extends AdminConsoleRealm {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clickUser(String username) {
|
public void clickUser(String username) {
|
||||||
waitUntilElement(body()).is().present();
|
URLUtils.navigateToUri(driver, getRowByUsername(username).findElement(By.xpath("./td[position()=1]/a")).getAttribute("href"), true);
|
||||||
WebElement link = body().findElement(
|
waitForPageToLoad(driver);
|
||||||
By.xpath(".//tr/td[./following::td[text()='" + username + "']]/a")
|
|
||||||
);
|
|
||||||
link.click();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void editUser(String username) {
|
public void editUser(String username) {
|
||||||
clickRowActionButton(getRowByUsername(username), EDIT);
|
clickRowActionButton(getRowByUsername(username), EDIT);
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void impersonateUser(String username) {
|
public void impersonateUser(String username) {
|
||||||
clickRowActionButton(getRowByUsername(username), IMPERSONATE);
|
clickRowActionButton(getRowByUsername(username), IMPERSONATE);
|
||||||
|
waitForPageToLoad(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteUser(String username) {
|
public void deleteUser(String username) {
|
||||||
|
@ -137,11 +144,9 @@ public class Users extends AdminConsoleRealm {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WebElement getRowByUsername(String userName) {
|
protected WebElement getRowByUsername(String userName) {
|
||||||
WebElement row = body().findElement(
|
return body().findElement(
|
||||||
By.xpath(".//tr[./td/following::td[text()='" + userName + "']]")
|
By.xpath(".//tr[./td[position()=2 and text()='" + userName + "']]")
|
||||||
);
|
);
|
||||||
waitUntilElement(row).is().present();
|
|
||||||
return row;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,14 +106,12 @@ public abstract class AbstractConsoleTest extends AbstractAuthTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertAlertSuccess() {
|
public void assertAlertSuccess() {
|
||||||
alert.waitUntilPresentAndClassSet();
|
assertTrue(alert.isSuccess());
|
||||||
assertTrue("Is not success; @class=" + alert.getAttributeClass(), alert.isSuccess());
|
|
||||||
alert.close();
|
alert.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertAlertDanger() {
|
public void assertAlertDanger() {
|
||||||
alert.waitUntilPresentAndClassSet();
|
assertTrue(alert.isDanger());
|
||||||
assertTrue("Is not danger; @class=" + alert.getAttributeClass(), alert.isDanger());
|
|
||||||
alert.close();
|
alert.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.keycloak.testsuite.console.AbstractConsoleTest;
|
||||||
import org.keycloak.testsuite.console.page.authentication.PasswordPolicy;
|
import org.keycloak.testsuite.console.page.authentication.PasswordPolicy;
|
||||||
import org.keycloak.testsuite.console.page.users.UserCredentials;
|
import org.keycloak.testsuite.console.page.users.UserCredentials;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy.Type.DIGITS;
|
||||||
import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy.Type.HASH_ITERATIONS;
|
import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy.Type.HASH_ITERATIONS;
|
||||||
import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy.Type.REGEX_PATTERN;
|
import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy.Type.REGEX_PATTERN;
|
||||||
|
|
||||||
|
@ -48,17 +49,17 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
|
||||||
@Test
|
@Test
|
||||||
public void testAddAndRemovePolicy() {
|
public void testAddAndRemovePolicy() {
|
||||||
passwordPolicyPage.navigateTo();
|
passwordPolicyPage.navigateTo();
|
||||||
passwordPolicyPage.addPolicy(HASH_ITERATIONS, 5);
|
passwordPolicyPage.addPolicy(DIGITS, 5);
|
||||||
passwordPolicyPage.removePolicy(HASH_ITERATIONS);
|
passwordPolicyPage.removePolicy(DIGITS);
|
||||||
assertAlertSuccess();
|
assertAlertSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidPolicyValues() {
|
public void testInvalidPolicyValues() {
|
||||||
passwordPolicyPage.navigateTo();
|
passwordPolicyPage.navigateTo();
|
||||||
passwordPolicyPage.addPolicy(HASH_ITERATIONS, "asd");
|
passwordPolicyPage.addPolicy(DIGITS, "asd");
|
||||||
assertAlertDanger();
|
assertAlertDanger();
|
||||||
passwordPolicyPage.removePolicy(HASH_ITERATIONS);
|
passwordPolicyPage.removePolicy(DIGITS);
|
||||||
|
|
||||||
passwordPolicyPage.addPolicy(REGEX_PATTERN, "([");
|
passwordPolicyPage.addPolicy(REGEX_PATTERN, "([");
|
||||||
assertAlertDanger();
|
assertAlertDanger();
|
||||||
|
|
|
@ -53,7 +53,6 @@ public abstract class AbstractClientTest extends AbstractConsoleTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createClient(ClientRepresentation client) {
|
public void createClient(ClientRepresentation client) {
|
||||||
WaitUtils.waitUntilElement(By.tagName("body")).is().present();
|
|
||||||
assertCurrentUrlEquals(clientsPage);
|
assertCurrentUrlEquals(clientsPage);
|
||||||
clientsPage.table().createClient();
|
clientsPage.table().createClient();
|
||||||
createClientPage.form().setValues(client);
|
createClientPage.form().setValues(client);
|
||||||
|
|
|
@ -25,7 +25,9 @@ public class ConfigTest extends AbstractConsoleTest {
|
||||||
@Test
|
@Test
|
||||||
public void configLoginEventsTest() {
|
public void configLoginEventsTest() {
|
||||||
configPage.form().setSaveEvents(true);
|
configPage.form().setSaveEvents(true);
|
||||||
configPage.form().addSaveType("REGISTER_NODE");
|
// IE webdriver has problem with clicking not visible (scrolling is needed) items in the menu,
|
||||||
|
// so we need to select some type from the beginning of the menu
|
||||||
|
configPage.form().addSaveType("CLIENT_INFO");
|
||||||
//after removeSavedType method stay input focused -> in phantomjs drop menu doesn't appear after first click
|
//after removeSavedType method stay input focused -> in phantomjs drop menu doesn't appear after first click
|
||||||
configPage.form().removeSaveType("LOGIN");
|
configPage.form().removeSaveType("LOGIN");
|
||||||
configPage.form().setExpiration("50", "Days");
|
configPage.form().setExpiration("50", "Days");
|
||||||
|
@ -35,7 +37,7 @@ public class ConfigTest extends AbstractConsoleTest {
|
||||||
RealmRepresentation realm = testRealmResource().toRepresentation();
|
RealmRepresentation realm = testRealmResource().toRepresentation();
|
||||||
assertTrue(realm.isEventsEnabled());
|
assertTrue(realm.isEventsEnabled());
|
||||||
assertFalse(realm.getEnabledEventTypes().contains("LOGIN"));
|
assertFalse(realm.getEnabledEventTypes().contains("LOGIN"));
|
||||||
assertTrue(realm.getEnabledEventTypes().contains("REGISTER_NODE"));
|
assertTrue(realm.getEnabledEventTypes().contains("CLIENT_INFO"));
|
||||||
assertEquals(4320000L, realm.getEventsExpiration().longValue());
|
assertEquals(4320000L, realm.getEventsExpiration().longValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ public class LoginEventsTest extends AbstractConsoleTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void userAccessEventsTest() {
|
public void userAccessEventsTest() {
|
||||||
|
deleteAllCookiesForTestRealm();
|
||||||
testRealmAdminConsolePage.navigateTo();
|
testRealmAdminConsolePage.navigateTo();
|
||||||
Users.setPasswordFor(testUser, "Wrong_password");
|
Users.setPasswordFor(testUser, "Wrong_password");
|
||||||
testRealmLoginPage.form().login(testUser);
|
testRealmLoginPage.form().login(testUser);
|
||||||
|
|
|
@ -11,7 +11,6 @@ import org.openqa.selenium.By;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.*;
|
|
||||||
import static org.keycloak.testsuite.util.URLAssert.*;
|
import static org.keycloak.testsuite.util.URLAssert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +31,6 @@ public class InternationalizationTest extends AbstractRealmTest {
|
||||||
themeSettingsPage.saveTheme();
|
themeSettingsPage.saveTheme();
|
||||||
assertAlertSuccess();
|
assertAlertSuccess();
|
||||||
realmSettingsPage.setAdminRealm(AuthRealm.TEST);
|
realmSettingsPage.setAdminRealm(AuthRealm.TEST);
|
||||||
accountPage.setAuthRealm(testRealmPage);
|
|
||||||
deleteAllCookiesForTestRealm();
|
deleteAllCookiesForTestRealm();
|
||||||
deleteAllCookiesForMasterRealm();
|
deleteAllCookiesForMasterRealm();
|
||||||
}
|
}
|
||||||
|
@ -55,7 +53,7 @@ public class InternationalizationTest extends AbstractRealmTest {
|
||||||
loginToTestRealmConsoleAs(testUser);
|
loginToTestRealmConsoleAs(testUser);
|
||||||
assertConsoleLocale("Temas");
|
assertConsoleLocale("Temas");
|
||||||
|
|
||||||
accountPage.navigateTo();
|
testRealmAccountPage.navigateTo();
|
||||||
assertAccountLocale("Cuenta");
|
assertAccountLocale("Cuenta");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,11 +62,11 @@ public class InternationalizationTest extends AbstractRealmTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void accountInternationalization() {
|
public void accountInternationalization() {
|
||||||
accountPage.navigateTo();
|
testRealmAccountPage.navigateTo();
|
||||||
loginPage.form().login(testUser);
|
loginPage.form().login(testUser);
|
||||||
|
|
||||||
localeDropdown.selectByText("Français");
|
localeDropdown.selectByText("Français");
|
||||||
accountPage.navigateTo();
|
testRealmAccountPage.navigateTo();
|
||||||
assertAccountLocale("Compte");
|
assertAccountLocale("Compte");
|
||||||
|
|
||||||
deleteAllCookiesForTestRealm();
|
deleteAllCookiesForTestRealm();
|
||||||
|
@ -78,14 +76,12 @@ public class InternationalizationTest extends AbstractRealmTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertConsoleLocale(String expected) {
|
private void assertConsoleLocale(String expected) {
|
||||||
pause(500);
|
|
||||||
assertCurrentUrlEquals(realmSettingsPage);
|
assertCurrentUrlEquals(realmSettingsPage);
|
||||||
assertLocale(".//a[contains(@href,'/theme-settings')]", expected); // Themes
|
assertLocale(".//a[contains(@href,'/theme-settings')]", expected); // Themes
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertAccountLocale(String expected) {
|
private void assertAccountLocale(String expected) {
|
||||||
pause(500);
|
assertCurrentUrlEquals(testRealmAccountPage);
|
||||||
assertCurrentUrlEquals(accountPage);
|
|
||||||
assertLocale(".//div[contains(@class,'bs-sidebar')]/ul/li", expected); // Account
|
assertLocale(".//div[contains(@class,'bs-sidebar')]/ul/li", expected); // Account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +91,6 @@ public class InternationalizationTest extends AbstractRealmTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertLocale(WebElement element, String expected) {
|
private void assertLocale(WebElement element, String expected) {
|
||||||
waitUntilElement(element);
|
|
||||||
assertEquals(expected, element.getText());
|
assertEquals(expected, element.getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,6 @@ public class LoginSettingsTest extends AbstractRealmTest {
|
||||||
public void beforeLoginSettingsTest() {
|
public void beforeLoginSettingsTest() {
|
||||||
// tabs().login();
|
// tabs().login();
|
||||||
loginSettingsPage.navigateTo();
|
loginSettingsPage.navigateTo();
|
||||||
assertCurrentUrlEquals(loginSettingsPage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in a new issue