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:
parent
2c23807742
commit
a9a34102bc
6 changed files with 50 additions and 66 deletions
|
@ -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 () => {
|
||||||
|
@ -102,7 +112,7 @@ describe("Group test", () => {
|
||||||
listingPage.deleteItem(groups[0]);
|
listingPage.deleteItem(groups[0]);
|
||||||
listingPage.deleteItem(groups[1]);
|
listingPage.deleteItem(groups[1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Group search", () => {
|
it("Group search", () => {
|
||||||
viewHeaderPage.clickAction("searchGroup");
|
viewHeaderPage.clickAction("searchGroup");
|
||||||
searchGroupPage.searchGroup("group").clickSearchButton();
|
searchGroupPage.searchGroup("group").clickSearchButton();
|
||||||
|
@ -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")
|
||||||
|
|
|
@ -229,13 +229,11 @@ 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 "";
|
||||||
};
|
};
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
Loading…
Reference in a new issue