From c51aa73e717e5392e602948cd92c4ce8fba2f5a3 Mon Sep 17 00:00:00 2001 From: ikhomyn <89014675+ikhomyn@users.noreply.github.com> Date: Mon, 27 Jun 2022 10:47:41 +0200 Subject: [PATCH] new group tests (#2789) --- cypress/e2e/clients_test.spec.ts | 10 +- cypress/e2e/group_test.spec.ts | 589 +++++++++++++----- ...ser_fed_ldap_hardcoded_mapper_test.spec.ts | 9 +- cypress/e2e/users_test.spec.ts | 9 +- .../pages/admin_console/ListingPage.ts | 7 + .../admin_console/components/PageObject.ts | 27 +- .../admin_console/manage/AttributesTab.ts | 48 +- .../manage/clients/ClientRolesTab.ts | 38 -- .../manage/groups/GroupDetailPage.ts | 73 --- .../admin_console/manage/groups/GroupModal.ts | 36 +- .../admin_console/manage/groups/GroupPage.ts | 177 ++++++ .../manage/groups/MoveGroupModal.ts | 4 +- .../manage/groups/SearchGroup.ts | 19 - .../manage/groups/SearchGroupPage.ts | 27 + .../groups/group_details/GroupDetailPage.ts | 130 ++++ .../group_details/tabs/ChildGroupsTab.ts | 11 + .../groups/group_details/tabs/MembersTab.ts | 85 +++ .../group_details/tabs/PermissionsTab.ts | 3 + cypress/support/util/AdminClient.ts | 5 + cypress/support/util/ModalUtils.ts | 34 +- 20 files changed, 990 insertions(+), 351 deletions(-) delete mode 100644 cypress/support/pages/admin_console/manage/groups/GroupDetailPage.ts create mode 100644 cypress/support/pages/admin_console/manage/groups/GroupPage.ts delete mode 100644 cypress/support/pages/admin_console/manage/groups/SearchGroup.ts create mode 100644 cypress/support/pages/admin_console/manage/groups/SearchGroupPage.ts create mode 100644 cypress/support/pages/admin_console/manage/groups/group_details/GroupDetailPage.ts create mode 100644 cypress/support/pages/admin_console/manage/groups/group_details/tabs/ChildGroupsTab.ts create mode 100644 cypress/support/pages/admin_console/manage/groups/group_details/tabs/MembersTab.ts create mode 100644 cypress/support/pages/admin_console/manage/groups/group_details/tabs/PermissionsTab.ts diff --git a/cypress/e2e/clients_test.spec.ts b/cypress/e2e/clients_test.spec.ts index 1beb03422b..efadc2ffb5 100644 --- a/cypress/e2e/clients_test.spec.ts +++ b/cypress/e2e/clients_test.spec.ts @@ -17,6 +17,7 @@ import ClientDetailsPage, { } from "../support/pages/admin_console/manage/clients/client_details/ClientDetailsPage"; import CommonPage from "../support/pages/CommonPage"; import ListingPage from "../support/pages/admin_console/ListingPage"; +import AttributesTab from "../support/pages/admin_console/manage/AttributesTab"; let itemId = "client_crud"; const loginPage = new LoginPage(); @@ -25,6 +26,7 @@ const createClientPage = new CreateClientPage(); const clientDetailsPage = new ClientDetailsPage(); const commonPage = new CommonPage(); const listingPage = new ListingPage(); +const attributesTab = new AttributesTab(); describe("Clients test", () => { describe("Client details - Client scopes subtab", () => { @@ -490,8 +492,10 @@ describe("Clients test", () => { commonPage.tableUtils().clickRowItemLink(itemId); rolesTab.goToAttributesTab(); cy.wait(["@load", "@load"]); - rolesTab.addAttribute(1, "crud_attribute_key", "crud_attribute_value"); - rolesTab.checkRowItemsEqualTo(1); + attributesTab + .addAttribute("crud_attribute_key", "crud_attribute_value") + .save(); + attributesTab.asseertRowItemsEqualTo(1); commonPage .masthead() .checkNotificationMessage("The role has been saved", true); @@ -502,7 +506,7 @@ describe("Clients test", () => { commonPage.tableUtils().clickRowItemLink(itemId); rolesTab.goToAttributesTab(); cy.wait(["@load", "@load"]); - rolesTab.deleteAttribute(1); + attributesTab.deleteAttribute(1); commonPage .masthead() .checkNotificationMessage("The role has been saved", true); diff --git a/cypress/e2e/group_test.spec.ts b/cypress/e2e/group_test.spec.ts index 328734ebdb..849d5bdfe8 100644 --- a/cypress/e2e/group_test.spec.ts +++ b/cypress/e2e/group_test.spec.ts @@ -1,219 +1,474 @@ -import ListingPage from "../support/pages/admin_console/ListingPage"; import GroupModal from "../support/pages/admin_console/manage/groups/GroupModal"; -import GroupDetailPage from "../support/pages/admin_console/manage/groups/GroupDetailPage"; +import GroupDetailPage from "../support/pages/admin_console/manage/groups/group_details/GroupDetailPage"; import AttributesTab from "../support/pages/admin_console/manage//AttributesTab"; -import MoveGroupModal from "../support/pages/admin_console/manage/groups/MoveGroupModal"; -import { SearchGroupPage } from "../support/pages/admin_console/manage/groups/SearchGroup"; -import Masthead from "../support/pages/admin_console/Masthead"; +import { SearchGroupPage } from "../support/pages/admin_console/manage/groups/SearchGroupPage"; import SidebarPage from "../support/pages/admin_console/SidebarPage"; import LoginPage from "../support/pages/LoginPage"; -import ViewHeaderPage from "../support/pages/ViewHeaderPage"; -import adminClient from "../support/util/AdminClient"; import { keycloakBefore } from "../support/util/keycloak_hooks"; -import ModalUtils from "../support/util/ModalUtils"; +import GroupPage from "../support/pages/admin_console/manage/groups/GroupPage"; +import ChildGroupsTab from "../support/pages/admin_console/manage/groups/group_details/tabs/ChildGroupsTab"; +import MembersTab from "../support/pages/admin_console/manage/groups/group_details/tabs/MembersTab"; +import adminClient from "../support/util/AdminClient"; +import { range } from "lodash-es"; describe("Group test", () => { const loginPage = new LoginPage(); - const masthead = new Masthead(); const sidebarPage = new SidebarPage(); - const listingPage = new ListingPage(); - const viewHeaderPage = new ViewHeaderPage(); const groupModal = new GroupModal(); const searchGroupPage = new SearchGroupPage(); - const moveGroupModal = new MoveGroupModal(); - const modalUtils = new ModalUtils(); const attributesTab = new AttributesTab(); + const groupPage = new GroupPage(); + const groupDetailPage = new GroupDetailPage(); + const childGroupsTab = new ChildGroupsTab(); + const membersTab = new MembersTab(); - let groupName = "group"; + const groupNamePrefix = "group_"; + let groupName: string; + const groupNames: string[] = []; + const predefinedGroups = ["level", "level1", "level2", "level3"]; + const emptyGroup = "empty-group"; + let users: { id: string; username: string }[] = []; + const username = "test-user"; - const clickGroup = (itemName: string) => { - sidebarPage.waitForPageLoad(); - cy.get("table").contains(itemName).click(); + before(async () => { + users = await Promise.all( + range(5).map((index) => { + const user = adminClient + .createUser({ + username: username + index, + enabled: true, + }) + .then((user) => { + return { id: user.id, username: username + index }; + }); + return user; + }) + ); + }); - return this; - }; + beforeEach(() => { + keycloakBefore(); + loginPage.logIn(); + sidebarPage.goToGroups(); + groupName = groupNamePrefix + (Math.random() + 1).toString(36).substring(7); + groupNames.push(groupName); + }); - describe("Group creation", () => { - beforeEach(() => { - keycloakBefore(); - loginPage.logIn(); - sidebarPage.goToGroups(); + describe("List", () => { + it("Create group from empty option", () => { + groupPage + .assertNoGroupsInThisRealmEmptyStateMessageExist(true) + .createGroup(groupName, true) + .assertNotificationGroupCreated() + .searchGroup(groupName) + .assertGroupItemExist(groupName, true); }); - it("Group CRUD test", () => { - groupName += "_" + (Math.random() + 1).toString(36).substring(7); - - groupModal - .open("no-groups-in-this-realm-empty-action") - .fillGroupForm(groupName) - .clickCreate(); - - masthead.checkNotificationMessage("Group created"); - - sidebarPage.goToGroups(); - listingPage.searchItem(groupName, false).itemExist(groupName); - - // Delete - listingPage.deleteItem(groupName); - modalUtils.checkModalTitle("Delete group?").confirmModal(); - masthead.checkNotificationMessage("Group deleted"); + it("Create group from search bar", () => { + groupPage + .assertNoGroupsInThisRealmEmptyStateMessageExist(false) + .createGroup(groupName, false) + .assertNotificationGroupCreated() + .searchGroup(groupName) + .assertGroupItemExist(groupName, true); }); - it("Should rename group", () => { - groupModal - .open("no-groups-in-this-realm-empty-action") - .fillGroupForm(groupName) - .clickCreate(); - clickGroup(groupName); - viewHeaderPage.clickAction("renameGroupAction"); - - const newName = "Renamed group"; - groupModal.fillGroupForm(newName).clickRename(); - masthead.checkNotificationMessage("Group updated"); - - sidebarPage.goToGroups(); - listingPage.searchItem(newName, false).itemExist(newName); - listingPage.deleteItem(newName); - modalUtils.checkModalTitle("Delete group?").confirmModal(); - masthead.checkNotificationMessage("Group deleted"); + it("Fail to create group with empty name", () => { + groupPage + .assertNoGroupsInThisRealmEmptyStateMessageExist(false) + .createGroup(" ", false) + .assertNotificationCouldNotCreateGroupWithEmptyName(); + groupModal.closeModal(); + groupPage.searchGroup(" ").assertNoSearchResultsMessageExist(true); }); - it("Should move group", () => { - const targetGroupName = "target"; - groupModal.open("no-groups-in-this-realm-empty-action"); - groupModal.fillGroupForm(groupName).clickCreate(); - - sidebarPage.waitForPageLoad(); - groupModal - .open("openCreateGroupModal") - .fillGroupForm(targetGroupName) - .clickCreate(); - - // For some reason, this fixes clickDetailMenu - sidebarPage.goToEvents(); - sidebarPage.goToGroups(); - - listingPage.clickRowDetails(groupName).clickDetailMenu("Move to"); - moveGroupModal - .clickRow(targetGroupName) - .checkTitle(`Move ${groupName} to ${targetGroupName}`); - moveGroupModal.clickMove(); - - masthead.checkNotificationMessage("Group moved"); - sidebarPage.waitForPageLoad(); - listingPage.itemExist(groupName, false); - clickGroup(targetGroupName); - sidebarPage.waitForPageLoad(); - listingPage.itemExist(groupName); - sidebarPage.goToGroups(); - listingPage.deleteItem(targetGroupName); - modalUtils.checkModalTitle("Delete group?").confirmModal(); - masthead.checkNotificationMessage("Group deleted"); + it("Fail to create group with duplicated name", () => { + groupPage + .assertNoGroupsInThisRealmEmptyStateMessageExist(false) + .createGroup(groupName, false) + .createGroup(groupName, false) + .assertNotificationCouldNotCreateGroupWithDuplicatedName(groupName); + groupModal.closeModal(); + groupPage.searchGroup(groupName).assertGroupItemsEqual(1); }); - describe("Move groups", () => { - const groups = ["group", "group1", "group2"]; - before(() => adminClient.createSubGroups(groups)); - - after(() => adminClient.deleteGroups()); - - it("Should move group to root", () => { - listingPage.goToItemDetails(groups[0]); - sidebarPage.waitForPageLoad(); - listingPage.clickRowDetails(groups[1]).clickDetailMenu("Move to"); - - moveGroupModal.clickMove(); - sidebarPage.goToGroups(); - - new GroupDetailPage().checkListSubGroup(groups.slice(0, -1)); - }); - - it("Should move group back", () => { - listingPage.clickRowDetails(groups[1]).clickDetailMenu("Move to"); - - moveGroupModal.clickRow(groups[0]).clickMove(); - sidebarPage.goToGroups(); - - new GroupDetailPage().checkListSubGroup(["group"]); - }); + it("Empty search", () => { + groupPage.searchGroup(" ").assertNoSearchResultsMessageExist(true); }); - it("Group search", () => { - viewHeaderPage.clickAction("searchGroup"); - searchGroupPage.searchGroup("group").clickSearchButton(); - searchGroupPage.checkTerm("group"); + it("Search group that exists", () => { + groupPage + .searchGroup(groupNames[0]) + .assertGroupItemExist(groupNames[0], true); + }); + + it("Search group that does not exists", () => { + groupPage + .searchGroup("not-existent-group") + .assertNoSearchResultsMessageExist(true); + }); + + it("Delete group from item bar", () => { + groupPage + .searchGroup(groupNames[0]) + .deleteGroupItem(groupNames[0]) + .assertNotificationGroupDeleted() + .searchGroup(groupNames[0]) + .assertNoSearchResultsMessageExist(true); + }); + + it("Delete group from search bar", () => { + groupPage + .selectGroupItemCheckbox([groupNames[1]]) + .deleteSelectedGroups() + .assertNotificationGroupDeleted() + .searchGroup(groupNames[1]) + .assertNoSearchResultsMessageExist(true); + }); + + it("Delete groups from search bar", () => { + cy.wrap(null).then(() => + adminClient.createGroup("group_multiple_deletion_test") + ); + cy.reload(); + groupPage + .selectGroupItemCheckboxAllRows() + .deleteSelectedGroups() + .assertNotificationGroupsDeleted() + .assertNoGroupsInThisRealmEmptyStateMessageExist(true); }); }); - describe("Group details", () => { - const groups = ["level", "level1", "level2"]; - const detailPage = new GroupDetailPage(); - + describe("Search group under current group", () => { before(async () => { - const createdGroups = await adminClient.createSubGroups(groups); - for (let i = 0; i < 5; i++) { - const username = "user" + i; - adminClient.createUserInGroup(username, createdGroups[i % 3].id); - } - adminClient.createUser({ username: "new", enabled: true }); + const createdGroups = await adminClient.createSubGroups(predefinedGroups); + await Promise.all([ + range(5).map((index) => { + adminClient.addUserToGroup( + users[index].id!, + createdGroups[index % 3].id + ); + }), + adminClient.createUser({ username: "new", enabled: true }), + ]); }); - beforeEach(() => { - keycloakBefore(); - loginPage.logIn(); - sidebarPage.goToGroups(); + it("Search child group in group", () => { + groupPage + .goToGroupChildGroupsTab(predefinedGroups[0]) + .searchGroup(predefinedGroups[1]) + .goToGroupChildGroupsTab(predefinedGroups[1]) + .searchGroup(predefinedGroups[2]) + .assertGroupItemExist(predefinedGroups[2], true); + }); + + it("Search non existing child group in group", () => { + groupPage + .goToGroupChildGroupsTab(predefinedGroups[0]) + .searchGroup("non-existent-sub-group") + .assertNoSearchResultsMessageExist(true); + }); + + it("Empty search in group", () => { + groupPage + .goToGroupChildGroupsTab(predefinedGroups[0]) + .searchGroup(" ") + .assertNoSearchResultsMessageExist(true); + }); + }); + + describe("Group Actions", () => { + const groupNameDeleteHeaderAction = "group_test_delete_header_action"; + + before(async () => { + await adminClient.createGroup(groupNameDeleteHeaderAction); }); after(async () => { await adminClient.deleteGroups(); - for (let i = 0; i < 5; i++) { - const username = "user" + i; - await adminClient.deleteUser(username); - } - await adminClient.deleteUser("new"); }); - it("Should display all the subgroups", () => { - clickGroup(groups[0]); - detailPage.checkListSubGroup([groups[1]]); + describe("Search globally", () => { + it("Check empty state", () => { + groupPage + .headerActionsearchGroup() + .assertNoSearchResultsMessageExist(true); + }); - const added = "addedGroup"; - groupModal - .open("openCreateGroupModal") - .fillGroupForm(added) - .clickCreate(); + it("Search with multiple words", () => { + groupPage.headerActionsearchGroup(); + searchGroupPage + .searchGroup( + predefinedGroups[0].substr(0, predefinedGroups[0].length / 2) + ) + .assertGroupItemExist(predefinedGroups[0], true) + .searchGroup( + predefinedGroups[0].substr( + predefinedGroups[0].length / 2, + predefinedGroups[0].length + ) + ) + .assertGroupItemExist(predefinedGroups[0], true); + }); - detailPage.checkListSubGroup([added, groups[1]]); + it("Navigate to parent group details", () => { + groupPage.headerActionsearchGroup(); + searchGroupPage + .searchGroup(predefinedGroups[0]) + .goToGroupChildGroupsTab(predefinedGroups[0]) + .assertGroupItemExist(predefinedGroups[1], true); + }); + + it("Navigate to sub-group details", () => { + groupPage.headerActionsearchGroup(); + searchGroupPage + .searchGroup(predefinedGroups[1]) + .goToGroupChildGroupsTab(predefinedGroups[1]) + .assertGroupItemExist(predefinedGroups[2], true); + }); }); - it("Should display members", () => { - clickGroup(groups[0]); - detailPage.clickMembersTab().checkListMembers(["user0", "user3"]); - detailPage - .clickIncludeSubGroups() - .checkListMembers(["user0", "user3", "user1", "user4", "user2"]); + it("Rename group", () => { + groupPage.goToGroupChildGroupsTab(predefinedGroups[0]); + groupDetailPage + .renameGroup("new_group_name") + .assertNotificationGroupUpdated() + .assertHeaderGroupNameEqual("new_group_name") + .renameGroup(predefinedGroups[0]) + .assertNotificationGroupUpdated() + .assertHeaderGroupNameEqual(predefinedGroups[0]); }); - it("Should add members", () => { - clickGroup(groups[0]); - detailPage - .clickMembersTab() - .clickAddMembers() - .checkSelectableMembers(["user1", "user4"]); - detailPage.selectUsers(["new"]).clickAdd(); + it("Delete group from group details", () => { + groupPage.goToGroupChildGroupsTab(groupNameDeleteHeaderAction); + groupDetailPage + .headerActionDeleteGroup() + .assertNotificationGroupDeleted() + .assertGroupItemExist(groupNameDeleteHeaderAction, false); + }); + }); - masthead.checkNotificationMessage("1 user added to the group"); - detailPage.checkListMembers(["new", "user0", "user3"]); + describe("Child Groups", () => { + before(async () => { + await adminClient.createGroup(predefinedGroups[0]); }); - it("Attributes CRUD test", () => { - clickGroup(groups[0]); + after(async () => { + await adminClient.deleteGroups(); + }); + + beforeEach(() => { + groupPage.goToGroupChildGroupsTab(predefinedGroups[0]); + }); + + it("Check empty state", () => { + childGroupsTab.assertNoGroupsInThisSubGroupEmptyStateMessageExist(true); + }); + + it("Create group from empty state", () => { + childGroupsTab + .createGroup(predefinedGroups[1], true) + .assertNotificationGroupCreated(); + }); + + it("Create group from search bar", () => { + childGroupsTab + .createGroup(predefinedGroups[2], false) + .assertNotificationGroupCreated(); + }); + + it("Fail to create group with empty name", () => { + childGroupsTab + .createGroup(" ", false) + .assertNotificationCouldNotCreateGroupWithEmptyName(); + }); + + // https://github.com/keycloak/keycloak-admin-ui/issues/2726 + it.skip("Fail to create group with duplicated name", () => { + childGroupsTab + .createGroup(predefinedGroups[2], false) + .assertNotificationCouldNotCreateGroupWithDuplicatedName( + predefinedGroups[2] + ); + }); + + it("Move group from item bar", () => { + childGroupsTab + .moveGroupItemAction(predefinedGroups[1], [ + predefinedGroups[0], + predefinedGroups[2], + ]) + .goToGroupChildGroupsTab(predefinedGroups[2]) + .assertGroupItemExist(predefinedGroups[1], true); + }); + + it("Search group", () => { + childGroupsTab + .searchGroup(predefinedGroups[2]) + .assertGroupItemExist(predefinedGroups[2], true); + }); + + it("Show child group in groups", () => { + childGroupsTab + .goToGroupChildGroupsTab(predefinedGroups[2]) + .goToGroupChildGroupsTab(predefinedGroups[1]) + .assertNoGroupsInThisSubGroupEmptyStateMessageExist(true); + }); + + it("Delete group from search bar", () => { + childGroupsTab + .goToGroupChildGroupsTab(predefinedGroups[2]) + .selectGroupItemCheckbox([predefinedGroups[1]]) + .deleteSelectedGroups() + .assertNotificationGroupDeleted(); + }); + + it("Delete group from item bar", () => { + childGroupsTab + .deleteGroupItem(predefinedGroups[2]) + .assertNotificationGroupDeleted() + .assertNoGroupsInThisSubGroupEmptyStateMessageExist(true); + }); + }); + + describe("Members", () => { + before(async () => { + const createdGroups = await adminClient.createSubGroups(predefinedGroups); + await Promise.all([ + range(5).map((index) => { + adminClient.addUserToGroup( + users[index].id!, + createdGroups[index % 3].id + ); + }), + adminClient.createGroup(emptyGroup), + ]); + }); + + beforeEach(() => { + groupPage.goToGroupChildGroupsTab(predefinedGroups[0]); + childGroupsTab.goToMembersTab(); + }); + + it("Add member from search bar", () => { + membersTab + .addMember(["new"], false) + .assertNotificationUserAddedToTheGroup(1); + }); + + it("Show members with sub-group users", () => { + membersTab + .assertUserItemExist(users[0].username, true) + .assertUserItemExist("new", true) + .assertUserItemExist(users[3].username, true) + .clickCheckboxIncludeSubGroupUsers() + .assertUserItemExist("new", true) + .assertUserItemExist(users[0].username, true) + .assertUserItemExist(users[1].username, true) + .assertUserItemExist(users[2].username, true) + .assertUserItemExist(users[3].username, true) + .assertUserItemExist(users[4].username, true) + .goToChildGroupsTab() + .goToGroupChildGroupsTab(predefinedGroups[1]) + .goToMembersTab() + .assertUserItemExist(users[1].username, true) + .assertUserItemExist(users[4].username, true) + .goToChildGroupsTab() + .goToGroupChildGroupsTab(predefinedGroups[2]) + .goToMembersTab() + .assertUserItemExist(users[2].username, true); + }); + + it("Add member from empty state", () => { + sidebarPage.goToGroups(); + groupPage.goToGroupChildGroupsTab(emptyGroup); + childGroupsTab.goToMembersTab(); + membersTab + .addMember([users[0].username, users[1].username], true) + .assertNotificationUserAddedToTheGroup(2); + }); + + it("Leave group from search bar", () => { + sidebarPage.goToGroups(); + groupPage.goToGroupChildGroupsTab(emptyGroup); + childGroupsTab.goToMembersTab(); + membersTab + .selectUserItemCheckbox([users[0].username]) + .leaveGroupSelectedUsers() + .assertNotificationUserLeftTheGroup(1) + .assertUserItemExist(users[0].username, false); + }); + + it("Leave group from item bar", () => { + sidebarPage.goToGroups(); + groupPage.goToGroupChildGroupsTab(emptyGroup); + childGroupsTab.goToMembersTab(); + membersTab + .leaveGroupUserItem(users[1].username) + .assertNotificationUserLeftTheGroup(1) + .assertNoUsersFoundEmptyStateMessageExist(true); + }); + }); + + describe("Breadcrumbs", () => { + it("Navigate to parent group", () => { + groupPage + .goToGroupChildGroupsTab(predefinedGroups[0]) + .goToGroupChildGroupsTab(predefinedGroups[1]) + .goToGroupChildGroupsTab(predefinedGroups[2]) + .goToGroupChildGroupsTab(predefinedGroups[3]); + cy.reload(); + groupPage.clickBreadcrumbItem(predefinedGroups[2]); + groupDetailPage.assertHeaderGroupNameEqual(predefinedGroups[2]); + groupPage.clickBreadcrumbItem(predefinedGroups[1]); + groupDetailPage.assertHeaderGroupNameEqual(predefinedGroups[1]); + groupPage.clickBreadcrumbItem(predefinedGroups[0]); + groupDetailPage.assertHeaderGroupNameEqual(predefinedGroups[0]); + groupPage + .clickBreadcrumbItem("Groups") + .assertGroupItemExist(predefinedGroups[0], true); + }); + }); + + describe("Attributes", () => { + beforeEach(() => { + groupPage.goToGroupChildGroupsTab(predefinedGroups[0]); + groupDetailPage.goToAttributesTab(); + }); + + it("Add attribute", () => { + attributesTab.addAttribute("key", "value").save(); + groupPage.assertNotificationGroupUpdated(); + }); + + it("Remove attribute", () => { + attributesTab.deleteAttribute(1).asseertRowItemsEqualTo(1); + groupPage.assertNotificationGroupUpdated(); + }); + + it("Revert changes", () => { attributesTab - .goToAttributesTab() - .fillLastRow("key", "value") - .saveAttribute(); + .addAttribute("key", "value") + .addAnAttributeButton() + .revert() + .asseertRowItemsEqualTo(1); + }); + }); - masthead.checkNotificationMessage("Group updated"); + describe("'Move to' function", () => { + it("Move group to other group", () => { + groupPage + .moveGroupItemAction(predefinedGroups[0], [emptyGroup]) + .goToGroupChildGroupsTab(emptyGroup) + .assertGroupItemExist(predefinedGroups[0], true); + }); + + it("Move group to root", () => { + groupPage + .goToGroupChildGroupsTab(emptyGroup) + .moveGroupItemAction(predefinedGroups[0], ["root"]); + sidebarPage.goToGroups(); + groupPage.assertGroupItemExist(predefinedGroups[0], true); }); }); }); diff --git a/cypress/e2e/user_fed_ldap_hardcoded_mapper_test.spec.ts b/cypress/e2e/user_fed_ldap_hardcoded_mapper_test.spec.ts index e619bbd95d..8c1c5f6c91 100644 --- a/cypress/e2e/user_fed_ldap_hardcoded_mapper_test.spec.ts +++ b/cypress/e2e/user_fed_ldap_hardcoded_mapper_test.spec.ts @@ -7,6 +7,7 @@ import CreateClientPage from "../support/pages/admin_console/manage/clients/Crea import Masthead from "../support/pages/admin_console/Masthead"; import ModalUtils from "../support/util/ModalUtils"; import { keycloakBefore } from "../support/util/keycloak_hooks"; +import GroupPage from "../support/pages/admin_console/manage/groups/GroupPage"; const loginPage = new LoginPage(); const masthead = new Masthead(); @@ -14,6 +15,7 @@ const sidebarPage = new SidebarPage(); const listingPage = new ListingPage(); const groupModal = new GroupModal(); const createClientPage = new CreateClientPage(); +const groupPage = new GroupPage(); const providersPage = new ProviderPage(); const modalUtils = new ModalUtils(); @@ -115,11 +117,8 @@ describe("User Fed LDAP mapper tests", () => { // create a new group it("Create group", () => { sidebarPage.goToGroups(); - groupModal - .open("no-groups-in-this-realm-empty-action") - .fillGroupForm(groupName) - .clickCreate(); - + groupPage.openCreateGroupModal(true); + groupModal.setGroupNameInput(groupName).create(); masthead.checkNotificationMessage(groupCreatedSuccess); }); diff --git a/cypress/e2e/users_test.spec.ts b/cypress/e2e/users_test.spec.ts index 2e5afe9244..b6a380816f 100644 --- a/cypress/e2e/users_test.spec.ts +++ b/cypress/e2e/users_test.spec.ts @@ -141,10 +141,7 @@ describe("User creation", () => { it("User attributes test", () => { listingPage.goToItemDetails(itemId); - attributesTab - .goToAttributesTab() - .fillLastRow("key", "value") - .saveAttribute(); + attributesTab.goToAttributesTab().addAttribute("key", "value").save(); masthead.checkNotificationMessage("The user has been saved"); }); @@ -158,8 +155,8 @@ describe("User creation", () => { const attributeKey = "key-multiple"; attributesTab .goToAttributesTab() - .fillLastRow(attributeKey, "other value") - .saveAttribute(); + .addAttribute(attributeKey, "other value") + .save(); cy.wait("@save-user").should(({ request, response }) => { expect(response?.statusCode).to.equal(204); diff --git a/cypress/support/pages/admin_console/ListingPage.ts b/cypress/support/pages/admin_console/ListingPage.ts index c9e78488ed..a076c4fa18 100644 --- a/cypress/support/pages/admin_console/ListingPage.ts +++ b/cypress/support/pages/admin_console/ListingPage.ts @@ -61,6 +61,8 @@ export default class ListingPage extends CommonElements { private toolbarChangeType = "#change-type-dropdown"; private tableNameColumnPrefix = "name-column-"; private rowGroup = "table:visible tbody[role='rowgroup']"; + private tableHeaderCheckboxItemAllRows = + "input[aria-label='Select all rows']"; showPreviousPageTableItems() { cy.get(this.previousPageBtn).first().click(); @@ -174,6 +176,11 @@ export default class ListingPage extends CommonElements { return this; } + clickTableHeaderItemCheckboxAllRows() { + cy.get(this.tableHeaderCheckboxItemAllRows).click(); + return this; + } + clickRowSelectButton(itemName: string) { cy.get(this.itemsRows) .contains(itemName) diff --git a/cypress/support/pages/admin_console/components/PageObject.ts b/cypress/support/pages/admin_console/components/PageObject.ts index 852480bf06..98934e18d2 100644 --- a/cypress/support/pages/admin_console/components/PageObject.ts +++ b/cypress/support/pages/admin_console/components/PageObject.ts @@ -11,6 +11,9 @@ export default class PageObject { private chipGroup = ".pf-c-chip-group"; private chipGroupCloseBtn = ".pf-c-chip-group__close"; private chipItem = ".pf-c-chip-group__list-item"; + private emptyStateDiv = ".pf-c-empty-state:visible"; + private toolbarActionsButton = ".pf-c-toolbar button[aria-label='Actions']"; + private breadcrumbItem = ".pf-c-breadcrumb .pf-c-breadcrumb__item"; protected assertExist(element: Cypress.Chainable, exist: boolean) { element.should((!exist ? "not." : "") + "exist"); @@ -90,7 +93,7 @@ export default class PageObject { itemName: string, element?: Cypress.Chainable ) { - (element ?? cy.get(this.drpDwnMenuItem)).contains(itemName).click(); + (element ?? cy.get(this.drpDwnMenuItem).contains(itemName)).click(); return this; } @@ -194,7 +197,7 @@ export default class PageObject { itemName: string, element?: Cypress.Chainable ) { - element = element ?? cy.get(this.selectMenuItem); + element = element ?? cy.get(this.selectMenuItem).contains(itemName); return this.clickDropdownMenuItem(itemName, element); } @@ -299,6 +302,12 @@ export default class PageObject { return this; } + protected clickToolbarAction(itemName: string) { + cy.get(this.toolbarActionsButton).click(); + this.clickDropdownMenuItem(itemName); + return this; + } + protected assertChipItemExist(itemName: string, exist: boolean) { cy.get(this.chipItem).within(() => { cy.contains(itemName).should((exist ? "" : "not.") + "exist"); @@ -317,4 +326,18 @@ export default class PageObject { ); return this; } + + protected assertEmptyStateExist(exist: boolean) { + if (exist) { + cy.get(this.emptyStateDiv).should("exist").should("be.visible"); + } else { + cy.get(this.emptyStateDiv).should("not.exist"); + } + return this; + } + + protected clickBreadcrumbItem(itemName: string) { + cy.get(this.breadcrumbItem).contains(itemName).click(); + return this; + } } diff --git a/cypress/support/pages/admin_console/manage/AttributesTab.ts b/cypress/support/pages/admin_console/manage/AttributesTab.ts index 1e156d719d..1df1d614e5 100644 --- a/cypress/support/pages/admin_console/manage/AttributesTab.ts +++ b/cypress/support/pages/admin_console/manage/AttributesTab.ts @@ -1,23 +1,18 @@ export default class AttributesTab { private saveAttributeBtn = "save-attributes"; - private addAttributeBtn = "attribute-add-row"; + private addAttributeBtn = "attributes-add-row"; private attributesTab = "attributes"; private attributeRow = "[data-testid=row]"; private keyInput = (index: number) => `attributes[${index}].key`; private valueInput = (index: number) => `attributes[${index}].value`; - goToAttributesTab() { + public goToAttributesTab() { cy.findByTestId(this.attributesTab).click(); return this; } - addRow() { - cy.findByTestId(this.addAttributeBtn).click(); - return this; - } - - fillLastRow(key: string, value: string) { + public addAttribute(key: string, value: string) { cy.get(this.attributeRow) .its("length") .then((index) => { @@ -27,8 +22,43 @@ export default class AttributesTab { return this; } - saveAttribute() { + public save() { cy.findByTestId(this.saveAttributeBtn).click(); return this; } + + public revert() { + cy.get(".pf-c-button.pf-m-link").contains("Revert").click(); + return this; + } + + public deleteAttributeButton(row: number) { + cy.findByTestId(`attributes[${row - 1}].remove`).click(); + return this; + } + + public addAnAttributeButton() { + cy.findByTestId(this.addAttributeBtn).click(); + return this; + } + + public deleteAttribute(rowIndex: number) { + this.deleteAttributeButton(rowIndex); + this.save(); + + cy.findAllByTestId(`attributes[${rowIndex - 1}].key`).should( + "have.value", + "" + ); + cy.findAllByTestId(`attributes[${rowIndex - 1}].value`).should( + "have.value", + "" + ); + return this; + } + + public asseertRowItemsEqualTo(amount: number) { + cy.findAllByTestId("row").its("length").should("be.eq", amount); + return this; + } } diff --git a/cypress/support/pages/admin_console/manage/clients/ClientRolesTab.ts b/cypress/support/pages/admin_console/manage/clients/ClientRolesTab.ts index 08404c323c..0cb669f003 100644 --- a/cypress/support/pages/admin_console/manage/clients/ClientRolesTab.ts +++ b/cypress/support/pages/admin_console/manage/clients/ClientRolesTab.ts @@ -53,44 +53,6 @@ export default class ClientRolesTab extends CommonPage { return this; } - clickAddAnAttributeButton() { - cy.findByTestId("attributes-add-row").click(); - return this; - } - - clickDeleteAttributeButton(row: number) { - cy.findByTestId(`attributes[${row - 1}].remove`).click(); - return this; - } - - addAttribute(rowIndex: number, key: string, value: string) { - cy.findAllByTestId(`attributes[${rowIndex - 1}].key`).type(key); - cy.findAllByTestId(`attributes[${rowIndex - 1}].value`).type(value); - this.clickAddAnAttributeButton(); - this.formUtils().save(); - return this; - } - - deleteAttribute(rowIndex: number) { - this.clickDeleteAttributeButton(rowIndex); - this.formUtils().save(); - - cy.findAllByTestId(`attributes[${rowIndex - 1}].key`).should( - "have.value", - "" - ); - cy.findAllByTestId(`attributes[${rowIndex - 1}].value`).should( - "have.value", - "" - ); - return this; - } - - checkRowItemsEqualTo(amount: number) { - cy.findAllByTestId("row").its("length").should("be.eq", amount); - return this; - } - hideInheritedRoles() { cy.get(this.hideInheritedRolesChkBox).check(); return this; diff --git a/cypress/support/pages/admin_console/manage/groups/GroupDetailPage.ts b/cypress/support/pages/admin_console/manage/groups/GroupDetailPage.ts deleted file mode 100644 index 7197d84cf1..0000000000 --- a/cypress/support/pages/admin_console/manage/groups/GroupDetailPage.ts +++ /dev/null @@ -1,73 +0,0 @@ -const expect = chai.expect; - -export default class GroupDetailPage { - private groupNamesColumn = '[data-label="Group name"] > a'; - private memberTab = "members"; - private memberNameColumn = - '[data-testid="members-table"] > tbody > tr > [data-label="Name"]'; - private includeSubGroupsCheck = "includeSubGroupsCheck"; - private addMembers = "addMember"; - private addMember = "add"; - private memberUsernameColumn = 'tbody > tr > [data-label="Username"]'; - - checkListSubGroup(subGroups: string[]) { - cy.get(this.groupNamesColumn).should((groups) => { - expect(groups).to.have.length(subGroups.length); - for (let index = 0; index < subGroups.length; index++) { - const subGroup = subGroups[index]; - expect(groups).to.contain(subGroup); - } - }); - return this; - } - - clickMembersTab() { - cy.findByTestId(this.memberTab).click(); - return this; - } - - checkListMembers(members: string[]) { - cy.get(this.memberNameColumn).should((member) => { - expect(member).to.have.length(members.length); - for (let index = 0; index < members.length; index++) { - expect(member.eq(index)).to.contain(members[index]); - } - }); - return this; - } - - checkSelectableMembers(members: string[]) { - cy.get(this.memberUsernameColumn).should((member) => { - for (const user of members) { - expect(member).to.contain(user); - } - }); - return this; - } - - selectUsers(users: string[]) { - for (const user of users) { - cy.get(this.memberUsernameColumn) - .contains(user) - .parent() - .find("input") - .click(); - } - return this; - } - - clickAdd() { - cy.findByTestId(this.addMember).click(); - return this; - } - - clickIncludeSubGroups() { - cy.findByTestId(this.includeSubGroupsCheck).click(); - return this; - } - - clickAddMembers() { - cy.findByTestId(this.addMembers).click(); - return this; - } -} diff --git a/cypress/support/pages/admin_console/manage/groups/GroupModal.ts b/cypress/support/pages/admin_console/manage/groups/GroupModal.ts index 3f9743a7a1..e61eb295ad 100644 --- a/cypress/support/pages/admin_console/manage/groups/GroupModal.ts +++ b/cypress/support/pages/admin_console/manage/groups/GroupModal.ts @@ -1,30 +1,30 @@ -export default class GroupModal { - private nameInput = "groupNameInput"; - private createButton = "createGroup"; +import ModalUtils from "../../../../util/ModalUtils"; + +export default class GroupModal extends ModalUtils { + private createGroupModalTitle = "Create a group"; + private groupNameInput = "groupNameInput"; + private createGroupBnt = "createGroup"; private renameButton = "renameGroup"; - open(name?: string) { - if (name) { - cy.findByTestId(name).click(); - } else { - cy.get("button").contains("Create").click(); - } + public setGroupNameInput(name: string) { + cy.findByTestId(this.groupNameInput).clear().type(name); return this; } - fillGroupForm(name = "") { - cy.findByTestId(this.nameInput).clear().type(name); + public create() { + cy.findByTestId(this.createGroupBnt).click(); return this; } - clickCreate() { - cy.findByTestId(this.createButton).click(); - - return this; - } - - clickRename() { + public rename() { cy.findByTestId(this.renameButton).click(); return this; } + + public assertCreateGroupModalVisible(isVisible: boolean) { + super + .assertModalVisible(isVisible) + .assertModalTitleEqual(this.createGroupModalTitle); + return this; + } } diff --git a/cypress/support/pages/admin_console/manage/groups/GroupPage.ts b/cypress/support/pages/admin_console/manage/groups/GroupPage.ts new file mode 100644 index 0000000000..e70f89d55b --- /dev/null +++ b/cypress/support/pages/admin_console/manage/groups/GroupPage.ts @@ -0,0 +1,177 @@ +import PageObject from "../../components/PageObject"; +import ListingPage from "../../ListingPage"; +import Masthead from "../../Masthead"; +import SidebarPage from "../../SidebarPage"; +import GroupModal from "./GroupModal"; +import MoveGroupModal from "./MoveGroupModal"; + +const groupModal = new GroupModal(); +const moveGroupModal = new MoveGroupModal(); +const listingPage = new ListingPage(); +const masthead = new Masthead(); +const sidebarPage = new SidebarPage(); + +export default class GroupPage extends PageObject { + protected createGroupEmptyStateBtn = "no-groups-in-this-realm-empty-action"; + private createGroupBtn = "openCreateGroupModal"; + protected actionDrpDwnButton = "action-dropdown"; + private actionDrpDwnItemSearchGroup = "searchGroup"; + + public openCreateGroupModal(emptyState: boolean) { + if (emptyState) { + cy.findByTestId(this.createGroupEmptyStateBtn).click(); + } else { + cy.findByTestId(this.createGroupBtn).click(); + } + return this; + } + + public createGroup(groupName: string, emptyState: boolean) { + this.openCreateGroupModal(emptyState); + groupModal + .assertCreateGroupModalVisible(true) + .setGroupNameInput(groupName) + .create(); + cy.intercept("POST", "*/admin/realms/master/groups").as("post"); + return this; + } + + public searchGroup(groupName: string) { + listingPage.searchItem(groupName, false); + return this; + } + + public headerActionsearchGroup() { + super.openDropdownMenu("", cy.findByTestId(this.actionDrpDwnButton)); + super.clickDropdownMenuItem( + "", + cy.findByTestId(this.actionDrpDwnItemSearchGroup) + ); + return this; + } + + public goToGroupChildGroupsTab(groupName: string) { + listingPage.goToItemDetails(groupName); + cy.intercept("GET", "*/admin/realms/master/groups/*").as("get"); + sidebarPage.waitForPageLoad(); + return this; + } + + public selectGroupItemCheckbox(items: string[]) { + for (const item of items) { + listingPage.clickItemCheckbox(item); + } + return this; + } + + public selectGroupItemCheckboxAllRows() { + listingPage.clickTableHeaderItemCheckboxAllRows(); + return this; + } + + public deleteSelectedGroups(confirmModal = true) { + this.clickToolbarAction("Delete"); + if (confirmModal) { + groupModal.confirmModal(); + } + return this; + } + + public deleteGroupItem(groupName: string, confirmModal = true) { + listingPage.deleteItem(groupName); + if (confirmModal) { + groupModal.confirmModal(); + } + return this; + } + + public moveGroupItemAction( + groupName: string, + destinationGroupName: string[] + ) { + listingPage.clickRowDetails(groupName); + listingPage.clickDetailMenu("Move to"); + moveGroupModal + .assertModalVisible(true) + .assertModalTitleEqual(`Move ${groupName} to root`); + if (!destinationGroupName.includes("root")) { + for (const destination of destinationGroupName) { + moveGroupModal + .clickRow(destination) + .assertModalTitleEqual(`Move ${groupName} to ${destination}`); + } + } + moveGroupModal.clickMove(); + this.assertNotificationGroupMoved(); + moveGroupModal.assertModalExist(false); + return this; + } + + public clickBreadcrumbItem(groupName: string) { + super.clickBreadcrumbItem(groupName); + return this; + } + + public assertGroupItemExist(groupName: string, exist: boolean) { + listingPage.itemExist(groupName, exist); + return this; + } + + public assertNoGroupsInThisRealmEmptyStateMessageExist(exist: boolean) { + this.assertEmptyStateExist(exist); + return this; + } + + public assertGroupItemsEqual(number: number) { + listingPage.itemsEqualTo(number); + return this; + } + + public assertNoSearchResultsMessageExist(exist: boolean) { + super.assertEmptyStateExist(exist); + return this; + } + + public assertNotificationGroupDeleted() { + masthead.checkNotificationMessage("Group deleted"); + return this; + } + + public assertNotificationGroupsDeleted() { + masthead.checkNotificationMessage("Groups deleted"); + return this; + } + + public assertNotificationGroupCreated() { + masthead.checkNotificationMessage("Group created"); + return this; + } + + public assertNotificationGroupMoved() { + masthead.checkNotificationMessage("Group moved"); + return this; + } + + public assertNotificationGroupUpdated() { + masthead.checkNotificationMessage("Group updated"); + return this; + } + + public assertNotificationCouldNotCreateGroupWithEmptyName() { + masthead.checkNotificationMessage( + "Could not create group Group name is missing" + ); + return this; + } + + public assertNotificationCouldNotCreateGroupWithDuplicatedName( + groupName: string + ) { + masthead.checkNotificationMessage( + "Could not create group Top level group named '" + + groupName + + "' already exists." + ); + return this; + } +} diff --git a/cypress/support/pages/admin_console/manage/groups/MoveGroupModal.ts b/cypress/support/pages/admin_console/manage/groups/MoveGroupModal.ts index c2b71da7b0..29c49ddf5a 100644 --- a/cypress/support/pages/admin_console/manage/groups/MoveGroupModal.ts +++ b/cypress/support/pages/admin_console/manage/groups/MoveGroupModal.ts @@ -1,4 +1,6 @@ -export default class MoveGroupModal { +import ModalUtils from "../../../../util/ModalUtils"; + +export default class MoveGroupModal extends ModalUtils { private moveButton = "groups:moveHere-button"; private title = ".pf-c-modal-box__title"; diff --git a/cypress/support/pages/admin_console/manage/groups/SearchGroup.ts b/cypress/support/pages/admin_console/manage/groups/SearchGroup.ts deleted file mode 100644 index d313d0b579..0000000000 --- a/cypress/support/pages/admin_console/manage/groups/SearchGroup.ts +++ /dev/null @@ -1,19 +0,0 @@ -export class SearchGroupPage { - private searchField = "group-search"; - private searchButton = "search-button"; - - searchGroup(search: string) { - cy.findByTestId(this.searchField).type(search); - return this; - } - - clickSearchButton() { - cy.findByTestId(this.searchButton).click(); - return this; - } - - checkTerm(searchTerm: string) { - cy.get(".pf-c-chip-group").children().contains(searchTerm).should("exist"); - return this; - } -} diff --git a/cypress/support/pages/admin_console/manage/groups/SearchGroupPage.ts b/cypress/support/pages/admin_console/manage/groups/SearchGroupPage.ts new file mode 100644 index 0000000000..37deb10f73 --- /dev/null +++ b/cypress/support/pages/admin_console/manage/groups/SearchGroupPage.ts @@ -0,0 +1,27 @@ +import GroupPage from "./GroupPage"; + +export class SearchGroupPage extends GroupPage { + private searchField = "group-search"; + private searchButton = "search-button"; + + public searchGroup(groupName: string) { + this.typeSearchInput(groupName); + this.clickSearchButton(); + return this; + } + + public typeSearchInput(value: string) { + cy.findByTestId(this.searchField).type(value); + return this; + } + + public clickSearchButton() { + cy.findByTestId(this.searchButton).click(); + return this; + } + + public checkTerm(searchTerm: string) { + cy.get(".pf-c-chip-group").children().contains(searchTerm).should("exist"); + return this; + } +} diff --git a/cypress/support/pages/admin_console/manage/groups/group_details/GroupDetailPage.ts b/cypress/support/pages/admin_console/manage/groups/group_details/GroupDetailPage.ts new file mode 100644 index 0000000000..d2831aee81 --- /dev/null +++ b/cypress/support/pages/admin_console/manage/groups/group_details/GroupDetailPage.ts @@ -0,0 +1,130 @@ +import ModalUtils from "../../../../../util/ModalUtils"; +import GroupPage from "../GroupPage"; + +const modalUtils = new ModalUtils(); + +export default class GroupDetailPage extends GroupPage { + private groupNamesColumn = '[data-label="Group name"] > a'; + private memberTab = "members"; + private childGroupsTab = "groups"; + private attributesTab = "attributes"; + private roleMappingTab = "role-mapping-tab"; + private memberNameColumn = + '[data-testid="members-table"] > tbody > tr > [data-label="Name"]'; + private addMembers = "addMember"; + private memberUsernameColumn = 'tbody > tr > [data-label="Username"]'; + private actionDrpDwnItemRenameGroup = "renameGroupAction"; + private actionDrpDwnItemDeleteGroup = "deleteGroup"; + private headerGroupName = ".pf-l-level.pf-m-gutter"; + private renameGroupModalGroupNameInput = "groupNameInput"; + private renameGroupModalRenameBtn = "renameGroup"; + + public goToChildGroupsTab() { + cy.findByTestId(this.childGroupsTab).click(); + return this; + } + + public goToMembersTab() { + cy.findByTestId(this.memberTab).click(); + return this; + } + + public goToAttributesTab() { + cy.findByTestId(this.attributesTab).click(); + return this; + } + + public goToRoleMappingTab() { + cy.findByTestId(this.roleMappingTab).click(); + return this; + } + + public headerActionRenameGroup() { + super.openDropdownMenu("", cy.findByTestId(this.actionDrpDwnButton)); + super.clickDropdownMenuItem( + "", + cy.findByTestId(this.actionDrpDwnItemRenameGroup) + ); + return this; + } + + public headerActionDeleteGroup() { + super.openDropdownMenu("", cy.findByTestId(this.actionDrpDwnButton)); + super.clickDropdownMenuItem( + "", + cy.findByTestId(this.actionDrpDwnItemDeleteGroup) + ); + return this; + } + + public renameGroup(newGroupName: string) { + this.headerActionRenameGroup(); + modalUtils.checkModalTitle("Rename group"); + cy.findByTestId(this.renameGroupModalGroupNameInput) + .clear() + .type(newGroupName); + cy.findByTestId(this.renameGroupModalRenameBtn).click(); + return this; + } + + public deleteGroupHeaderAction() { + this.headerActionDeleteGroup(); + return this; + } + + public assertHeaderGroupNameEqual(groupName: string) { + cy.get(this.headerGroupName).find("h1").should("have.text", groupName); + return this; + } + + checkListSubGroup(subGroups: string[]) { + cy.get(this.groupNamesColumn).should((groups) => { + expect(groups).to.have.length(subGroups.length); + for (let index = 0; index < subGroups.length; index++) { + const subGroup = subGroups[index]; + expect(groups).to.contain(subGroup); + } + }); + return this; + } + + clickMembersTab() { + cy.findByTestId(this.memberTab).click(); + return this; + } + + checkListMembers(members: string[]) { + cy.get(this.memberNameColumn).should((member) => { + expect(member).to.have.length(members.length); + for (let index = 0; index < members.length; index++) { + expect(member.eq(index)).to.contain(members[index]); + } + }); + return this; + } + + checkSelectableMembers(members: string[]) { + cy.get(this.memberUsernameColumn).should((member) => { + for (const user of members) { + expect(member).to.contain(user); + } + }); + return this; + } + + selectUsers(users: string[]) { + for (const user of users) { + cy.get(this.memberUsernameColumn) + .contains(user) + .parent() + .find("input") + .click(); + } + return this; + } + + clickAddMembers() { + cy.findByTestId(this.addMembers).click(); + return this; + } +} diff --git a/cypress/support/pages/admin_console/manage/groups/group_details/tabs/ChildGroupsTab.ts b/cypress/support/pages/admin_console/manage/groups/group_details/tabs/ChildGroupsTab.ts new file mode 100644 index 0000000000..25f8e5e954 --- /dev/null +++ b/cypress/support/pages/admin_console/manage/groups/group_details/tabs/ChildGroupsTab.ts @@ -0,0 +1,11 @@ +import GroupDetailPage from "../GroupDetailPage"; + +export default class ChildGroupsTab extends GroupDetailPage { + protected createGroupEmptyStateBtn = + "no-groups-in-this-sub-group-empty-action"; + + public assertNoGroupsInThisSubGroupEmptyStateMessageExist(exist: boolean) { + super.assertEmptyStateExist(exist); + return this; + } +} diff --git a/cypress/support/pages/admin_console/manage/groups/group_details/tabs/MembersTab.ts b/cypress/support/pages/admin_console/manage/groups/group_details/tabs/MembersTab.ts new file mode 100644 index 0000000000..12e88baaf1 --- /dev/null +++ b/cypress/support/pages/admin_console/manage/groups/group_details/tabs/MembersTab.ts @@ -0,0 +1,85 @@ +import ModalUtils from "../../../../../../util/ModalUtils"; +import ListingPage from "../../../../ListingPage"; +import Masthead from "../../../../Masthead"; +import SidebarPage from "../../../../SidebarPage"; +import GroupDetailPage from "../GroupDetailPage"; + +const modalUtils = new ModalUtils(); +const listingPage = new ListingPage(); +const masthead = new Masthead(); +const sidebarPage = new SidebarPage(); + +export default class MembersTab extends GroupDetailPage { + private addMemberEmptyStateBtn = "no-users-found-empty-action"; + private addMemberBtn = "addMember"; + private includeSubGroupsCheck = "includeSubGroupsCheck"; + + public openAddMemberModal(emptyState: boolean) { + cy.intercept("GET", "*/admin/realms/master/users?first=*").as("get"); + if (emptyState) { + cy.findByTestId(this.addMemberEmptyStateBtn).click(); + } else { + cy.findByTestId(this.addMemberBtn).click(); + } + sidebarPage.waitForPageLoad(); + return this; + } + + public addMember(usernames: string[], emptyState: boolean) { + this.openAddMemberModal(emptyState); + modalUtils.assertModalVisible(true).assertModalTitleEqual("Add member"); + for (const username of usernames) { + listingPage.clickItemCheckbox(username); + } + modalUtils.add(); + modalUtils.assertModalExist(false); + return this; + } + + public selectUserItemCheckbox(items: string[]) { + for (const item of items) { + listingPage.clickItemCheckbox(item); + } + return this; + } + + public leaveGroupSelectedUsers() { + this.clickToolbarAction("Leave group"); + return this; + } + + public leaveGroupUserItem(username: string) { + listingPage.clickRowDetails(username); + listingPage.clickDetailMenu("Leave group"); + return this; + } + + public clickCheckboxIncludeSubGroupUsers() { + cy.findByTestId(this.includeSubGroupsCheck).click(); + return this; + } + + public assertNotificationUserAddedToTheGroup(amount: number) { + masthead.checkNotificationMessage( + `${amount} user${amount > 1 ? "s" : ""} added to the group` + ); + return this; + } + + public assertNotificationUserLeftTheGroup(amount: number) { + masthead.checkNotificationMessage( + `${amount} user${amount > 1 ? "s" : ""} left the group` + ); + return this; + } + + public assertNoUsersFoundEmptyStateMessageExist(exist: boolean) { + super.assertEmptyStateExist(exist); + return this; + } + + public assertUserItemExist(username: string, exist: boolean) { + listingPage.itemExist(username, exist); + return this; + } +} diff --git a/cypress/support/pages/admin_console/manage/groups/group_details/tabs/PermissionsTab.ts b/cypress/support/pages/admin_console/manage/groups/group_details/tabs/PermissionsTab.ts new file mode 100644 index 0000000000..c7027e53f0 --- /dev/null +++ b/cypress/support/pages/admin_console/manage/groups/group_details/tabs/PermissionsTab.ts @@ -0,0 +1,3 @@ +import GroupDetailPage from "../GroupDetailPage"; + +export default class PermissionsTab extends GroupDetailPage {} diff --git a/cypress/support/util/AdminClient.ts b/cypress/support/util/AdminClient.ts index b56cb49794..9d4f4db8ad 100644 --- a/cypress/support/util/AdminClient.ts +++ b/cypress/support/util/AdminClient.ts @@ -95,6 +95,11 @@ class AdminClient { return await this.client.users.create(user); } + async addUserToGroup(userId: string, groupId: string) { + await this.login(); + await this.client.users.addToGroup({ id: userId, groupId }); + } + async createUserInGroup(username: string, groupId: string) { await this.login(); const user = await this.createUser({ username, enabled: true }); diff --git a/cypress/support/util/ModalUtils.ts b/cypress/support/util/ModalUtils.ts index c52a4abff5..1b879665d6 100644 --- a/cypress/support/util/ModalUtils.ts +++ b/cypress/support/util/ModalUtils.ts @@ -1,7 +1,8 @@ +import PageObject from "../pages/admin_console/components/PageObject"; import TablePage from "../pages/admin_console/components/TablePage"; -import CommonElements from "../pages/CommonElements"; -export default class ModalUtils extends CommonElements { +export default class ModalUtils extends PageObject { + private modalDiv = ".pf-c-modal-box"; private modalTitle = ".pf-c-modal-box .pf-c-modal-box__title-text"; private modalMessage = ".pf-c-modal-box .pf-c-modal-box__body"; private confirmModalBtn = "confirm"; @@ -10,18 +11,16 @@ export default class ModalUtils extends CommonElements { private copyToClipboardBtn = '[id*="copy-button"]'; private addModalDropdownBtn = "#add-dropdown > button"; private addModalDropdownItem = "#add-dropdown [role='menuitem']"; + private primaryBtn = ".pf-c-button.pf-m-primary"; + private addBtn = "add"; private tablePage = new TablePage(TablePage.tableSelector); - constructor() { - super(".pf-c-modal-box"); - } - table() { return this.tablePage; } add() { - cy.get(this.primaryBtn).contains("Add").click(); + cy.findByTestId(this.addBtn).click(); return this; } @@ -69,8 +68,8 @@ export default class ModalUtils extends CommonElements { } checkModalTitle(title: string) { - cy.get(this.modalTitle).invoke("text").should("eq", title); - + //deprecated + this.assertModalTitleEqual(title); return this; } @@ -86,9 +85,24 @@ export default class ModalUtils extends CommonElements { } assertModalHasElement(elementSelector: string, exist: boolean) { - cy.get(this.parentSelector) + cy.get(this.modalDiv) .find(elementSelector) .should((exist ? "" : ".not") + "exist"); return this; } + + assertModalVisible(isVisible: boolean) { + super.assertIsVisible(cy.get(this.modalDiv), isVisible); + return this; + } + + assertModalExist(exist: boolean) { + super.assertExist(cy.get(this.modalDiv), exist); + return this; + } + + assertModalTitleEqual(text: string) { + cy.get(this.modalTitle).invoke("text").should("eq", text); + return this; + } }