diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementPatternFlyAlert.java similarity index 85% rename from testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java rename to testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementPatternFlyAlert.java index f7b0911039..f9fdcbdc13 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementPatternFlyAlert.java @@ -16,13 +16,13 @@ */ package org.keycloak.testsuite.auth.page.account.fragment; -import org.keycloak.testsuite.page.AbstractAlert; +import org.keycloak.testsuite.page.AbstractPatternFlyAlert; /** * * @author tkyjovsk */ -public class AccountManagementAlert extends AbstractAlert { +public class AccountManagementPatternFlyAlert extends AbstractPatternFlyAlert { public boolean isError() { return checkAlertType("error"); diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/AbstractAccountPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/AbstractAccountPage.java new file mode 100644 index 0000000000..9b0a3869c8 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/AbstractAccountPage.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 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.auth.page.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.auth.page.AuthRealm; +import org.keycloak.testsuite.page.PatternFlyClosableAlert; + +import javax.ws.rs.core.UriBuilder; +import java.util.List; + +/** + * @author Vaclav Muzikar + */ +public abstract class AbstractAccountPage extends AuthRealm { + @Page + private PatternFlyClosableAlert alert; + + public AbstractAccountPage() { + setAuthRealm(TEST); + } + + /** + * Account Console is based on hash routing, e.g. [server_root]/auth/realms/test/account/#/password. + * All page objects for Account Console need to specify their "hash path" using this method. + * + * @return the hash path + */ + protected abstract List createHashPath(); + + @Override + public UriBuilder createUriBuilder() { + String fragment = null; + final List hashPath = createHashPath(); + if (hashPath != null) { + fragment = "/" + String.join("/", hashPath); + } + + return super.createUriBuilder().path("account/").fragment(fragment); + } + + public PatternFlyClosableAlert alert() { + return alert; + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/AbstractLoggedInPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/AbstractLoggedInPage.java new file mode 100644 index 0000000000..1b65ce4654 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/AbstractLoggedInPage.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 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.auth.page.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.auth.page.account2.fragment.VerticalNavBar; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Vaclav Muzikar + */ +public abstract class AbstractLoggedInPage extends AbstractAccountPage { + @Page + protected WelcomeScreen welcomeScreen; + + @FindBy(className = "nav-pf-vertical nav-pf-vertical-with-badges") + private VerticalNavBar verticalNavBar; + + @FindBy(id = "pageTitle") + protected WebElement pageTitle; + + @Override + protected List createHashPath() { + return new ArrayList<>(); + } + + /** + * This should simulate a user navigating to this page using links in the nav bar. It assume that user is logged in + * and at some Account Console page (not Welcome Screen), i.e. that the nav bar is visible. + */ + public abstract void navigateToUsingNavBar(); + + public VerticalNavBar verticalNavBar() { + return verticalNavBar; + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/ApplicationsPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/ApplicationsPage.java new file mode 100644 index 0000000000..662a514eee --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/ApplicationsPage.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 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.auth.page.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.auth.page.account2.fragment.Card; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +import java.util.List; + +import static org.keycloak.testsuite.util.UIUtils.isElementVisible; + +/** + * @author Vaclav Muzikar + */ +public class ApplicationsPage extends AbstractLoggedInPage { + @Page + private ApplicationsCard applicationsCard; + + @Override + protected List createHashPath() { + List hashPath = super.createHashPath(); + hashPath.add("applications"); + return hashPath; + } + + @Override + public void navigateToUsingNavBar() { + // TODO + } + + @Override + public boolean isCurrent() { + return super.isCurrent() && applicationsCard.isVisible(); + } + + public ApplicationsCard applications() { + return applicationsCard; + } + + public class ApplicationsCard extends Card { + @FindBy(className = "card-pf-application") + private WebElement cardRoot; + + @Override + public boolean isVisible() { + return isElementVisible(cardRoot); + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/AuthenticatorPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/AuthenticatorPage.java new file mode 100644 index 0000000000..638d161dfd --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/AuthenticatorPage.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 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.auth.page.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.auth.page.account2.fragment.Card; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +import java.util.List; + +import static org.keycloak.testsuite.util.UIUtils.isElementVisible; + +/** + * @author Vaclav Muzikar + */ +public class AuthenticatorPage extends AbstractLoggedInPage { + @Page + private YourAuthenticatorsCard yourAuthenticatorsCard; + @Page + private AddAuthenticatorCard addAuthenticatorCard; + + @Override + protected List createHashPath() { + List hashPath = super.createHashPath(); + hashPath.add("authenticator"); + return hashPath; + } + + @Override + public void navigateToUsingNavBar() { + // TODO + } + + @Override + public boolean isCurrent() { + return super.isCurrent() && yourAuthenticators().isVisible() && addAuthenticator().isVisible(); + } + + public YourAuthenticatorsCard yourAuthenticators() { + return yourAuthenticatorsCard; + } + + public AddAuthenticatorCard addAuthenticator() { + return addAuthenticatorCard; + } + + public class YourAuthenticatorsCard extends Card { + @FindBy(id = "authenticatorFinishSetUpTitle") + private WebElement yourAuthenticatorsTitle; + + @Override + public boolean isVisible() { + return isElementVisible(yourAuthenticatorsTitle); + } + } + + public class AddAuthenticatorCard extends Card { + @FindBy(id = "authenticatorSubTitle") + private WebElement addAuthenticatorTitle; + + @Override + public boolean isVisible() { + return isElementVisible(addAuthenticatorTitle); + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/ChangePasswordPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/ChangePasswordPage.java new file mode 100644 index 0000000000..ab10ace266 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/ChangePasswordPage.java @@ -0,0 +1,131 @@ +/* + * Copyright 2018 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.auth.page.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.auth.page.account2.fragment.Card; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import static org.keycloak.testsuite.util.UIUtils.clickBtnAndWaitForAlert; +import static org.keycloak.testsuite.util.UIUtils.getTextFromElement; +import static org.keycloak.testsuite.util.UIUtils.isElementVisible; +import static org.keycloak.testsuite.util.UIUtils.setTextInputValue; + +/** + * @author Vaclav Muzikar + */ +public class ChangePasswordPage extends AbstractLoggedInPage { + @Page + private UpdatePasswordCard updatePasswordCard; + @Page + private PasswordLastUpdateCard passwordLastUpdateCard; + + @Override + protected List createHashPath() { + List hashPath = super.createHashPath(); + hashPath.add("password"); + return hashPath; + } + + @Override + public void navigateToUsingNavBar() { + // TODO + } + + @Override + public boolean isCurrent() { + return super.isCurrent() && updatePassword().isVisible(); + } + + public PasswordLastUpdateCard passwordLastUpdate() { + return passwordLastUpdateCard; + } + + public UpdatePasswordCard updatePassword() { + return updatePasswordCard; + } + + public class PasswordLastUpdateCard extends Card { + @FindBy(id = "passwordLastUpdate") + private WebElement cardRoot; + + @Override + public boolean isVisible() { + return isElementVisible(cardRoot); + } + + public String getTextDateTime() { + return getTextFromElement(cardRoot.findElement(By.tagName("strong"))); + } + + public LocalDateTime getDateTime() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM d, yyyy, h:m:s a"); // e.g. Aug 31, 2018, 5:41:24 PM + return LocalDateTime.from(formatter.parse(getTextDateTime())); + } + } + + public class UpdatePasswordCard extends Card { + @FindBy(id = "updatePasswordSubTitle") + private WebElement updatePasswordSubTitle; + @FindBy(id = "password") + private WebElement currentPassword; + @FindBy(id = "newPassword") + private WebElement newPassword; + @FindBy(id = "confirmation") + private WebElement confirmPassword; + @FindBy(name = "submitAction") + private WebElement submitBtn; + + @Override + public boolean isVisible() { + return isElementVisible(updatePasswordSubTitle); + } + + public void setCurrentPassword(String value) { + setTextInputValue(currentPassword, value); + } + + public void setNewPassword(String value) { + setTextInputValue(newPassword, value); + } + + public void setConfirmPassword(String value) { + setTextInputValue(confirmPassword, value); + } + + public boolean isSaveDisabled() { + return submitBtn.getAttribute("disabled") != null; + } + + public void clickSave() { + clickBtnAndWaitForAlert(submitBtn); + } + + public void setPasswords(String currentPassword, String newPassword) { + setCurrentPassword(currentPassword); + setNewPassword(newPassword); + setConfirmPassword(newPassword); + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/DeviceActivityPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/DeviceActivityPage.java new file mode 100644 index 0000000000..e5f5904c1a --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/DeviceActivityPage.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 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.auth.page.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.auth.page.account2.fragment.Card; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +import java.util.List; + +import static org.keycloak.testsuite.util.UIUtils.isElementVisible; + +/** + * @author Vaclav Muzikar + */ +public class DeviceActivityPage extends AbstractLoggedInPage { + @Page + private SignedInDevicesCard signedInDevicesCard; + @Page + private RecentlyUsedDevicesCard recentlyUsedDevicesCard; + + @Override + protected List createHashPath() { + List hashPath = super.createHashPath(); + hashPath.add("device-activity"); + return hashPath; + } + + @Override + public void navigateToUsingNavBar() { + // TODO + } + + @Override + public boolean isCurrent() { + return super.isCurrent() && signedInDevices().isVisible() && recentlyUsedDevices().isVisible(); + } + + public SignedInDevicesCard signedInDevices() { + return signedInDevicesCard; + } + + public RecentlyUsedDevicesCard recentlyUsedDevices() { + return recentlyUsedDevicesCard; + } + + public class SignedInDevicesCard extends Card { + @FindBy(id = "signedInDevicesTitle") + private WebElement signedInDevicesTitle; + + @Override + public boolean isVisible() { + return isElementVisible(signedInDevicesTitle); + } + } + + public class RecentlyUsedDevicesCard extends Card { + @FindBy(id = "recentlyUsedDevicesTitle") + private WebElement recentlyUsedDevicesTitle; + + @Override + public boolean isVisible() { + return isElementVisible(recentlyUsedDevicesTitle); + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/LinkedAccountsPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/LinkedAccountsPage.java new file mode 100644 index 0000000000..e00bfdc834 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/LinkedAccountsPage.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 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.auth.page.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.auth.page.account2.fragment.Card; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +import java.util.List; + +import static org.keycloak.testsuite.util.UIUtils.isElementVisible; + +/** + * @author Vaclav Muzikar + */ +public class LinkedAccountsPage extends AbstractLoggedInPage { + @Page + private AuthorizedProvidersCard authorizedProvidersCard; + @Page + private AvailableProvidersCard availableProvidersCard; + + @Override + protected List createHashPath() { + List hashPath = super.createHashPath(); + hashPath.add("linked-accounts"); + return hashPath; + } + + @Override + public void navigateToUsingNavBar() { + // TODO + } + + @Override + public boolean isCurrent() { + return super.isCurrent() && authorizedProviders().isVisible() && availableProviders().isVisible(); + } + + public AuthorizedProvidersCard authorizedProviders() { + return authorizedProvidersCard; + } + + public AvailableProvidersCard availableProviders() { + return availableProvidersCard; + } + + public class AuthorizedProvidersCard extends Card { + @FindBy(id = "authorizedProvidersSubTitle") + private WebElement authorizedProvidersTitle; + + @Override + public boolean isVisible() { + return isElementVisible(authorizedProvidersTitle); + } + } + + public class AvailableProvidersCard extends Card { + @FindBy(id = "identityProviderSubTitle") + private WebElement availableProvidersTitle; + + @Override + public boolean isVisible() { + return isElementVisible(availableProvidersTitle); + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/PersonalInfoPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/PersonalInfoPage.java new file mode 100644 index 0000000000..7f3dfc0542 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/PersonalInfoPage.java @@ -0,0 +1,138 @@ +/* + * Copyright 2018 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.auth.page.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.representations.idm.UserRepresentation; +import org.keycloak.testsuite.auth.page.account2.fragment.Card; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +import java.util.List; + +import static org.keycloak.testsuite.util.UIUtils.clickBtnAndWaitForAlert; +import static org.keycloak.testsuite.util.UIUtils.getTextInputValue; +import static org.keycloak.testsuite.util.UIUtils.isElementVisible; +import static org.keycloak.testsuite.util.UIUtils.setTextInputValue; + +/** + * @author Vaclav Muzikar + */ +public class PersonalInfoPage extends AbstractLoggedInPage { + @Page + private PersonalInfoCard personalInfoCard; + + @Override + protected List createHashPath() { + List hashPath = super.createHashPath(); + hashPath.add("account"); + return hashPath; + } + + @Override + public void navigateToUsingNavBar() { + // TODO + } + + @Override + public boolean isCurrent() { + return super.isCurrent() && personalInfo().isVisible(); + } + + public PersonalInfoCard personalInfo() { + return personalInfoCard; + } + + public class PersonalInfoCard extends Card { + @FindBy(id = "personalSubTitle") + private WebElement personalSubTitle; + @FindBy(id = "username") + private WebElement username; + @FindBy(id = "email") + private WebElement email; + @FindBy(id = "firstName") + private WebElement firstName; + @FindBy(id = "lastName") + private WebElement lastName; + @FindBy(name = "submitAction") + private WebElement submitBtn; + + @Override + public boolean isVisible() { + return isElementVisible(personalSubTitle); + } + + public boolean isUsernameDisabled() { + return !username.getTagName().equals("input"); //
for disabled + } + + public String getUsername() { + return getTextInputValue(username); + } + + public void setUsername(String value) { + setTextInputValue(username, value); + } + + public String getEmail() { + return getTextInputValue(email); + } + + public void setEmail(String value) { + setTextInputValue(email, value); + } + + public String getFirstName() { + return getTextInputValue(firstName); + } + + public void setFirstName(String value) { + setTextInputValue(firstName, value); + } + + public String getLastName() { + return getTextInputValue(lastName); + } + + public void setLastName(String value) { + setTextInputValue(lastName, value); + } + + public boolean isSaveDisabled() { + return submitBtn.getAttribute("disabled") != null; + } + + public void clickSave() { + clickBtnAndWaitForAlert(submitBtn); + } + + public void setValues(UserRepresentation user) { + if (!isUsernameDisabled()) {setUsername(user.getUsername());} + setEmail(user.getEmail()); + setFirstName(user.getFirstName()); + setLastName(user.getLastName()); + } + + public boolean valuesEqual(UserRepresentation user) { + return user.getUsername().equals(getUsername()) + && user.getEmail().equals(getEmail()) + && user.getFirstName().equals(getFirstName()) + && user.getLastName().equals(getLastName()); + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/ResourcesPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/ResourcesPage.java new file mode 100644 index 0000000000..4004dc830f --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/ResourcesPage.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 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.auth.page.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.auth.page.account2.fragment.Card; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +import java.util.List; + +import static org.keycloak.testsuite.util.UIUtils.isElementVisible; + +/** + * @author Vaclav Muzikar + */ +public class ResourcesPage extends AbstractLoggedInPage { + @Page + private ResourcesListCard resourcesListCard; + + @Override + protected List createHashPath() { + List hashPath = super.createHashPath(); + hashPath.add("my-resources"); + return hashPath; + } + + @Override + public void navigateToUsingNavBar() { + // TODO + } + + @Override + public boolean isCurrent() { + return super.isCurrent() && resourcesListCard.isVisible(); + } + + public ResourcesListCard resourcesList() { + return resourcesListCard; + } + + public class ResourcesListCard extends Card { + @FindBy(className = "resources-list") + private WebElement cardRoot; + + @Override + public boolean isVisible() { + return isElementVisible(cardRoot); + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/WelcomeScreen.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/WelcomeScreen.java new file mode 100644 index 0000000000..74e01e9735 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/WelcomeScreen.java @@ -0,0 +1,167 @@ +/* + * Copyright 2018 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.auth.page.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.auth.page.account2.fragment.Card; +import org.keycloak.testsuite.util.URLUtils; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +import java.util.List; + +import static org.keycloak.testsuite.util.UIUtils.clickLink; +import static org.keycloak.testsuite.util.UIUtils.isElementVisible; + +/** + * @author Vaclav Muzikar + */ +public class WelcomeScreen extends AbstractAccountPage { + @Page + private PersonalInfoCard personalInfo; + @Page + private AccountSecurityCard accountSecurityCard; + @Page + private ApplicationsCard applicationsCard; + @Page + private MyResourcesCard myResourcesCard; + @FindBy(id = "welcomeMsg") + private WebElement welcomeMsg; + @FindBy(id = "signInButton") + private WebElement signInBtn; + + @Override + protected List createHashPath() { + return null; + } + + @Override + public boolean isCurrent() { + return URLUtils.currentUrlEquals(toString() + "#/") && isElementVisible(welcomeMsg); // the hash will be eventually added after the page is loaded + } + + public PersonalInfoCard personalInfo() { + return personalInfo; + } + + public AccountSecurityCard accountSecurityCard() { + return accountSecurityCard; + } + + public ApplicationsCard applicationsCard() { + return applicationsCard; + } + + public MyResourcesCard myResourcesCard() { + return myResourcesCard; + } + + public void clickLoginBtn() { + clickLink(signInBtn); + } + + public boolean isLoginBtnVisible() { + return isElementVisible(signInBtn); + } + + public class PersonalInfoCard extends Card { + @FindBy(id = "personalInfoCard") + private WebElement personalInfoCard; + @FindBy(id = "personalInfoLink") + private WebElement personalInfoLink; + + @Override + public boolean isVisible() { + return isElementVisible(personalInfoCard); + } + + public void clickPersonalInfo() { + clickLink(personalInfoLink); + } + } + + public class AccountSecurityCard extends Card { + @FindBy(id = "accountSecurityCard") + private WebElement accountSecurityCard; + @FindBy(id = "changePasswordLink") + private WebElement changePasswordLink; + @FindBy(id = "authenticatorLink") + private WebElement authenticatorLink; + @FindBy(id = "deviceActivityLink") + private WebElement deviceActivityLink; + @FindBy(id = "linkedAccountsLink") + private WebElement linkedAccountsLink; + + @Override + public boolean isVisible() { + return isElementVisible(accountSecurityCard); + } + + public void clickChangePassword() { + clickLink(changePasswordLink); + } + + public void clickAuthenticator() { + clickLink(authenticatorLink); + } + + public void clickDeviceActivity() { + clickLink(deviceActivityLink); + } + + public void clickLinkedAccounts() { + clickLink(linkedAccountsLink); + } + + public boolean isLinkedAccountsVisible() { + return isElementVisible(linkedAccountsLink); + } + } + + public class ApplicationsCard extends Card { + @FindBy(id = "applicationsCard") + private WebElement applicationsCard; + @FindBy(id = "applicationsLink") + private WebElement applicationsLink; + + @Override + public boolean isVisible() { + return isElementVisible(applicationsCard); + } + + public void clickApplicationsLink() { + clickLink(applicationsLink); + } + } + + public class MyResourcesCard extends Card { + @FindBy(id = "myResourcesCard") + private WebElement myResourcesCard; + @FindBy(id = "myResourcesLink") + private WebElement myResourcesLink; + + @Override + public boolean isVisible() { + return isElementVisible(myResourcesCard); + } + + public void clickMyResources() { + clickLink(myResourcesLink); + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/fragment/Card.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/fragment/Card.java new file mode 100644 index 0000000000..b8540ed69c --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/fragment/Card.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 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.auth.page.account2.fragment; + +import org.jboss.arquillian.drone.api.annotation.Drone; +import org.openqa.selenium.WebDriver; + +/** + * @author Vaclav Muzikar + */ +public abstract class Card { + @Drone + private WebDriver driver; + + public abstract boolean isVisible(); +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/fragment/VerticalNavBar.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/fragment/VerticalNavBar.java new file mode 100644 index 0000000000..ddcf46fdb1 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account2/fragment/VerticalNavBar.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 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.auth.page.account2.fragment; + +import org.jboss.arquillian.graphene.fragment.Root; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import static org.keycloak.testsuite.util.UIUtils.clickLink; + +/** + * @author Vaclav Muzikar + */ +// TODO rewrite this (blocked by KEYCLOAK-8217) +public class VerticalNavBar { + @Root + private WebElement navBarRoot; + + public void clickNavLinkByIndex(int i) { + clickLink(getNavLinkByIndex(i)); + } + + public void clickSubNavLinkByIndex(int i1, int i2) { + clickLink(getNavLinkByIndex(i1)); + clickLink(getSubNavLinkByIndex(i1, i2)); + } + + public boolean isNavLinkActive(int i) { + return isNavLinkActive(getNavLinkByIndex(i)); + } + + public boolean isSubNavLinkActive(int i1, int i2) { + return isNavLinkActive(getSubNavLinkByIndex(i1, i2)); + } + + private WebElement getNavLinkByIndex(int i) { + return navBarRoot.findElement(By.xpath(String.format("./ul/li[%d]", i))); + } + + private WebElement getSubNavLinkByIndex(int i1, int i2) { + return navBarRoot.findElement(By.xpath(String.format("./ul/li[%d]/div[contains(@class,'nav-pf-secondary-nav')]/ul/li[%d]", i1, i2))); + } + + private boolean isNavLinkActive(WebElement navLink) { + return navLink.getAttribute("class").contains("active"); + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java deleted file mode 100644 index 4778da62da..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java +++ /dev/null @@ -1,64 +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.page; - -import org.jboss.arquillian.drone.api.annotation.Drone; -import org.jboss.arquillian.graphene.fragment.Root; -import org.jboss.logging.Logger; -import org.keycloak.testsuite.util.WaitUtils; -import org.openqa.selenium.TimeoutException; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.ExpectedConditions; -import org.openqa.selenium.support.ui.WebDriverWait; - -/** - * - * @author tkyjovsk - */ -public abstract class AbstractAlert { - - protected final Logger log = Logger.getLogger(this.getClass()); - - @Root - protected WebElement root; - - @Drone - protected WebDriver driver; - - public String getText() { - return root.getText(); - } - - public boolean isSuccess() { - log.debug("Alert.isSuccess()"); - return checkAlertType("success"); - } - - protected boolean checkAlertType(String type) { - WaitUtils.waitForPageToLoad(); - try { - (new WebDriverWait(driver, 1)).until(ExpectedConditions.attributeContains(root, "class", "alert-" + type)); - } - catch (TimeoutException e) { - return false; - } - return true; - } - -} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPatternFlyAlert.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPatternFlyAlert.java new file mode 100644 index 0000000000..335b2f98dc --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPatternFlyAlert.java @@ -0,0 +1,99 @@ +/* + * 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.page; + +import org.jboss.arquillian.drone.api.annotation.Drone; +import org.jboss.logging.Logger; +import org.openqa.selenium.By; +import org.openqa.selenium.TimeoutException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.keycloak.testsuite.util.DroneUtils.getCurrentDriver; +import static org.keycloak.testsuite.util.UIUtils.getTextFromElement; +import static org.keycloak.testsuite.util.UIUtils.isElementVisible; +import static org.keycloak.testsuite.util.WaitUtils.PAGELOAD_TIMEOUT_MILLIS; + +/** + * + * @author tkyjovsk + */ +public abstract class AbstractPatternFlyAlert { + public static final String ALERT_CLASS_NAME = "alert"; + + protected final Logger log = Logger.getLogger(this.getClass()); + + @FindBy(className = ALERT_CLASS_NAME) + protected WebElement alertRoot; + + @Drone + protected WebDriver driver; + + public boolean isDisplayed() { + return isElementVisible(alertRoot); + } + + public static void waitUntilDisplayed() { + new WebDriverWait(getCurrentDriver(), PAGELOAD_TIMEOUT_MILLIS / 1000).until( + ExpectedConditions.visibilityOfElementLocated(By.className(ALERT_CLASS_NAME)) + ); + } + + public String getText() { + return getTextFromElement(alertRoot); + } + + public boolean isSuccess() { + return checkAlertType("success"); + } + + public void assertDisplayed() { + assertTrue("Alert should displayed", isDisplayed()); + } + + public void assertNotDisplayed() { + assertFalse("Alert shouldn't be displayed", isDisplayed()); + } + + public void assertSuccess() { + assertSuccess(null); + } + + public void assertSuccess(String expectedText) { + assertDisplayed(); + assertTrue("Alert type should be success", isSuccess()); + if (expectedText != null) assertEquals(expectedText, getText()); + } + + protected boolean checkAlertType(String type) { + try { + new WebDriverWait(driver, 1).until(ExpectedConditions.attributeContains(alertRoot, "class", "alert-" + type)); + } + catch (TimeoutException e) { + return false; + } + return true; + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/PatternFlyClosableAlert.java similarity index 52% rename from testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java rename to testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/PatternFlyClosableAlert.java index bc089a94ce..c3b4f38a64 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/PatternFlyClosableAlert.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Red Hat, Inc. and/or its affiliates + * Copyright 2018 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"); @@ -14,20 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.testsuite.console.page.fragment; +package org.keycloak.testsuite.page; -import org.jboss.arquillian.graphene.fragment.Root; -import org.keycloak.testsuite.page.AbstractAlert; import org.keycloak.testsuite.util.WaitUtils; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * * @author Petr Mensik * @author tkyjovsk */ -public class AdminConsoleAlert extends AbstractAlert { +public class PatternFlyClosableAlert extends AbstractPatternFlyAlert { @FindBy(xpath = ".//button[@class='close']") protected WebElement closeButton; @@ -44,6 +45,45 @@ public class AdminConsoleAlert extends AbstractAlert { return checkAlertType("danger"); } + @Override + public void assertSuccess(String expectedText) { + super.assertSuccess(expectedText); + close(); + } + + public void assertInfo() { + assertInfo(null); + } + + public void assertInfo(String expectedText) { + assertDisplayed(); + assertTrue("Alert type should be info", isInfo()); + if (expectedText != null) assertEquals(expectedText, getText()); + close(); + } + + public void assertWarning() { + assertWarning(null); + } + + public void assertWarning(String expectedText) { + assertDisplayed(); + assertTrue("Alert type should be warning", isWarning()); + if (expectedText != null) assertEquals(expectedText, getText()); + close(); + } + + public void assertDanger() { + assertDanger(null); + } + + public void assertDanger(String expectedText) { + assertDisplayed(); + assertTrue("Alert type should be danger", isDanger()); + if (expectedText != null) assertEquals(expectedText, getText()); + close(); + } + public void close() { closeButton.click(); WaitUtils.pause(500); // Sometimes, when a test is too fast, diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UIUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UIUtils.java index 81c7b4a911..c497e1ab16 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UIUtils.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UIUtils.java @@ -1,7 +1,12 @@ package org.keycloak.testsuite.util; import io.appium.java_client.android.AndroidDriver; +import org.apache.commons.lang3.StringUtils; +import org.keycloak.testsuite.page.AbstractPatternFlyAlert; +import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.Keys; +import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; @@ -19,6 +24,7 @@ import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad; public final class UIUtils { public static final String VALUE_ATTR_NAME = "value"; + public static final short EXPECTED_UI_LAYOUT = Short.parseShort(System.getProperty("testsuite.ui.layout")); // 0 == desktop layout, 1 == smartphone layout, 2 == tablet layout public static boolean selectContainsOption(Select select, String optionText) { for (WebElement option : select.getOptions()) { @@ -55,6 +61,18 @@ public final class UIUtils { performOperationWithPageReload(element::click); } + /** + * This is as an alternative for {@link #clickLink(WebElement)} and should be used in situations where we can't use + * {@link WaitUtils#waitForPageToLoad()}. This is because {@link WaitUtils#waitForPageToLoad()} would wait until the + * alert would disappeared itself (timeout). + * + * @param button to click on + */ + public static void clickBtnAndWaitForAlert(WebElement button) { + button.click(); + AbstractPatternFlyAlert.waitUntilDisplayed(); + } + /** * 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, @@ -93,9 +111,13 @@ public final class UIUtils { public static void setTextInputValue(WebElement input, String value) { input.click(); input.clear(); - if (value != null) { + if (!StringUtils.isEmpty(value)) { // setting new input input.sendKeys(value); } + else { // just clearing the input; input.clear() may not fire all JS events so we need to let the page know that something's changed + input.sendKeys("a"); + input.sendKeys(Keys.BACK_SPACE); + } WebDriver driver = getCurrentDriver(); if (driver instanceof AndroidDriver) { @@ -117,4 +139,21 @@ public final class UIUtils { } return text; } + + /** + * Should be used solely with {@link org.jboss.arquillian.graphene.GrapheneElement}, i.e. all elements annotated by + * {@link org.openqa.selenium.support.FindBy}. CANNOT be used with elements found directly using + * {@link WebDriver#findElement(By)} and similar. + * + * @param element + * @return true if element is present and visible + */ + public static boolean isElementVisible(WebElement element) { + try { + return element.isDisplayed(); + } + catch (NoSuchElementException e) { + return false; + } + } } 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 7d40f68f01..73398cfee8 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java @@ -16,21 +16,25 @@ */ package org.keycloak.testsuite.util; -import java.time.Duration; -import java.util.logging.Level; -import java.util.logging.Logger; import org.jboss.arquillian.graphene.wait.ElementBuilder; import org.openqa.selenium.By; import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.htmlunit.HtmlUnitDriver; +import org.openqa.selenium.support.ui.ExpectedCondition; import org.openqa.selenium.support.ui.FluentWait; import org.openqa.selenium.support.ui.WebDriverWait; +import java.time.Duration; +import java.util.logging.Level; +import java.util.logging.Logger; + import static org.jboss.arquillian.graphene.Graphene.waitGui; import static org.keycloak.testsuite.util.DroneUtils.getCurrentDriver; -import static org.openqa.selenium.support.ui.ExpectedConditions.*; +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.urlToBe; /** * @@ -97,9 +101,11 @@ public final class WaitUtils { return; // not needed } + String currentUrl = null; + // 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(); + for (int maxRedirects = 4; maxRedirects > 0; maxRedirects--) { + currentUrl = driver.getCurrentUrl(); FluentWait wait = new FluentWait<>(driver).withTimeout(Duration.ofMillis(250)); try { wait.until(not(urlToBe(currentUrl))); @@ -113,19 +119,34 @@ public final class WaitUtils { } WebDriverWait wait = new WebDriverWait(getCurrentDriver(), PAGELOAD_TIMEOUT_MILLIS / 1000); + ExpectedCondition waitCondition = null; - try { - // Checks if the document is ready and asks AngularJS, if present, whether there are any REST API requests - // in progress - wait.until(javaScriptThrowsNoExceptions( + // Different wait strategies for Admin and Account Consoles + if (currentUrl.matches("^[^\\/]+:\\/\\/[^\\/]+\\/auth\\/admin\\/.*$")) { // Admin Console + // Checks if the document is ready and asks AngularJS, if present, whether there are any REST API requests in progress + waitCondition = javaScriptThrowsNoExceptions( "if (document.readyState !== 'complete' " + "|| (typeof angular !== 'undefined' && angular.element(document.body).injector().get('$http').pendingRequests.length !== 0)) {" + "throw \"Not ready\";" - + "}")); - } catch (TimeoutException e) { - // Sometimes, for no obvious reason, the browser/JS doesn't set document.readyState to 'complete' correctly - // but that's no reason to let the test fail; after the timeout the page is surely fully loaded - log.warn("waitForPageToLoad time exceeded!"); + + "}"); + } + else if ( + currentUrl.matches("^[^\\/]+:\\/\\/[^\\/]+\\/auth\\/realms\\/[^\\/]+\\/account\\/.*$") // check for Account Console URL + && driver.getPageSource().contains("patternfly-ng") // check for new Account Console (don't use this strategy with the old one) + ) { + waitCondition = javaScriptThrowsNoExceptions( + "if (!window.getAngularTestability(document.querySelector('app-root')).isStable()) {" + + "throw 'Not ready';" + + "}" + ); + } + + if (waitCondition != null) { + try { + wait.until(waitCondition); + } catch (TimeoutException e) { + log.warn("waitForPageToLoad time exceeded!"); + } } } 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 ee8ab62428..d488c789b4 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 @@ -137,7 +137,7 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest { deleteAllSessionsInRealm(testRealmAccountPage.getAuthRealm()); } - private void resetTestRealmSession() { + protected void resetTestRealmSession() { resetRealmSession(testRealmAccountPage.getAuthRealm()); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java index 9eda4a4f5f..fe1b9daf7f 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java @@ -21,8 +21,7 @@ import org.jboss.arquillian.graphene.page.Page; import org.junit.Before; import org.keycloak.testsuite.AbstractAuthTest; import org.keycloak.testsuite.auth.page.account.AccountManagement; -import org.keycloak.testsuite.auth.page.account.fragment.AccountManagementAlert; -import org.openqa.selenium.support.FindBy; +import org.keycloak.testsuite.auth.page.account.fragment.AccountManagementPatternFlyAlert; import static org.junit.Assert.assertTrue; import static org.keycloak.testsuite.auth.page.AuthRealm.TEST; @@ -36,8 +35,8 @@ public abstract class AbstractAccountManagementTest extends AbstractAuthTest { @Page protected AccountManagement testRealmAccountManagementPage; - @FindBy(className = "alert") - protected AccountManagementAlert alert; + @Page + protected AccountManagementPatternFlyAlert alert; @Override public void setDefaultPageUriParameters() { diff --git a/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/AbstractUiTest.java b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/AbstractUiTest.java index 389a6d5649..93d847da94 100644 --- a/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/AbstractUiTest.java +++ b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/AbstractUiTest.java @@ -17,16 +17,16 @@ package org.keycloak.testsuite.ui; +import org.junit.Before; +import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractAuthTest; import java.util.Arrays; -import java.util.List; +import java.util.HashMap; import java.util.Set; import java.util.stream.Collectors; -import static org.keycloak.testsuite.auth.page.AuthRealm.TEST; - /** * @author Vaclav Muzikar */ @@ -34,14 +34,9 @@ public abstract class AbstractUiTest extends AbstractAuthTest { public static final String LOCALIZED_THEME = "localized-theme"; public static final String CUSTOM_LOCALE_NAME = "Přísný jazyk"; - @Override - public void addTestRealms(List testRealms) { - RealmRepresentation testRealmRep = new RealmRepresentation(); - testRealmRep.setId(TEST); - testRealmRep.setRealm(TEST); - testRealmRep.setEnabled(true); - configureInternationalizationForRealm(testRealmRep); - testRealms.add(testRealmRep); + @Before + public void addTestUser() { + createTestUserWithAdminClient(false); } protected void configureInternationalizationForRealm(RealmRepresentation realm) { @@ -58,4 +53,12 @@ public abstract class AbstractUiTest extends AbstractAuthTest { realm.setAccountTheme(LOCALIZED_THEME); realm.setEmailTheme(LOCALIZED_THEME); } + + protected IdentityProviderRepresentation createIdentityProviderRepresentation(String alias, String providerId) { + IdentityProviderRepresentation idpRep = new IdentityProviderRepresentation(); + idpRep.setProviderId(providerId); + idpRep.setAlias(alias); + idpRep.setConfig(new HashMap<>()); + return idpRep; + } } diff --git a/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/AbstractAccountTest.java b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/AbstractAccountTest.java new file mode 100644 index 0000000000..2006872986 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/AbstractAccountTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 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.ui.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.junit.Before; +import org.junit.BeforeClass; +import org.keycloak.common.Profile; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.ProfileAssume; +import org.keycloak.testsuite.auth.page.account2.WelcomeScreen; +import org.keycloak.testsuite.ui.AbstractUiTest; + +import java.util.List; + +import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf; + +/** + * @author Vaclav Muzikar + */ +public abstract class AbstractAccountTest extends AbstractUiTest { + public static final String ACCOUNT_THEME_NAME = "keycloak-preview"; + + @Page + protected WelcomeScreen accountWelcomeScreen; + + @Override + public void addTestRealms(List testRealms) { + super.addTestRealms(testRealms); + RealmRepresentation testRealmRep = testRealms.get(0); + testRealmRep.setAccountTheme(ACCOUNT_THEME_NAME); + } + + @BeforeClass + public static void enabled() { + ProfileAssume.assumeFeatureEnabled(Profile.Feature.ACCOUNT2); + } + + @Before + public void beforeAccountTest() { + accountWelcomeScreen.navigateTo(); + } + + protected void loginToAccount() { + assertCurrentUrlStartsWithLoginUrlOf(accountWelcomeScreen); + loginPage.form().login(testUser); + } +} diff --git a/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/BaseAccountPageTest.java b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/BaseAccountPageTest.java new file mode 100644 index 0000000000..a83f558cc1 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/BaseAccountPageTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 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.ui.account2; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.keycloak.testsuite.auth.page.account2.AbstractLoggedInPage; + +/** + * @author Vaclav Muzikar + */ +public abstract class BaseAccountPageTest extends AbstractAccountTest { + protected abstract AbstractLoggedInPage getAccountPage(); + + @Before + public void beforeBaseAccountPageTest() { + getAccountPage().navigateTo(); + loginToAccount(); + getAccountPage().assertCurrent(); + } + + @Test + @Ignore // TODO, blocked by KEYCLOAK-8217 + public void navigationTest() { + getAccountPage().navigateToUsingNavBar(); + getAccountPage().assertCurrent(); + } +} diff --git a/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/ChangePasswordTest.java b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/ChangePasswordTest.java new file mode 100644 index 0000000000..801d4eda21 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/ChangePasswordTest.java @@ -0,0 +1,127 @@ +/* + * Copyright 2018 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.ui.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.junit.Test; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.auth.page.account2.AbstractLoggedInPage; +import org.keycloak.testsuite.auth.page.account2.ChangePasswordPage; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.keycloak.testsuite.admin.Users.getPasswordOf; +import static org.keycloak.testsuite.admin.Users.setPasswordFor; + +/** + * @author Vaclav Muzikar + */ +public class ChangePasswordTest extends BaseAccountPageTest { + @Page + private ChangePasswordPage changePasswordPage; + + @Override + public void addTestRealms(List testRealms) { + super.addTestRealms(testRealms); + RealmRepresentation realm = testRealms.get(0); + realm.setPasswordPolicy("length(3)"); + } + + @Override + protected AbstractLoggedInPage getAccountPage() { + return changePasswordPage; + } + + @Test + public void changePassword() { + final LocalDateTime testStartTime = LocalDateTime.now(); + + final String oldPwd = getPasswordOf(testUser); + final String newPwd = "nějaké nové heslo s háčky a čárkami"; + setPasswordFor(testUser, newPwd); + + assertTrue("The current password should be older than the start time of this test", + testStartTime.isAfter(changePasswordPage.passwordLastUpdate().getDateTime())); + + changePasswordPage.updatePassword().setPasswords(oldPwd, newPwd); + changePasswordPage.updatePassword().clickSave(); + changePasswordPage.alert().assertSuccess(); + + // try the new password + deleteAllSessionsInTestRealm(); // logout + changePasswordPage.navigateTo(); + loginToAccount(); + changePasswordPage.assertCurrent(); + + assertTrue("The new password should be newer than the start time of this test", + testStartTime.isBefore(changePasswordPage.passwordLastUpdate().getDateTime())); + } + + @Test + public void formValidationTest() { + assertTrue(changePasswordPage.updatePassword().isSaveDisabled()); + changePasswordPage.updatePassword().setPasswords("abc", "def"); + assertFalse(changePasswordPage.updatePassword().isSaveDisabled()); + + // clear current password + changePasswordPage.updatePassword().setCurrentPassword(""); + assertTrue(changePasswordPage.updatePassword().isSaveDisabled()); + changePasswordPage.updatePassword().setCurrentPassword("abc"); + assertFalse(changePasswordPage.updatePassword().isSaveDisabled()); + + // clear new password + changePasswordPage.updatePassword().setNewPassword(""); + assertTrue(changePasswordPage.updatePassword().isSaveDisabled()); + changePasswordPage.updatePassword().setNewPassword("def"); + assertFalse(changePasswordPage.updatePassword().isSaveDisabled()); + + // clear confirm password + changePasswordPage.updatePassword().setConfirmPassword(""); + assertTrue(changePasswordPage.updatePassword().isSaveDisabled()); + changePasswordPage.updatePassword().setConfirmPassword("def"); + assertFalse(changePasswordPage.updatePassword().isSaveDisabled()); + + // invalid current password + changePasswordPage.updatePassword().setPasswords("invalid", "ab"); + changePasswordPage.updatePassword().clickSave(); + changePasswordPage.alert().assertDanger("Invalid existing password."); + + // non-matching passwords + changePasswordPage.updatePassword().setPasswords(getPasswordOf(testUser), "ab"); + changePasswordPage.updatePassword().setConfirmPassword("no match"); + changePasswordPage.updatePassword().clickSave(); + changePasswordPage.alert().assertDanger("Passwords don't match."); + + // password policy + changePasswordPage.updatePassword().setPasswords(getPasswordOf(testUser), "ab"); + changePasswordPage.updatePassword().clickSave(); + changePasswordPage.alert().assertDanger("Invalid password: minimum length 3."); + + // check the password is not changed + deleteAllSessionsInTestRealm(); + changePasswordPage.navigateTo(); + loginToAccount(); + changePasswordPage.assertCurrent(); + } + + // TODO test the last update timestamp when the password was never updated (blocked by KEYCLOAK-8193) + // TODO test internationalization for last update timestamp (blocked by KEYCLOAK-8194) +} diff --git a/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/PersonalInfoTest.java b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/PersonalInfoTest.java new file mode 100644 index 0000000000..d40baa2260 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/PersonalInfoTest.java @@ -0,0 +1,148 @@ +/* + * Copyright 2018 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.ui.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.junit.Before; +import org.junit.Test; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.representations.idm.UserRepresentation; +import org.keycloak.testsuite.admin.ApiUtil; +import org.keycloak.testsuite.auth.page.account2.AbstractLoggedInPage; +import org.keycloak.testsuite.auth.page.account2.PersonalInfoPage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author Vaclav Muzikar + */ +public class PersonalInfoTest extends BaseAccountPageTest { + private UserRepresentation testUser2; + @Page + private PersonalInfoPage personalInfoPage; + + @Before + public void setTestUser() { + testUser2 = new UserRepresentation(); + testUser2.setUsername("vmuzikar"); + testUser2.setEmail("vmuzikar@redhat.com"); + testUser2.setFirstName("Václav"); + testUser2.setLastName("Muzikář"); + ApiUtil.removeUserByUsername(testRealmResource(), testUser2.getUsername()); + } + + @Override + protected AbstractLoggedInPage getAccountPage() { + return personalInfoPage; + } + + @Test + public void updateUserInfo() { + setEditUsernameAllowed(true); + + assertTrue(personalInfoPage.personalInfo().valuesEqual(testUser)); + assertFalse(personalInfoPage.personalInfo().isUsernameDisabled()); + assertTrue(personalInfoPage.personalInfo().isSaveDisabled()); + + personalInfoPage.personalInfo().setValues(testUser2); + assertTrue(personalInfoPage.personalInfo().valuesEqual(testUser2)); + assertFalse(personalInfoPage.personalInfo().isSaveDisabled()); + personalInfoPage.personalInfo().clickSave(); + personalInfoPage.alert().assertSuccess(); + + personalInfoPage.navigateTo(); + personalInfoPage.personalInfo().valuesEqual(testUser2); + + // change just first and last name + testUser2.setFirstName("Another"); + testUser2.setLastName("Name"); + personalInfoPage.personalInfo().setValues(testUser2); + personalInfoPage.personalInfo().clickSave(); + personalInfoPage.alert().assertSuccess(); + personalInfoPage.navigateTo(); + personalInfoPage.personalInfo().valuesEqual(testUser2); + } + + @Test + public void formValidationTest() { + setEditUsernameAllowed(true); + + // clear username + personalInfoPage.personalInfo().setUsername(""); + assertTrue(personalInfoPage.personalInfo().isSaveDisabled()); + personalInfoPage.personalInfo().setUsername("abc"); + assertFalse(personalInfoPage.personalInfo().isSaveDisabled()); + + // clear email + personalInfoPage.personalInfo().setEmail(""); + assertTrue(personalInfoPage.personalInfo().isSaveDisabled()); + personalInfoPage.personalInfo().setEmail("vmuzikar@redhat.com"); + assertFalse(personalInfoPage.personalInfo().isSaveDisabled()); + + // TODO test email validation (blocked by KEYCLOAK-8098) + + // clear first name + personalInfoPage.personalInfo().setFirstName(""); + assertTrue(personalInfoPage.personalInfo().isSaveDisabled()); + personalInfoPage.personalInfo().setFirstName("abc"); + assertFalse(personalInfoPage.personalInfo().isSaveDisabled()); + + // clear last name + personalInfoPage.personalInfo().setLastName(""); + assertTrue(personalInfoPage.personalInfo().isSaveDisabled()); + personalInfoPage.personalInfo().setLastName("abc"); + assertFalse(personalInfoPage.personalInfo().isSaveDisabled()); + + // duplicity tests + ApiUtil.createUserWithAdminClient(testRealmResource(), testUser2); + // duplicate username + personalInfoPage.personalInfo().setUsername(testUser2.getUsername()); + personalInfoPage.personalInfo().clickSave(); + personalInfoPage.alert().assertDanger("Username already exists."); + personalInfoPage.personalInfo().setUsername(testUser.getUsername()); + // duplicate email + personalInfoPage.personalInfo().setEmail(testUser2.getEmail()); + personalInfoPage.personalInfo().clickSave(); + personalInfoPage.alert().assertDanger("Email already exists."); + // check no changes were saved + personalInfoPage.navigateTo(); + personalInfoPage.personalInfo().valuesEqual(testUser); + } + + @Test + public void disabledEditUsername() { + setEditUsernameAllowed(false); + + assertTrue(personalInfoPage.personalInfo().isUsernameDisabled()); + personalInfoPage.personalInfo().setValues(testUser2); + personalInfoPage.personalInfo().clickSave(); + personalInfoPage.alert().assertSuccess(); + + testUser2.setUsername(testUser.getUsername()); // the username should remain the same + personalInfoPage.navigateTo(); + personalInfoPage.personalInfo().valuesEqual(testUser2); + } + + private void setEditUsernameAllowed(boolean value) { + RealmRepresentation realm = testRealmResource().toRepresentation(); + realm.setEditUsernameAllowed(value); + testRealmResource().update(realm); + personalInfoPage.navigateTo(); + } +} diff --git a/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/WelcomeScreenTest.java b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/WelcomeScreenTest.java new file mode 100644 index 0000000000..dedef72cc4 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/WelcomeScreenTest.java @@ -0,0 +1,131 @@ +/* + * Copyright 2018 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.ui.account2; + +import org.jboss.arquillian.graphene.page.Page; +import org.junit.Test; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.auth.page.account2.ApplicationsPage; +import org.keycloak.testsuite.auth.page.account2.AuthenticatorPage; +import org.keycloak.testsuite.auth.page.account2.ChangePasswordPage; +import org.keycloak.testsuite.auth.page.account2.DeviceActivityPage; +import org.keycloak.testsuite.auth.page.account2.LinkedAccountsPage; +import org.keycloak.testsuite.auth.page.account2.PersonalInfoPage; +import org.keycloak.testsuite.auth.page.account2.ResourcesPage; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author Vaclav Muzikar + */ +public class WelcomeScreenTest extends AbstractAccountTest { + @Page + private PersonalInfoPage personalInfoPage; + @Page + private ChangePasswordPage changePasswordPage; + @Page + private AuthenticatorPage authenticatorPage; + @Page + private DeviceActivityPage deviceActivityPage; + @Page + private LinkedAccountsPage linkedAccountsPage; + @Page + private ApplicationsPage applicationsPage; + @Page + private ResourcesPage resourcesPage; + + @Test + public void loginTest() { + accountWelcomeScreen.assertCurrent(); + assertTrue(accountWelcomeScreen.isLoginBtnVisible()); + + // login + accountWelcomeScreen.clickLoginBtn(); + loginToAccount(); + accountWelcomeScreen.assertCurrent(); + assertFalse(accountWelcomeScreen.isLoginBtnVisible()); + + // TODO logout test (blocked by KEYCLOAK-8084) + } + + @Test + public void personalInfoTest() { + assertTrue(accountWelcomeScreen.personalInfo().isVisible()); + accountWelcomeScreen.personalInfo().clickPersonalInfo(); + loginToAccount(); + personalInfoPage.assertCurrent(); + } + + @Test + public void accountSecurityTest() { + assertTrue(accountWelcomeScreen.accountSecurityCard().isVisible()); + + // change password link + accountWelcomeScreen.accountSecurityCard().clickChangePassword(); + loginToAccount(); + changePasswordPage.assertCurrent(); + + // authenticator link + accountWelcomeScreen.navigateTo(); + accountWelcomeScreen.accountSecurityCard().clickAuthenticator(); + authenticatorPage.assertCurrent(); + + // device activity link + accountWelcomeScreen.navigateTo(); + accountWelcomeScreen.accountSecurityCard().clickDeviceActivity(); + deviceActivityPage.assertCurrent(); + + // linked accounts link + accountWelcomeScreen.navigateTo(); + assertFalse(accountWelcomeScreen.accountSecurityCard().isLinkedAccountsVisible()); + // add simple IdP + testRealmResource().identityProviders().create(createIdentityProviderRepresentation("test-idp", "test-provider")); + // test link appeared + accountWelcomeScreen.navigateTo(); + accountWelcomeScreen.accountSecurityCard().clickLinkedAccounts(); + linkedAccountsPage.assertCurrent(); + // no need to remove the IdP + } + + @Test + public void applicationsTest() { + assertTrue(accountWelcomeScreen.applicationsCard().isVisible()); + accountWelcomeScreen.applicationsCard().clickApplicationsLink(); + loginToAccount(); + applicationsPage.assertCurrent(); + } + + @Test + public void resourcesTest() { + assertFalse(accountWelcomeScreen.myResourcesCard().isVisible()); + + // set user managed access + RealmRepresentation testRealm = testRealmResource().toRepresentation(); + testRealm.setUserManagedAccessAllowed(true); + testRealmResource().update(testRealm); + + // test my resources appeared + accountWelcomeScreen.navigateTo(); + assertTrue(accountWelcomeScreen.myResourcesCard().isVisible()); + accountWelcomeScreen.myResourcesCard().clickMyResources(); + loginToAccount(); + resourcesPage.assertCurrent(); + // no need to disable user managed access + } +} diff --git a/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/login/AbstractLoginTest.java b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/login/AbstractLoginTest.java index e9c673ef8f..9ff8bbc1b3 100644 --- a/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/login/AbstractLoginTest.java +++ b/testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/login/AbstractLoginTest.java @@ -17,9 +17,11 @@ package org.keycloak.testsuite.ui.login; -import org.junit.Before; +import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.ui.AbstractUiTest; +import java.util.List; + import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertTrue; import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith; @@ -29,9 +31,11 @@ import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; * @author Vaclav Muzikar */ public abstract class AbstractLoginTest extends AbstractUiTest { - @Before - public void addTestUser() { - createTestUserWithAdminClient(false); + @Override + public void addTestRealms(List testRealms) { + super.addTestRealms(testRealms); + RealmRepresentation testRealmRep = testRealms.get(0); + configureInternationalizationForRealm(testRealmRep); } protected void assertLoginFailed(String message) { diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java index d01e4a5660..183e91d7f0 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java @@ -26,8 +26,8 @@ import org.keycloak.testsuite.console.page.AdminConsole; import org.keycloak.testsuite.console.page.AdminConsoleRealm; import org.keycloak.testsuite.console.page.AdminConsoleRealm.ConfigureMenu; import org.keycloak.testsuite.console.page.AdminConsoleRealm.ManageMenu; -import org.keycloak.testsuite.console.page.fragment.AdminConsoleAlert; import org.keycloak.testsuite.console.page.fragment.ModalDialog; +import org.keycloak.testsuite.page.PatternFlyClosableAlert; import org.openqa.selenium.support.FindBy; import static org.junit.Assert.assertTrue; @@ -53,8 +53,8 @@ public abstract class AbstractConsoleTest extends AbstractAuthTest { @FindBy(xpath = "//div[@class='modal-dialog']") protected ModalDialog modalDialog; - @FindBy(className = "alert") - protected AdminConsoleAlert alert; + @Page + protected PatternFlyClosableAlert alert; protected boolean adminLoggedIn = false; @@ -111,13 +111,11 @@ public abstract class AbstractConsoleTest extends AbstractAuthTest { } public void assertAlertSuccess() { - assertTrue("Alert is not success", alert.isSuccess()); - alert.close(); + alert.assertSuccess(); } public void assertAlertDanger() { - assertTrue("Alert is not danger", alert.isDanger()); - alert.close(); + alert.assertDanger(); } public ConfigureMenu configure() { diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml index 4f03c09d64..9793adeaff 100755 --- a/testsuite/integration-arquillian/tests/pom.xml +++ b/testsuite/integration-arquillian/tests/pom.xml @@ -167,6 +167,7 @@ true ${project.build.directory}/dependency/test-constants.properties + 0 false true @@ -461,6 +462,7 @@ ${kie.maven.settings} ${testsuite.constants} + ${testsuite.ui.layout} ${cli.log.output} ${test.intermittent} diff --git a/themes/src/main/resources/theme/keycloak-preview/account/index.ftl b/themes/src/main/resources/theme/keycloak-preview/account/index.ftl index e0947383b3..7fd189705c 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/index.ftl +++ b/themes/src/main/resources/theme/keycloak-preview/account/index.ftl @@ -194,7 +194,7 @@

${msg("accountSecurityTitle")}

${msg("accountSecurityIntroMessage")}

- +