import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; describe("API client", () => { const originalFetch = global.fetch; beforeEach(() => { vi.resetModules(); }); afterEach(() => { global.fetch = originalFetch; }); it("getQuestions builds correct query string with filters", async () => { let capturedUrl = ""; global.fetch = vi.fn().mockImplementation((url: string) => { capturedUrl = url; return Promise.resolve({ ok: true, json: () => Promise.resolve({ items: [], total: 0, page: 1, limit: 20, pages: 0, }), }); }); const { getQuestions } = await import("./api"); await getQuestions({ page: 2, difficulty: "easy", category: "arrays" }); expect(capturedUrl).toContain("page=2"); expect(capturedUrl).toContain("difficulty=easy"); expect(capturedUrl).toContain("category=arrays"); }); it("getQuestions omits empty filters", async () => { let capturedUrl = ""; global.fetch = vi.fn().mockImplementation((url: string) => { capturedUrl = url; return Promise.resolve({ ok: true, json: () => Promise.resolve({ items: [], total: 0, page: 1, limit: 20, pages: 0, }), }); }); const { getQuestions } = await import("./api"); await getQuestions({}); expect(capturedUrl).not.toContain("?"); }); it("throws error on non-ok response", async () => { global.fetch = vi.fn().mockResolvedValue({ ok: false, status: 404, statusText: "Not Found", }); const { getQuestion } = await import("./api"); await expect(getQuestion("nonexistent")).rejects.toThrow("API error: 404"); }); it("getStats returns stats data", async () => { const mockStats = { total_questions: 10, by_difficulty: { easy: 3, medium: 5, hard: 2 }, by_category: [], by_pattern: [], }; global.fetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(mockStats), }); const { getStats } = await import("./api"); const result = await getStats(); expect(result).toEqual(mockStats); }); });