KEYCLOAK-5229 Update testsuite dependencies

This commit is contained in:
Vaclav Muzikar 2017-08-23 15:36:29 +02:00
parent 8e5752c9db
commit da9a88c45c
52 changed files with 410 additions and 312 deletions

View file

@ -336,9 +336,15 @@ To run the tests run:
#### Mozilla Firefox
* **Supported version:** [latest ESR](https://www.mozilla.org/en-US/firefox/organizations/) (Extended Support Release)
* **Driver download required:** no
* **Driver download required:** no (using the old legacy Firefox driver)
* **Run with:** `-Dbrowser=firefox`; optionally you can specify `-Dfirefox_binary=path/to/firefox/binary`
#### Mozilla Firefox with GeckoDriver
You can also use Firefox automation with modern Marionette protocol and GeckoDriver. However, this is **highly experimental** and the testsuite may not work as expected.
* **Supported version:** as latest as possible (Firefox has better support for Marionette with each version released)
* **Driver download required:** [GeckoDriver](https://github.com/mozilla/geckodriver/releases)
* **Run with:** `-Dbrowser=firefox -DfirefoxLegacyDriver=false -Dwebdriver.gecko.driver=path/to/geckodriver`
#### Google Chrome
* **Supported version:** latest stable
* **Driver download required:** [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/) which corresponds with your version of the browser
@ -346,9 +352,12 @@ To run the tests run:
#### Internet Explorer
* **Supported version:** 11
* **Driver download required:** [Internet Explorer Driver Server](http://www.seleniumhq.org/download/); recommended version [2.53.1 32-bit](http://selenium-release.storage.googleapis.com/2.53/IEDriverServer_Win32_2.53.1.zip)
* **Driver download required:** [Internet Explorer Driver Server](http://www.seleniumhq.org/download/); recommended version [3.5.1 32-bit](http://selenium-release.storage.googleapis.com/3.5/IEDriverServer_Win32_3.5.1.zip)
* **Run with:** `-Dbrowser=internetExplorer -Dwebdriver.ie.driver=path/to/IEDriverServer.exe`
#### Automatic driver downloads
You can rely on automatic driver downloads which is provided by [Arquillian Drone](http://arquillian.org/arquillian-extension-drone/#_automatic_download). To do so just omit the `-Dwebdriver.{browser}.driver` CLI argument when running the tests.
## Run X.509 tests
To run the X.509 client certificate authentication tests:

View file

@ -41,14 +41,14 @@
<app.server.java.home>${java.home}</app.server.java.home>
<!--component versions-->
<arquillian-core.version>1.1.11.Final</arquillian-core.version>
<selenium.version>2.53.0</selenium.version>
<arquillian-drone.version>2.0.1.Final</arquillian-drone.version>
<arquillian-graphene.version>2.1.0.Alpha3</arquillian-graphene.version>
<arquillian-core.version>1.1.13.Final</arquillian-core.version>
<selenium.version>3.5.1</selenium.version>
<arquillian-drone.version>2.4.0</arquillian-drone.version>
<arquillian-graphene.version>2.3.1</arquillian-graphene.version>
<arquillian-wildfly-container.version>2.1.0.Beta1</arquillian-wildfly-container.version>
<arquillian-wls-container.version>1.0.1.Final</arquillian-wls-container.version>
<arquillian-infinispan-container.version>1.2.0.Alpha2</arquillian-infinispan-container.version>
<version.shrinkwrap.resolvers>2.2.2</version.shrinkwrap.resolvers>
<arquillian-infinispan-container.version>1.2.0.Beta2</arquillian-infinispan-container.version>
<version.shrinkwrap.resolvers>2.2.6</version.shrinkwrap.resolvers>
<undertow-embedded.version>1.0.0.Alpha2</undertow-embedded.version>
<!--migration properties-->

View file

@ -93,9 +93,9 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
}
public void navigateToAdminAlbum() {
URLUtils.navigateToUri(driver, toString() + "/#/admin/album", true);
URLUtils.navigateToUri(toString() + "/#/admin/album", true);
driver.navigate().refresh(); // This is sometimes necessary for loading the new policy settings
waitForPageToLoad(driver);
waitForPageToLoad();
pause(WAIT_AFTER_OPERATION);
}
@ -136,7 +136,7 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
scopesValue.append(scope);
}
URLUtils.navigateToUri(driver, this.driver.getCurrentUrl() + " " + scopesValue, true);
URLUtils.navigateToUri(this.driver.getCurrentUrl() + " " + scopesValue, true);
}
this.loginPage.form().login(username, password);
@ -155,7 +155,7 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
public void viewAlbum(String name) throws InterruptedException {
this.driver.findElement(By.xpath("//a[text() = '" + name + "']")).click();
waitForPageToLoad(driver);
waitForPageToLoad();
driver.navigate().refresh(); // This is sometimes necessary for loading the new policy settings
pause(WAIT_AFTER_OPERATION);
}
@ -172,6 +172,6 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
@Override
public boolean isCurrent() {
return URLUtils.currentUrlStartWith(driver, toString());
return URLUtils.currentUrlStartWith(toString());
}
}

View file

@ -17,18 +17,17 @@
package org.keycloak.testsuite.arquillian;
import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
import org.jboss.arquillian.container.osgi.OSGiApplicationArchiveProcessor;
import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
import org.jboss.arquillian.container.test.impl.enricher.resource.URLResourceProvider;
import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentScenarioGenerator;
import org.jboss.arquillian.core.spi.LoadableExtension;
import org.jboss.arquillian.drone.spi.Configurator;
import org.jboss.arquillian.drone.spi.Instantiator;
import org.jboss.arquillian.drone.webdriver.factory.HtmlUnitDriverFactory;
import org.jboss.arquillian.drone.webdriver.factory.WebDriverFactory;
import org.jboss.arquillian.graphene.location.ContainerCustomizableURLResourceProvider;
import org.jboss.arquillian.graphene.location.CustomizableURLResourceProvider;
import org.jboss.arquillian.test.spi.TestEnricher;
import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
import org.jboss.arquillian.test.spi.execution.TestExecutionDecider;
import org.keycloak.testsuite.arquillian.h2.H2TestEnricher;
@ -43,9 +42,7 @@ import org.keycloak.testsuite.arquillian.provider.TestContextProvider;
import org.keycloak.testsuite.arquillian.provider.URLProvider;
import org.keycloak.testsuite.drone.HtmlUnitScreenshots;
import org.keycloak.testsuite.drone.KeycloakDronePostSetup;
import org.keycloak.testsuite.drone.KeycloakHtmlUnitInstantiator;
import org.keycloak.testsuite.drone.KeycloakWebDriverConfigurator;
import org.jboss.arquillian.test.spi.TestEnricher;
/**
*
@ -83,7 +80,6 @@ public class KeycloakArquillianExtension implements LoadableExtension {
builder
.override(Configurator.class, WebDriverFactory.class, KeycloakWebDriverConfigurator.class)
.override(Instantiator.class, HtmlUnitDriverFactory.class, KeycloakHtmlUnitInstantiator.class)
.observer(HtmlUnitScreenshots.class)
.observer(KeycloakDronePostSetup.class);

View file

@ -83,7 +83,7 @@ public class AccountFields extends Form {
}
public void waitForUsernameInputNotPresent() {
waitUntilElementIsNotPresent(driver, usernameInput);
waitUntilElementIsNotPresent(usernameInput);
}
}

View file

@ -24,6 +24,7 @@ import org.openqa.selenium.support.FindBy;
import javax.ws.rs.core.UriBuilder;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
/**
@ -77,6 +78,7 @@ public class AccountManagement extends AuthRealm implements PageWithLogOutAction
public void signOut() {
signOutLink.click();
waitForPageToLoad();
}
@Override
@ -86,34 +88,36 @@ public class AccountManagement extends AuthRealm implements PageWithLogOutAction
public void account() {
accountLink.click();
waitForPageToLoad();
}
public void password() {
passwordLink.click();
waitForPageToLoad();
}
public void authenticator() {
authenticatorLink.click();
waitForPageToLoad();
}
public void sessions() {
sessionsLink.click();
waitForPageToLoad();
}
public void applications() {
applicationsLink.click();
waitForPageToLoad();
}
public void save() {
save.click();
waitForPageToLoad();
}
// public RealmResource realmResource() {
// return keycloak().realm(getAuthRealm());
// }
public void waitForAccountLinkPresent() {
waitUntilElement(accountLink, "account link should be present").is().present();
}
}

View file

@ -25,7 +25,7 @@ import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import static org.keycloak.testsuite.admin.Users.getPasswordOf;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
import static org.keycloak.testsuite.util.UIUtils.clickLink;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElementIsNotPresent;
@ -76,28 +76,24 @@ public class LoginForm extends Form {
}
public void register() {
registerLink.click();
waitForPageToLoad(driver);
clickLink(registerLink);
}
public void login() {
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);
clickLink(loginButton);
}
public void forgotPassword() {
forgottenPassword.click();
waitForPageToLoad(driver);
clickLink(forgottenPassword);
}
public void rememberMe(boolean value) {
boolean selected = rememberMe.isSelected();
if ((value && !selected) || !value && selected) {
rememberMe.click();
waitForPageToLoad(driver);
}
}
@ -111,7 +107,7 @@ public class LoginForm extends Form {
}
public void waitForRegisterLinkNotPresent() {
waitUntilElementIsNotPresent(driver, registerLink);
waitUntilElementIsNotPresent(registerLink);
}
public void waitForResetPasswordLinkNotPresent() {
@ -123,7 +119,7 @@ public class LoginForm extends Form {
}
public void waitForRememberMeNotPresent() {
waitUntilElementIsNotPresent(driver, rememberMe);
waitUntilElementIsNotPresent(rememberMe);
}
public void waitForLoginButtonPresent() {
@ -157,8 +153,7 @@ public class LoginForm extends Form {
}
public void submit() {
submit.click();
waitForPageToLoad(driver);
clickLink(submit);
}
}
}

View file

@ -37,16 +37,16 @@ public class TermsAndConditions extends LoginActions {
@Override
public boolean isCurrent() {
return UIUtils.currentTitleEquals(driver, "Terms and Conditions");
return UIUtils.currentTitleEquals("Terms and Conditions");
}
public void acceptTerms() {
acceptButton.click();
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
}
public void declineTerms() {
declineButton.click();
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
}
public String getAcceptButtonText() {

View file

@ -16,22 +16,23 @@
*/
package org.keycloak.testsuite.console.page.fragment;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.fragment.Root;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.fragment.Root;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.FindBy;
import static org.keycloak.testsuite.util.WaitUtils.pause;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@ -44,7 +45,7 @@ public abstract class AbstractMultipleSelect2<R> {
@Drone
private WebDriver driver;
@FindBy(xpath = ".//input[contains(@class,'select2-input')]")
@FindBy(xpath = "//input[contains(@class,'select2-focused')]")
private WebElement search;
@FindBy(xpath = "//div[contains(@class,'select2-result-label')]")
@ -76,17 +77,17 @@ public abstract class AbstractMultipleSelect2<R> {
}
public void select(R value) {
pause(500);
root.click();
WaitUtils.pause(500);
pause(500);
String id = identity().apply(value);
Actions actions = new Actions(driver);
actions.sendKeys(id).perform();
WaitUtils.pause(500);
search.sendKeys(id);
waitForPageToLoad();
if (result.isEmpty()) {
actions.sendKeys(Keys.ESCAPE).perform();
search.sendKeys(Keys.ESCAPE);
return;
}
@ -137,7 +138,7 @@ public abstract class AbstractMultipleSelect2<R> {
WebElement element = selected.findElement(By.xpath(".//a[contains(@class,'select2-search-choice-close')]"));
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", element);
WaitUtils.pause(500);
pause(500);
return true;
}
return false;

View file

@ -25,6 +25,7 @@ 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.openqa.selenium.By.xpath;
@ -59,12 +60,12 @@ public class DataTable {
public void clickHeaderButton(String buttonText) {
header.findElement(By.xpath(".//button[text()='" + buttonText + "']")).click();
waitForPageToLoad(driver);
waitForPageToLoad();
}
public void clickHeaderLink(String linkText) {
header.findElement(By.linkText(linkText)).click();
waitForPageToLoad(driver);
waitForPageToLoad();
}
public WebElement body() {
@ -72,6 +73,7 @@ public class DataTable {
}
public List<WebElement> rows() {
pause(500); // wait a bit to ensure the table is no more changing
return rows;
}

View file

@ -6,6 +6,7 @@ import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import static org.keycloak.testsuite.util.URLUtils.navigateToUri;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
/**
@ -27,6 +28,6 @@ public class Dropdown {
public void selectByText(String text) {
waitUntilElement(dropDownRoot).is().present();
WebElement element = dropDownRoot.findElement(By.xpath("./ul/li/a[text()='" + text + "']"));
driver.navigate().to(element.getAttribute("href"));
navigateToUri(element.getAttribute("href"), true); // TODO: move cursor to show the menu and then click the menu item
}
}

View file

@ -52,21 +52,21 @@ public class ModalDialog {
private WebElement message;
public void ok() {
waitForModalFadeIn(driver);
waitForModalFadeIn();
okButton.click();
waitForModalFadeOut(driver);
waitForModalFadeOut();
}
public void confirmDeletion() {
waitForModalFadeIn(driver);
waitForModalFadeIn();
deleteButton.click();
waitForModalFadeOut(driver);
waitForModalFadeOut();
}
public void cancel() {
waitForModalFadeIn(driver);
waitForModalFadeIn();
cancelButton.click();
waitForModalFadeOut(driver);
waitForModalFadeOut();
}
public void setName(String name) {

View file

@ -17,12 +17,8 @@
package org.keycloak.testsuite.console.page.fragment;
import org.jboss.arquillian.graphene.fragment.Root;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.support.FindBy;
/**
*
@ -33,26 +29,18 @@ public class OnOffSwitch {
@Root
private WebElement root;
@ArquillianResource
private Actions actions;
@FindBy(tagName = "input")
private WebElement inputTag;
public OnOffSwitch() {
}
public OnOffSwitch(WebElement root, Actions actions) {
this.root = root;
this.actions = actions;
}
@FindBy(tagName = "label")
private WebElement labelTag;
public boolean isOn() {
waitUntilElement(root).is().present();
return root.findElement(By.tagName("input")).isSelected();
return inputTag.isSelected();
}
private void click() {
waitUntilElement(root).is().present();
actions.moveToElement(root.findElement(By.tagName("label")))
.click().build().perform();
labelTag.click();
}
public void toggle() {

View file

@ -1,55 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.drone;
import java.lang.reflect.Method;
import com.gargoylesoftware.htmlunit.WebClient;
import org.jboss.arquillian.drone.spi.Instantiator;
import org.jboss.arquillian.drone.webdriver.configuration.WebDriverConfiguration;
import org.jboss.arquillian.drone.webdriver.factory.HtmlUnitDriverFactory;
import org.jboss.logging.Logger;
import org.keycloak.common.util.reflections.Reflections;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class KeycloakHtmlUnitInstantiator extends HtmlUnitDriverFactory implements Instantiator<HtmlUnitDriver, WebDriverConfiguration> {
protected final Logger log = Logger.getLogger(KeycloakHtmlUnitInstantiator.class);
@Override
public int getPrecedence() {
return 1;
}
@Override
public HtmlUnitDriver createInstance(WebDriverConfiguration configuration) {
HtmlUnitDriver htmlUnitDriver = super.createInstance(configuration);
// Disable CSS
Method getWebClient = Reflections.findDeclaredMethod(HtmlUnitDriver.class, "getWebClient");
WebClient webClient = (WebClient) Reflections.invokeMethod(true, getWebClient, htmlUnitDriver);
webClient.getOptions().setCssEnabled(false);
return htmlUnitDriver;
}
}

View file

@ -51,7 +51,7 @@ public abstract class AbstractAlert {
}
protected boolean checkAlertType(String type) {
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
try {
(new WebDriverWait(driver, 1)).until(ExpectedConditions.attributeContains(root, "class", "alert-" + type));
}

View file

@ -95,11 +95,11 @@ public abstract class AbstractPage {
}
public void navigateTo(boolean waitForMatch) {
URLUtils.navigateToUri(driver, buildUri().toASCIIString(), waitForMatch);
URLUtils.navigateToUri(buildUri().toASCIIString(), waitForMatch);
}
public boolean isCurrent() {
return URLUtils.currentUrlEqual(driver, toString());
return URLUtils.currentUrlEqual(toString());
}
}

View file

@ -47,7 +47,7 @@ public class Form {
public void save() {
// guardAjax(save).click();
save.click();
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
}
public void cancel() {

View file

@ -50,29 +50,29 @@ public class AppServerWelcomePage extends AppServerContextRoot {
public void navigateToConsole() {
WaitUtils.pause(2000);
URLUtils.navigateToUri(driver, getInjectedUrl().toString() + "/console", true);
waitForPageToLoad(driver);
URLUtils.navigateToUri(getInjectedUrl().toString() + "/console", true);
waitForPageToLoad();
}
public void login(String username, String password) {
loginPage.form().waitForLoginButtonPresent();
loginPage.form().login(username, password);
waitForPageToLoad(driver);
waitForPageToLoad();
}
public void navigateToAccessControl() {
accessControlLink.click();
waitForPageToLoad(driver);
waitForPageToLoad();
}
public void navigateManageProfile() {
manageProfileLink.click();
waitForPageToLoad(driver);
waitForPageToLoad();
}
public void logout() {
logoutLink.click();
waitForPageToLoad(driver);
waitForPageToLoad();
}
public boolean isLoginPage() {

View file

@ -0,0 +1,30 @@
/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.util;
import org.jboss.arquillian.graphene.context.GrapheneContext;
import org.openqa.selenium.WebDriver;
/**
* @author Vaclav Muzikar <vmuzikar@redhat.com>
*/
public final class DroneUtils {
public static WebDriver getCurrentDriver() {
return GrapheneContext.lastContext().getWebDriver();
}
}

View file

@ -19,7 +19,6 @@ package org.keycloak.testsuite.util;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
@ -50,7 +49,6 @@ import org.keycloak.representations.IDToken;
import org.keycloak.representations.RefreshToken;
import org.keycloak.representations.idm.KeysMetadataRepresentation;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import org.keycloak.testsuite.arquillian.SuiteContext;
import org.keycloak.util.BasicAuthHelper;
import org.keycloak.util.JsonSerialization;
import org.keycloak.util.TokenUtil;
@ -60,7 +58,6 @@ import org.openqa.selenium.WebDriver;
import javax.ws.rs.core.UriBuilder;
import java.io.Closeable;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
@ -204,7 +201,7 @@ public class OAuthClient {
}
public void fillLoginForm(String username, String password) {
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
String src = driver.getPageSource();
try {
driver.findElement(By.id("username")).sendKeys(username);

View file

@ -1,12 +1,14 @@
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;
import static org.keycloak.testsuite.util.DroneUtils.getCurrentDriver;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
/**
* @author Vaclav Muzikar <vmuzikar@redhat.com>
*/
@ -21,13 +23,40 @@ public final class UIUtils {
return false;
}
public static boolean currentTitleEquals(WebDriver driver, String url) {
public static boolean currentTitleEquals(String url) {
try {
(new WebDriverWait(driver, 5)).until(ExpectedConditions.titleIs(url));
(new WebDriverWait(getCurrentDriver(), 5)).until(ExpectedConditions.titleIs(url));
}
catch (TimeoutException e) {
return false;
}
return true;
}
/**
* Safely performs an operation which is expected to cause a page reload, e.g. a link click.
* This ensures the page will be fully loaded after the operation.
* This is intended for use in UI tests only.
*
* @param operation
*/
public static void performOperationWithPageReload(Runnable operation) {
operation.run();
waitForPageToLoad();
}
public static void clickLink(WebElement element) {
performOperationWithPageReload(element::click);
}
/**
* Navigates to a link directly instead of clicking on it.
* Some browsers are sometimes having problems with clicking on links, so this should be used only in that cases,
* i.e. only when clicking directly doesn't work
*
* @param element
*/
public static void navigateToLink(WebElement element) {
URLUtils.navigateToUri(element.getAttribute("href"), true);
}
}

View file

@ -10,8 +10,9 @@ import org.openqa.selenium.support.ui.WebDriverWait;
import java.util.regex.Pattern;
import static org.keycloak.testsuite.util.DroneUtils.getCurrentDriver;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
import static org.openqa.selenium.support.ui.ExpectedConditions.not;
import static org.openqa.selenium.support.ui.ExpectedConditions.or;
import static org.openqa.selenium.support.ui.ExpectedConditions.urlMatches;
import static org.openqa.selenium.support.ui.ExpectedConditions.urlToBe;
@ -20,12 +21,15 @@ import static org.openqa.selenium.support.ui.ExpectedConditions.urlToBe;
*/
public final class URLUtils {
public static void navigateToUri(WebDriver driver, String uri, boolean waitForMatch) {
navigateToUri(driver, uri, waitForMatch, true);
private static Logger log = Logger.getLogger(URLUtils.class);
public static void navigateToUri(String uri, boolean waitForMatch) {
navigateToUri(uri, waitForMatch, true);
}
private static void navigateToUri(WebDriver driver, String uri, boolean waitForMatch, boolean enableIEWorkaround) {
Logger log = Logger.getLogger(URLUtils.class);
// TODO: remove waitForMatch
private static void navigateToUri(String uri, boolean waitForMatch, boolean enableIEWorkaround) {
WebDriver driver = getCurrentDriver();
log.info("starting navigation");
@ -34,27 +38,20 @@ public final class URLUtils {
if (driver instanceof InternetExplorerDriver && driver.getCurrentUrl().equals(uri)) {
log.info("IE workaround: target URL equals current URL - refreshing the page");
driver.navigate().refresh();
waitForPageToLoad();
}
WaitUtils.waitForPageToLoad(driver);
log.info("current URL: " + driver.getCurrentUrl());
log.info("navigating to " + uri);
driver.navigate().to(uri);
if (waitForMatch) {
// Possible login URL; this is to eliminate unnecessary wait when navigating to a secured page and being
// redirected to the login page
String loginUrl = "^[^\\?]+/auth/realms/[^/]+/(protocol|login-actions).+$";
try {
(new WebDriverWait(driver, 3)).until(or(urlMatches("^" + Pattern.quote(uri) + ".*$"), urlMatches(loginUrl)));
} catch (TimeoutException e) {
log.info("new current URL doesn't start with desired URL");
}
if (driver.getCurrentUrl().equals(uri)) { // Some browsers won't do anything if navigating to the same URL; this "fixes" it
log.info("target URL equals current URL - refreshing the page");
driver.navigate().refresh();
}
else {
driver.navigate().to(uri);
}
WaitUtils.waitForPageToLoad(driver);
waitForPageToLoad();
log.info("new current URL: " + driver.getCurrentUrl());
@ -65,45 +62,45 @@ public final class URLUtils {
&& (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);
navigateToUri(uri, waitForMatch, false);
}
else {
log.info("navigation complete");
}
}
public static boolean currentUrlEqual(WebDriver driver, String url) {
return urlCheck(driver, urlToBe(url));
public static boolean currentUrlEqual(String url) {
return urlCheck(urlToBe(url));
}
public static boolean currentUrlDoesntEqual(WebDriver driver, String url) {
return urlCheck(driver, not(urlToBe(url)));
public static boolean currentUrlDoesntEqual(String url) {
return urlCheck(not(urlToBe(url)));
}
public static boolean currentUrlStartWith(WebDriver driver, String url) {
return urlCheck(driver, urlMatches("^" + Pattern.quote(url) + ".*$"));
public static boolean currentUrlStartWith(String url) {
return urlCheck(urlMatches("^" + Pattern.quote(url) + ".*$"));
}
public static boolean currentUrlDoesntStartWith(WebDriver driver, String url) {
return urlCheck(driver, urlMatches("^(?!" + Pattern.quote(url) + ").+$"));
public static boolean currentUrlDoesntStartWith(String url) {
return urlCheck(urlMatches("^(?!" + Pattern.quote(url) + ").+$"));
}
private static boolean urlCheck(WebDriver driver, ExpectedCondition condition) {
return urlCheck(driver, condition, false);
private static boolean urlCheck(ExpectedCondition condition) {
return urlCheck(condition, false);
}
private static boolean urlCheck(WebDriver driver, ExpectedCondition condition, boolean secondTry) {
Logger log = Logger.getLogger(URLUtils.class);
private static boolean urlCheck(ExpectedCondition condition, boolean secondTry) {
WebDriver driver = getCurrentDriver();
try {
(new WebDriverWait(driver, 1, 100)).until(condition);
(new WebDriverWait(driver, 5, 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);
urlCheck(condition, true);
}
else {
return false;

View file

@ -21,17 +21,18 @@ import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.jboss.arquillian.graphene.Graphene.waitGui;
import static org.openqa.selenium.support.ui.ExpectedConditions.invisibilityOfAllElements;
import static org.openqa.selenium.support.ui.ExpectedConditions.javaScriptThrowsNoExceptions;
import static org.openqa.selenium.support.ui.ExpectedConditions.not;
import static org.openqa.selenium.support.ui.ExpectedConditions.urlContains;
import static org.keycloak.testsuite.util.DroneUtils.getCurrentDriver;
import static org.openqa.selenium.support.ui.ExpectedConditions.*;
/**
*
@ -64,13 +65,14 @@ public final class WaitUtils {
return waitGui().until(failMessage).element(element);
}
public static void waitUntilElementIsNotPresent(WebDriver driver, By locator) {
waitUntilElementIsNotPresent(driver, driver.findElement(locator));
public static void waitUntilElementIsNotPresent(By locator) {
waitUntilElement(locator).is().not().present();
}
public static void waitUntilElementIsNotPresent(WebDriver driver, WebElement element) {
(new WebDriverWait(driver, IMPLICIT_ELEMENT_WAIT_MILLIS))
.until(invisibilityOfAllElements(Collections.singletonList(element)));
public static void waitUntilElementIsNotPresent(WebElement element) {
waitUntilElement(element).is().not().present();
// (new WebDriverWait(driver, IMPLICIT_ELEMENT_WAIT_MILLIS))
// .until(invisibilityOfAllElements(Collections.singletonList(element)));
}
public static void pause(long millis) {
@ -89,15 +91,32 @@ 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);
public static void waitForPageToLoad() {
WebDriver driver = getCurrentDriver();
if (driver instanceof HtmlUnitDriver) {
return; // not needed
}
// Ensure the URL is "stable", i.e. is not changing anymore; if it'd changing, some redirects are probably still in progress
for (int maxRedirects = 2; maxRedirects > 0; maxRedirects--) {
String currentUrl = driver.getCurrentUrl();
FluentWait<WebDriver> wait = new FluentWait<>(driver).withTimeout(250, TimeUnit.MILLISECONDS);
try {
wait.until(not(urlToBe(currentUrl)));
}
catch (TimeoutException e) {
break; // URL has not changed recently - ok, the URL is stable and page is current
}
if (maxRedirects == 1) {
log.warn("URL seems unstable! (Some redirect are probably still in progress)");
}
}
WebDriverWait wait = new WebDriverWait(getCurrentDriver(), 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(
@ -112,12 +131,12 @@ public final class WaitUtils {
}
}
public static void waitForModalFadeIn(WebDriver driver) {
public static void waitForModalFadeIn() {
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"));
public static void waitForModalFadeOut() {
waitUntilElementIsNotPresent(By.className("modal-backdrop"));
}
}

View file

@ -207,7 +207,7 @@ public abstract class AbstractServletAuthzFunctionalAdapterTest extends Abstract
public void testAccessPublicResource() throws Exception {
performTests(() -> {
driver.navigate().to(getResourceServerUrl() + "/public-html.html");
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
assertTrue(hasText("This is public resource that should be accessible without login."));
});
}

View file

@ -48,7 +48,6 @@ import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
import org.keycloak.testsuite.pages.ErrorPage;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
import org.keycloak.testsuite.pages.UpdateAccountInformationPage;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.WaitUtils;
import org.keycloak.util.JsonSerialization;
@ -61,8 +60,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT;
import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT_LINKS;
@ -545,7 +542,7 @@ public abstract class AbstractClientInitiatedAccountLinkTest extends AbstractSer
// Login to account mgmt first
profilePage.open(CHILD_IDP);
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
Assert.assertTrue(loginPage.isCurrent(CHILD_IDP));
loginPage.login("child", "password");
@ -590,7 +587,7 @@ public abstract class AbstractClientInitiatedAccountLinkTest extends AbstractSer
// Login to account mgmt first
profilePage.open(CHILD_IDP);
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
Assert.assertTrue(loginPage.isCurrent(CHILD_IDP));
loginPage.login("child", "password");
@ -624,7 +621,7 @@ public abstract class AbstractClientInitiatedAccountLinkTest extends AbstractSer
private void navigateTo(String uri) {
driver.navigate().to(uri);
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
}

View file

@ -53,8 +53,6 @@ import org.keycloak.testsuite.util.*;
import org.keycloak.testsuite.util.URLUtils;
import org.keycloak.util.BasicAuthHelper;
import org.openqa.selenium.By;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
@ -197,7 +195,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
testRealmLoginPage.form().login("bburke@redhat.com", "password");
assertCurrentUrlEquals(driver, inputPortal + "/secured/post");
waitForPageToLoad(driver);
waitForPageToLoad();
String pageSource = driver.getPageSource();
assertThat(pageSource, containsString("parameter=hello"));
@ -564,7 +562,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
// Test I need to reauthenticate with prompt=login
String appUri = tokenMinTTLPage.getUriBuilder().queryParam(OIDCLoginProtocol.PROMPT_PARAM, OIDCLoginProtocol.PROMPT_VALUE_LOGIN).build().toString();
URLUtils.navigateToUri(driver, appUri, true);
URLUtils.navigateToUri(appUri, true);
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
testRealmLoginPage.form().login("bburke@redhat.com", "password");
AccessToken token = tokenMinTTLPage.getAccessToken();
@ -624,7 +622,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
oAuthGrantPage.accept();
String pageSource = driver.getPageSource();
waitForPageToLoad(driver);
waitForPageToLoad();
assertThat(pageSource, containsString("Bill Burke"));
assertThat(pageSource, containsString("Stian Thorgersen"));
@ -682,7 +680,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
testRealmLoginPage.form().login("bburke@redhat.com", "password");
waitForPageToLoad(driver);
waitForPageToLoad();
String pageSource = driver.getPageSource();
assertThat(pageSource, containsString("Bill Burke"));
assertThat(pageSource, containsString("Stian Thorgersen"));

View file

@ -397,7 +397,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
private void checkLoggedOut(AbstractPage page, Login loginPage) {
page.navigateTo();
waitForPageToLoad(driver);
waitForPageToLoad();
assertCurrentUrlStartsWith(loginPage);
}
@ -950,7 +950,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
testRealmSAMLPostLoginPage.form().login("bburke", "password");
assertCurrentUrlStartsWith(employeeServletPage);
waitForPageToLoad(driver);
waitForPageToLoad();
String pageSource = driver.getPageSource();
assertThat(pageSource, containsString("Relay state: " + SamlSPFacade.RELAY_STATE));
assertThat(pageSource, not(containsString("SAML response: null")));

View file

@ -17,7 +17,6 @@
package org.keycloak.testsuite.adapter.servlet.cluster;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.*;
import org.keycloak.testsuite.Retry;
import org.keycloak.testsuite.adapter.page.EmployeeServletDistributable;
@ -57,7 +56,6 @@ import org.openqa.selenium.support.ui.WebDriverWait;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import static org.keycloak.testsuite.AbstractAuthTest.createUserRepresentation;
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.getNearestSuperclassWithAnnotation;
import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
@ -223,7 +221,7 @@ public abstract class AbstractSAMLAdapterClusterTest extends AbstractServletsAda
protected void checkLoggedOut(AbstractPage page, AuthRealm loginPage) {
page.navigateTo();
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
assertCurrentUrlStartsWith(loginPage);
}

View file

@ -225,10 +225,10 @@ public class SocialLoginTest extends AbstractKeycloakTest {
// Just to be sure there's no redirect in progress
WaitUtils.pause(3000);
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
// Only when there's not active session for the social provider, i.e. login is required
if (URLUtils.currentUrlDoesntStartWith(driver, getAuthServerRoot().toASCIIString())) {
if (URLUtils.currentUrlDoesntStartWith(getAuthServerRoot().toASCIIString())) {
log.infof("current URL: %s", driver.getCurrentUrl());
log.infof("performing log in to '%s' ...", currentTestProvider.id());
AbstractSocialLoginPage loginPage = Graphene.createPageFragment(currentTestProvider.pageObjectClazz(), driver.findElement(By.tagName("html")));
@ -240,7 +240,7 @@ public class SocialLoginTest extends AbstractKeycloakTest {
}
private void assertAccount() {
assertTrue(URLUtils.currentUrlStartWith(driver, accountPage.toString())); // Sometimes after login the URL ends with /# or similar
assertTrue(URLUtils.currentUrlStartWith(accountPage.toString())); // Sometimes after login the URL ends with /# or similar
assertEquals(getConfig("profile.firstName"), accountPage.getFirstName());
assertEquals(getConfig("profile.lastName"), accountPage.getLastName());
@ -248,7 +248,7 @@ public class SocialLoginTest extends AbstractKeycloakTest {
}
private void assertUpdateProfile(boolean firstName, boolean lastName, boolean email) {
assertTrue(URLUtils.currentUrlDoesntStartWith(driver, accountPage.toString()));
assertTrue(URLUtils.currentUrlDoesntStartWith(accountPage.toString()));
if (firstName) {
assertTrue(updateAccountPage.fields().getFirstName().isEmpty());

View file

@ -53,12 +53,12 @@ public class URLAssert {
public static void assertCurrentUrlEquals(WebDriver driver, final AbstractPage page) {
String expected = page.toString();
assertTrue("Expected URL: " + expected + "; actual: " + driver.getCurrentUrl(),
currentUrlEqual(driver, page.toString()));
currentUrlEqual(page.toString()));
}
public static void assertCurrentUrlEquals(WebDriver driver, final String url) {
assertTrue("Expected URL: " + url + "; actual: " + driver.getCurrentUrl(),
currentUrlEqual(driver, url));
currentUrlEqual(url));
}
public static void assertCurrentUrlStartsWith(AbstractPage page) {
@ -67,7 +67,7 @@ public class URLAssert {
public static void assertCurrentUrlStartsWith(WebDriver driver, final String url) {
assertTrue("URL expected to begin with:" + url + "; actual URL: " + driver.getCurrentUrl(),
currentUrlStartWith(driver, url));
currentUrlStartWith(url));
}
public static void assertCurrentUrlDoesntStartWith(AbstractPage page) {
@ -76,7 +76,7 @@ public class URLAssert {
public static void assertCurrentUrlDoesntStartWith(WebDriver driver, final String url) {
assertTrue("URL expected NOT to begin with:" + url + "; actual URL: " + driver.getCurrentUrl(),
currentUrlDoesntStartWith(driver, url));
currentUrlDoesntStartWith(url));
}
public static void assertCurrentUrlStartsWithLoginUrlOf(PageWithLoginUrl page) {

View file

@ -24,10 +24,22 @@
<extension qualifier="webdriver">
<property name="browser">${browser}</property>
<property name="downloadBinaries">${webdriverDownloadBinaries}</property>
<!-- htmlunit -->
<property name="htmlUnit.version">${htmlUnitBrowserVersion}</property>
<property name="firefox_binary">${firefox_binary}</property>
<property name="chromeArguments">${chromeArguments}</property>
<property name="htmlUnitWebClientOptions">cssEnabled=false;historyPageCacheLimit=1</property>
<!-- phantomjs -->
<property name="phantomjs.cli.args">${phantomjs.cli.args} --ssl-certificates-path=${client.certificate.ca.path} --ssl-client-certificate-file=${client.certificate.file} --ssl-client-key-file=${client.key.file} --ssl-client-key-passphrase=${client.key.passphrase}</property>
<!-- firefox -->
<property name="firefox_binary">${firefox_binary}</property>
<property name="firefoxLogLevel">OFF</property>
<property name="firefoxLegacy">${firefoxLegacyDriver}</property>
<!-- chrome -->
<property name="chromeArguments">${chromeArguments}</property>
</extension>
<extension qualifier="graphene">

View file

@ -33,6 +33,7 @@
<properties>
<keycloak.theme.dir>${auth.server.home}/themes</keycloak.theme.dir>
<supportedBrowsers>firefox|chrome|internetExplorer</supportedBrowsers>
</properties>
<build>
@ -55,6 +56,27 @@
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>browser</property>
<message>Browser property must be set!</message>
<regex>${supportedBrowsers}</regex>
<regexMessage>Unsupported browser "${browser}"! Only the following are supported: ${supportedBrowsers}</regexMessage>
</requireProperty>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>

View file

@ -36,7 +36,7 @@ public class PasswordPolicy extends Authentication {
addPolicySelect.selectByVisibleText(policy.getName());
if (value != null) {setPolicyValue(policy, value);}
primaryButton.click();
waitForPageToLoad(driver);
waitForPageToLoad();
}
@ -53,7 +53,7 @@ public class PasswordPolicy extends Authentication {
if (primaryButton.isEnabled()) {
primaryButton.click();
}
waitForPageToLoad(driver);
waitForPageToLoad();
}
public void editPolicy(Type policy, int value) {
@ -65,7 +65,7 @@ public class PasswordPolicy extends Authentication {
if (primaryButton.isEnabled()) {
primaryButton.click();
}
waitForPageToLoad(driver);
waitForPageToLoad();
}
private void setPolicyValue(Type policy, String value) {

View file

@ -33,7 +33,7 @@ public class RequiredActions extends Authentication {
WebElement checkbox = requiredActionTable.findElement(By.id(id));
if (checkbox.isSelected() != value) {
if (checkbox.isEnabled() && checkbox.isSelected() != value) {
checkbox.click();
}
}

View file

@ -8,6 +8,8 @@ import org.openqa.selenium.support.ui.Select;
import java.util.List;
import java.util.stream.Collectors;
import static org.keycloak.testsuite.util.UIUtils.performOperationWithPageReload;
/**
* @author tkyjovsk
* @author mhajas
@ -61,7 +63,7 @@ public class Flows extends Authentication {
}
public void selectFlowOption(FlowOption option) {
flowSelect.selectByVisibleText(option.getName());
performOperationWithPageReload(() -> flowSelect.selectByVisibleText(option.getName()));
}
public String getFlowSelectValue() {

View file

@ -6,6 +6,8 @@ import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import static org.keycloak.testsuite.console.page.fragment.Breadcrumb.BREADCRUMB_XPATH;
import static org.keycloak.testsuite.util.UIUtils.clickLink;
import org.openqa.selenium.NoSuchElementException;
/**
@ -44,7 +46,7 @@ public class Client extends Clients {
private WebElement deleteIcon;
public void delete() {
deleteIcon.click();
clickLink(deleteIcon);
modalDialog.confirmDeletion();
}
@ -80,35 +82,35 @@ public class Client extends Clients {
private WebElement authorizationLink;
public void settings() {
settingsLink.click();
clickLink(settingsLink);
}
public void roles() {
rolesLink.click();
clickLink(rolesLink);
}
public void mappers() {
mappersLink.click();
clickLink(mappersLink);
}
public void scope() {
scopeLink.click();
clickLink(scopeLink);
}
public void revocation() {
revocationLink.click();
clickLink(revocationLink);
}
public void sessions() {
sessionsLink.click();
clickLink(sessionsLink);
}
public void installation() {
installationLink.click();
clickLink(installationLink);
}
public void authorization() {
authorizationLink.click();
clickLink(authorizationLink);
}
public boolean isServiceAccountRolesDisplayed() {

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.testsuite.console.page.clients.authorization;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.fragment.Root;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.testsuite.console.page.clients.Client;
@ -23,9 +24,12 @@ import org.keycloak.testsuite.console.page.clients.authorization.permission.Perm
import org.keycloak.testsuite.console.page.clients.authorization.policy.Policies;
import org.keycloak.testsuite.console.page.clients.authorization.resource.Resources;
import org.keycloak.testsuite.console.page.clients.authorization.scope.Scopes;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import static org.keycloak.testsuite.util.UIUtils.navigateToLink;
/**
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@ -97,6 +101,9 @@ public class Authorization extends Client {
@Root
private WebElement root;
@Drone
private WebDriver driver;
@FindBy(linkText = "Settings")
private WebElement settingsLink;
@ -113,23 +120,28 @@ public class Authorization extends Client {
private WebElement policiesLink;
public void settings() {
settingsLink.click();
//clickLink(settingsLink);
navigateToLink(settingsLink); // for some reason, GeckoDriver is currently having problems clicking on those tabs
}
public void resources() {
resourcesLink.click();
//clickLink(resourcesLink);
navigateToLink(resourcesLink);
}
private void scopes() {
scopesLink.click();
//clickLink(scopesLink);
navigateToLink(scopesLink);
}
private void permissions() {
permissionsLink.click();
//clickLink(permissionsLink);
navigateToLink(permissionsLink);
}
private void policies() {
policiesLink.click();
//clickLink(policiesLink);
navigateToLink(policiesLink);
}
}
}

View file

@ -16,8 +16,6 @@
*/
package org.keycloak.testsuite.console.page.clients.authorization.permission;
import static org.openqa.selenium.By.tagName;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
@ -25,13 +23,15 @@ import org.keycloak.representations.idm.authorization.ResourcePermissionRepresen
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
import org.keycloak.testsuite.console.page.clients.authorization.policy.PolicyTypeUI;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.URLUtils;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
import static org.keycloak.testsuite.util.UIUtils.clickLink;
import static org.openqa.selenium.By.tagName;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@ -73,8 +73,8 @@ public class Permissions extends Form {
for (WebElement row : permissions().rows()) {
PolicyRepresentation actual = permissions().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
WaitUtils.waitForPageToLoad(driver);
clickLink(row.findElements(tagName("a")).get(0));
WaitUtils.waitForPageToLoad();
String type = representation.getType();
if ("resource".equals(type)) {
@ -92,8 +92,8 @@ public class Permissions extends Form {
for (WebElement row : permissions().rows()) {
PolicyRepresentation actual = permissions().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
WaitUtils.waitForPageToLoad(driver);
clickLink(row.findElements(tagName("a")).get(0));
WaitUtils.waitForPageToLoad();
String type = actual.getType();
if ("resource".equals(type)) {
return (P) resourcePermission;
@ -109,8 +109,8 @@ public class Permissions extends Form {
for (WebElement row : permissions().rows()) {
PolicyRepresentation actual = permissions().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
WaitUtils.waitForPageToLoad(driver);
clickLink(row.findElements(tagName("a")).get(0));
WaitUtils.waitForPageToLoad();
String type = actual.getType();

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import static org.openqa.selenium.By.tagName;
import java.util.ArrayList;
@ -93,6 +94,7 @@ public class GroupPolicyForm extends Form {
String groupName = path.substring(path.lastIndexOf('/') + 1);
WebElement element = driver.findElement(By.xpath("//span[text()='" + groupName + "']"));
element.click();
waitUntilElement(selectGroupButton).is().enabled();
selectGroupButton.click();
driver.findElements(By.xpath("(//table[@id='selected-groups'])/tbody/tr")).stream()
.filter(webElement -> webElement.findElements(tagName("td")).size() > 1)

View file

@ -16,8 +16,6 @@
*/
package org.keycloak.testsuite.console.page.clients.authorization.policy;
import static org.openqa.selenium.By.tagName;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentation;
@ -30,13 +28,15 @@ import org.keycloak.representations.idm.authorization.RulePolicyRepresentation;
import org.keycloak.representations.idm.authorization.TimePolicyRepresentation;
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.URLUtils;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
import static org.keycloak.testsuite.util.UIUtils.clickLink;
import static org.keycloak.testsuite.util.UIUtils.performOperationWithPageReload;
import static org.openqa.selenium.By.tagName;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@ -79,7 +79,7 @@ public class Policies extends Form {
public <P extends PolicyTypeUI> P create(AbstractPolicyRepresentation expected) {
String type = expected.getType();
createSelect.selectByValue(type);
performOperationWithPageReload(() -> createSelect.selectByValue(type));
if ("role".equals(type)) {
rolePolicy.form().populate((RolePolicyRepresentation) expected);
@ -104,7 +104,6 @@ public class Policies extends Form {
return (P) clientPolicy;
} else if ("group".equals(type)) {
groupPolicy.form().populate((GroupPolicyRepresentation) expected);
groupPolicy.form().save();
return (P) groupPolicy;
}
@ -115,8 +114,7 @@ public class Policies extends Form {
for (WebElement row : policies().rows()) {
PolicyRepresentation actual = policies().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
WaitUtils.waitForPageToLoad(driver);
clickLink(row.findElements(tagName("a")).get(0));
String type = representation.getType();
if ("role".equals(type)) {
@ -146,7 +144,7 @@ public class Policies extends Form {
for (WebElement row : policies().rows()) {
PolicyRepresentation actual = policies().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
clickLink(row.findElements(tagName("a")).get(0));
String type = actual.getType();
if ("role".equals(type)) {
return (P) rolePolicy;
@ -174,7 +172,7 @@ public class Policies extends Form {
for (WebElement row : policies().rows()) {
PolicyRepresentation actual = policies().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
clickLink(row.findElements(tagName("a")).get(0));
String type = actual.getType();

View file

@ -77,7 +77,7 @@ public class RulePolicyForm extends Form {
setInputValue(artifactVersion, expected.getArtifactVersion());
resolveModuleButton.click();
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
moduleName.selectByVisibleText(expected.getModuleName());
WaitUtils.pause(1000);

View file

@ -16,17 +16,17 @@
*/
package org.keycloak.testsuite.console.page.clients.authorization.resource;
import static org.openqa.selenium.By.tagName;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.URLUtils;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import static org.keycloak.testsuite.util.UIUtils.clickLink;
import static org.openqa.selenium.By.tagName;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@ -54,8 +54,8 @@ public class Resources extends Form {
for (WebElement row : resources().rows()) {
ResourceRepresentation actual = resources().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
WaitUtils.waitForPageToLoad(driver);
clickLink(row.findElements(tagName("a")).get(0));
WaitUtils.waitForPageToLoad();
resource.form().populate(representation);
return;
}
@ -66,8 +66,8 @@ public class Resources extends Form {
for (WebElement row : resources().rows()) {
ResourceRepresentation actual = resources().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
WaitUtils.waitForPageToLoad(driver);
clickLink(row.findElements(tagName("a")).get(0));
WaitUtils.waitForPageToLoad();
resource.form().delete();
return;
}
@ -89,8 +89,8 @@ public class Resources extends Form {
for (WebElement row : resources().rows()) {
ResourceRepresentation actual = resources().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
WaitUtils.waitForPageToLoad(driver);
clickLink(row.findElements(tagName("a")).get(0));
WaitUtils.waitForPageToLoad();
return resource;
}
}

View file

@ -16,16 +16,16 @@
*/
package org.keycloak.testsuite.console.page.clients.authorization.scope;
import static org.openqa.selenium.By.tagName;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.URLUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import static org.keycloak.testsuite.util.UIUtils.clickLink;
import static org.openqa.selenium.By.tagName;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@ -53,7 +53,7 @@ public class Scopes extends Form {
for (WebElement row : scopes().rows()) {
ScopeRepresentation actual = scopes().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
clickLink(row.findElements(tagName("a")).get(0));
scope.form().populate(representation);
}
}
@ -63,7 +63,7 @@ public class Scopes extends Form {
for (WebElement row : scopes().rows()) {
ScopeRepresentation actual = scopes().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
URLUtils.navigateToUri(driver, row.findElements(tagName("a")).get(0).getAttribute("href"), true);
clickLink(row.findElements(tagName("a")).get(0));
scope.form().delete();
}
}

View file

@ -57,18 +57,18 @@ public class ClientCredentialsForm extends Form {
public void regenerateSecret() {
waitUntilElement(regenerateSecretButton).is().visible();
regenerateSecretButton.click();
waitForPageToLoad(driver);
waitForPageToLoad();
}
public void regenerateRegistrationAccessToken() {
waitUntilElement(regenerateRegistrationAccessTokenButton).is().visible();
regenerateRegistrationAccessTokenButton.click();
waitForPageToLoad(driver);
waitForPageToLoad();
}
public void generateNewKeysAndCert() {
waitUntilElement(generateNewKeysAndCert).is().visible();
generateNewKeysAndCert.click();
waitForPageToLoad(driver);
waitForPageToLoad();
}
}

View file

@ -41,7 +41,7 @@ public class ClientInstallationForm extends Form {
public void setConfigFormat(String value) {
configFormatsSelect.selectByVisibleText(value);
WaitUtils.waitForPageToLoad(driver);
WaitUtils.waitForPageToLoad();
}
public String getTextareaContent() {

View file

@ -116,7 +116,7 @@ public class CreateClientMappersForm extends Form {
}
WaitUtils.pause(1000);
selectRealmRoleButton.click();
WaitUtils.waitForModalFadeOut(driver);
WaitUtils.waitForModalFadeOut();
}
public void selectClientRole(String clientName, String roleName) {
@ -126,7 +126,7 @@ public class CreateClientMappersForm extends Form {
}
WaitUtils.pause(1000);
selectClientRoleButton.click();
WaitUtils.waitForModalFadeOut(driver);
WaitUtils.waitForModalFadeOut();
}
}

View file

@ -79,18 +79,18 @@ public class Users extends AdminConsoleRealm {
}
public void clickUser(String username) {
URLUtils.navigateToUri(driver, getRowByUsername(username).findElement(By.xpath("./td[position()=1]/a")).getAttribute("href"), true);
waitForPageToLoad(driver);
URLUtils.navigateToUri(getRowByUsername(username).findElement(By.xpath("./td[position()=1]/a")).getAttribute("href"), true);
waitForPageToLoad();
}
public void editUser(String username) {
clickRowActionButton(getRowByUsername(username), EDIT);
waitForPageToLoad(driver);
waitForPageToLoad();
}
public void impersonateUser(String username) {
clickRowActionButton(getRowByUsername(username), IMPERSONATE);
waitForPageToLoad(driver);
waitForPageToLoad();
}
public void deleteUser(String username) {

View file

@ -22,10 +22,8 @@ import org.junit.Before;
import org.junit.Test;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.auth.page.AuthRealm;
import org.keycloak.testsuite.auth.page.login.Registration;
import org.keycloak.testsuite.console.AbstractConsoleTest;
import org.keycloak.testsuite.console.page.AdminConsoleRealm;
import org.keycloak.testsuite.console.page.authentication.RequiredActions;
import org.keycloak.testsuite.console.page.realm.LoginSettings;
import org.openqa.selenium.By;

View file

@ -62,7 +62,7 @@ public class LoginEventsTest extends AbstractConsoleTest {
resultList.get(0).findElement(By.xpath("//td[text()='LOGIN']"));
resultList.get(0).findElement(By.xpath("//td[text()='User']/../td[text()='" + testUser.getId() + "']"));
resultList.get(0).findElement(By.xpath("//td[text()='Client']/../td[text()='security-admin-console']"));
resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1']"));
resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
loginEventsPage.table().reset();
loginEventsPage.table().filterForm().addEventType("LOGOUT");
@ -73,7 +73,7 @@ public class LoginEventsTest extends AbstractConsoleTest {
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath("//td[text()='LOGOUT']"));
resultList.get(0).findElement(By.xpath("//td[text()='User']/../td[text()='" + testUser.getId() + "']"));
resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1']"));
resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
loginEventsPage.table().reset();
loginEventsPage.table().filterForm().addEventType("LOGIN_ERROR");
@ -86,7 +86,7 @@ public class LoginEventsTest extends AbstractConsoleTest {
resultList.get(0).findElement(By.xpath("//td[text()='User']/../td[text()='" + testUser.getId() + "']"));
resultList.get(0).findElement(By.xpath("//td[text()='Client']/../td[text()='security-admin-console']"));
resultList.get(0).findElement(By.xpath("//td[text()='Error']/../td[text()='invalid_user_credentials']"));
resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1']"));
resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
}

View file

@ -42,6 +42,7 @@ import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWit
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
/**
*
@ -136,15 +137,16 @@ public class LoginSettingsTest extends AbstractRealmTest {
log.info("edit username");
testAccountPage.navigateTo();
testRealmLoginPage.form().login(testUser);
testAccountPage.waitForAccountLinkPresent();
assertCurrentUrlStartsWith(testAccountPage);
testAccountPage.setUsername(NEW_USERNAME);
testAccountPage.save();
testAccountPage.signOut();
log.debug("edited");
log.info("log in with edited username");
assertCurrentUrlStartsWithLoginUrlOf(testAccountPage);
testRealmLoginPage.form().login(NEW_USERNAME, PASSWORD);
testAccountPage.waitForAccountLinkPresent();
assertCurrentUrlStartsWith(testAccountPage);
log.debug("user is logged in with edited username");
log.info("disabling edit username");
@ -202,6 +204,7 @@ public class LoginSettingsTest extends AbstractRealmTest {
testAccountPage.navigateTo();
testRealmLoginPage.form().rememberMe(true);
testRealmLoginPage.form().login(testUser);
assertCurrentUrlStartsWith(testAccountPage);
assertTrue("Cookie KEYCLOAK_REMEMBER_ME should be present.", getCookieNames().contains("KEYCLOAK_REMEMBER_ME"));
@ -265,7 +268,7 @@ public class LoginSettingsTest extends AbstractRealmTest {
log.info("log in as new user");
testAccountPage.navigateTo();
testRealmLoginPage.form().login(newUser);
testAccountPage.waitForAccountLinkPresent();
assertCurrentUrlStartsWith(testAccountPage);
log.info("verified verify email is disabled");

View file

@ -50,11 +50,11 @@ public class NodejsExamplePage extends AbstractNodejsExamplePage {
public boolean isOnLoginSecuredPage() {
UriBuilder uriBuilder = createUriBuilder().path("login");
return URLUtils.currentUrlEqual(driver, uriBuilder.build().toASCIIString());
return URLUtils.currentUrlEqual(uriBuilder.build().toASCIIString());
}
@Override
public boolean isCurrent() {
return URLUtils.currentUrlStartWith(driver, toString());
return URLUtils.currentUrlStartWith(toString());
}
}

View file

@ -93,9 +93,12 @@
<examples.home>${project.build.directory}/examples</examples.home>
<browser>htmlUnit</browser>
<webdriverDownloadBinaries>true</webdriverDownloadBinaries>
<htmlUnitBrowserVersion>chrome</htmlUnitBrowserVersion>
<firefox_binary>/usr/bin/firefox</firefox_binary>
<phantomjs.cli.args>--ignore-ssl-errors=true --web-security=false</phantomjs.cli.args>
<firefox_binary>/usr/bin/firefox</firefox_binary>
<firefoxLegacyDriver>true</firefoxLegacyDriver>
<chromeArguments/>
<frontend.console.output>true</frontend.console.output>
<backends.console.output>true</backends.console.output>
@ -252,8 +255,13 @@
<browser>${browser}</browser>
<htmlUnitBrowserVersion>${htmlUnitBrowserVersion}</htmlUnitBrowserVersion>
<webdriverDownloadBinaries>${webdriverDownloadBinaries}</webdriverDownloadBinaries>
<firefox_binary>${firefox_binary}</firefox_binary>
<phantomjs.cli.args>${phantomjs.cli.args}</phantomjs.cli.args>
<chromeArguments>${chromeArguments}</chromeArguments>
<firefoxLegacyDriver>${firefoxLegacyDriver}</firefoxLegacyDriver>
<project.version>${project.version}</project.version>
<migration.project.version>${migration.project.version}</migration.project.version>
@ -313,6 +321,12 @@
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-container-osgi</artifactId>
<version>2.1.0.CR18</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
@ -986,9 +1000,18 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>jfree</groupId>
<artifactId>jfreechart</artifactId>
@ -1067,6 +1090,12 @@
<groupId>org.keycloak</groupId>
<artifactId>keycloak-dependencies-server-all</artifactId>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
@ -1184,6 +1213,18 @@
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- we need to specify the correct version because of conflict in arquillian-drone-webdriver-depchain -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>htmlunit-driver</artifactId>
<version>2.27</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>