// @vitest-environment jsdom import { cleanup, fireEvent, render, screen } from "@testing-library/react"; import type React from "react"; import { afterEach, describe, expect, it, vi } from "vitest"; vi.mock("framer-motion", () => ({ motion: { div: ({ children, ...props }: React.PropsWithChildren>) => (
{children}
), }, AnimatePresence: ({ children }: React.PropsWithChildren) => <>{children}, })); import { BentoGrid } from "@landing/components/bento-grid"; afterEach(cleanup); function getCountText(): string { const el = screen.getByText(/^Showing/); return el.textContent ?? ""; } describe("BentoGrid", () => { it("renders the section heading", () => { render(); expect(screen.getByText("50 tools. Zero cloud dependency.")).toBeDefined(); }); it("renders the search input", () => { render(); expect(screen.getByPlaceholderText("Search tools...")).toBeDefined(); }); it("shows all tools by default", () => { render(); const text = getCountText(); expect(text).toMatch(/Showing 50 of 50 tools/); }); it("renders category filter pills including All", () => { render(); expect(screen.getByText((_, el) => el?.textContent === "All (50)")).toBeDefined(); expect(screen.getByText(/Essentials/)).toBeDefined(); expect(screen.getByText(/AI Tools/)).toBeDefined(); expect(screen.getByText(/Optimization/)).toBeDefined(); }); it("filters tools by search query", () => { render(); const input = screen.getByPlaceholderText("Search tools..."); fireEvent.change(input, { target: { value: "resize" } }); expect(screen.getByText("Resize")).toBeDefined(); const text = getCountText(); expect(text).toMatch(/Showing \d+ of 50 tools/); expect(screen.queryByText("OCR / Text Extraction")).toBeNull(); }); it("filters tools by category", () => { render(); const aiButton = screen.getByText(/AI Tools/); fireEvent.click(aiButton); const text = getCountText(); expect(text).toMatch(/Showing 15 of 50 tools/); expect(screen.getByText("Remove Background")).toBeDefined(); expect(screen.queryByText("Resize")).toBeNull(); }); it("shows empty state when search matches nothing", () => { render(); const input = screen.getByPlaceholderText("Search tools..."); fireEvent.change(input, { target: { value: "xyznonexistent" } }); expect(screen.getByText("No tools found. Try a different search.")).toBeDefined(); const text = getCountText(); expect(text).toMatch(/Showing 0 of 50 tools/); }); it("combines search and category filter", () => { render(); const aiButton = screen.getByText(/AI Tools/); fireEvent.click(aiButton); const input = screen.getByPlaceholderText("Search tools..."); fireEvent.change(input, { target: { value: "background" } }); expect(screen.getByText("Remove Background")).toBeDefined(); expect(screen.queryByText("Image Upscaling")).toBeNull(); }); it("clicking All resets category filter", () => { render(); fireEvent.click(screen.getByText(/AI Tools/)); expect(getCountText()).toMatch(/Showing 15 of 50 tools/); fireEvent.click(screen.getByText((_, el) => el?.textContent === "All (50)")); expect(getCountText()).toMatch(/Showing 50 of 50 tools/); }); it("renders each tool with name and description", () => { render(); expect(screen.getByText("Crop")).toBeDefined(); expect(screen.getByText("Freeform crop, aspect ratio presets, shape crop")).toBeDefined(); }); it("renders all 8 category pills", () => { render(); const categoryNames = [ "Essentials", "Optimization", "Adjustments", "AI Tools", "Watermark & Overlay", "Utilities", "Layout & Composition", "Format & Conversion", ]; for (const name of categoryNames) { expect(screen.getByText(new RegExp(name))).toBeDefined(); } }); });