- Scaffold Vite + React 19 + TypeScript strict project - Neumorphic dark design system (Tailwind v3, amber/orange LED accents) - Zustand stores for auth (persist) and UI state (notifications, sidebar) - TanStack Query v5 hooks for server CRUD operations - WebSocket hook with reconnection backoff and query invalidation - Components: StatusLed, Sidebar, ServerCard, LoginPage, DashboardPage - Protected routing with auth guard - Axios client with JWT interceptor and 401 redirect - 68 tests across 11 test files (89% statement coverage, 90% function coverage) - TDD workflow: RED validated, GREEN achieved, coverage verified
116 lines
3.7 KiB
TypeScript
116 lines
3.7 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
import { render, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
|
|
import { ServerCard } from "@/components/servers/ServerCard";
|
|
import type { Server } from "@/hooks/useServers";
|
|
import {
|
|
useStartServer,
|
|
useStopServer,
|
|
useRestartServer,
|
|
} from "@/hooks/useServers";
|
|
|
|
vi.mock("@/hooks/useServers", () => ({
|
|
useStartServer: vi.fn(),
|
|
useStopServer: vi.fn(),
|
|
useRestartServer: vi.fn(),
|
|
}));
|
|
|
|
const mockMutation = (resolve?: boolean) => ({
|
|
mutateAsync: vi.fn(() => (resolve === false ? Promise.reject(new Error("fail")) : Promise.resolve())),
|
|
isPending: false,
|
|
});
|
|
|
|
function renderCard(server: Partial<Server> = {}) {
|
|
const fullServer: Server = {
|
|
id: 1,
|
|
name: "Test Arma3",
|
|
game_type: "arma3",
|
|
status: "running",
|
|
port: 2302,
|
|
max_players: 64,
|
|
current_players: 32,
|
|
restart_count: 3,
|
|
auto_restart: true,
|
|
created_at: "2026-01-01T00:00:00Z",
|
|
...server,
|
|
};
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: { queries: { retry: false } },
|
|
});
|
|
|
|
return {
|
|
user: userEvent.setup(),
|
|
...render(
|
|
<QueryClientProvider client={queryClient}>
|
|
<ServerCard server={fullServer} />
|
|
</QueryClientProvider>,
|
|
),
|
|
};
|
|
}
|
|
|
|
describe("ServerCard", () => {
|
|
beforeEach(() => {
|
|
vi.mocked(useStartServer).mockReturnValue(mockMutation() as unknown as ReturnType<typeof useStartServer>);
|
|
vi.mocked(useStopServer).mockReturnValue(mockMutation() as unknown as ReturnType<typeof useStopServer>);
|
|
vi.mocked(useRestartServer).mockReturnValue(mockMutation() as unknown as ReturnType<typeof useRestartServer>);
|
|
});
|
|
|
|
it("should render server name and game type", () => {
|
|
renderCard();
|
|
expect(screen.getByText("Test Arma3")).toBeInTheDocument();
|
|
expect(screen.getByText("arma3")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should display player count", () => {
|
|
renderCard();
|
|
expect(screen.getByText("32/64")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should display port number", () => {
|
|
renderCard({ port: 2302 });
|
|
expect(screen.getByText("2302")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should display restart count", () => {
|
|
renderCard({ restart_count: 3 });
|
|
expect(screen.getByText("3")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should show Stop button when server is running", () => {
|
|
renderCard({ status: "running" });
|
|
expect(screen.getByLabelText("Stop Test Arma3")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should show Start button when server is stopped", () => {
|
|
renderCard({ status: "stopped" });
|
|
expect(screen.getByLabelText("Start Test Arma3")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should not show Start button when server is running", () => {
|
|
renderCard({ status: "running" });
|
|
expect(screen.queryByLabelText(/Start Test Arma3/)).not.toBeInTheDocument();
|
|
});
|
|
|
|
it("should show Restart button when server is running", () => {
|
|
renderCard({ status: "running" });
|
|
expect(screen.getByLabelText("Restart Test Arma3")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should disable Stop button when server is starting", () => {
|
|
renderCard({ status: "starting" });
|
|
const stopBtn = screen.getByLabelText("Stop Test Arma3");
|
|
expect(stopBtn).toBeDisabled();
|
|
});
|
|
|
|
it("should call startServer on Start click", async () => {
|
|
const startMutation = mockMutation();
|
|
vi.mocked(useStartServer).mockReturnValue(startMutation as unknown as ReturnType<typeof useStartServer>);
|
|
|
|
const { user } = renderCard({ status: "stopped" });
|
|
await user.click(screen.getByLabelText("Start Test Arma3"));
|
|
expect(startMutation.mutateAsync).toHaveBeenCalledWith(1);
|
|
});
|
|
}); |