Skip to content

Commit

Permalink
chore(tests): add tests for the client list
Browse files Browse the repository at this point in the history
  • Loading branch information
huwshimi committed Dec 9, 2024
1 parent 3bb0555 commit ac21d96
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 20 deletions.
3 changes: 2 additions & 1 deletion ui/src/components/EditPanelButton/EditPanelButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import usePanelParams from "util/usePanelParams";

import { Label, Props } from "./types";

const EditPanelButton: FC<Props> = ({ openPanel }: Props) => {
const EditPanelButton: FC<Props> = ({ openPanel, ...props }: Props) => {
const panelParams = usePanelParams();

return (
<Button
className="u-no-margin--bottom"
hasIcon
onClick={() => openPanel(panelParams)}
{...props}
>
<Icon name="edit" />
<span>{Label.EDIT}</span>
Expand Down
97 changes: 97 additions & 0 deletions ui/src/pages/clients/ClientList/ClientList.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { screen, within } from "@testing-library/dom";
import MockAdapter from "axios-mock-adapter";
import userEvent from "@testing-library/user-event";

import { axiosInstance } from "api/axios";
import { customWithin } from "test/queries/within";
import { isoTimeToString } from "util/date";
import { LoaderTestId } from "components/Loader";
import { mockClient } from "test/mocks/clients";
import { mockPaginatedResponse } from "test/mocks/responses";
import { PAGE_SIZE } from "util/api";
import { renderComponent } from "test/utils";

import { DeleteClientBtnTestId } from "../DeleteClientBtn";
import { EditClientBtnTestId } from "../EditClientBtn";

import { Label } from "./types";
import ClientList from "./ClientList";
import { Location } from "react-router-dom";
import { panels } from "util/usePanelParams";

const mock = new MockAdapter(axiosInstance);

beforeEach(() => {
mock.reset();
mock
.onGet(`/clients?page_token=&page_size=${PAGE_SIZE}`)
.reply(200, mockPaginatedResponse([], { _meta: {} }));
});

test("displays loading state", () => {
renderComponent(<ClientList />);
expect(screen.getByTestId(LoaderTestId.COMPONENT)).toBeInTheDocument();
});

test("displays empty state", async () => {
renderComponent(<ClientList />);
expect(
await within(await screen.findByRole("grid")).findByText(Label.NO_DATA),
).toBeInTheDocument();
});

test("displays client rows", async () => {
const client = mockClient();
const clients = [client];
mock
.onGet(`/clients?page_token=&size=${PAGE_SIZE}`)
.reply(200, mockPaginatedResponse(clients, { _meta: {} }));
renderComponent(<ClientList />);
const row = await screen.findByRole("row", {
name: new RegExp(client.client_id),
});
expect(
customWithin(row).getCellByHeader(Label.HEADER_ID, { role: "rowheader" }),
).toHaveTextContent(client.client_id);
expect(
customWithin(row).getCellByHeader(Label.HEADER_NAME, {
role: "gridcell",
hasRowHeader: true,
}),
).toHaveTextContent(client.client_name);
expect(
customWithin(row).getCellByHeader(Label.HEADER_DATE, {
role: "gridcell",
hasRowHeader: true,
}),
).toHaveTextContent(
`Created: ${isoTimeToString(client.created_at)}Updated: ${isoTimeToString(client.updated_at)}`,
);
});

test("opens add client panel", async () => {
let location: Location | null = null;
renderComponent(<ClientList />, {
setLocation: (newLocation) => {
location = newLocation;
},
});
await userEvent.click(screen.getByRole("button", { name: Label.ADD }));
expect((location as Location | null)?.search).toBe(
`?panel=${panels.clientCreate}`,
);
});

test("displays edit and delete buttons", async () => {
const clients = [mockClient()];
mock
.onGet(`/clients?page_token=&size=${PAGE_SIZE}`)
.reply(200, mockPaginatedResponse(clients, { _meta: {} }));
renderComponent(<ClientList />);
expect(
await screen.findByTestId(EditClientBtnTestId.COMPONENT),
).toBeInTheDocument();
expect(
await screen.findByTestId(DeleteClientBtnTestId.COMPONENT),

Check failure on line 95 in ui/src/pages/clients/ClientList/ClientList.test.tsx

View workflow job for this annotation

GitHub Actions / Test (20.x)

src/pages/clients/ClientList/ClientList.test.tsx > displays edit and delete buttons

TestingLibraryElementError: Unable to find an element by: [data-testid="DeleteClientBtn"] Ignored nodes: comments, script, style <body> <div> <div class="p-panel" > <div class="p-panel__header " > <div class="p-panel__title" > <h1 class="p-heading--4 u-no-margin--bottom" > Clients </h1> </div> <div class="p-panel__controls" > <button class="p-button--positive" > Add client </button> </div> </div> <div class="p-panel__content" > <div class="row" > <div class="col-12" > <table class="u-table-layout--auto p-table--mobile-card" role="grid" > <thead> <tr role="row" > <th role="columnheader" > Id </th> <th role="columnheader" > Name </th> <th role="columnheader" > Date </th> <th role="columnheader" > Actions </th> </tr> </thead> <tbody> <tr role="row" > <td aria-hidden="false" class="" data-heading="Id" role="rowheader" > factorize </td> <td aria-hidden="false" class="" data-heading="Name" role="gridcell" > brr </td> <td aria-hidden="false" class="" data-heading="Date" role="gridcell" > <div> Created: May 22, 2025, 10:31 PM </div> <div class="u-text--muted" > Updated: Aug 7, 2025, 04:32 AM </div> </td> <td aria-hidden="false" class="" data-heading="Actions" role="gridcell" > <button class="p-button has-icon u-no-margin--bottom" data-testid="EditClientBtn" > <i class="p-icon--edit" /> <span> Edit </span> </button> <button class="u-no-margin--bottom p-action-button p-button" title="Delete client" > Delete </button> </td> </tr> </tbody> </table> </div> </div> </div> </div> </div> <div /> </body> Ignored nodes: comments, script, style <body> <div> <div class="p-panel" > <div class="p-panel__header " > <div class="p-panel__title" > <h1 class="p-heading--4 u-no-margin--bottom" > Clients </h1> </div> <div class="p-panel__controls" > <button class="p-button--positive" > Add
).toBeInTheDocument();
});
24 changes: 7 additions & 17 deletions ui/src/pages/clients/ClientList/ClientList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import DeleteClientBtn from "pages/clients/DeleteClientBtn";
import Loader from "components/Loader";
import Pagination from "components/Pagination";
import { usePagination } from "util/usePagination";
import { Label } from "./types";

const ClientList: FC = () => {
const panelParams = usePanelParams();
Expand All @@ -34,7 +35,7 @@ const ClientList: FC = () => {
</div>
<div className="p-panel__controls">
<Button appearance="positive" onClick={panelParams.openClientCreate}>
Add client
{Label.ADD}
</Button>
</div>
</div>
Expand All @@ -46,23 +47,20 @@ const ClientList: FC = () => {
className="u-table-layout--auto"
responsive
headers={[
{ content: "Id" },
{ content: "Name" },
{ content: "Date" },
{ content: "Actions" },
{ content: Label.HEADER_ID },
{ content: Label.HEADER_NAME },
{ content: Label.HEADER_DATE },
{ content: Label.HEADER_ACTIONS },
]}
rows={response?.data.map((client) => {
return {
columns: [
{
content: client.client_id,
role: "rowheader",
"aria-label": "Id",
},
{
content: client.client_name,
role: "rowheader",
"aria-label": "Name",
},
{
content: (
Expand All @@ -75,8 +73,6 @@ const ClientList: FC = () => {
</div>
</>
),
role: "rowheader",
"aria-label": "Created",
},
{
content: (
Expand All @@ -85,18 +81,12 @@ const ClientList: FC = () => {
<DeleteClientBtn client={client} />
</>
),
role: "rowheader",
"aria-label": "Actions",
},
],
};
})}
emptyStateMsg={
isLoading ? (
<Loader text="Loading clients..." />
) : (
"No data to display"
)
isLoading ? <Loader text="Loading clients..." /> : Label.NO_DATA
}
/>
<Pagination response={response} />
Expand Down
8 changes: 8 additions & 0 deletions ui/src/pages/clients/ClientList/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export enum Label {
ADD = "Add client",
HEADER_ACTIONS = "Actions",
HEADER_DATE = "Date",
HEADER_ID = "Id",
HEADER_NAME = "Name",
NO_DATA = "No data to display",
}
1 change: 1 addition & 0 deletions ui/src/pages/clients/DeleteClientBtn/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default } from "./DeleteClientBtn";
export { TestId as DeleteClientBtnTestId } from "./test-types";
3 changes: 3 additions & 0 deletions ui/src/pages/clients/DeleteClientBtn/test-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum TestId {
COMPONENT = "DeleteClientBtn",
}
4 changes: 4 additions & 0 deletions ui/src/pages/clients/EditClientBtn/EditClientBtn.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { FC } from "react";

import EditPanelButton from "components/EditPanelButton";
import { testId } from "test/utils";

import { TestId } from "./test-types";

interface Props {
clientId: string;
Expand All @@ -10,6 +13,7 @@ const EditClientBtn: FC<Props> = ({ clientId }) => {
return (
<EditPanelButton
openPanel={(panelParams) => panelParams.openClientEdit(clientId)}
{...testId(TestId.COMPONENT)}
/>
);
};
Expand Down
1 change: 1 addition & 0 deletions ui/src/pages/clients/EditClientBtn/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default } from "./EditClientBtn";
export { TestId as EditClientBtnTestId } from "./test-types";
3 changes: 3 additions & 0 deletions ui/src/pages/clients/EditClientBtn/test-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum TestId {
COMPONENT = "EditClientBtn",
}
4 changes: 2 additions & 2 deletions ui/src/test/mocks/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const mockClient = (overrides?: Partial<Client>): Client => ({
client_secret_expires_at: faker.number.int(),
client_uri: faker.word.sample(),
contacts: [],
created_at: faker.word.sample(),
created_at: faker.date.anytime().toISOString(),
grant_types: [],
logo_uri: faker.word.sample(),
owner: faker.word.sample(),
Expand All @@ -23,7 +23,7 @@ export const mockClient = (overrides?: Partial<Client>): Client => ({
subject_type: faker.word.sample(),
token_endpoint_auth_method: faker.word.sample(),
tos_uri: faker.word.sample(),
updated_at: faker.word.sample(),
updated_at: faker.date.anytime().toISOString(),
userinfo_signed_response_alg: faker.word.sample(),
...overrides,
});

0 comments on commit ac21d96

Please sign in to comment.