From 5f386c0f4e48e55198a2bc2ca2819a8eba4b4227 Mon Sep 17 00:00:00 2001 From: iliyasone Date: Sat, 19 Oct 2024 10:48:21 +0300 Subject: [PATCH] some progress --- __tests__/Home.test.jsx | 60 ++++++++++++++++++++++++++++++++++++++ __tests__/SignIn.test.jsx | 52 +++++++++++++++++++++++++++++++++ jest.config.ts | 4 +++ package-lock.json | 11 +++++++ package.json | 1 + src.zip | Bin 0 -> 30190 bytes 6 files changed, 128 insertions(+) create mode 100644 __tests__/Home.test.jsx create mode 100644 __tests__/SignIn.test.jsx create mode 100644 src.zip 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 0000000000000000000000000000000000000000..5f00fec0a4019091b7d8c08a9a355d92d1a56f47 GIT binary patch literal 30190 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

NH5~1R+06v8x~2DZ>2n~-l;%+F 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 U$ZPbpX-df7Ao5(&ZVrC^4