diff --git a/__tests__/Home.test.jsx b/__tests__/Home.test.jsx new file mode 100644 index 0000000..bb0ea6f --- /dev/null +++ b/__tests__/Home.test.jsx @@ -0,0 +1,60 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { Provider } from "react-redux"; +import configureStore from "redux-mock-store"; +import Home from "src/pages/Home"; +import { useGetChatsQuery } from "../backend/redux/api_slice"; + +// Mock Redux store +const mockStore = configureStore([]); + +// Mock the useGetChatsQuery hook +jest.mock("src/backend/redux/api_slice", () => ({ + useGetChatsQuery: jest.fn(), +})); + +describe("Home Page", () => { + let store; + + beforeEach(() => { + store = mockStore({}); + }); + + test("renders Home page with loading state", () => { + useGetChatsQuery.mockReturnValue({ isLoading: true }); + + render( + + + + ); + + expect(screen.getByText(/loading/i)).toBeInTheDocument(); + }); + + test("renders Home page with chat data", () => { + const chatsData = [{ id: 1, name: "Chat 1" }, { id: 2, name: "Chat 2" }]; + useGetChatsQuery.mockReturnValue({ data: chatsData, isLoading: false }); + + render( + + + + ); + + expect(screen.getByText("Chat 1")).toBeInTheDocument(); + expect(screen.getByText("Chat 2")).toBeInTheDocument(); + }); + + test("renders error message when fetching chats fails", () => { + useGetChatsQuery.mockReturnValue({ error: true, isLoading: false }); + + render( + + + + ); + + expect(screen.getByText(/error/i)).toBeInTheDocument(); + }); +}); diff --git a/__tests__/SignIn.test.jsx b/__tests__/SignIn.test.jsx new file mode 100644 index 0000000..29204ba --- /dev/null +++ b/__tests__/SignIn.test.jsx @@ -0,0 +1,52 @@ +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import SignIn from "../pages/SignIn"; +import { displayMessage } from "../backend/notifications/notifications"; +import { post } from "../backend/api"; + +// Mock the displayMessage and post functions +jest.mock("../backend/notifications/notifications", () => ({ + displayMessage: jest.fn(), +})); +jest.mock("../backend/api", () => ({ + post: jest.fn(), +})); + +describe("SignIn Page", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test("renders SignIn form", () => { + render(); + expect(screen.getByLabelText(/username/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/password/i)).toBeInTheDocument(); + expect(screen.getByText(/sign in/i)).toBeInTheDocument(); + }); + + test("displays error message on failed login", async () => { + post.mockResolvedValueOnce({ ok: false, data: { message: "Invalid credentials" } }); + + render(); + fireEvent.change(screen.getByLabelText(/username/i), { target: { value: "user" } }); + fireEvent.change(screen.getByLabelText(/password/i), { target: { value: "password" } }); + fireEvent.click(screen.getByText(/sign in/i)); + + expect(await screen.findByText(/invalid credentials/i)).toBeInTheDocument(); + expect(displayMessage).toHaveBeenCalledWith("Invalid credentials", "error"); + }); + + test("displays additional info message after multiple login attempts", async () => { + post.mockResolvedValueOnce({ ok: false, data: { message: "Invalid credentials" } }); + + render(); + fireEvent.change(screen.getByLabelText(/username/i), { target: { value: "user" } }); + fireEvent.change(screen.getByLabelText(/password/i), { target: { value: "password" } }); + + // Simulate two failed login attempts + fireEvent.click(screen.getByText(/sign in/i)); + fireEvent.click(screen.getByText(/sign in/i)); + + expect(displayMessage).toHaveBeenCalledWith("Note that you need to enter your ID name", "info"); + }); +}); diff --git a/jest.config.ts b/jest.config.ts index 2bb5326..f158775 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -17,6 +17,10 @@ const config: Config = { // transform: { // '^.+\\.(ts|tsx|js|jsx)$': 'babel-jest', // }, + moduleNameMapper: { + "^@/src/(.*)$": "/src/$1", // Map '@/src' to the 'src' folder + "^src/(.*)$": "/src/$1", // Map 'src' to the 'src' folder + }, moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts', 'tsx', 'js', 'jsx'], }; diff --git a/package-lock.json b/package-lock.json index 3a7d8a7..5339fd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,6 +42,7 @@ "babel-jest": "^29.7.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", + "redux-mock-store": "^1.5.4", "ts-jest": "^29.2.5", "ts-node": "^10.9.2" } @@ -11778,6 +11779,16 @@ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", "license": "MIT" }, + "node_modules/redux-mock-store": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/redux-mock-store/-/redux-mock-store-1.5.4.tgz", + "integrity": "sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.isplainobject": "^4.0.6" + } + }, "node_modules/redux-thunk": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", diff --git a/package.json b/package.json index 1a15561..d2ccec1 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "babel-jest": "^29.7.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", + "redux-mock-store": "^1.5.4", "ts-jest": "^29.2.5", "ts-node": "^10.9.2" } diff --git a/src.zip b/src.zip new file mode 100644 index 0000000..5f00fec Binary files /dev/null and b/src.zip differ