/** * QuickCaptureWidget Component Tests * Following TDD principles */ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { QuickCaptureWidget } from "../QuickCaptureWidget"; global.fetch = vi.fn() as typeof global.fetch; describe("QuickCaptureWidget", (): void => { beforeEach((): void => { vi.clearAllMocks(); // Set development mode by default for existing tests vi.stubEnv("NODE_ENV", "development"); }); afterEach((): void => { vi.unstubAllEnvs(); }); it("should render input field", (): void => { render(); expect(screen.getByRole("textbox")).toBeInTheDocument(); }); it("should render submit button", (): void => { render(); expect(screen.getByRole("button", { name: /add|capture|submit/i })).toBeInTheDocument(); }); it("should allow text input", async (): Promise => { const user = userEvent.setup(); render(); const input = screen.getByRole("textbox"); await user.type(input, "Quick note for later"); expect(input).toHaveValue("Quick note for later"); }); // TODO: Enable when API is implemented it.skip("should submit note when button clicked", async (): Promise => { const user = userEvent.setup(); vi.mocked(global.fetch).mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ success: true }), } as unknown as Response); render(); const input = screen.getByRole("textbox"); const button = screen.getByRole("button", { name: /add|capture|submit/i }); await user.type(input, "New quick note"); await user.click(button); await waitFor(() => { expect(global.fetch).toHaveBeenCalledWith( expect.stringContaining("/api"), expect.objectContaining({ method: "POST", }) ); }); }); it("should clear input after successful submission", async (): Promise => { const user = userEvent.setup(); vi.mocked(global.fetch).mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ success: true }), } as unknown as Response); render(); const input = screen.getByRole("textbox"); const button = screen.getByRole("button", { name: /add|capture|submit/i }); await user.type(input, "Test note"); await user.click(button); await waitFor(() => { expect(input).toHaveValue(""); }); }); // TODO: Enable when API is implemented it.skip("should handle submission errors", async (): Promise => { const user = userEvent.setup(); vi.mocked(global.fetch).mockRejectedValueOnce(new Error("API Error")); render(); const input = screen.getByRole("textbox"); const button = screen.getByRole("button", { name: /add|capture|submit/i }); await user.type(input, "Test note"); await user.click(button); await waitFor(() => { expect(screen.getByText(/error|failed/i)).toBeInTheDocument(); }); }); it("should not submit empty notes", async (): Promise => { const user = userEvent.setup(); render(); const button = screen.getByRole("button", { name: /add|capture|submit/i }); await user.click(button); expect(global.fetch).not.toHaveBeenCalled(); }); // TODO: Enable when API is implemented it.skip("should support keyboard shortcut (Enter)", async (): Promise => { const user = userEvent.setup(); vi.mocked(global.fetch).mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ success: true }), } as unknown as Response); render(); const input = screen.getByRole("textbox"); await user.type(input, "Quick note{Enter}"); await waitFor(() => { expect(global.fetch).toHaveBeenCalled(); }); }); it("should show success feedback after submission", async (): Promise => { const user = userEvent.setup(); render(); const input = screen.getByRole("textbox"); const button = screen.getByRole("button", { name: /submit/i }); await user.type(input, "Test note"); await user.click(button); await waitFor(() => { // Check for "Recently captured:" text which shows success expect(screen.getByText(/Recently captured/i)).toBeInTheDocument(); // Check that the note appears in the list expect(screen.getByText("Test note")).toBeInTheDocument(); }); }); describe("Environment-based behavior", (): void => { it("should show Coming Soon placeholder in production", (): void => { vi.stubEnv("NODE_ENV", "production"); render(); // Should show Coming Soon badge expect(screen.getByText("Coming Soon")).toBeInTheDocument(); // Should show feature name expect(screen.getByText("Quick Capture")).toBeInTheDocument(); // Should show description expect( screen.getByText(/Quickly jot down ideas for later organization/i) ).toBeInTheDocument(); // Should NOT show the input field expect(screen.queryByRole("textbox")).not.toBeInTheDocument(); // Should NOT show the submit button expect(screen.queryByRole("button")).not.toBeInTheDocument(); }); it("should show full widget in development mode", (): void => { vi.stubEnv("NODE_ENV", "development"); render(); // Should show the input field expect(screen.getByRole("textbox")).toBeInTheDocument(); // Should show the submit button expect(screen.getByRole("button", { name: /submit/i })).toBeInTheDocument(); // Should NOT show Coming Soon badge expect(screen.queryByText("Coming Soon")).not.toBeInTheDocument(); }); it("should show Coming Soon placeholder in test mode (non-development)", (): void => { vi.stubEnv("NODE_ENV", "test"); render(); // Test mode is not development, so should show Coming Soon expect(screen.getByText("Coming Soon")).toBeInTheDocument(); expect(screen.queryByRole("textbox")).not.toBeInTheDocument(); }); }); });