Multiple active tabs when realm name equals name of the tab in Admin console (#9438)

Closes #9421
This commit is contained in:
Martin Bartoš 2022-01-11 22:01:28 +01:00 committed by GitHub
parent fe506bceaa
commit 8649ca3d50
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 240 additions and 41 deletions

View file

@ -17,10 +17,14 @@
package org.keycloak.testsuite.console.page;
import org.keycloak.testsuite.util.UIUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import java.util.Optional;
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
@ -58,16 +62,14 @@ public class AdminConsoleRealm extends AdminConsoleRealmsRoot {
return configureMenu;
}
// public RealmResource realmResource() {
// return realmsResource().realm(getConsoleRealm());
// }
public static class ConfigureMenu {
@FindBy(partialLinkText = "Realm Settings")
private WebElement realmSettingsLink;
@FindBy(partialLinkText = "Clients")
private WebElement clientsLink;
@FindBy(partialLinkText = "Client Scopes")
private WebElement clientScopesLink;
@FindBy(partialLinkText = "Roles")
private WebElement rolesLink;
@FindBy(partialLinkText = "Identity Providers")
@ -78,29 +80,61 @@ public class AdminConsoleRealm extends AdminConsoleRealmsRoot {
private WebElement authenticationLink;
public void realmSettings() {
realmSettingsLink.click();
navigateToTab(realmSettingsLink);
}
public void clients() {
clientsLink.click();
navigateToTab(clientsLink);
}
public void clientScopesLink() {
navigateToTab(clientScopesLink);
}
public void roles() {
rolesLink.click();
navigateToTab(rolesLink);
}
public void identityProviders() {
identityProvidersLink.click();
navigateToTab(identityProvidersLink);
}
public void userFederation() {
userFederationLink.click();
navigateToTab(userFederationLink);
}
public void authentication() {
authenticationLink.click();
navigateToTab(authenticationLink);
}
// Elements
public WebElement getRealmSettingsTab() {
return realmSettingsLink;
}
public WebElement getClientsTab() {
return clientsLink;
}
public WebElement getClientScopesTab() {
return clientScopesLink;
}
public WebElement getRolesTab() {
return rolesLink;
}
public WebElement getUserFederationTab() {
return userFederationLink;
}
public WebElement getIdentityProvidersTab() {
return identityProvidersLink;
}
public WebElement getAuthenticationTab() {
return authenticationLink;
}
}
@FindBy(xpath = "//div[./h2[text()='Manage']]")
@ -112,25 +146,83 @@ public class AdminConsoleRealm extends AdminConsoleRealmsRoot {
}
public static class ManageMenu {
@FindBy(partialLinkText = "Groups")
private WebElement groupsLink;
@FindBy(partialLinkText = "Users")
private WebElement usersLink;
@FindBy(partialLinkText = "Sessions")
private WebElement sessionsLink;
@FindBy(partialLinkText = "Events")
private WebElement eventsLink;
@FindBy(partialLinkText = "Import")
private WebElement importLink;
@FindBy(partialLinkText = "Export")
private WebElement exportLink;
public void groups() {
navigateToTab(groupsLink);
}
public void users() {
usersLink.click();
navigateToTab(usersLink);
}
public void sessions() {
sessionsLink.click();
navigateToTab(sessionsLink);
}
public void events() {
eventsLink.click();
navigateToTab(eventsLink);
}
public void importTab() {
navigateToTab(importLink);
}
public void exportTab() {
navigateToTab(exportLink);
}
// Elements
public WebElement getGroupsTab() {
return groupsLink;
}
public WebElement getUsersTab() {
return groupsLink;
}
public WebElement getSessionsTab() {
return groupsLink;
}
public WebElement getEventsTab() {
return groupsLink;
}
public WebElement getImportTab() {
return groupsLink;
}
public WebElement getExportTab() {
return groupsLink;
}
}
public static void navigateToTab(WebElement tab) {
if (tab == null) return;
UIUtils.clickLink(tab);
}
public static boolean isTabActive(WebElement tab) {
try {
final WebElement parent = tab != null ? tab.findElement(By.xpath("./..")) : null;
return parent != null && Optional.ofNullable(parent.getAttribute("class"))
.map(f -> f.equals("active"))
.orElse(false);
} catch (NoSuchElementException e) {
return false;
}
}
}

View file

@ -18,16 +18,17 @@
package org.keycloak.testsuite.console.page.realm;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.UIUtils;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
/**
*
* @author Petr Mensik
*/
public class GeneralSettings extends RealmSettings {
public class GeneralSettings extends Form {
@FindBy(id = "name")
private WebElement realmName;
@ -50,18 +51,11 @@ public class GeneralSettings extends RealmSettings {
@FindBy(id = "emailTheme")
private Select emailThemeSelect;
@FindBy(className = "btn btn-primary btn-lg")
private WebElement saveButton;
public void saveSettings() {
saveButton.click();
}
public void selectLoginTheme(String theme) {
loginThemeSelect.selectByVisibleText(theme);
}
public void selecAccountTheme(String theme) {
public void selectAccountTheme(String theme) {
accountThemeSelect.selectByVisibleText(theme);
}
@ -72,4 +66,8 @@ public class GeneralSettings extends RealmSettings {
public void selectEmailTheme(String theme) {
emailThemeSelect.selectByVisibleText(theme);
}
public void setRealmName(String name) {
UIUtils.setTextInputValue(realmName, name);
}
}

View file

@ -0,0 +1,105 @@
/*
* Copyright 2021 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.console.other;
import org.hamcrest.CoreMatchers;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Test;
import org.keycloak.testsuite.console.AbstractConsoleTest;
import org.keycloak.testsuite.console.page.AdminConsoleRealm;
import org.keycloak.testsuite.console.page.realm.GeneralSettings;
import org.openqa.selenium.WebElement;
import java.util.function.Supplier;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.keycloak.testsuite.console.page.AdminConsoleRealm.isTabActive;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
/**
* @author <a href="mailto:mabartos@redhat.com">Martin Bartos</a>
*/
public class ConsoleActiveMenuTest extends AbstractConsoleTest {
@Page
GeneralSettings generalSettings;
@Test
public void clientsActive() {
checkActiveTab("client", () -> adminConsoleRealmPage.configure().getClientsTab());
}
@Test
public void clientScopesActive() {
checkActiveTab("client-scope", () -> adminConsoleRealmPage.configure().getClientScopesTab());
}
@Test
public void rolesActive() {
checkActiveTab("role", () -> adminConsoleRealmPage.configure().getRolesTab());
}
@Test
public void identityProvidersActive() {
checkActiveTab("identity-provider", () -> adminConsoleRealmPage.configure().getIdentityProvidersTab());
}
@Test
public void userFederationActive() {
checkActiveTab("user-storage", () -> adminConsoleRealmPage.configure().getUserFederationTab());
}
@Test
public void authenticationActive() {
checkActiveTab("authentication", () -> adminConsoleRealmPage.configure().getAuthenticationTab());
}
// Manage
@Test
public void groupsActive() {
checkActiveTab("group", () -> adminConsoleRealmPage.manage().getGroupsTab());
}
@Test
public void usersActive() {
checkActiveTab("user", () -> adminConsoleRealmPage.manage().getUsersTab());
}
private void checkActiveTab(String realmName, Supplier<WebElement> getElement) {
adminConsoleRealmPage.navigateTo();
adminConsoleRealmPage.assertCurrent();
adminConsoleRealmPage.configure().realmSettings();
generalSettings.setRealmName(realmName);
try {
generalSettings.save();
waitForPageToLoad();
final WebElement tab = getElement.get();
assertThat(isTabActive(tab), CoreMatchers.is(false));
AdminConsoleRealm.navigateToTab(tab);
waitForPageToLoad();
assertThat(isTabActive(getElement.get()), CoreMatchers.is(true));
} finally {
adminConsoleRealmPage.configure().realmSettings();
generalSettings.setRealmName("test");
generalSettings.save();
}
}
}

View file

@ -187,6 +187,10 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
// Current.realms = Realm.get();
$scope.current = Current;
$scope.isCreateEndpoint = function(endpoint) {
return $scope.path.length > 1 && $scope.path[0] === 'create' && $scope.path[1] === endpoint;
}
$scope.changeRealm = function(selectedRealm) {
$location.url("/realms/" + selectedRealm);
}

View file

@ -34,26 +34,26 @@
|| path[2] == 'keys-settings' || path[2] == 'smtp-settings' || path[2] == 'ldap-settings' || path[2] == 'auth-settings') && path[3] != 'clients') && 'active'">
<a href="#/realms/{{realm.realm}}"><span class="pficon pficon-settings"></span> {{:: 'realm-settings' | translate}}</a>
</li>
<li data-ng-show="access.queryClients" data-ng-class="(path[1] == 'client' || path[2] == 'clients' || path[3] == 'clients') && 'active'"><a href="#/realms/{{realm.realm}}/clients"><i class="fa fa-cube"></i> {{:: 'clients' | translate}}</a></li>
<li data-ng-show="access.viewClients" data-ng-class="(path[1] == 'client-scope' || path[2] == 'client-scopes' || path[3] == 'client-scopes' || path[2] == 'default-client-scopes') && 'active'"><a href="#/realms/{{realm.realm}}/client-scopes"><i class="fa fa-cubes"></i> {{:: 'client-scopes' | translate}}</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[1] == 'role' || path[2] == 'roles' || path[2] == 'default-roles') && 'active'"><a href="#/realms/{{realm.realm}}/roles"><i class="fa fa-tasks"></i> {{:: 'roles' | translate}}</a></li>
<li data-ng-show="access.viewIdentityProviders" data-ng-class="(path[1] == 'identity-provider' || path[2] == 'identity-provider-settings' || path[2] == 'identity-provider-mappers') && 'active'"><a href="#/realms/{{realm.realm}}/identity-provider-settings"><i class="fa fa-exchange"></i> {{:: 'identity-providers' | translate}}</a></li>
<li data-ng-show="access.queryClients" data-ng-class="(isCreateEndpoint('client') || path[2] == 'clients' || path[3] == 'clients') && 'active'"><a href="#/realms/{{realm.realm}}/clients"><i class="fa fa-cube"></i> {{:: 'clients' | translate}}</a></li>
<li data-ng-show="access.viewClients" data-ng-class="(isCreateEndpoint('client-scope') || path[2] == 'client-scopes' || path[3] == 'client-scopes' || path[2] == 'default-client-scopes') && 'active'"><a href="#/realms/{{realm.realm}}/client-scopes"><i class="fa fa-cubes"></i> {{:: 'client-scopes' | translate}}</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(isCreateEndpoint('role') || path[2] == 'roles' || path[2] == 'default-roles') && 'active'"><a href="#/realms/{{realm.realm}}/roles"><i class="fa fa-tasks"></i> {{:: 'roles' | translate}}</a></li>
<li data-ng-show="access.viewIdentityProviders" data-ng-class="(isCreateEndpoint('identity-provider') || path[2] == 'identity-provider-settings' || path[2] == 'identity-provider-mappers') && 'active'"><a href="#/realms/{{realm.realm}}/identity-provider-settings"><i class="fa fa-exchange"></i> {{:: 'identity-providers' | translate}}</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(
path[1] == 'user-storage'
isCreateEndpoint('user-storage')
|| path[2] == 'user-federation'
|| path[2] == 'user-storage'
|| path[2] == 'ldap-mappers'
) && 'active'"><a href="#/realms/{{realm.realm}}/user-federation"><i class="fa fa-database"></i> {{:: 'user-federation' | translate}}</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[1] == 'authentication' || path[2] == 'authentication') && 'active'"><a href="#/realms/{{realm.realm}}/authentication/flows"><i class="fa fa-lock"></i> {{:: 'authentication' | translate}}</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(isCreateEndpoint('authentication') || path[2] == 'authentication') && 'active'"><a href="#/realms/{{realm.realm}}/authentication/flows"><i class="fa fa-lock"></i> {{:: 'authentication' | translate}}</a></li>
</ul>
</div>
<div class="nav-category" data-ng-show="current.realm && (access.viewRealm || access.queryGroups || access.queryUsers || access.viewEvents)">
<h2>{{:: 'manage' | translate}}</h2>
<ul class="nav nav-pills nav-stacked">
<li data-ng-show="access.queryGroups" data-ng-class="(path[1] == 'group' || path[2] == 'groups'
<li data-ng-show="access.queryGroups" data-ng-class="(isCreateEndpoint('group') || path[2] == 'groups'
|| path[2] == 'default-groups') && 'active'"><a href="#/realms/{{realm.realm}}/groups"><span class="pficon pficon-users"></span> {{:: 'groups' | translate}}</a></li>
<li data-ng-show="access.queryUsers" data-ng-class="(path[1] == 'user' || path[2] == 'users' || path[2] == 'users-permissions') && 'active'"><a href="#/realms/{{realm.realm}}/users"><span class="pficon pficon-user"></span> {{:: 'users' | translate}}</a></li>
<li data-ng-show="access.queryUsers" data-ng-class="(isCreateEndpoint('user') || path[2] == 'users' || path[2] == 'users-permissions') && 'active'"><a href="#/realms/{{realm.realm}}/users"><span class="pficon pficon-user"></span> {{:: 'users' | translate}}</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'sessions') && 'active'"><a href="#/realms/{{realm.realm}}/sessions/realm"><i class="fa fa-clock-o"></i> {{:: 'sessions' | translate}}</a></li>
<li data-ng-show="access.viewEvents" data-ng-class="(path[2] == 'events'
|| path[2] == 'events-settings'