-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create tests for utilities, functions and components (#10)
* Install vitest and test date utilities and validation functions - Installed **Vitest** for `unit testing` framework. - Created test cases for the `formatDate` utility function to ensure correct formatting of valid date strings. - Added validation tests for `username`, `email`, `password`, and `confirm password` fields to verify proper validation logic. - Updated the testing configuration to support the new tests and ensure they run successfully. * Add unit test for hooks - Implemented tests for the `useResize` hook to verify behavior across different screen sizes. - Added tests for the `useTheme` hook to check the default theme and verify that it updates to light or dark when changed. * Add unit test for providers - Added a test to ensure the `ThemeProvider` correctly applies the selected `theme` to the document's `root` element. - Mocked `localStorage` to return a predefined `theme` value for testing. - Verified that the appropriate `class` is applied to `document.documentElement` based on the `theme`. * Add unit test for zustand stores - Implemented tests for `userStore` to verify user state and persistence in session storage. - Created tests for `authStore` to ensure authentication logic and state management function correctly. * Add tests for authService methods Implemented tests for the following **AuthService** methods: - `signIn`: Verified successful sign-in and error handling. - `signUp`: Tested user registration process and error responses. - `signOut`: Checked the sign-out functionality. - `verifyEmail`: Confirmed email verification process. - `resendVerify`: Ensured resend verification logic works as expected. - `verifyToken`: Tested token verification and error handling. - `forgotPassword`: Validated forgot password request handling. - `resetPassword`: Checked password reset process. - `changePassword`: Tested password change functionality. * Add tests for guard components - Created unit tests for `AuthGuard` and `PrivateGuard` components to ensure proper functionality. - Verified that guards correctly redirect unauthorized users and allow access for authorized users.
- Loading branch information
1 parent
cf697b9
commit b1f7b26
Showing
29 changed files
with
3,069 additions
and
18 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { | ||
createMemoryRouter, | ||
RouteObject, | ||
RouterProvider, | ||
} from "react-router-dom"; | ||
import { describe, it, expect, vi, Mock, beforeAll } from "vitest"; | ||
import { render } from "@testing-library/react"; | ||
|
||
import { useAuthStore } from "@/lib/stores/auth-store"; | ||
import { AppRoutes } from "@/constants/routes"; | ||
|
||
import AuthGuard from "./auth-guard"; | ||
|
||
vi.mock("../lib/stores/auth-store.ts", () => ({ | ||
useAuthStore: vi.fn(), | ||
})); | ||
|
||
const routes: RouteObject[] = [ | ||
{ | ||
path: AppRoutes.Root, | ||
element: <div>Root</div>, | ||
}, | ||
{ | ||
element: <AuthGuard />, | ||
children: [ | ||
{ | ||
path: AppRoutes.SignIn, | ||
element: <div>Sign In</div>, | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
describe("Auth Guard", () => { | ||
let router: ReturnType<typeof createMemoryRouter>; | ||
|
||
beforeAll(() => { | ||
(useAuthStore as unknown as Mock).mockReturnValueOnce({ | ||
authorized: true, | ||
}); | ||
|
||
router = createMemoryRouter(routes, { | ||
initialEntries: [AppRoutes.SignIn], | ||
}); | ||
|
||
render(<RouterProvider router={router} />); | ||
}); | ||
|
||
it("redirects to the root page when authorized", () => { | ||
expect(router.state.location.pathname).toBe(AppRoutes.Root); | ||
}); | ||
|
||
it("renders the outlet when not authorized", () => { | ||
(useAuthStore as unknown as Mock).mockReturnValueOnce({ | ||
authorized: false, | ||
}); | ||
|
||
render(<RouterProvider router={router} />); | ||
|
||
expect(router); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { | ||
createMemoryRouter, | ||
RouteObject, | ||
RouterProvider, | ||
} from "react-router-dom"; | ||
import { describe, it, expect, vi, Mock } from "vitest"; | ||
import { useQuery } from "@tanstack/react-query"; | ||
import { render } from "@testing-library/react"; | ||
import "@testing-library/jest-dom"; | ||
|
||
import { useAuthStore } from "@/lib/stores/auth-store"; | ||
import { AppRoutes } from "@/constants/routes"; | ||
|
||
import PrivateGuard from "./private-guard"; | ||
|
||
vi.mock("@/lib/stores/auth-store", () => ({ | ||
useAuthStore: vi.fn().mockReturnValueOnce({ | ||
authorized: false, | ||
setAuthorized: vi.fn(), | ||
}), | ||
})); | ||
|
||
vi.mock("@tanstack/react-query", () => ({ | ||
useQuery: vi.fn().mockReturnValueOnce({ | ||
isLoading: false, | ||
isError: false, | ||
isSuccess: false, | ||
}), | ||
})); | ||
|
||
const routes: RouteObject[] = [ | ||
{ | ||
path: AppRoutes.SignIn, | ||
element: <div>Sign In</div>, | ||
}, | ||
{ | ||
element: <PrivateGuard />, | ||
children: [ | ||
{ | ||
path: AppRoutes.Root, | ||
element: <div>Root</div>, | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
describe("Private Guard", () => { | ||
it("redirects to sign-in page when not authorized", () => { | ||
const router = createMemoryRouter(routes, { | ||
initialEntries: [AppRoutes.Root], | ||
}); | ||
|
||
render(<RouterProvider router={router} />); | ||
|
||
expect(router.state.location.pathname).toEqual(AppRoutes.SignIn); | ||
}); | ||
|
||
it("redirects to sign in page when an error occurs", () => { | ||
const router = createMemoryRouter(routes, { | ||
initialEntries: [AppRoutes.Root], | ||
}); | ||
|
||
(useAuthStore as unknown as Mock).mockReturnValueOnce({ | ||
authenticated: true, | ||
setAuthorized: vi.fn(), | ||
}); | ||
|
||
(useQuery as Mock).mockReturnValueOnce({ | ||
isError: true, | ||
isLoading: false, | ||
isSuccess: false, | ||
}); | ||
|
||
render(<RouterProvider router={router} />); | ||
|
||
expect(router.state.location.pathname).toEqual(AppRoutes.SignIn); | ||
}); | ||
|
||
it("allows access to root page when authorized", () => { | ||
const router = createMemoryRouter(routes, { | ||
initialEntries: [AppRoutes.Root], | ||
}); | ||
|
||
(useAuthStore as unknown as Mock).mockReturnValueOnce({ | ||
authorized: true, | ||
setAuthorized: vi.fn(), | ||
}); | ||
|
||
(useQuery as Mock).mockReturnValueOnce({ | ||
isError: false, | ||
isLoading: false, | ||
isSuccess: true, | ||
}); | ||
|
||
render(<RouterProvider router={router} />); | ||
|
||
expect(router.state.location.pathname).toEqual(AppRoutes.Root); | ||
}); | ||
|
||
it("renders loading component when query is loading", () => { | ||
const router = createMemoryRouter(routes, { | ||
initialEntries: [AppRoutes.Root], | ||
}); | ||
|
||
(useAuthStore as unknown as Mock).mockReturnValueOnce({ | ||
authorized: true, | ||
setAuthorized: vi.fn(), | ||
}); | ||
|
||
(useQuery as Mock).mockReturnValueOnce({ | ||
isError: false, | ||
isLoading: true, | ||
isSuccess: false, | ||
}); | ||
|
||
const { container } = render(<RouterProvider router={router} />); | ||
|
||
const loader = container.querySelector("svg"); | ||
|
||
expect(loader).toBeInTheDocument(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,18 @@ | ||
type ErrorResponseType = { | ||
status: number; | ||
message: string; | ||
response: Response; | ||
}; | ||
|
||
export class ErrorResponse extends Error { | ||
public status: number; | ||
public message: string; | ||
public response: Response; | ||
|
||
constructor({ status, message }: ErrorResponseType) { | ||
constructor({ status, message, response }: ErrorResponseType) { | ||
super(message); | ||
this.status = status; | ||
this.message = message; | ||
this.response = response; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
type GenericResponseType = { | ||
message: string; | ||
response: Response; | ||
}; | ||
|
||
export class GenericResponse { | ||
public message: string; | ||
public response: Response; | ||
|
||
constructor({ message }: GenericResponseType) { | ||
constructor({ message, response }: GenericResponseType) { | ||
this.message = message; | ||
this.response = response; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { describe, it, expect, beforeAll } from "vitest"; | ||
import { act, renderHook } from "@testing-library/react"; | ||
|
||
import { useResize } from "./use-resize"; | ||
|
||
describe("useResize", () => { | ||
const sm = 640; | ||
const md = 768; | ||
const lg = 1024; | ||
const xl = 1280; | ||
const xl2 = 1536; | ||
|
||
beforeAll(() => { | ||
window.innerWidth = 800; | ||
window.innerHeight = 600; | ||
}); | ||
|
||
it("should initialize with the correct window size", () => { | ||
const { result } = renderHook(() => useResize()); | ||
expect(result.current).toEqual({ width: 800, height: 600 }); | ||
}); | ||
|
||
it("should update size on window resize", () => { | ||
const { result } = renderHook(() => useResize()); | ||
expect(result.current).toEqual({ width: 800, height: 600 }); | ||
|
||
act(() => { | ||
window.innerWidth = 1024; | ||
window.innerHeight = 768; | ||
window.dispatchEvent(new Event("resize")); | ||
}); | ||
|
||
expect(result.current).toEqual({ width: 1024, height: 768 }); | ||
}); | ||
|
||
it("should be small screen", () => { | ||
const { result } = renderHook(() => useResize()); | ||
|
||
act(() => { | ||
window.innerWidth = sm; | ||
window.dispatchEvent(new Event("resize")); | ||
}); | ||
|
||
expect(result.current.width).toEqual(sm); | ||
}); | ||
|
||
it("should be medium screen", () => { | ||
const { result } = renderHook(() => useResize()); | ||
|
||
act(() => { | ||
window.innerWidth = md; | ||
window.dispatchEvent(new Event("resize")); | ||
}); | ||
|
||
expect(result.current.width).toEqual(md); | ||
}); | ||
|
||
it("should be large screen", () => { | ||
const { result } = renderHook(() => useResize()); | ||
|
||
act(() => { | ||
window.innerWidth = lg; | ||
window.dispatchEvent(new Event("resize")); | ||
}); | ||
|
||
expect(result.current.width).toEqual(lg); | ||
}); | ||
|
||
it("should be extra large screen", () => { | ||
const { result } = renderHook(() => useResize()); | ||
|
||
act(() => { | ||
window.innerWidth = xl; | ||
window.dispatchEvent(new Event("resize")); | ||
}); | ||
|
||
expect(result.current.width).toEqual(xl); | ||
}); | ||
|
||
it("should be 2x extra large screen", () => { | ||
const { result } = renderHook(() => useResize()); | ||
|
||
act(() => { | ||
window.innerWidth = xl2; | ||
window.dispatchEvent(new Event("resize")); | ||
}); | ||
|
||
expect(result.current.width).toEqual(xl2); | ||
}); | ||
}); |
Oops, something went wrong.