Skip to content

Commit

Permalink
chore: added ui unit tests (#1353)
Browse files Browse the repository at this point in the history
Signed-off-by: Darshan Simha <[email protected]>
Co-authored-by: Darshan Simha <[email protected]>
  • Loading branch information
darshansimha and Darshan Simha authored Nov 8, 2023
1 parent 343c509 commit 380dd21
Show file tree
Hide file tree
Showing 13 changed files with 1,704 additions and 549 deletions.
2 changes: 1 addition & 1 deletion ui/src/components/common/ErrorIndicator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function ErrorIndicator() {
) : (
<ErrorOutlineIcon sx={{ color: "#6B6C72" }} />
)}
{errors.length ? (
{errors?.length ? (
<span className="error-indicator-text">Error occurred</span>
) : undefined}
</Box>
Expand Down
169 changes: 169 additions & 0 deletions ui/src/components/pages/Cluster/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import { Cluster } from "./index";
import { BrowserRouter } from "react-router-dom";
import { AppContext } from "../../../App";
import { act } from "react-dom/test-utils";
import { useClusterSummaryFetch } from "../../../utils/fetchWrappers/clusterSummaryFetch";

jest.mock("../../../utils/fetchWrappers/clusterSummaryFetch");

window.ResizeObserver = class ResizeObserver {
observe() {
// do nothing
}
unobserve() {
// do nothing
}
disconnect() {
// do nothing
}
};
const mockData = {
namespacesCount: 3,
pipelinesCount: 4,
pipelinesActiveCount: 3,
pipelinesInactiveCount: 1,
pipelinesHealthyCount: 3,
pipelinesWarningCount: 0,
pipelinesCriticalCount: 0,
isbsCount: 5,
isbsActiveCount: 5,
isbsInactiveCount: 0,
isbsHealthyCount: 5,
isbsWarningCount: 0,
isbsCriticalCount: 0,
nameSpaceSummaries: [
{
name: "default",
isEmpty: true,
pipelinesCount: 0,
pipelinesActiveCount: 0,
pipelinesInactiveCount: 0,
pipelinesHealthyCount: 0,
pipelinesWarningCount: 0,
pipelinesCriticalCount: 0,
isbsCount: 0,
isbsActiveCount: 0,
isbsInactiveCount: 0,
isbsHealthyCount: 0,
isbsWarningCount: 0,
isbsCriticalCount: 0,
},
{
name: "local-path-storage",
isEmpty: true,
pipelinesCount: 0,
pipelinesActiveCount: 0,
pipelinesInactiveCount: 0,
pipelinesHealthyCount: 0,
pipelinesWarningCount: 0,
pipelinesCriticalCount: 0,
isbsCount: 0,
isbsActiveCount: 0,
isbsInactiveCount: 0,
isbsHealthyCount: 0,
isbsWarningCount: 0,
isbsCriticalCount: 0,
},
{
name: "numaflow-system",
isEmpty: false,
pipelinesCount: 4,
pipelinesActiveCount: 3,
pipelinesInactiveCount: 1,
pipelinesHealthyCount: 3,
pipelinesWarningCount: 0,
pipelinesCriticalCount: 0,
isbsCount: 5,
isbsActiveCount: 5,
isbsInactiveCount: 0,
isbsHealthyCount: 5,
isbsWarningCount: 0,
isbsCriticalCount: 0,
},
],
};

describe("Cluster", () => {
beforeEach(() => {
jest.resetAllMocks();
});
it("renders without crashing", async () => {
useClusterSummaryFetch.mockImplementation(() => ({
data: mockData,
loading: false,
error: null,
}));
render(
<AppContext.Provider value="">
<BrowserRouter>
<Cluster />
</BrowserRouter>
</AppContext.Provider>
);
await act(() => {
expect(screen.getByTestId("summary-page-layout")).toBeInTheDocument();
});
});

it("renders loading indicator", async () => {
useClusterSummaryFetch.mockImplementation(() => ({
data: null,
loading: true,
error: null,
}));
render(
<AppContext.Provider value="">
<BrowserRouter>
<Cluster />
</BrowserRouter>
</AppContext.Provider>
);

await act(() => {
expect(screen.getByTestId("cluster-loading-icon")).toBeInTheDocument();
});
});

it("Loads when data is null", async () => {
useClusterSummaryFetch.mockImplementation(() => ({
data: null,
loading: false,
error: null,
}));
render(
<AppContext.Provider value="">
<BrowserRouter>
<Cluster />
</BrowserRouter>
</AppContext.Provider>
);

await act(() => {
expect(screen.getByTestId("summary-page-layout")).toBeInTheDocument();
});
});

it("renders error message", async () => {
useClusterSummaryFetch.mockImplementation(() => ({
data: null,
loading: false,
error: "Error",
}));
render(
<AppContext.Provider value="">
<BrowserRouter>
<Cluster />
</BrowserRouter>
</AppContext.Provider>
);

await act(() => {
expect(
screen.getByText("Error loading cluster namespaces")
).toBeInTheDocument();
});
});
});
2 changes: 1 addition & 1 deletion ui/src/components/pages/Cluster/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export function Cluster() {
alignItems: "center",
}}
>
<CircularProgress />
<CircularProgress data-testid="cluster-loading-icon" />
</Box>
);
}
Expand Down
107 changes: 107 additions & 0 deletions ui/src/components/pages/Login/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from "react";
import { render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import { BrowserRouter, useSearchParams } from "react-router-dom";
import fetchMock from "jest-fetch-mock";
import { act } from "react-dom/test-utils";

import { AppContext } from "../../../App";
import { Login } from "./index";

const mockData = {
data: {
id_token_claims: {
iss: "",
sub: "Cg",
aud: "numaflow",
exp: 1699394116,
iat: 1699307716,
at_hash: "qi",
c_hash: "eW",
email: "[email protected]",
email_verified: true,
groups: ["sandbox-sandbox"],
name: "testUser",
preferred_username: "testUser",
},
id_token: "eyJ",
refresh_token: "Chl",
},
};

// Enable fetch mocks
fetchMock.enableMocks();

// Mock the useSearchParams hook
jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
useSearchParams: jest.fn(),
}));

