keycloak-uncached

added UI tests for clients

11/25/2015 6:27:23 AM

Changes

Details

diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java
index 783cd0b..d1e37da 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java
@@ -1,8 +1,11 @@
 package org.keycloak.testsuite.console.page.clients;
 
+import java.util.List;
+import org.jboss.arquillian.graphene.fragment.Root;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.testsuite.console.page.fragment.Breadcrumb;
 import static org.keycloak.testsuite.console.page.fragment.Breadcrumb.BREADCRUMB_XPATH;
+import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
@@ -55,6 +58,9 @@ public class Client extends Clients {
 
     public class ClientTabs {
 
+        @Root
+        private WebElement tabs;
+        
         @FindBy(linkText = "Settings")
         private WebElement settingsLink;
         @FindBy(linkText = "Roles")
@@ -97,6 +103,10 @@ public class Client extends Clients {
         public void installation() {
             installationLink.click();
         }
+        
+        public WebElement getTabs() {
+            return tabs;
+        }
 
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java
index d0a0b0d..4abdb67 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java
@@ -1,6 +1,8 @@
 package org.keycloak.testsuite.console.page.clients;
 
 import org.keycloak.testsuite.console.page.roles.*;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
 
 /**
  *
@@ -9,6 +11,9 @@ import org.keycloak.testsuite.console.page.roles.*;
 public class ClientRole extends ClientRoles {
 
     public static final String ROLE_ID = "roleId";
+    
+    @FindBy(xpath = "//i[contains(@class, 'delete')]")
+    private WebElement deleteIcon;
 
     @Override
     public String getUriFragment() {
@@ -32,5 +37,11 @@ public class ClientRole extends ClientRoles {
     public void backToClientRolesViaBreadcrumb() {
         breadcrumb().clickItemOneLevelUp();
     }
+    
+    @Override
+    public void delete() {
+        deleteIcon.click();
+        modalDialog.confirmDeletion();
+    }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java
index 6f9cccd..415093b 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java
@@ -126,11 +126,6 @@ public class Clients extends AdminConsoleRealm {
         }
     }
 
-    public void deleteClient(String clientId) {
-        clientsTable.searchClients(clientId);
-        clientsTable.deleteClient(clientId);
-    }
-
     public ClientsResource clientsResource() {
         return realmResource().clients();
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java
index 87eadb5..40772ae 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java
@@ -2,13 +2,14 @@ package org.keycloak.testsuite.console.page.clients;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import org.jboss.arquillian.graphene.page.Page;
 import org.keycloak.representations.idm.ClientRepresentation;
 import static org.keycloak.testsuite.auth.page.login.OIDCLogin.OIDC;
 import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
 import org.keycloak.testsuite.page.Form;
 import static org.keycloak.testsuite.page.Form.getInputValue;
-import static org.keycloak.testsuite.util.WaitUtils.pause;
-import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import static org.keycloak.testsuite.util.WaitUtils.*;
 import org.keycloak.testsuite.util.Timer;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
@@ -37,10 +38,8 @@ public class CreateClientForm extends Form {
 
     @FindBy(id = "protocol")
     private Select protocolSelect;
-    @FindBy(id = "protocol")
-    private WebElement protocolSelectElement;
-
-    @FindBy
+    
+    @Page
     private SAMLClientSettingsForm samlForm;
 
     public SAMLClientSettingsForm samlForm() {
@@ -49,14 +48,13 @@ public class CreateClientForm extends Form {
 
     @FindBy(id = "accessType")
     private Select accessTypeSelect;
-    @FindBy(id = "accessType")
-    private WebElement accessTypeSelectElement;
-
     @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='serviceAccountsEnabled']]")
     private OnOffSwitch serviceAccountsEnabledSwitch;
 
     @FindBy(id = "newRedirectUri")
     private WebElement newRedirectUriInput;
+    @FindBy(xpath = ".//i[contains(@data-ng-click, 'newRedirectUri')]")
+    private WebElement newRedirectUriSubmit;
     @FindBy(xpath = ".//input[@ng-model='client.redirectUris[i]']")
     private List<WebElement> redirectUriInputs;
     @FindBy(xpath = ".//i[contains(@data-ng-click, 'deleteRedirectUri')]")
@@ -130,7 +128,7 @@ public class CreateClientForm extends Form {
     public static final String BEARER_ONLY = "bearer-only";
     public static final String PUBLIC = "public";
     public static final String CONFIDENTIAL = "confidential";
-
+        
     public boolean isBearerOnly() {
         return BEARER_ONLY.equals(
                 accessTypeSelect.getFirstSelectedOption().getAttribute(VALUE));
@@ -141,26 +139,19 @@ public class CreateClientForm extends Form {
                 accessTypeSelect.getFirstSelectedOption().getAttribute(VALUE));
     }
 
-    public void setBearerOnly(boolean bearerOnly) {
-        accessTypeSelectElement.sendKeys(BEARER_ONLY);
-//        accessTypeSelect.selectByVisibleText(BEARER_ONLY);
-    }
-
-    public void setPublicClient(boolean publicClient) {
-        accessTypeSelectElement.sendKeys(PUBLIC);
-//        accessTypeSelect.selectByVisibleText(PUBLIC);
-    }
-
-    public void setAccessType(ClientRepresentation client) { // TODO verify
-        setBearerOnly(client.isBearerOnly());
-        setPublicClient(client.isPublicClient());
-        if (!client.isBearerOnly() && !client.isPublicClient()) {
+    public void setAccessType(ClientRepresentation client) {
+        if (client.isBearerOnly()) {
+            accessTypeSelect.selectByVisibleText(BEARER_ONLY);
+        } else if (client.isPublicClient()) {
+            accessTypeSelect.selectByVisibleText(PUBLIC);
+        } else {
             accessTypeSelect.selectByVisibleText(CONFIDENTIAL);
         }
     }
 
     public void addRedirectUri(String redirectUri) {
         newRedirectUriInput.sendKeys(redirectUri);
+        newRedirectUriSubmit.click();
     }
 
     public List<String> getRedirectUris() {
@@ -210,7 +201,7 @@ public class CreateClientForm extends Form {
 
     public void setProtocol(String protocol) {
         Timer.time();
-        protocolSelectElement.sendKeys(protocol);
+        protocolSelect.selectByVisibleText(protocol);
         Timer.time("clientSettings.setProtocol()");
     }
 
@@ -224,7 +215,83 @@ public class CreateClientForm extends Form {
 
     public class SAMLClientSettingsForm extends Form {
 
-        // TODO add SAML client attributes
+        public static final String SAML_ASSERTION_SIGNATURE = "saml.assertion.signature";
+        public static final String SAML_AUTHNSTATEMENT = "saml.authnstatement";
+	public static final String SAML_CLIENT_SIGNATURE = "saml.client.signature";
+	public static final String SAML_ENCRYPT = "saml.encrypt";
+	public static final String SAML_FORCE_POST_BINDING = "saml.force.post.binding";
+	public static final String SAML_MULTIVALUED_ROLES = "saml.multivalued.roles";
+	public static final String SAML_SERVER_SIGNATURE = "saml.server.signature";
+	public static final String SAML_SIGNATURE_ALGORITHM = "saml.signature.algorithm";
+	public static final String SAML_ASSERTION_CONSUMER_URL_POST = "saml_assertion_consumer_url_post";
+	public static final String SAML_ASSERTION_CONSUMER_URL_REDIRECT = "saml_assertion_consumer_url_redirect";
+	public static final String SAML_FORCE_NAME_ID_FORMAT = "saml_force_name_id_format";
+	public static final String SAML_NAME_ID_FORMAT = "saml_name_id_format";
+	public static final String SAML_SIGNATURE_CANONICALIZATION_METHOD = "saml_signature_canonicalization_method";
+	public static final String SAML_SINGLE_LOGOUT_SERVICE_URL_POST = "saml_single_logout_service_url_post";
+	public static final String SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT = "saml_single_logout_service_url_redirect";
+        
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='samlAuthnStatement']]")
+        private OnOffSwitch samlAuthnStatement;
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='samlServerSignature']]")
+        private OnOffSwitch samlServerSignature;
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='samlAssertionSignature']]")
+        private OnOffSwitch samlAssertionSignature;
+        @FindBy(id = "signatureAlgorithm")
+        private Select signatureAlgorithm;
+        @FindBy(id = "canonicalization")
+        private Select canonicalization;
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='samlEncrypt']]")
+        private OnOffSwitch samlEncrypt;
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='samlClientSignature']]")
+        private OnOffSwitch samlClientSignature;
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='samlForcePostBinding']]")
+        private OnOffSwitch samlForcePostBinding;
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='frontchannelLogout']]")
+        private OnOffSwitch frontchannelLogout;
+        @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='samlForceNameIdFormat']]")
+        private OnOffSwitch samlForceNameIdFormat;
+        @FindBy(id = "samlNameIdFormat")
+        private Select samlNameIdFormat;
+        
+        @FindBy(xpath = "//fieldset[contains(@data-ng-show, 'saml')]//i")
+        private WebElement fineGrainCollapsor;
+        
+        @FindBy(id = "consumerServicePost")
+        private WebElement consumerServicePostInput;
+        @FindBy(id = "consumerServiceRedirect")
+        private WebElement consumerServiceRedirectInput;
+        @FindBy(id = "logoutPostBinding")
+        private WebElement logoutPostBindingInput;
+        @FindBy(id = "logoutRedirectBinding")
+        private WebElement logoutRedirectBindingInput;
+        
+        public void setValues(ClientRepresentation client) {
+            waitAjaxForElementVisible(fineGrainCollapsor);
+            
+            Map<String, String> attributes = client.getAttributes();
+            samlAuthnStatement.setOn("true".equals(attributes.get(SAML_AUTHNSTATEMENT)));
+            samlServerSignature.setOn("true".equals(attributes.get(SAML_SERVER_SIGNATURE)));
+            samlAssertionSignature.setOn("true".equals(attributes.get(SAML_ASSERTION_SIGNATURE)));
+            if (samlServerSignature.isOn() || samlAssertionSignature.isOn()) {
+                signatureAlgorithm.selectByVisibleText(attributes.get(SAML_SIGNATURE_ALGORITHM));
+                canonicalization.selectByValue("string:" + attributes.get(SAML_SIGNATURE_CANONICALIZATION_METHOD));
+            }
+            samlEncrypt.setOn("true".equals(attributes.get(SAML_ENCRYPT)));
+            samlClientSignature.setOn("true".equals(attributes.get(SAML_CLIENT_SIGNATURE)));
+            samlForcePostBinding.setOn("true".equals(attributes.get(SAML_FORCE_POST_BINDING)));
+            frontchannelLogout.setOn(client.isFrontchannelLogout());
+            samlForceNameIdFormat.setOn("true".equals(attributes.get(SAML_FORCE_NAME_ID_FORMAT)));
+            samlNameIdFormat.selectByVisibleText(attributes.get(SAML_NAME_ID_FORMAT));
+            
+            fineGrainCollapsor.click();
+            waitAjaxForElement(consumerServicePostInput);
+            
+            setInputValue(consumerServicePostInput, attributes.get(SAML_ASSERTION_CONSUMER_URL_POST));
+            setInputValue(consumerServiceRedirectInput, attributes.get(SAML_ASSERTION_CONSUMER_URL_REDIRECT));
+            setInputValue(logoutPostBindingInput, attributes.get(SAML_SINGLE_LOGOUT_SERVICE_URL_POST));
+            setInputValue(logoutRedirectBindingInput, attributes.get(SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT));
+        }
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java
index 8a3317a..eef5c6b 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java
@@ -14,11 +14,11 @@ public class CreateClientRole extends CreateRole {
         return super.getUriFragment() + "/clients/{" + ID + "}";
     }
 
-    public void setClientId(String id) {
+    public void setId(String id) {
         setUriParameter(ID, id);
     }
 
-    public String getClientId() {
+    public String getId() {
         return getUriParameter(ID).toString();
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java
new file mode 100644
index 0000000..991b175
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java
@@ -0,0 +1,66 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.console.page.clients.credentials;
+
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ *
+ * @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
+ */
+public class ClientCredentialsForm extends Form {
+
+    @FindBy(id = "clientAuthenticatorType")
+    private Select clientAuthenticatorType;
+    
+    @FindBy(xpath = "//button[text()='Regenerate Secret']")
+    private WebElement regenerateSecretButton;
+
+    @FindBy(xpath = "//button[text()='Generate new keys and certificate']")
+    private WebElement generateNewKeysAndCert;
+    
+    @FindBy(xpath = "//button[text()='Regenerate registration access token']")
+    private WebElement regenerateRegistrationAccessTokenButton;
+    
+    public void selectClientIdAndSecret() {
+        clientAuthenticatorType.selectByVisibleText("Client Id and Secret");
+    }
+    
+    public void selectSignedJwt() {
+        clientAuthenticatorType.selectByVisibleText("Signed Jwt");
+    }
+
+    public void regenerateSecret() {
+        regenerateSecretButton.click();
+    }
+
+    public void regenerateRegistrationAccessToken() {
+        regenerateRegistrationAccessTokenButton.click();
+    }
+
+    public void generateNewKeysAndCert() {
+        generateNewKeysAndCert.click();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsGeneratePrivateKeys.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsGeneratePrivateKeys.java
new file mode 100644
index 0000000..808ade6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsGeneratePrivateKeys.java
@@ -0,0 +1,44 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.console.page.clients.credentials;
+
+import org.jboss.arquillian.graphene.page.Page;
+
+/**
+ *
+ * @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
+ */
+public class ClientCredentialsGeneratePrivateKeys extends ClientCredentials {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/client-jwt/Signing/export/jwt.credential";
+    }
+    
+    @Page
+    private ClientCredentialsGeneratePrivateKeysForm form;
+
+    public ClientCredentialsGeneratePrivateKeysForm generateForm() {
+        return form;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsGeneratePrivateKeysForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsGeneratePrivateKeysForm.java
new file mode 100644
index 0000000..1994c0a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsGeneratePrivateKeysForm.java
@@ -0,0 +1,73 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.console.page.clients.credentials;
+
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ *
+ * @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
+ */
+public class ClientCredentialsGeneratePrivateKeysForm extends Form {
+
+    @FindBy(id = "downloadKeyFormat")
+    private Select downloadKeyFormat;
+    
+    @FindBy(id = "keyAlias")
+    private WebElement keyAliasInput;
+
+    @FindBy(id = "keyPassword")
+    private WebElement keyPasswordInput;
+    
+    @FindBy(id = "storePassword")
+    private WebElement storePasswordInput;
+    
+    @FindBy(xpath = "//button[text()='Generate and Download']")
+    private WebElement generateAndDownloadButton;
+    
+    public void selectFormatJKS() {
+        downloadKeyFormat.selectByVisibleText("JKS");
+    }
+
+    public void selectFormatPKCS12() {
+        downloadKeyFormat.selectByVisibleText("PKCS12");
+    }
+    
+    public void setKeyAlias(String value) {
+        setInputValue(keyAliasInput, value);
+    }
+    
+    public void setKeyPassword(String value) {
+        setInputValue(keyPasswordInput, value);
+    }
+    
+    public void setStorePassword(String value) {
+        setInputValue(storePasswordInput, value);
+    }
+    
+    public void clickGenerateAndDownload() {
+        generateAndDownloadButton.click();
+    }    
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/roles/ClientRole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/roles/ClientRole.java
new file mode 100644
index 0000000..472ef02
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/roles/ClientRole.java
@@ -0,0 +1,36 @@
+package org.keycloak.testsuite.console.page.clients.roles;
+
+import org.keycloak.testsuite.console.page.roles.*;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientRole extends ClientRoles {
+
+    public static final String ROLE_ID = "roleId";
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/{" + ROLE_ID + "}";
+    }
+
+    public void setRoleId(String id) {
+        setUriParameter(ROLE_ID, id);
+    }
+
+    public String getRoleId() {
+        return getUriParameter(ROLE_ID).toString();
+    }
+
+    private RoleForm form;
+
+    public RoleForm form() {
+        return form;
+    }
+
+    public void backToClientRolesViaBreadcrumb() {
+        breadcrumb().clickItemOneLevelUp();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/roles/ClientRoles.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/roles/ClientRoles.java
new file mode 100644
index 0000000..3542af2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/roles/ClientRoles.java
@@ -0,0 +1,30 @@
+package org.keycloak.testsuite.console.page.clients.roles;
+
+import org.keycloak.testsuite.console.page.clients.*;
+import org.keycloak.admin.client.resource.RolesResource;
+import org.keycloak.testsuite.console.page.roles.RolesTable;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientRoles extends Client {
+
+    @Override
+    public String getUriFragment() {
+        return super.getUriFragment() + "/roles";
+    }
+    
+    @FindBy(css = "table[class*='table']")
+    private RolesTable table;
+
+    public RolesTable roles() {
+        return table;
+    }
+    
+    public RolesResource rolesResource() {
+        return clientResource().roles();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/FlashMessage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/FlashMessage.java
index b117b5c..f78b660 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/FlashMessage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/FlashMessage.java
@@ -20,7 +20,8 @@ package org.keycloak.testsuite.console.page.fragment;
 import static org.jboss.arquillian.graphene.Graphene.waitGui;
 import org.jboss.arquillian.graphene.fragment.Root;
 
-import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementPresent;
+import static org.keycloak.testsuite.util.WaitUtils.*;
+import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
 
 /**
@@ -31,7 +32,15 @@ public class FlashMessage {
 
     @Root
     private WebElement root;
-
+    
+    public void close() {
+        WebElement close = root.findElement(By.tagName("button"));
+        if (close.isDisplayed()) {
+            close.click();
+        }
+        waitAjaxForElementNotVisible(close);
+    }
+    
     public boolean isSuccess() {
         waitGui().until("Flash message should be success")
                 .element(root)
@@ -61,6 +70,6 @@ public class FlashMessage {
     }
 
     public void waitUntilPresent() {
-        waitGuiForElementPresent(root, "Flash message should be visible.");
+        waitAjaxForElement(root);
     }
 }
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 00aaed3..1b31081 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
@@ -53,6 +53,11 @@ public final class WaitUtils {
                 .until().element(element).is().not().present();
     }
 
+    public static void waitAjaxForElementVisible(WebElement element) {
+        waitAjax().withTimeout(SCRIPT_TIMEOUT, TimeUnit.MILLISECONDS).pollingEvery(POLLING_INTERVAL, TimeUnit.MILLISECONDS)
+                .until().element(element).is().visible();
+    }
+
     public static void waitAjaxForElementNotVisible(WebElement element) {
         waitAjax().withTimeout(SCRIPT_TIMEOUT, TimeUnit.MILLISECONDS).pollingEvery(POLLING_INTERVAL, TimeUnit.MILLISECONDS)
                 .until().element(element).is().not().visible();
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 31c9b77..c67e151 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
@@ -104,16 +104,22 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest {
     public void assertFlashMessageSuccess() {
         flashMessage.waitUntilPresent();
         assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//        assertEquals(message, flashMessage.getText());
+        flashMessage.close();
     }
 
     public void assertFlashMessageDanger() {
         flashMessage.waitUntilPresent();
         assertTrue(flashMessage.getText(), flashMessage.isDanger());
+//        assertEquals(message, flashMessage.getText());
+        flashMessage.close();
     }
 
     public void assertFlashMessageError() {
         flashMessage.waitUntilPresent();
         assertTrue(flashMessage.getText(), flashMessage.isError());
+//        assertEquals(message, flashMessage.getText());
+        flashMessage.close();
     }
 
     public RealmResource testRealmResource() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java
index 4d0eed9..2a48dac 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java
@@ -17,7 +17,7 @@ import org.keycloak.testsuite.admin.ApiUtil;
 import org.keycloak.testsuite.auth.page.account.Account;
 import org.keycloak.testsuite.auth.page.account.Applications;
 import org.keycloak.testsuite.auth.page.login.OAuthGrant;
-import org.keycloak.testsuite.console.page.clients.ClientSettings;
+import org.keycloak.testsuite.console.page.clients.settings.ClientSettings;
 import org.keycloak.testsuite.console.page.clients.Clients;
 import org.keycloak.testsuite.console.page.events.Config;
 import org.keycloak.testsuite.console.page.events.LoginEvents;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
index ab63862..5b7888c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
@@ -12,7 +12,7 @@ import org.keycloak.testsuite.adapter.page.JSConsoleExample;
 import org.keycloak.testsuite.admin.ApiUtil;
 import org.keycloak.testsuite.auth.page.account.Applications;
 import org.keycloak.testsuite.auth.page.login.OAuthGrant;
-import org.keycloak.testsuite.console.page.clients.ClientSettings;
+import org.keycloak.testsuite.console.page.clients.settings.ClientSettings;
 import org.keycloak.testsuite.console.page.clients.Clients;
 import org.keycloak.testsuite.console.page.events.Config;
 import org.keycloak.testsuite.console.page.events.LoginEvents;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
index 6c40d64..7bb39c7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
@@ -6,11 +6,16 @@ import java.util.List;
 import org.jboss.arquillian.graphene.page.Page;
 import org.junit.Before;
 import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
 import static org.keycloak.testsuite.auth.page.login.OIDCLogin.OIDC;
+import static org.keycloak.testsuite.auth.page.login.OIDCLogin.SAML;
 import org.keycloak.testsuite.console.AbstractConsoleTest;
 import org.keycloak.testsuite.console.page.clients.Client;
 import org.keycloak.testsuite.console.page.clients.Clients;
 import org.keycloak.testsuite.console.page.clients.CreateClient;
+import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsBooleanAttributes;
+import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsListAttributes;
+import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsStringAttributes;
 import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
 
 /**
@@ -19,6 +24,9 @@ import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
  */
 public abstract class AbstractClientTest extends AbstractConsoleTest {
 
+    public final String TEST_CLIENT_ID = "test-client";
+    public final String TEST_REDIRECT_URIS = "http://example.test/app/*";
+    
     @Page
     protected Clients clientsPage;
     @Page
@@ -36,21 +44,12 @@ public abstract class AbstractClientTest extends AbstractConsoleTest {
         assertCurrentUrlEquals(clientsPage);
         clientsPage.table().createClient();
         createClientPage.form().setValues(client);
+        if (SAML.equals(client.getProtocol())) {
+            createClientPage.form().samlForm().setValues(client);
+        }
         createClientPage.form().save();
     }
 
-    public void deleteClientViaTable(String clientId) {
-        assertCurrentUrlEquals(clientsPage);
-        clientsPage.deleteClient(clientId);
-    }
-
-    public void deleteClientViaPage(String clientId) {
-        assertCurrentUrlEquals(clientsPage);
-        clientsPage.table().search(clientId);
-        clientsPage.table().clickClient(clientId);
-        clientPage.delete();
-    }
-
     public static ClientRepresentation createClientRepresentation(String clientId, String... redirectUris) {
         ClientRepresentation client = new ClientRepresentation();
         client.setClientId(clientId);
@@ -68,7 +67,47 @@ public abstract class AbstractClientTest extends AbstractConsoleTest {
         redirectUrisList.addAll(Arrays.asList(redirectUris));
         client.setRedirectUris(redirectUrisList);
         
+        //set expected web origins to newClient
+        List<String> webOrigins = new ArrayList<>();
+        for (String redirectUri : redirectUris) {
+            //parse webOrigin from redirectUri: take substring from index 0 to 
+            //first occurence of "/", excluded "http://" by starting search on index 7
+            webOrigins.add(redirectUri.substring(0, redirectUri.indexOf("/", 7)));
+        }
+        client.setWebOrigins(webOrigins);
         return client;
     }
+    
+    public ClientRepresentation findClientRepByClientId(String clientId) {
+        ClientRepresentation found = null;
+        for (ClientRepresentation clientRepresentation : testRealmResource().clients().findAll()) {
+            if (clientRepresentation.getClientId().equals(clientId)) {
+                found = clientRepresentation;
+                break;
+            }
+        }
+        return found;
+    }
+    
+    public void assertClientSettingsEqual(ClientRepresentation c1, ClientRepresentation c2) {
+        assertEqualsStringAttributes(c1.getClientId(), c2.getClientId());
+        assertEqualsStringAttributes(c1.getName(), c2.getName());
+        assertEqualsBooleanAttributes(c1.isEnabled(), c2.isEnabled());
+        assertEqualsBooleanAttributes(c1.isConsentRequired(), c2.isConsentRequired());
+        assertEqualsBooleanAttributes(c1.isDirectGrantsOnly(), c2.isDirectGrantsOnly());
+        assertEqualsStringAttributes(c1.getProtocol(), c2.getProtocol());
+
+        assertEqualsBooleanAttributes(c1.isBearerOnly(), c2.isBearerOnly());
+        assertEqualsBooleanAttributes(c1.isPublicClient(), c2.isPublicClient());
+        assertEqualsBooleanAttributes(c1.isSurrogateAuthRequired(), c2.isSurrogateAuthRequired());
+
+        assertEqualsBooleanAttributes(c1.isFrontchannelLogout(), c2.isFrontchannelLogout());
+
+        assertEqualsBooleanAttributes(c1.isServiceAccountsEnabled(), c2.isServiceAccountsEnabled());
+        assertEqualsListAttributes(c1.getRedirectUris(), c2.getRedirectUris());
+        assertEqualsStringAttributes(c1.getBaseUrl(), c2.getBaseUrl());
+        assertEqualsStringAttributes(c1.getAdminUrl(), c2.getAdminUrl());
+        assertEqualsListAttributes(c1.getWebOrigins(), c2.getWebOrigins());
+    }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientCredentialsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientCredentialsTest.java
new file mode 100644
index 0000000..a813f73
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientCredentialsTest.java
@@ -0,0 +1,84 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.console.clients;
+
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.ClientRepresentation;
+import static org.keycloak.testsuite.console.clients.AbstractClientTest.createClientRepresentation;
+import org.keycloak.testsuite.console.page.clients.credentials.ClientCredentials;
+import org.keycloak.testsuite.console.page.clients.credentials.ClientCredentialsGeneratePrivateKeys;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+
+/**
+ *
+ * @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
+ */
+public class ClientCredentialsTest extends AbstractClientTest {
+
+    private ClientRepresentation newClient;
+    
+    @Page
+    private ClientCredentials clientCredentials;
+    @Page
+    private ClientCredentialsGeneratePrivateKeys generatePrivateKeysPage;
+    
+    @Before
+    public void beforeClientsTest() {
+        newClient = createClientRepresentation(TEST_CLIENT_ID, TEST_REDIRECT_URIS);
+        testRealmResource().clients().create(newClient).close();
+        
+        ClientRepresentation found = findClientRepByClientId(TEST_CLIENT_ID);
+        assertNotNull("Client " + TEST_CLIENT_ID + " was not found.", found);
+        clientCredentials.setId(found.getId());
+        clientCredentials.navigateTo();
+    }
+    
+    @Test
+    public void regenerateSecret() {
+        clientCredentials.form().selectClientIdAndSecret();
+        clientCredentials.form().regenerateSecret();
+        assertFlashMessageSuccess();
+    }
+    
+    @Test
+    public void regenerateRegistrationAccessToken() {
+        clientCredentials.form().regenerateRegistrationAccessToken();
+        assertFlashMessageSuccess();
+    }
+    
+    @Test
+    public void generateNewKeysAndCert() {
+        generatePrivateKeysPage.setId(clientCredentials.getId());
+        clientCredentials.form().selectSignedJwt();
+        clientCredentials.form().generateNewKeysAndCert();
+        assertCurrentUrlEquals(generatePrivateKeysPage);
+        
+        generatePrivateKeysPage.generateForm().setKeyPassword("pass");
+        generatePrivateKeysPage.generateForm().setStorePassword("pass2");
+        generatePrivateKeysPage.generateForm().clickGenerateAndDownload();
+        
+        assertFlashMessageSuccess();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java
index a8a4c35..7463c70 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java
@@ -1,22 +1,28 @@
 package org.keycloak.testsuite.console.clients;
 
+import java.util.List;
 import org.jboss.arquillian.graphene.page.Page;
 import org.junit.Test;
 import org.keycloak.testsuite.console.page.users.UserRoleMappingsForm;
 
 import static org.junit.Assert.*;
+import org.junit.Before;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.testsuite.console.page.clients.ClientRole;
 import org.keycloak.testsuite.console.page.clients.ClientRoles;
 import org.keycloak.testsuite.console.page.clients.CreateClientRole;
 import org.keycloak.testsuite.console.page.users.User;
+import org.keycloak.testsuite.util.URLAssert;
 
 /**
  * Created by fkiss.
  */
 public class ClientRolesTest extends AbstractClientTest {
 
+    private String id;
+    private final String TEST_CLIENT_ROLE_NAME = "test-client-role";
+    
     @Page
     private ClientRoles clientRolesPage;
     @Page
@@ -30,38 +36,57 @@ public class ClientRolesTest extends AbstractClientTest {
     @Page
     private UserRoleMappingsForm userRolesPage;
 
-    public void addClientRole(RoleRepresentation roleRep) {
-//        assertCurrentUrl(clientRoles);
+    @Before
+    public void beforeClientRolesTest() {
+        ClientRepresentation newClient = createClientRepresentation(TEST_CLIENT_ID, TEST_REDIRECT_URIS);
+        testRealmResource().clients().create(newClient).close();
+        
+        id = findClientRepByClientId(TEST_CLIENT_ID).getId();
+        clientPage.setId(id);
+        clientRolePage.setId(id);
+        clientRolesPage.setId(id);
+        createClientRolePage.setId(id);
+        
+        clientPage.navigateTo();
+    }
+    
+    public void addNewClientRole(RoleRepresentation roleRep) {
         clientRolesPage.roles().addRole();
-//        assertCurrentUrl(createClientRole); // can't do this, need client id to build uri
         createClientRolePage.form().setBasicAttributes(roleRep);
         createClientRolePage.form().save();
         assertFlashMessageSuccess();
-        createClientRolePage.form().setCompositeRoles(roleRep);
+        System.out.println("TODO ClientRolesTest.addNewClientRole");
+//        createClientRolePage.form().setCompositeRoles(roleRep);
         // TODO add verification of notification message when KEYCLOAK-1497 gets resolved
     }
 
     @Test
-    public void testAddClientRole() {
-        ClientRepresentation newClient = createClientRepresentation("test-client1", "http://example.com/*");
-        RoleRepresentation newRole = new RoleRepresentation("client-role", "", false);
-
-        createClient(newClient);
-        assertFlashMessageSuccess();
-
+    public void testCRUDClientRole() {
+        RoleRepresentation newRole = new RoleRepresentation(TEST_CLIENT_ROLE_NAME, "description", false);
+                
         clientPage.tabs().roles();
-        addClientRole(newRole);
-        assertFlashMessageSuccess();
-
-        clientRolePage.backToClientRolesViaBreadcrumb();
-        assertFalse(clientRolesPage.roles().getRolesFromTableRows().isEmpty());
+        addNewClientRole(newRole);
 
-        configure().clients();
-        clientsPage.table().search(newClient.getClientId());
-        clientsPage.table().deleteClient(newClient.getClientId());
-        modalDialog.confirmDeletion();
+        List<RoleRepresentation> clientRoles = testRealmResource().clients().get(id).roles().list();
+        assertEquals("Client roles should contain exactly 1 role.", 1, clientRoles.size());
+        RoleRepresentation role = clientRoles.get(0);
+        assertEquals(TEST_CLIENT_ROLE_NAME, role.getName());
+        assertEquals("description", role.getDescription());
+        assertFalse(role.isScopeParamRequired());
+        assertFalse(role.isComposite());
+        assertNull(role.getComposites());
+        
+        //edit
+        clientRolesPage.navigateTo();
+        clientRolesPage.roles().editRole(TEST_CLIENT_ROLE_NAME);
+        
+        clientRolePage.setRoleId(role.getId());
+        URLAssert.assertCurrentUrlEquals(clientRolePage);
+        
+        //delete
+        clientRolePage.delete();
         assertFlashMessageSuccess();
-        assertNull(clientsPage.table().findClient(newClient.getClientId()));
+        assertTrue("Role should be deleted.", testRealmResource().clients().get(id).roles().list().isEmpty());
     }
 
 //    @Test
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java
index 5229527..54782a8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java
@@ -17,19 +17,20 @@
  */
 package org.keycloak.testsuite.console.clients;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import javax.ws.rs.core.Response;
 import org.jboss.arquillian.graphene.page.Page;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 import org.junit.Test;
 
 import org.keycloak.representations.idm.ClientRepresentation;
 import static org.keycloak.testsuite.admin.ApiUtil.getCreatedId;
-import org.keycloak.testsuite.console.page.clients.ClientSettings;
-import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsBooleanAttributes;
-import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsListAttributes;
-import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsStringAttributes;
-import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.auth.page.login.Login.SAML;
+import org.keycloak.testsuite.console.page.clients.settings.ClientSettings;
+import static org.keycloak.testsuite.console.page.clients.CreateClientForm.SAMLClientSettingsForm.*;
 import static org.keycloak.testsuite.util.WaitUtils.pause;
 import org.keycloak.testsuite.util.Timer;
 
@@ -45,54 +46,93 @@ public class ClientSettingsTest extends AbstractClientTest {
 
     private ClientRepresentation newClient;
 
+    @Test
     public void crudOIDCConfidential() {
-        newClient = createClientRepresentation("oidc-confidential", "http://example.test/app/*");
+        newClient = createClientRepresentation("oidc-confidential", TEST_REDIRECT_URIS);
         createClient(newClient);
         assertFlashMessageSuccess();
 
-        clientPage.backToClientsViaBreadcrumb();
-        assertCurrentUrlEquals(clientsPage);
-        assertEquals(1, clientsPage.table().searchClients(newClient.getClientId()).size());
-
         // read & verify
-        clientsPage.table().clickClient(newClient);
-        ClientRepresentation found = clientSettingsPage.form().getValues();
+        ClientRepresentation found = findClientRepByClientId(newClient.getClientId());
+        assertNotNull("Client " + newClient.getClientId() + " was not found.", found);
         assertClientSettingsEqual(newClient, found);
-
+        
         // update & verify
-        // TODO change attributes, add redirect uris and weborigins
+        newClient.setClientId("oidc-confidential-updated");
+        newClient.setName("updatedName");
+        
+        List<String> redirectUris = new ArrayList<>();
+        redirectUris.add("http://example2.test/app/*");
+        redirectUris.add("http://example2.test/app2/*");
+        redirectUris.add("http://example3.test/app/*");
+        newClient.setRedirectUris(redirectUris);
+        
+        List<String> webOrigins = new ArrayList<>();
+        webOrigins.clear();
+        webOrigins.add("http://example2.test");
+        webOrigins.add("http://example3.test");
+        newClient.setWebOrigins(webOrigins);
+        
+        clientSettingsPage.form().setClientId("oidc-confidential-updated");
+        clientSettingsPage.form().setName("updatedName");
+        clientSettingsPage.form().setRedirectUris(redirectUris);
+        clientSettingsPage.form().setWebOrigins(webOrigins);
+        clientSettingsPage.form().save();
+        assertFlashMessageSuccess();
+        
+        found = findClientRepByClientId(newClient.getClientId());
+        assertNotNull("Client " + newClient.getClientId() + " was not found.", found);
+        assertClientSettingsEqual(newClient, found);
+
         // delete
-        // TODO
-        clientPage.backToClientsViaBreadcrumb();
+        clientPage.delete();
+        assertFlashMessageSuccess();
+        found = findClientRepByClientId(newClient.getClientId());
+        assertNull("Deleted client " + newClient.getClientId() + " was found.", found);
     }
 
+    @Test
     public void createOIDCPublic() {
-        newClient = createClientRepresentation("oidc-public", "http://example.test/app/*");
+        newClient = createClientRepresentation("oidc-public", TEST_REDIRECT_URIS);
         newClient.setPublicClient(true);
         createClient(newClient);
         assertFlashMessageSuccess();
 
-        clientPage.backToClientsViaBreadcrumb();
-        assertCurrentUrlEquals(clientsPage);
-        assertEquals(1, clientsPage.table().searchClients(newClient.getClientId()).size());
+        ClientRepresentation found = findClientRepByClientId(newClient.getClientId());
+        assertNotNull("Client " + newClient.getClientId() + " was not found.", found);
+        assertClientSettingsEqual(newClient, found);
     }
 
+    @Test
     public void createOIDCBearerOnly() {
-        newClient = createClientRepresentation("oidc-bearer-only", "http://example.test/app/*");
+        newClient = createClientRepresentation("oidc-bearer-only", TEST_REDIRECT_URIS);
         newClient.setBearerOnly(true);
+        newClient.setRedirectUris(null);
+        newClient.setWebOrigins(null);
         createClient(newClient);
         assertFlashMessageSuccess();
 
-        clientPage.backToClientsViaBreadcrumb();
-        assertCurrentUrlEquals(clientsPage);
-        assertEquals(1, clientsPage.table().searchClients(newClient.getClientId()).size());
+        ClientRepresentation found = findClientRepByClientId(newClient.getClientId());
+        assertNotNull("Client " + newClient.getClientId() + " was not found.", found);
+        assertClientSettingsEqual(newClient, found);
     }
 
     @Test
-    public void successfulCRUD() {
-        crudOIDCConfidential();
-        createOIDCPublic();
-        createOIDCBearerOnly();
+    public void createSAML() {
+        newClient = createClientRepresentation("saml", "http://example.test/app/*");
+        newClient.setProtocol(SAML);
+        newClient.setFrontchannelLogout(true);
+        newClient.setRedirectUris(null);
+        newClient.setWebOrigins(null);
+        newClient.setAttributes(getSAMLAttributes());
+        
+        createClient(newClient);
+        assertFlashMessageSuccess();
+
+        ClientRepresentation found = findClientRepByClientId(newClient.getClientId());
+        assertNotNull("Client " + newClient.getClientId() + " was not found.", found);
+        assertClientSettingsEqual(newClient, found);
+        assertClientSamlAttributes(getSAMLAttributes(), found.getAttributes());
     }
 
     @Test
@@ -106,27 +146,6 @@ public class ClientSettingsTest extends AbstractClientTest {
         assertFlashMessageDanger();
     }
 
-    public void assertClientSettingsEqual(ClientRepresentation c1, ClientRepresentation c2) {
-        assertEqualsStringAttributes(c1.getClientId(), c2.getClientId());
-        assertEqualsStringAttributes(c1.getName(), c2.getName());
-        assertEqualsBooleanAttributes(c1.isEnabled(), c2.isEnabled());
-        assertEqualsBooleanAttributes(c1.isConsentRequired(), c2.isConsentRequired());
-        assertEqualsBooleanAttributes(c1.isDirectGrantsOnly(), c2.isDirectGrantsOnly());
-        assertEqualsStringAttributes(c1.getProtocol(), c2.getProtocol());
-
-        assertEqualsBooleanAttributes(c1.isBearerOnly(), c2.isBearerOnly());
-        assertEqualsBooleanAttributes(c1.isPublicClient(), c2.isPublicClient());
-        assertEqualsBooleanAttributes(c1.isSurrogateAuthRequired(), c2.isSurrogateAuthRequired());
-
-        assertEqualsBooleanAttributes(c1.isFrontchannelLogout(), c2.isFrontchannelLogout());
-
-        assertEqualsBooleanAttributes(c1.isServiceAccountsEnabled(), c2.isServiceAccountsEnabled());
-        assertEqualsListAttributes(c1.getRedirectUris(), c2.getRedirectUris());
-        assertEqualsStringAttributes(c1.getBaseUrl(), c2.getBaseUrl());
-        assertEqualsStringAttributes(c1.getAdminUrl(), c2.getAdminUrl());
-        assertEqualsListAttributes(c1.getWebOrigins(), c2.getWebOrigins());
-    }
-
 //    @Test
     public void createInconsistentClient() {
         ClientRepresentation c = createClientRepresentation("inconsistent_client");
@@ -159,5 +178,31 @@ public class ClientSettingsTest extends AbstractClientTest {
         clientsPage.navigateTo();
         pause(120000);
     }
+    
+    private Map<String, String> getSAMLAttributes() {
+        Map<String, String> attributes = new HashMap<>();
+        attributes.put(SAML_ASSERTION_SIGNATURE, "true");
+        attributes.put(SAML_AUTHNSTATEMENT, "false");
+	attributes.put(SAML_CLIENT_SIGNATURE,	"true");
+	attributes.put(SAML_ENCRYPT, "true");
+	attributes.put(SAML_FORCE_POST_BINDING, "true");
+	attributes.put(SAML_MULTIVALUED_ROLES, "false");
+	attributes.put(SAML_SERVER_SIGNATURE,	"true");
+	attributes.put(SAML_SIGNATURE_ALGORITHM, "RSA_SHA512");
+	attributes.put(SAML_ASSERTION_CONSUMER_URL_POST, "http://example0.test");
+	attributes.put(SAML_ASSERTION_CONSUMER_URL_REDIRECT, "http://example1.test");
+	attributes.put(SAML_FORCE_NAME_ID_FORMAT, "true");
+	attributes.put(SAML_NAME_ID_FORMAT, "email");
+	attributes.put(SAML_SIGNATURE_CANONICALIZATION_METHOD, "http://www.w3.org/2001/10/xml-exc-c14n#WithComments");
+	attributes.put(SAML_SINGLE_LOGOUT_SERVICE_URL_POST, "http://example2.test");
+	attributes.put(SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT, "http://example3.test");
+        return attributes;
+    }
+    
+    private void assertClientSamlAttributes(Map<String, String> expected, Map<String, String> actual) {
+        for (String key : expected.keySet()) {
+            assertEquals("Expected attribute " + key, expected.get(key), actual.get(key));
+        }
+    }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientsTest.java
new file mode 100644
index 0000000..c977dbe
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientsTest.java
@@ -0,0 +1,163 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.console.clients;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.testsuite.console.page.clients.settings.ClientSettings;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+/**
+ *
+ * @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
+ */
+public class ClientsTest extends AbstractClientTest {
+
+    private ClientRepresentation newClient;
+    
+    @Page
+    private ClientSettings clientSettingsPage;
+    
+    @Before
+    public void beforeClientsTest() {
+        newClient = createClientRepresentation(TEST_CLIENT_ID, TEST_REDIRECT_URIS);
+        testRealmResource().clients().create(newClient).close();
+        
+        ClientRepresentation found = findClientRepByClientId(TEST_CLIENT_ID);
+        assertNotNull("Client " + TEST_CLIENT_ID + " was not found.", found);
+        clientSettingsPage.setId(found.getId());
+    }
+    
+    @Test
+    public void clientsCRUD() {
+        //create
+        clientsPage.table().createClient();
+        assertCurrentUrlEquals(createClientPage);
+        
+        //edit
+        clientsPage.navigateTo();
+        clientsPage.table().editClient(TEST_CLIENT_ID);
+        assertEquals(TEST_CLIENT_ID, clientSettingsPage.form().getClientId());
+        
+        //delete
+        clientsPage.navigateTo();
+        clientsPage.table().deleteClient(TEST_CLIENT_ID);
+        modalDialog.confirmDeletion();
+        assertFlashMessageSuccess();
+        
+        ClientRepresentation found = findClientRepByClientId(TEST_CLIENT_ID);
+        assertNull("Deleted client " + TEST_CLIENT_ID + " was found.", found);
+    }
+    
+    @Test
+    public void tabs() {
+        clientSettingsPage.navigateTo();
+        
+        //oidc-confidential
+        WebElement tabs = clientPage.tabs().getTabs();
+        List<String> visibleTabs = new ArrayList<>();
+        visibleTabs.add("Settings");
+        visibleTabs.add("Credentials");
+        visibleTabs.add("Roles");
+        visibleTabs.add("Mappers");
+        visibleTabs.add("Scope");
+        visibleTabs.add("Revocation");
+        visibleTabs.add("Sessions");
+        visibleTabs.add("Offline Access");
+        visibleTabs.add("Clustering");
+        visibleTabs.add("Installation");
+        
+        List<String> invisibleTabs = new ArrayList<>();
+        invisibleTabs.add("SAML Keys");
+        invisibleTabs.add("Service Account Roles");
+        
+        assertVisibilityOfTabs(tabs, visibleTabs, invisibleTabs);
+        
+        //oidc-public
+        newClient.setPublicClient(true);
+        clientSettingsPage.form().setAccessType(newClient);
+        clientSettingsPage.form().save();
+        assertFlashMessageSuccess();
+        
+        tabs = clientPage.tabs().getTabs();
+        visibleTabs.clear();
+        invisibleTabs.clear();
+        
+        visibleTabs.add("Settings");
+        visibleTabs.add("Roles");
+        visibleTabs.add("Mappers");
+        visibleTabs.add("Scope");
+        visibleTabs.add("Revocation");
+        visibleTabs.add("Sessions");
+        visibleTabs.add("Offline Access");
+        visibleTabs.add("Installation");
+        
+        invisibleTabs.add("Credentials");
+        invisibleTabs.add("SAML Keys");
+        invisibleTabs.add("Clustering");
+        invisibleTabs.add("Service Account Roles");
+        
+        assertVisibilityOfTabs(tabs, visibleTabs, invisibleTabs);
+        
+        //oidc-bearer-only
+        newClient.setPublicClient(false);
+        newClient.setBearerOnly(true);
+        clientSettingsPage.form().setAccessType(newClient);
+        clientSettingsPage.form().save();
+        assertFlashMessageSuccess();
+        
+        tabs = clientPage.tabs().getTabs();
+        visibleTabs.clear();
+        invisibleTabs.clear();
+        
+        visibleTabs.add("Settings");
+        visibleTabs.add("Credentials");
+        visibleTabs.add("Roles");
+        visibleTabs.add("Revocation");
+        visibleTabs.add("Clustering");
+        visibleTabs.add("Installation");
+        
+        invisibleTabs.add("SAML Keys");
+        invisibleTabs.add("Mappers");
+        invisibleTabs.add("Scope");
+        invisibleTabs.add("Sessions");
+        invisibleTabs.add("Service Account Roles");
+        
+        assertVisibilityOfTabs(tabs, visibleTabs, invisibleTabs);
+    }
+    
+    private void assertVisibilityOfTabs(WebElement tabs, List<String> visible, List<String> invisible) {
+        for (String visibleLink : visible) {
+            assertTrue(tabs.findElement(By.linkText(visibleLink)).isDisplayed());
+        }
+        for (String invisibleLink : invisible) {
+            assertTrue(tabs.findElements(By.linkText(invisibleLink)).isEmpty());
+        }
+    }
+}