diff --git a/testsuite/integration-arquillian/pom.xml b/testsuite/integration-arquillian/pom.xml index eca8df43f6..f1bc7e9552 100644 --- a/testsuite/integration-arquillian/pom.xml +++ b/testsuite/integration-arquillian/pom.xml @@ -42,7 +42,7 @@ 1.1.11.Final - 2.52.0 + 2.53.0 2.0.0.Beta1 2.1.0.Alpha3 2.0.0.Final diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java index fb08bfbfca..8ca2531f45 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java @@ -20,6 +20,8 @@ package org.keycloak.testsuite.auth.page.account; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.page.Form; 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.support.FindBy; @@ -69,7 +71,7 @@ public class AccountFields extends Form { } public void waitForUsernameInputNotPresent() { - waitUntilElement(usernameInput).is().not().present(); + waitUntilElementIsNotPresent(driver, usernameInput); } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java index 4d5b2641b8..f7b0911039 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java @@ -25,7 +25,7 @@ import org.keycloak.testsuite.page.AbstractAlert; public class AccountManagementAlert extends AbstractAlert { public boolean isError() { - return getAttributeClass().contains("alert-error"); + return checkAlertType("error"); } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java index ad914cdafb..ec92f58081 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java @@ -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.PasswordFields; import static org.keycloak.testsuite.util.WaitUtils.*; + import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; @@ -51,6 +52,9 @@ public class LoginForm extends Form { @FindBy(id = "rememberMe") private WebElement rememberMe; + @FindBy(xpath = ".//label[@for='password']") + private WebElement labelPassword; + public void setUsername(String username) { accountFields.setUsername(username); } @@ -70,26 +74,28 @@ public class LoginForm extends Form { } public void register() { - waitForUsernameInputPresent(); - waitUntilElement(registerLink).is().present(); registerLink.click(); + waitForPageToLoad(driver); } 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(); + waitForPageToLoad(driver); } public void forgotPassword() { - waitUntilElement(forgottenPassword).is().present(); forgottenPassword.click(); + waitForPageToLoad(driver); } public void rememberMe(boolean value) { - waitForRememberMePresent(); boolean selected = rememberMe.isSelected(); if ((value && !selected) || !value && selected) { rememberMe.click(); + waitForPageToLoad(driver); } } @@ -103,7 +109,7 @@ public class LoginForm extends Form { } public void waitForRegisterLinkNotPresent() { - waitUntilElement(registerLink).is().not().present(); + waitUntilElementIsNotPresent(driver, registerLink); } public void waitForResetPasswordLinkNotPresent() { @@ -115,7 +121,7 @@ public class LoginForm extends Form { } public void waitForRememberMeNotPresent() { - waitUntilElement(rememberMe).is().not().present(); + waitUntilElementIsNotPresent(driver, rememberMe); } public void waitForLoginButtonPresent() { @@ -150,6 +156,7 @@ public class LoginForm extends Form { public void submit() { submit.click(); + waitForPageToLoad(driver); } } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/TermsAndConditions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/TermsAndConditions.java index a4c425eac2..fb7d9b1d65 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/TermsAndConditions.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/TermsAndConditions.java @@ -16,6 +16,7 @@ */ package org.keycloak.testsuite.auth.page.login; +import org.keycloak.testsuite.util.UIUtils; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; @@ -35,7 +36,7 @@ public class TermsAndConditions extends LoginActions { @Override public boolean isCurrent() { - return driver.getTitle().equals("Terms and Conditions"); + return UIUtils.currentTitleEquals(driver, "Terms and Conditions"); } public void acceptTerms() { diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java index cbcfc897d4..b46a13eeb5 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java @@ -50,17 +50,14 @@ public class AdminEvents extends Events { private AdminEventsTableFilterForm filterForm; public void update() { - waitForBody(); clickHeaderButton("Update"); } public void reset() { - waitForBody(); clickHeaderButton("Reset"); } public void filter() { - waitForBody(); filterButton.click(); } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java index 6f2094fe20..a263a2f845 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java @@ -50,17 +50,14 @@ public class LoginEvents extends Events { private LoginEventsTableFilterForm filterForm; public void update() { - waitForBody(); clickHeaderButton("Update"); } public void reset() { - waitForBody(); clickHeaderButton("Reset"); } public void filter() { - waitForBody(); filterButton.click(); } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java index 36d12d6734..9e582d8a04 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java @@ -27,19 +27,19 @@ import org.openqa.selenium.support.FindBy; */ public class AdminConsoleAlert extends AbstractAlert { - @FindBy(xpath = "//button[@class='close']") + @FindBy(xpath = ".//button[@class='close']") protected WebElement closeButton; public boolean isInfo() { - return getAttributeClass().contains("alert-info"); + return checkAlertType("info"); } public boolean isWarning() { - return getAttributeClass().contains("alert-warning"); + return checkAlertType("waring"); } public boolean isDanger() { - return getAttributeClass().contains("alert-danger"); + return checkAlertType("danger"); } public void close() { diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java index 2b1040a808..a29814d700 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java @@ -17,12 +17,14 @@ 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.support.FindBy; 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 org.openqa.selenium.By; import static org.openqa.selenium.By.xpath; @@ -33,6 +35,9 @@ import static org.openqa.selenium.By.xpath; */ public class DataTable { + @Drone + protected WebDriver driver; + @FindBy(css = "input[class*='search']") private WebElement searchInput; @FindBy(css = "div[class='input-group-addon'] i") @@ -49,38 +54,30 @@ public class DataTable { private WebElement infoRow; public void search(String pattern) { - waitForBody(); searchInput.sendKeys(pattern); searchButton.click(); } public void clickHeaderButton(String buttonText) { - waitForBody(); header.findElement(By.xpath(".//button[text()='" + buttonText + "']")).click(); + waitForPageToLoad(driver); } public void clickHeaderLink(String linkText) { - waitForBody(); header.findElement(By.linkText(linkText)).click(); + waitForPageToLoad(driver); } public WebElement body() { return body; } - public void waitForBody() { - waitUntilElement(body).is().present(); - } - public List rows() { - waitForBody(); - pause(250); return rows; } public WebElement getRowByLinkText(String text) { WebElement row = body.findElement(By.xpath(".//tr[./td/a[text()='" + text + "']]")); - waitUntilElement(row).is().present(); return row; } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java index 6dc90073b8..57918b7dc9 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java @@ -17,12 +17,12 @@ 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 static org.keycloak.testsuite.util.WaitUtils.pause; +import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; +import static org.keycloak.testsuite.util.WaitUtils.*; /** * @@ -33,6 +33,9 @@ public class ModalDialog { @Root private WebElement root; + @Drone + private WebDriver driver; + @FindBy(xpath = ".//button[text()='Cancel']") private WebElement cancelButton; @FindBy(xpath = ".//button[text()='Delete']") @@ -44,26 +47,24 @@ public class ModalDialog { private WebElement nameInput; public void ok() { - waitUntilElement(okButton).is().present(); + waitForModalFadeIn(driver); okButton.click(); - waitUntilElement(root).is().not().present(); + waitForModalFadeOut(driver); } public void confirmDeletion() { - waitUntilElement(deleteButton).is().present(); + waitForModalFadeIn(driver); deleteButton.click(); - waitUntilElement(root).is().not().present(); - pause(200); + waitForModalFadeOut(driver); } public void cancel() { - waitUntilElement(cancelButton).is().present(); + waitForModalFadeIn(driver); cancelButton.click(); - waitUntilElement(root).is().not().present(); + waitForModalFadeOut(driver); } public void setName(String name) { - waitUntilElement(nameInput).is().present(); nameInput.clear(); nameInput.sendKeys(name); } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java index c173f9aa99..a0c475ff43 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java @@ -17,14 +17,16 @@ package org.keycloak.testsuite.page; -import com.google.common.base.Predicate; -import java.util.Arrays; -import static org.jboss.arquillian.graphene.Graphene.waitModel; +import org.jboss.arquillian.drone.api.annotation.Drone; import org.jboss.arquillian.graphene.fragment.Root; 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.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; /** * @@ -37,33 +39,27 @@ public abstract class AbstractAlert { @Root protected WebElement root; - public void waitUntilPresent() { - waitUntilElement(root, "Flash message should be present.").is().present(); - } - - public void waitUntilPresentAndClassSet() { - waitUntilPresent(); - waitModel().until(new Predicate() { - @Override - public boolean apply(WebDriver input) { - return !Arrays.asList(getAttributeClass().split(" ")).contains("alert-"); - } - }); - } + @Drone + protected WebDriver driver; public String getText() { return root.getText(); } - public String getAttributeClass() { - String attrClass = root.getAttribute("class"); - log.debug("Alert @class = '" + attrClass + "'"); - return attrClass; - } - public boolean 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; } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java index 2e5836e501..62510e0469 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java @@ -23,10 +23,8 @@ import java.util.Map; import javax.ws.rs.core.UriBuilder; import org.jboss.arquillian.drone.api.annotation.Drone; 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; /** @@ -88,17 +86,15 @@ public abstract class AbstractPage { } public void navigateTo() { - String uri = buildUri().toASCIIString(); - log.debug("current URL: " + driver.getCurrentUrl()); - log.info("navigating to " + uri); - driver.navigate().to(uri); - pause(300); // this is needed for FF for some reason - waitUntilElement(By.tagName("body")).is().visible(); - log.info("current URL: " + driver.getCurrentUrl()); + navigateTo(true); + } + + public void navigateTo(boolean waitForMatch) { + URLUtils.navigateToUri(driver, buildUri().toASCIIString(), waitForMatch); } public boolean isCurrent() { - return driver.getCurrentUrl().equals(toString()); + return URLUtils.currentUrlEqual(driver, toString()); } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java index 8f3232b54d..1bec1260a2 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java @@ -21,6 +21,8 @@ import org.jboss.arquillian.drone.api.annotation.Drone; import static org.jboss.arquillian.graphene.Graphene.guardAjax; import org.jboss.logging.Logger; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement; + +import org.keycloak.testsuite.util.WaitUtils; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; @@ -45,8 +47,8 @@ public class Form { public void save() { // guardAjax(save).click(); - waitUntilElement(save).is().present(); save.click(); + WaitUtils.waitForPageToLoad(driver); } public void cancel() { @@ -54,14 +56,12 @@ public class Form { } public static String getInputValue(WebElement input) { - waitUntilElement(input).is().present(); return input.getAttribute(VALUE); } public static final String VALUE = "value"; public static void setInputValue(WebElement input, String value) { - waitUntilElement(input).is().present(); if (input.isEnabled()) { input.clear(); if (value != null) { diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UIUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UIUtils.java new file mode 100644 index 0000000000..ec54244a04 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UIUtils.java @@ -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 + */ +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; + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/URLUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/URLUtils.java new file mode 100644 index 0000000000..dcf3795115 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/URLUtils.java @@ -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 + */ +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; + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java index 5124377871..17a8485108 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java @@ -16,36 +16,60 @@ */ package org.keycloak.testsuite.util; +import java.util.Collections; import java.util.logging.Level; import java.util.logging.Logger; import static org.jboss.arquillian.graphene.Graphene.waitGui; import org.jboss.arquillian.graphene.wait.ElementBuilder; import org.openqa.selenium.By; +import org.openqa.selenium.TimeoutException; +import org.openqa.selenium.WebDriver; 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 tkyjovsk + * @author Vaclav Muzikar */ 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 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 waitUntilElement(By by) { return waitGui().until().element(by); } + // Should be no longer necessary for finding elements since we have implicit wait public static ElementBuilder waitUntilElement(WebElement element) { return waitGui().until().element(element); } + // Should be no longer necessary for finding elements since we have implicit wait public static ElementBuilder waitUntilElement(WebElement element, String failMessage) { 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) { try { 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")); + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java index 697323caf0..4057d2004e 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java @@ -22,6 +22,7 @@ import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserRepresentation; 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.SAMLPostLogin; import org.keycloak.testsuite.auth.page.login.SAMLRedirectLogin; @@ -46,6 +47,8 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest { protected AuthRealm testRealmPage; @Page protected OIDCLogin testRealmLoginPage; + @Page + protected Account testRealmAccountPage; @Page protected SAMLPostLogin testRealmSAMLPostLoginPage; @@ -68,6 +71,7 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest { @Before public void beforeAuthTest() { testRealmLoginPage.setAuthRealm(testRealmPage); + testRealmAccountPage.setAuthRealm(testRealmPage); testUser = createUserRepresentation("test", "test@email.test", "test", "user", true); setPasswordFor(testUser, PASSWORD); @@ -97,7 +101,8 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest { } 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"); driver.manage().deleteAllCookies(); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java index a14abf3421..ae0dcb641e 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java @@ -169,13 +169,15 @@ public abstract class AbstractKeycloakTest { } 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"); driver.manage().deleteAllCookies(); } 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(); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java index 6ceb4f8895..8122e0ab2c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java @@ -52,12 +52,10 @@ public abstract class AbstractAccountManagementTest extends AbstractAuthTest { } public void assertAlertSuccess() { - alert.waitUntilPresentAndClassSet(); assertTrue(alert.isSuccess()); } public void assertAlertError() { - alert.waitUntilPresentAndClassSet(); assertTrue(alert.isError()); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java index 6ef0bbe321..573a3340c8 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java @@ -17,8 +17,6 @@ package org.keycloak.testsuite.util; -import javax.ws.rs.core.UriBuilder; - import org.apache.http.Header; import org.apache.http.HttpEntity; 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.junit.Assert; 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 org.keycloak.testsuite.auth.page.login.PageWithLoginUrl; import org.openqa.selenium.WebDriver; +import static org.keycloak.testsuite.util.URLUtils.*; + import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; @@ -51,16 +49,9 @@ public class URLAssert { } public static void assertCurrentUrlEquals(WebDriver driver, final AbstractPage page) { -// WebDriverWait wait = new WebDriverWait(driver, 1); -// ExpectedCondition urlStartsWith = new ExpectedCondition() { -// -// @Override -// public Boolean apply(WebDriver wd) { -// return startsWithNormalized(wd.getCurrentUrl(), page.toString()); -// } -// }; -// wait.until(urlStartsWith); - assertEqualsNormalized(page.toString(), driver.getCurrentUrl()); + String expected = page.toString(); + assertTrue("Expected URL: " + expected + "; actual: " + driver.getCurrentUrl(), + currentUrlEqual(driver, page.toString())); } public static void assertCurrentUrlStartsWith(AbstractPage page) { @@ -68,16 +59,8 @@ public class URLAssert { } public static void assertCurrentUrlStartsWith(WebDriver driver, final String url) { -// WebDriverWait wait = new WebDriverWait(driver, 1); -// ExpectedCondition urlStartsWith = new ExpectedCondition() { -// -// @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)); + assertTrue("URL expected to begin with:" + url + "; actual URL: " + driver.getCurrentUrl(), + currentUrlStartWith(driver, url)); } public static void assertCurrentUrlDoesntStartWith(AbstractPage page) { @@ -85,35 +68,10 @@ public class URLAssert { } public static void assertCurrentUrlDoesntStartWith(WebDriver driver, final String url) { -// WebDriverWait wait = new WebDriverWait(driver, 1, 250); -// ExpectedCondition urlDoesntStartWith = new ExpectedCondition() { -// -// @Override -// public Boolean apply(WebDriver wd) { -// return !startsWithNormalized(wd.getCurrentUrl(), url); -// } -// }; -// wait.until(urlDoesntStartWith); - assertFalse(startsWithNormalized(driver.getCurrentUrl(), url)); + assertTrue("URL expected NOT to begin with:" + url + "; actual URL: " + driver.getCurrentUrl(), + currentUrlDoesntStartWith(driver, 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) { assertCurrentUrlStartsWithLoginUrlOf(page.getDriver(), page); } diff --git a/testsuite/integration-arquillian/tests/other/console/pom.xml b/testsuite/integration-arquillian/tests/other/console/pom.xml index c84d085e3e..9e3e6fdf69 100644 --- a/testsuite/integration-arquillian/tests/other/console/pom.xml +++ b/testsuite/integration-arquillian/tests/other/console/pom.xml @@ -31,6 +31,10 @@ Admin Console UI Tests + + ${auth.server.home}/themes + + @@ -54,6 +58,14 @@ + + maven-surefire-plugin + + + ${keycloak.theme.dir} + + + diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java index 39ce3f0471..1b1348d412 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java @@ -52,7 +52,9 @@ public class PasswordPolicy extends Authentication { public void removePolicy(Type policy) { getPolicyRow(policy).findElement(By.cssSelector("td.kc-action-cell")).click(); - primaryButton.click(); + if (!primaryButton.isDisplayed()) { + primaryButton.click(); + } } public void editPolicy(Type policy, int value) { diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java index 945e72fe0b..8f52163bb6 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java @@ -62,32 +62,26 @@ public class Clients extends AdminConsoleRealm { } public void createClient() { - waitForBody(); clickHeaderLink(CREATE); } public void importClient() { - waitForBody(); clickHeaderLink(IMPORT); } public void clickClient(ClientRepresentation client) { - waitForBody(); clickClient(client.getClientId()); } public void clickClient(String clientId) { - waitForBody(); body().findElement(linkText(clientId)).click(); } public void editClient(String clientId) { - waitForBody(); clickRowActionButton(getRowByLinkText(clientId), EDIT); } public void deleteClient(String clientId) { - waitForBody(); clickRowActionButton(getRowByLinkText(clientId), DELETE); } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java index 51d1b24f5a..d105a01171 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java @@ -56,15 +56,18 @@ public class ClientCredentialsForm extends Form { public void regenerateSecret() { waitUntilElement(regenerateSecretButton).is().visible(); regenerateSecretButton.click(); + waitForPageToLoad(driver); } public void regenerateRegistrationAccessToken() { waitUntilElement(regenerateRegistrationAccessTokenButton).is().visible(); regenerateRegistrationAccessTokenButton.click(); + waitForPageToLoad(driver); } public void generateNewKeysAndCert() { waitUntilElement(generateNewKeysAndCert).is().visible(); generateNewKeysAndCert.click(); + waitForPageToLoad(driver); } } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/installation/ClientInstallationForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/installation/ClientInstallationForm.java index 6ed4d9e3ab..fbd415ab69 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/installation/ClientInstallationForm.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/installation/ClientInstallationForm.java @@ -22,6 +22,7 @@ package org.keycloak.testsuite.console.page.clients.installation; import org.keycloak.testsuite.page.Form; +import org.keycloak.testsuite.util.WaitUtils; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.ui.Select; @@ -40,6 +41,7 @@ public class ClientInstallationForm extends Form { public void setConfigFormat(String value) { configFormatsSelect.selectByVisibleText(value); + WaitUtils.waitForPageToLoad(driver); } public String getTextareaContent() { diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/ClientMappers.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/ClientMappers.java index 20634b7c55..98eead5bac 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/ClientMappers.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/ClientMappers.java @@ -42,17 +42,14 @@ public class ClientMappers extends Client { } public void createMapper() { - waitForBody(); clickHeaderLink(CREATE); } public void addBuiltin() { - waitForBody(); clickHeaderLink(ADD_BUILTIN); } public void clickMapper(String mapperName) { - waitForBody(); body().findElement(By.linkText(mapperName)).click(); } @@ -61,7 +58,6 @@ public class ClientMappers extends Client { } private void clickMapperActionButton(String mapperName, String buttonText) { - waitForBody(); clickRowActionButton(getRowByLinkText(mapperName), buttonText); } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/CreateClientMappersForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/CreateClientMappersForm.java index 9eae0bef8f..70e4316f75 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/CreateClientMappersForm.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/CreateClientMappersForm.java @@ -1,8 +1,11 @@ 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.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.support.FindBy; import org.openqa.selenium.support.ui.Select; @@ -44,40 +47,40 @@ public class CreateClientMappersForm extends Form { @FindBy(id = "mapperTypeCreate") 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; - @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; - @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; - @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; @FindBy(xpath = ".//button[text() = 'Select Role']/../..//input") 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; - @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; - @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; - @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; - @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; - @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; - @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; @FindBy(xpath = ".//button[text() = 'Select Role']") @@ -87,16 +90,19 @@ public class CreateClientMappersForm extends Form { private RoleSelectorModalDialog roleSelectorModalDialog; public class RoleSelectorModalDialog { + @Drone + private WebDriver driver; + @FindBy(id = "available") private Select realmAvailable; - @FindBy(xpath = ".//button[@tooltip='Select realm role']") + @FindBy(xpath = ".//button[@tooltip='Select realm role' and not(@disabled)]") private WebElement selectRealmRoleButton; @FindBy(id = "available-client") private Select clientAvailable; @FindBy(id = "clients") private Select clientSelect; - @FindBy(xpath = ".//button[@tooltip='Select client role']") + @FindBy(xpath = ".//button[@tooltip='Select client role' and not(@disabled)]") private WebElement selectClientRoleButton; @FindBy(xpath = ".//button[@class='close']") private WebElement closeButton; @@ -109,8 +115,9 @@ public class CreateClientMappersForm extends Form { if (roleName != null) { realmAvailable.selectByVisibleText(roleName); } + WaitUtils.pause(1000); selectRealmRoleButton.click(); - pause(500); // wait for the modal dialog to fade out + WaitUtils.waitForModalFadeOut(driver); } public void selectClientRole(String clientName, String roleName) { @@ -118,8 +125,9 @@ public class CreateClientMappersForm extends Form { clientSelect.selectByVisibleText(clientName); clientAvailable.selectByVisibleText(roleName); } + WaitUtils.pause(1000); 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 - @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; - @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; - @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; - @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; - @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; - @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; - @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; public void setRoleAttributeName(String value) { diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/realm/ThemeSettings.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/realm/ThemeSettings.java index 2392c7caa3..4095cc99da 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/realm/ThemeSettings.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/realm/ThemeSettings.java @@ -51,7 +51,6 @@ public class ThemeSettings extends RealmSettings { private OnOffSwitch internatEnabledSwitch; public void changeLoginTheme(String themeName) { - waitUntilElement(By.id("loginTheme")).is().present(); loginThemeSelect.selectByVisibleText(themeName); } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java index b4ab777635..eabaf0263d 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java @@ -3,7 +3,6 @@ package org.keycloak.testsuite.console.page.roles; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -11,12 +10,12 @@ import java.util.Map; import java.util.Set; import org.keycloak.representations.idm.RoleRepresentation.Composites; import org.keycloak.testsuite.page.Form; -import static org.keycloak.testsuite.util.WaitUtils.pause; + import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement; + +import org.keycloak.testsuite.util.UIUtils; import org.openqa.selenium.By; 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.ui.Select; @@ -156,22 +155,12 @@ public class RoleCompositeRoles extends Form { public boolean isAssignedRole(String role) { waitUntilElement(By.id("assigned")).is().present(); - try { - assignedRealmRolesSelect.selectByVisibleText(role); - } catch (Exception ex) { - return false; - } - return true; + return UIUtils.selectContainsOption(assignedRealmRolesSelect, role); } public boolean isAssignedClientRole(String role) { waitUntilElement(By.id("assigned")).is().present(); - try { - assignedClientRolesSelect.selectByVisibleText(role); - } catch (Exception ex) { - return false; - } - return true; + return UIUtils.selectContainsOption(assignedClientRolesSelect, role); } public void selectClientRole(String client) { diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java index 3bec08dc04..e0a9a51015 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java @@ -28,7 +28,6 @@ public class RolesTable extends DataTable { } public void clickRole(String name) { - waitForBody(); clickRowByLinkText(name); } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java index 0652fa4506..277dd67f00 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java @@ -42,7 +42,6 @@ public class UserCredentials extends User { } public void clickResetPasswordAndConfirm() { - waitUntilElement(resetPasswordButton); resetPasswordButton.click(); modalDialog.ok(); } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java index 82a490604e..87bd600f9f 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java @@ -17,7 +17,10 @@ */ 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.WebDriver; import org.openqa.selenium.WebElement; 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.fragment.DataTable; + +import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement; import static org.openqa.selenium.By.*; @@ -59,6 +64,9 @@ public class Users extends AdminConsoleRealm { public class UsersTable extends DataTable { + @Drone + private WebDriver driver; + public List searchUsers(String searchPattern) { search(searchPattern); return getUsersFromTableRows(); @@ -73,19 +81,18 @@ public class Users extends AdminConsoleRealm { } public void clickUser(String username) { - waitUntilElement(body()).is().present(); - WebElement link = body().findElement( - By.xpath(".//tr/td[./following::td[text()='" + username + "']]/a") - ); - link.click(); + URLUtils.navigateToUri(driver, getRowByUsername(username).findElement(By.xpath("./td[position()=1]/a")).getAttribute("href"), true); + waitForPageToLoad(driver); } public void editUser(String username) { clickRowActionButton(getRowByUsername(username), EDIT); + waitForPageToLoad(driver); } public void impersonateUser(String username) { clickRowActionButton(getRowByUsername(username), IMPERSONATE); + waitForPageToLoad(driver); } public void deleteUser(String username) { @@ -137,11 +144,9 @@ public class Users extends AdminConsoleRealm { } protected WebElement getRowByUsername(String userName) { - WebElement row = body().findElement( - By.xpath(".//tr[./td/following::td[text()='" + userName + "']]") + return body().findElement( + By.xpath(".//tr[./td[position()=2 and text()='" + userName + "']]") ); - waitUntilElement(row).is().present(); - return row; } } diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java index d061210f64..dc81e13959 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java @@ -106,14 +106,12 @@ public abstract class AbstractConsoleTest extends AbstractAuthTest { } public void assertAlertSuccess() { - alert.waitUntilPresentAndClassSet(); - assertTrue("Is not success; @class=" + alert.getAttributeClass(), alert.isSuccess()); + assertTrue(alert.isSuccess()); alert.close(); } public void assertAlertDanger() { - alert.waitUntilPresentAndClassSet(); - assertTrue("Is not danger; @class=" + alert.getAttributeClass(), alert.isDanger()); + assertTrue(alert.isDanger()); alert.close(); } diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java index f9046136be..68da020b1a 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java @@ -25,6 +25,7 @@ import org.keycloak.testsuite.console.AbstractConsoleTest; import org.keycloak.testsuite.console.page.authentication.PasswordPolicy; 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.REGEX_PATTERN; @@ -48,17 +49,17 @@ public class PasswordPolicyTest extends AbstractConsoleTest { @Test public void testAddAndRemovePolicy() { passwordPolicyPage.navigateTo(); - passwordPolicyPage.addPolicy(HASH_ITERATIONS, 5); - passwordPolicyPage.removePolicy(HASH_ITERATIONS); + passwordPolicyPage.addPolicy(DIGITS, 5); + passwordPolicyPage.removePolicy(DIGITS); assertAlertSuccess(); } @Test public void testInvalidPolicyValues() { passwordPolicyPage.navigateTo(); - passwordPolicyPage.addPolicy(HASH_ITERATIONS, "asd"); + passwordPolicyPage.addPolicy(DIGITS, "asd"); assertAlertDanger(); - passwordPolicyPage.removePolicy(HASH_ITERATIONS); + passwordPolicyPage.removePolicy(DIGITS); passwordPolicyPage.addPolicy(REGEX_PATTERN, "(["); assertAlertDanger(); diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java index 877aa3fdb2..5ba0484615 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java @@ -53,7 +53,6 @@ public abstract class AbstractClientTest extends AbstractConsoleTest { } public void createClient(ClientRepresentation client) { - WaitUtils.waitUntilElement(By.tagName("body")).is().present(); assertCurrentUrlEquals(clientsPage); clientsPage.table().createClient(); createClientPage.form().setValues(client); diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/ConfigTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/ConfigTest.java index 2c44e5a6b6..fabd63b38c 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/ConfigTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/ConfigTest.java @@ -25,7 +25,9 @@ public class ConfigTest extends AbstractConsoleTest { @Test public void configLoginEventsTest() { 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 configPage.form().removeSaveType("LOGIN"); configPage.form().setExpiration("50", "Days"); @@ -35,7 +37,7 @@ public class ConfigTest extends AbstractConsoleTest { RealmRepresentation realm = testRealmResource().toRepresentation(); assertTrue(realm.isEventsEnabled()); assertFalse(realm.getEnabledEventTypes().contains("LOGIN")); - assertTrue(realm.getEnabledEventTypes().contains("REGISTER_NODE")); + assertTrue(realm.getEnabledEventTypes().contains("CLIENT_INFO")); assertEquals(4320000L, realm.getEventsExpiration().longValue()); } diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java index f53beef6fe..f573e8f17b 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java @@ -40,6 +40,7 @@ public class LoginEventsTest extends AbstractConsoleTest { @Test public void userAccessEventsTest() { + deleteAllCookiesForTestRealm(); testRealmAdminConsolePage.navigateTo(); Users.setPasswordFor(testUser, "Wrong_password"); testRealmLoginPage.form().login(testUser); diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/InternationalizationTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/InternationalizationTest.java index 785158d2b9..090288b453 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/InternationalizationTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/InternationalizationTest.java @@ -11,7 +11,6 @@ import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import static org.junit.Assert.*; -import static org.keycloak.testsuite.util.WaitUtils.*; import static org.keycloak.testsuite.util.URLAssert.*; /** @@ -32,7 +31,6 @@ public class InternationalizationTest extends AbstractRealmTest { themeSettingsPage.saveTheme(); assertAlertSuccess(); realmSettingsPage.setAdminRealm(AuthRealm.TEST); - accountPage.setAuthRealm(testRealmPage); deleteAllCookiesForTestRealm(); deleteAllCookiesForMasterRealm(); } @@ -55,7 +53,7 @@ public class InternationalizationTest extends AbstractRealmTest { loginToTestRealmConsoleAs(testUser); assertConsoleLocale("Temas"); - accountPage.navigateTo(); + testRealmAccountPage.navigateTo(); assertAccountLocale("Cuenta"); } @@ -64,11 +62,11 @@ public class InternationalizationTest extends AbstractRealmTest { */ @Test public void accountInternationalization() { - accountPage.navigateTo(); + testRealmAccountPage.navigateTo(); loginPage.form().login(testUser); localeDropdown.selectByText("Français"); - accountPage.navigateTo(); + testRealmAccountPage.navigateTo(); assertAccountLocale("Compte"); deleteAllCookiesForTestRealm(); @@ -78,14 +76,12 @@ public class InternationalizationTest extends AbstractRealmTest { } private void assertConsoleLocale(String expected) { - pause(500); assertCurrentUrlEquals(realmSettingsPage); assertLocale(".//a[contains(@href,'/theme-settings')]", expected); // Themes } private void assertAccountLocale(String expected) { - pause(500); - assertCurrentUrlEquals(accountPage); + assertCurrentUrlEquals(testRealmAccountPage); 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) { - waitUntilElement(element); assertEquals(expected, element.getText()); } } diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java index 0a6b6a5632..75f86a2033 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java @@ -75,7 +75,6 @@ public class LoginSettingsTest extends AbstractRealmTest { public void beforeLoginSettingsTest() { // tabs().login(); loginSettingsPage.navigateTo(); - assertCurrentUrlEquals(loginSettingsPage); } @Test