// @vitest-environment jsdom import { cleanup, 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}
), span: ({ children, ...props }: React.PropsWithChildren>) => ( {children} ), }, AnimatePresence: ({ children }: React.PropsWithChildren) => <>{children}, })); const fetchMock = vi.fn().mockResolvedValue({ json: () => Promise.resolve({ stargazers_count: 500 }), }); vi.stubGlobal("fetch", fetchMock); import { Enterprise } from "@landing/components/enterprise"; import { Footer } from "@landing/components/footer"; import { Hero } from "@landing/components/hero"; import { OpenSource } from "@landing/components/open-source"; import { Pricing } from "@landing/components/pricing"; import { TypingCursor } from "@landing/components/typing-cursor"; import { WhyChoose } from "@landing/components/why-choose"; afterEach(cleanup); // ── Hero ────────────────────────────────────────────────────────────── describe("Hero", () => { it("renders the headline", () => { render(); expect(screen.getByText("Your images. Stay yours.")).toBeDefined(); }); it("renders the subheadline", () => { render(); expect(screen.getByText("Every image tool you need.")).toBeDefined(); }); it("renders the CTA button linking to GitHub", () => { render(); const cta = screen.getByText("Get it for free"); const link = cta.closest("a"); expect(link?.getAttribute("href")).toBe("https://github.com/snapotter-hq/snapotter"); expect(link?.getAttribute("target")).toBe("_blank"); }); it("renders the word cloud (hidden on mobile)", () => { render(); expect(screen.getByText("Resize")).toBeDefined(); expect(screen.getByText("OCR")).toBeDefined(); expect(screen.getByText("Remove BG")).toBeDefined(); }); }); // ── TypingCursor ────────────────────────────────────────────────────── describe("TypingCursor", () => { it("renders the first phrase", () => { render(); expect(screen.getByText("No signups. No accounts.")).toBeDefined(); }); it("uses a 3-second interval for rotation", () => { vi.useFakeTimers(); render(); const first = screen.getByText("No signups. No accounts."); expect(first).toBeDefined(); vi.useRealTimers(); }); }); // ── WhyChoose ───────────────────────────────────────────────────────── describe("WhyChoose", () => { it("renders the section heading", () => { render(); expect(screen.getByText("Built different. On purpose.")).toBeDefined(); }); it("renders all 9 benefit cards", () => { render(); const titles = [ "No Signup", "No Uploads", "Forever Free", "No Limits", "Batch Processing", "Lightning Fast", "Open Source", "REST API", "Pipeline Automation", ]; for (const title of titles) { expect(screen.getByText(title)).toBeDefined(); } }); it("renders descriptions for each card", () => { render(); expect(screen.getByText("Start instantly, no accounts or emails required.")).toBeDefined(); expect(screen.getByText("Chain tools together. Automate your workflows.")).toBeDefined(); }); }); // ── Enterprise ──────────────────────────────────────────────────────── describe("Enterprise", () => { it("renders the section heading", () => { render(); expect(screen.getByText("Your data never leaves your network.")).toBeDefined(); }); it("renders all 3 enterprise feature cards", () => { render(); expect(screen.getByText("Data Sovereignty")).toBeDefined(); expect(screen.getByText("Enterprise Controls")).toBeDefined(); expect(screen.getByText("Deploy Anywhere")).toBeDefined(); }); it("mentions compliance standards", () => { render(); expect(screen.getByText(/GDPR, HIPAA, CCPA/)).toBeDefined(); }); }); // ── Pricing ─────────────────────────────────────────────────────────── describe("Pricing", () => { it("renders the section heading", () => { render(); expect(screen.getByText(/Free for everyone/)).toBeDefined(); }); it("renders both plan names", () => { render(); expect(screen.getByText("Open Source")).toBeDefined(); expect(screen.getByText("Enterprise")).toBeDefined(); }); it("renders Free price", () => { render(); expect(screen.getByText("Free")).toBeDefined(); }); it("renders Custom price for enterprise", () => { render(); expect(screen.getByText("Custom")).toBeDefined(); }); it("renders free plan features", () => { render(); expect(screen.getByText("All 51 image processing tools")).toBeDefined(); expect(screen.getByText("Unlimited usage, no hidden caps")).toBeDefined(); expect(screen.getByText("15 local AI models included")).toBeDefined(); expect(screen.getByText("AGPL-3.0 licensed")).toBeDefined(); }); it("renders enterprise features", () => { render(); expect(screen.getByText("Everything in Open Source")).toBeDefined(); expect(screen.getByText("Priority email and video support")).toBeDefined(); expect(screen.getByText("OEM and white-label options")).toBeDefined(); }); it("links free plan CTA to GitHub", () => { render(); const freeButton = screen.getByText(/Get Started Free/); expect(freeButton.closest("a")?.getAttribute("href")).toBe( "https://github.com/snapotter-hq/snapotter", ); }); it("links enterprise CTA to contact page", () => { render(); const contactButton = screen.getByText(/Contact Sales/); expect(contactButton.closest("a")?.getAttribute("href")).toBe("/contact"); }); }); // ── OpenSource ──────────────────────────────────────────────────────── describe("OpenSource", () => { it("renders the heading", () => { render(); expect(screen.getByText("Open source. Always.")).toBeDefined(); }); it("renders the description mentioning AGPL-3.0", () => { render(); expect(screen.getByText(/AGPL-3.0 licensed/)).toBeDefined(); }); it("links to GitHub", () => { render(); const link = screen.getByText("Star on GitHub").closest("a"); expect(link?.getAttribute("href")).toBe("https://github.com/snapotter-hq/snapotter"); }); }); // ── Footer ──────────────────────────────────────────────────────────── describe("Footer", () => { it("renders the brand", () => { render(