tests passing
This commit is contained in:
parent
0995e1cc77
commit
7ebfb7a2dd
20 changed files with 2009 additions and 126 deletions
|
|
@ -1,68 +1,199 @@
|
|||
import { render, screen, fireEvent, waitFor, cleanup } from "@testing-library/react";
|
||||
import { expect, test, vi, beforeEach, afterEach } from "vitest";
|
||||
import { expect, test, vi, beforeEach, afterEach, describe } from "vitest";
|
||||
import Home from "./page";
|
||||
|
||||
// Mock next/navigation
|
||||
const mockPush = vi.fn();
|
||||
vi.mock("next/navigation", () => ({
|
||||
useRouter: () => ({
|
||||
push: mockPush,
|
||||
}),
|
||||
}));
|
||||
|
||||
// Default mock values
|
||||
let mockUser: { id: number; email: string } | null = { id: 1, email: "test@example.com" };
|
||||
let mockToken: string | null = "valid-token";
|
||||
let mockIsLoading = false;
|
||||
const mockLogout = vi.fn();
|
||||
|
||||
vi.mock("./auth-context", () => ({
|
||||
useAuth: () => ({
|
||||
user: mockUser,
|
||||
token: mockToken,
|
||||
isLoading: mockIsLoading,
|
||||
logout: mockLogout,
|
||||
}),
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.clearAllMocks();
|
||||
// Reset to authenticated state
|
||||
mockUser = { id: 1, email: "test@example.com" };
|
||||
mockToken = "valid-token";
|
||||
mockIsLoading = false;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
test("renders loading state initially", () => {
|
||||
vi.spyOn(global, "fetch").mockImplementation(() => new Promise(() => {}));
|
||||
render(<Home />);
|
||||
expect(screen.getByText("...")).toBeDefined();
|
||||
});
|
||||
describe("Home - Authenticated", () => {
|
||||
test("renders loading state when isLoading is true", () => {
|
||||
mockIsLoading = true;
|
||||
vi.spyOn(global, "fetch").mockImplementation(() => new Promise(() => {}));
|
||||
|
||||
test("renders counter value after fetch", async () => {
|
||||
vi.spyOn(global, "fetch").mockResolvedValue({
|
||||
json: () => Promise.resolve({ value: 42 }),
|
||||
} as Response);
|
||||
render(<Home />);
|
||||
expect(screen.getByText("Loading...")).toBeDefined();
|
||||
});
|
||||
|
||||
render(<Home />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("42")).toBeDefined();
|
||||
test("renders user email in header", async () => {
|
||||
vi.spyOn(global, "fetch").mockResolvedValue({
|
||||
json: () => Promise.resolve({ value: 42 }),
|
||||
} as Response);
|
||||
|
||||
render(<Home />);
|
||||
expect(screen.getByText("test@example.com")).toBeDefined();
|
||||
});
|
||||
|
||||
test("renders sign out button", async () => {
|
||||
vi.spyOn(global, "fetch").mockResolvedValue({
|
||||
json: () => Promise.resolve({ value: 42 }),
|
||||
} as Response);
|
||||
|
||||
render(<Home />);
|
||||
expect(screen.getByText("Sign out")).toBeDefined();
|
||||
});
|
||||
|
||||
test("clicking sign out calls logout", async () => {
|
||||
vi.spyOn(global, "fetch").mockResolvedValue({
|
||||
json: () => Promise.resolve({ value: 42 }),
|
||||
} as Response);
|
||||
|
||||
render(<Home />);
|
||||
fireEvent.click(screen.getByText("Sign out"));
|
||||
expect(mockLogout).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("renders counter value after fetch", async () => {
|
||||
vi.spyOn(global, "fetch").mockResolvedValue({
|
||||
json: () => Promise.resolve({ value: 42 }),
|
||||
} as Response);
|
||||
|
||||
render(<Home />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("42")).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
test("fetches counter with auth header", async () => {
|
||||
const fetchSpy = vi.spyOn(global, "fetch").mockResolvedValue({
|
||||
json: () => Promise.resolve({ value: 0 }),
|
||||
} as Response);
|
||||
|
||||
render(<Home />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchSpy).toHaveBeenCalledWith(
|
||||
"http://localhost:8000/api/counter",
|
||||
expect.objectContaining({
|
||||
headers: { Authorization: "Bearer valid-token" },
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("renders increment button", async () => {
|
||||
vi.spyOn(global, "fetch").mockResolvedValue({
|
||||
json: () => Promise.resolve({ value: 0 }),
|
||||
} as Response);
|
||||
|
||||
render(<Home />);
|
||||
expect(screen.getByText("Increment")).toBeDefined();
|
||||
});
|
||||
|
||||
test("clicking increment button calls API with auth header", async () => {
|
||||
const fetchSpy = vi
|
||||
.spyOn(global, "fetch")
|
||||
.mockResolvedValueOnce({ json: () => Promise.resolve({ value: 0 }) } as Response)
|
||||
.mockResolvedValueOnce({ json: () => Promise.resolve({ value: 1 }) } as Response);
|
||||
|
||||
render(<Home />);
|
||||
await waitFor(() => expect(screen.getByText("0")).toBeDefined());
|
||||
|
||||
fireEvent.click(screen.getByText("Increment"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchSpy).toHaveBeenCalledWith(
|
||||
"http://localhost:8000/api/counter/increment",
|
||||
expect.objectContaining({
|
||||
method: "POST",
|
||||
headers: { Authorization: "Bearer valid-token" },
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("clicking increment updates displayed count", async () => {
|
||||
vi.spyOn(global, "fetch")
|
||||
.mockResolvedValueOnce({ json: () => Promise.resolve({ value: 0 }) } as Response)
|
||||
.mockResolvedValueOnce({ json: () => Promise.resolve({ value: 1 }) } as Response);
|
||||
|
||||
render(<Home />);
|
||||
await waitFor(() => expect(screen.getByText("0")).toBeDefined());
|
||||
|
||||
fireEvent.click(screen.getByText("Increment"));
|
||||
await waitFor(() => expect(screen.getByText("1")).toBeDefined());
|
||||
});
|
||||
});
|
||||
|
||||
test("renders +1 button", async () => {
|
||||
vi.spyOn(global, "fetch").mockResolvedValue({
|
||||
json: () => Promise.resolve({ value: 0 }),
|
||||
} as Response);
|
||||
describe("Home - Unauthenticated", () => {
|
||||
test("redirects to login when not authenticated", async () => {
|
||||
mockUser = null;
|
||||
mockToken = null;
|
||||
|
||||
render(<Home />);
|
||||
expect(screen.getByText("+1")).toBeDefined();
|
||||
});
|
||||
render(<Home />);
|
||||
|
||||
test("clicking button calls increment endpoint", async () => {
|
||||
const fetchSpy = vi.spyOn(global, "fetch")
|
||||
.mockResolvedValueOnce({ json: () => Promise.resolve({ value: 0 }) } as Response)
|
||||
.mockResolvedValueOnce({ json: () => Promise.resolve({ value: 1 }) } as Response);
|
||||
await waitFor(() => {
|
||||
expect(mockPush).toHaveBeenCalledWith("/login");
|
||||
});
|
||||
});
|
||||
|
||||
render(<Home />);
|
||||
await waitFor(() => expect(screen.getByText("0")).toBeDefined());
|
||||
test("returns null when not authenticated", () => {
|
||||
mockUser = null;
|
||||
mockToken = null;
|
||||
|
||||
fireEvent.click(screen.getByText("+1"));
|
||||
const { container } = render(<Home />);
|
||||
// Should render nothing (just redirects)
|
||||
expect(container.querySelector("main")).toBeNull();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchSpy).toHaveBeenCalledWith(
|
||||
"http://localhost:8000/api/counter/increment",
|
||||
{ method: "POST" }
|
||||
);
|
||||
test("does not fetch counter when no token", () => {
|
||||
mockUser = null;
|
||||
mockToken = null;
|
||||
const fetchSpy = vi.spyOn(global, "fetch");
|
||||
|
||||
render(<Home />);
|
||||
|
||||
expect(fetchSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
test("clicking button updates displayed count", async () => {
|
||||
vi.spyOn(global, "fetch")
|
||||
.mockResolvedValueOnce({ json: () => Promise.resolve({ value: 0 }) } as Response)
|
||||
.mockResolvedValueOnce({ json: () => Promise.resolve({ value: 1 }) } as Response);
|
||||
describe("Home - Loading State", () => {
|
||||
test("does not redirect while loading", () => {
|
||||
mockIsLoading = true;
|
||||
mockUser = null;
|
||||
mockToken = null;
|
||||
|
||||
render(<Home />);
|
||||
await waitFor(() => expect(screen.getByText("0")).toBeDefined());
|
||||
render(<Home />);
|
||||
|
||||
fireEvent.click(screen.getByText("+1"));
|
||||
await waitFor(() => expect(screen.getByText("1")).toBeDefined());
|
||||
expect(mockPush).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("shows loading indicator while loading", () => {
|
||||
mockIsLoading = true;
|
||||
|
||||
render(<Home />);
|
||||
|
||||
expect(screen.getByText("Loading...")).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue