using smarter wait to fix group tests (#604)

* using smarter wait

instead of static waiting wait for the memeber query to finish

* revert

* query less by creating navigation on click

* only search in the displayed table

* fixed test
This commit is contained in:
Erik Jan de Wit 2021-05-18 14:25:46 +02:00 committed by GitHub
parent 2c23807742
commit a9a34102bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 66 deletions

View file

@ -22,8 +22,17 @@ describe("Group test", () => {
let groupName = "group"; let groupName = "group";
const clickGroup = (itemName: string) => {
const membersUrl = `/auth/admin/realms/master/groups/*/members`;
cy.intercept(membersUrl).as("groupFetch");
cy.get("table").contains(itemName).click();
cy.wait(["@groupFetch"]);
return this;
};
describe("Group creation", () => { describe("Group creation", () => {
beforeEach(function () { beforeEach(() => {
keycloakBefore(); keycloakBefore();
loginPage.logIn(); loginPage.logIn();
sidebarPage.goToGroups(); sidebarPage.goToGroups();
@ -52,7 +61,7 @@ describe("Group test", () => {
.open("empty-primary-action") .open("empty-primary-action")
.fillGroupForm(groupName) .fillGroupForm(groupName)
.clickCreate(); .clickCreate();
listingPage.goToItemDetails(groupName); clickGroup(groupName);
viewHeaderPage.clickAction("renameGroupAction"); viewHeaderPage.clickAction("renameGroupAction");
const newName = "Renamed group"; const newName = "Renamed group";
@ -62,6 +71,7 @@ describe("Group test", () => {
sidebarPage.goToGroups(); sidebarPage.goToGroups();
listingPage.searchItem(newName, false).itemExist(newName); listingPage.searchItem(newName, false).itemExist(newName);
listingPage.deleteItem(newName); listingPage.deleteItem(newName);
masthead.checkNotificationMessage("Group deleted");
}); });
it("Should move group", () => { it("Should move group", () => {
@ -78,12 +88,12 @@ describe("Group test", () => {
moveGroupModal.clickMove(); moveGroupModal.clickMove();
masthead.checkNotificationMessage("Group moved"); masthead.checkNotificationMessage("Group moved");
listingPage.itemExist(groupName, false).goToItemDetails(targetGroupName); listingPage.itemExist(groupName, false);
cy.wait(2000); clickGroup(targetGroupName);
listingPage.itemExist(groupName); listingPage.itemExist(groupName);
cy.wait(1000);
sidebarPage.goToGroups(); sidebarPage.goToGroups();
listingPage.deleteItem(targetGroupName); listingPage.deleteItem(targetGroupName);
masthead.checkNotificationMessage("Group deleted");
}); });
it("Should move group to root", async () => { it("Should move group to root", async () => {
@ -141,7 +151,7 @@ describe("Group test", () => {
}); });
it("Should display all the subgroups", () => { it("Should display all the subgroups", () => {
listingPage.goToItemDetails(groups[0]); clickGroup(groups[0]);
detailPage.checkListSubGroup([groups[1]]); detailPage.checkListSubGroup([groups[1]]);
const added = "addedGroup"; const added = "addedGroup";
@ -151,7 +161,7 @@ describe("Group test", () => {
}); });
it("Should display members", () => { it("Should display members", () => {
listingPage.goToItemDetails(groups[0]); clickGroup(groups[0]);
detailPage.clickMembersTab().checkListMembers(["user0", "user3"]); detailPage.clickMembersTab().checkListMembers(["user0", "user3"]);
detailPage detailPage
.clickIncludeSubGroups() .clickIncludeSubGroups()
@ -159,7 +169,7 @@ describe("Group test", () => {
}); });
it("Should add members", () => { it("Should add members", () => {
listingPage.goToItemDetails(groups[0]); clickGroup(groups[0]);
detailPage detailPage
.clickMembersTab() .clickMembersTab()
.clickAddMembers() .clickAddMembers()
@ -171,7 +181,7 @@ describe("Group test", () => {
}); });
it("Attributes CRUD test", () => { it("Attributes CRUD test", () => {
listingPage.goToItemDetails(groups[0]); clickGroup(groups[0]);
detailPage detailPage
.clickAttributesTab() .clickAttributesTab()
.fillAttribute("key", "value") .fillAttribute("key", "value")

View file

@ -229,14 +229,12 @@ export function KeycloakDataTable<T>({
return node.map(getNodeText).join(""); return node.map(getNodeText).join("");
} }
if (typeof node === "object" && node) { if (typeof node === "object" && node) {
if ((node as TitleCell).title) {
return getNodeText( return getNodeText(
isValidElement((node as TitleCell).title) isValidElement((node as TitleCell).title)
? (node as TitleCell).title.props.children ? (node as TitleCell).title.props.children
: (node as JSX.Element).props.children : (node as JSX.Element).props.children
); );
} }
}
return ""; return "";
}; };

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react"; import React, { useState } from "react";
import { Link, useHistory, useLocation } from "react-router-dom"; import { Link, useHistory, useLocation } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import _ from "lodash"; import _ from "lodash";
@ -14,7 +14,6 @@ import { UsersIcon } from "@patternfly/react-icons";
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation"; import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
import { useAdminClient } from "../context/auth/AdminClient"; import { useAdminClient } from "../context/auth/AdminClient";
import { useSubGroups } from "./SubGroupsContext";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
@ -22,6 +21,7 @@ import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
import { GroupsModal } from "./GroupsModal"; import { GroupsModal } from "./GroupsModal";
import { getLastId } from "./groupIdUtils"; import { getLastId } from "./groupIdUtils";
import { MoveGroupDialog } from "./MoveGroupDialog"; import { MoveGroupDialog } from "./MoveGroupDialog";
import { useSubGroups } from "./SubGroupsContext";
type GroupTableData = GroupRepresentation & { type GroupTableData = GroupRepresentation & {
membersLength?: number; membersLength?: number;
@ -38,7 +38,7 @@ export const GroupTable = () => {
const [selectedRows, setSelectedRows] = useState<GroupRepresentation[]>([]); const [selectedRows, setSelectedRows] = useState<GroupRepresentation[]>([]);
const [move, setMove] = useState<GroupTableData>(); const [move, setMove] = useState<GroupTableData>();
const { subGroups } = useSubGroups(); const { subGroups, setSubGroups } = useSubGroups();
const [key, setKey] = useState(0); const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime()); const refresh = () => setKey(new Date().getTime());
@ -47,30 +47,15 @@ export const GroupTable = () => {
const location = useLocation(); const location = useLocation();
const id = getLastId(location.pathname); const id = getLastId(location.pathname);
useEffect(() => {
refresh();
}, [subGroups]);
const getMembers = async (id: string) => { const getMembers = async (id: string) => {
const response = await adminClient.groups.listMembers({ id }); const response = await adminClient.groups.listMembers({ id });
return response ? response.length : 0; return response ? response.length : 0;
}; };
const loader = async (first?: number, max?: number, search?: string) => { const loader = async () => {
const params: { [name: string]: string | number } = {
first: first!,
max: max!,
};
const searchParam = search || "";
if (searchParam) {
params.search = searchParam;
}
const groupsData = id const groupsData = id
? (await adminClient.groups.findOne({ id, ...params })).subGroups ? (await adminClient.groups.findOne({ id })).subGroups
: await adminClient.groups.find(params); : await adminClient.groups.find();
if (groupsData) { if (groupsData) {
const memberPromises = groupsData.map((group) => getMembers(group.id!)); const memberPromises = groupsData.map((group) => getMembers(group.id!));
@ -111,7 +96,14 @@ export const GroupTable = () => {
const GroupNameCell = (group: GroupTableData) => ( const GroupNameCell = (group: GroupTableData) => (
<> <>
<Link key={group.id} to={`${location.pathname}/${group.id}`}> <Link
key={group.id}
to={`${location.pathname}/${group.id}`}
onClick={() => {
delete group.membersLength;
setSubGroups([...subGroups, group]);
}}
>
{group.name} {group.name}
</Link> </Link>
</> </>
@ -131,8 +123,7 @@ export const GroupTable = () => {
return ( return (
<> <>
<KeycloakDataTable <KeycloakDataTable
key={key} key={`${id}${key}`}
isPaginated
onSelect={(rows) => setSelectedRows([...rows])} onSelect={(rows) => setSelectedRows([...rows])}
canSelectAll={false} canSelectAll={false}
loader={loader} loader={loader}

View file

@ -60,8 +60,8 @@ export const GroupsSection = () => {
asyncStateFetch( asyncStateFetch(
async () => { async () => {
const ids = getId(location.pathname); const ids = getId(location.pathname);
const isNavigationStateInValid = const isNavigationStateInValid = ids && ids.length > subGroups.length;
ids && ids.length !== subGroups.length + 1;
if (isNavigationStateInValid) { if (isNavigationStateInValid) {
const groups: GroupRepresentation[] = []; const groups: GroupRepresentation[] = [];
for (const i of ids!) { for (const i of ids!) {
@ -69,20 +69,12 @@ export const GroupsSection = () => {
if (group) groups.push(group); if (group) groups.push(group);
} }
return groups; return groups;
} else {
if (id) {
const group = await adminClient.groups.findOne({ id: id });
if (group) {
return [...subGroups, group];
} else {
return subGroups;
}
} else {
return subGroups;
}
} }
return [];
},
(groups: GroupRepresentation[]) => {
if (groups.length) setSubGroups(groups);
}, },
(groups: GroupRepresentation[]) => setSubGroups(groups),
errorHandler errorHandler
), ),
[id] [id]

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react"; import React, { useState } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import _ from "lodash"; import _ from "lodash";
@ -35,7 +35,7 @@ export const Members = () => {
const location = useLocation(); const location = useLocation();
const id = getLastId(location.pathname); const id = getLastId(location.pathname);
const [includeSubGroup, setIncludeSubGroup] = useState(false); const [includeSubGroup, setIncludeSubGroup] = useState(false);
const { currentGroup, subGroups } = useSubGroups(); const { currentGroup } = useSubGroups();
const [addMembers, setAddMembers] = useState(false); const [addMembers, setAddMembers] = useState(false);
const [isKebabOpen, setIsKebabOpen] = useState(false); const [isKebabOpen, setIsKebabOpen] = useState(false);
const [selectedRows, setSelectedRows] = useState<UserRepresentation[]>([]); const [selectedRows, setSelectedRows] = useState<UserRepresentation[]>([]);
@ -43,10 +43,6 @@ export const Members = () => {
const [key, setKey] = useState(0); const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime()); const refresh = () => setKey(new Date().getTime());
useEffect(() => {
refresh();
}, [id, subGroups, includeSubGroup]);
const getMembership = async (id: string) => const getMembership = async (id: string) =>
await adminClient.users.listGroups({ id: id! }); await adminClient.users.listGroups({ id: id! });
@ -107,7 +103,7 @@ export const Members = () => {
/> />
)} )}
<KeycloakDataTable <KeycloakDataTable
key={key} key={`${id}${key}${includeSubGroup}`}
loader={loader} loader={loader}
ariaLabelKey="groups:members" ariaLabelKey="groups:members"
isPaginated isPaginated

View file

@ -25,10 +25,7 @@ export const SubGroups = ({ children }: { children: ReactNode }) => {
const clear = () => setSubGroups([]); const clear = () => setSubGroups([]);
const remove = (group: GroupRepresentation) => const remove = (group: GroupRepresentation) =>
setSubGroups( setSubGroups(
subGroups.slice( subGroups.slice(0, subGroups.findIndex((g) => g.id === group.id) + 1)
0,
subGroups.findIndex((g) => g.id === group.id)
)
); );
const currentGroup = () => subGroups[subGroups.length - 1]; const currentGroup = () => subGroups[subGroups.length - 1];
return ( return (