describe("Login", () => {
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams(""),
() => {},
]);
it("renders the login page", async () => {
render(
<AppContext.Provider value={{ isAuthenticated: false }}>
<BrowserRouter>
<Login />
</BrowserRouter>
</AppContext.Provider>
);
await act(() => {
expect(screen.getByText("Login")).toBeInTheDocument();
});
});

it("Tests clicking the login button", async () => {
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams(""),
() => {},
]);
render(
<AppContext.Provider value={{ isAuthenticated: false }}>
<BrowserRouter>
<Login />
</BrowserRouter>
</AppContext.Provider>
);
fetchMock.mockResponseOnce(JSON.stringify(mockData));
await waitFor(() => {
expect(screen.getByText("Login via Github")).toBeInTheDocument();
});
const loginButton = screen.getByText("Login via Github");

expect(loginButton).toBeInTheDocument();
await act(async () => {
loginButton.click();
expect(loginButton).toBeInTheDocument();
});
});
it("should make API call on callback", async () => {
fetch.mockResponseOnce(JSON.stringify(mockData));

// Mock the search params to simulate the conditions for handleCallback
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams("code=123&state=abc"),
]);

render(
<AppContext.Provider value={{ isAuthenticated: false }}>
<BrowserRouter>
<Login />
</BrowserRouter>
</AppContext.Provider>
);

// Assert
await waitFor(() => expect(fetch).toHaveBeenCalledTimes(1));
expect(fetch).toHaveBeenCalledWith("/auth/v1/callback?code=123&state=abc");
});
afterEach(() => {
fetchMock.resetMocks();
(useSearchParams as jest.Mock).mockReset();
});
});
Loading

0 comments on commit 380dd21

Please sign in to comment.