diff --git a/tests/unit/landing/privacy.test.tsx b/tests/unit/landing/privacy.test.tsx
new file mode 100644
index 00000000..890fdcf0
--- /dev/null
+++ b/tests/unit/landing/privacy.test.tsx
@@ -0,0 +1,103 @@
+// @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("@/components/fade-in", () => ({
+ FadeIn: ({ children }: React.PropsWithChildren) =>
{children}
,
+}));
+
+vi.mock("@/components/footer", () => ({
+ Footer: () => ,
+}));
+
+vi.mock("@/components/navbar", () => ({
+ Navbar: () => ,
+}));
+
+const fetchMock = vi.fn().mockResolvedValue({
+ json: () => Promise.resolve({ stargazers_count: 100 }),
+});
+vi.stubGlobal("fetch", fetchMock);
+
+import PrivacyPage from "@landing/app/privacy/page";
+
+afterEach(cleanup);
+
+describe("PrivacyPage", () => {
+ it("renders the page heading", () => {
+ render();
+ expect(screen.getByText("Privacy Policy")).toBeDefined();
+ });
+
+ it("renders the last updated date", () => {
+ render();
+ expect(screen.getByText(/Last updated/)).toBeDefined();
+ });
+
+ it("renders the Navbar and Footer", () => {
+ render();
+ expect(screen.getByTestId("navbar")).toBeDefined();
+ expect(screen.getByTestId("footer")).toBeDefined();
+ });
+
+ it("renders the Overview section", () => {
+ render();
+ expect(screen.getByText("Overview")).toBeDefined();
+ expect(screen.getByText(/self-hosted software/)).toBeDefined();
+ });
+
+ it("renders all section headings", () => {
+ render();
+ const headings = [
+ "Overview",
+ "Website (snapotter.com)",
+ "Self-Hosted Software",
+ "Optional Analytics",
+ "Contact Form",
+ "Open Source",
+ "Changes",
+ "Contact",
+ ];
+ for (const heading of headings) {
+ expect(screen.getByText(heading)).toBeDefined();
+ }
+ });
+
+ it("states no tracking cookies are used", () => {
+ render();
+ expect(screen.getByText("We do not use tracking cookies.")).toBeDefined();
+ });
+
+ it("states all processing happens on user server", () => {
+ render();
+ expect(screen.getByText("All image processing happens entirely on your server.")).toBeDefined();
+ });
+
+ it("states analytics is disabled by default", () => {
+ render();
+ expect(screen.getByText("Analytics is disabled by default.")).toBeDefined();
+ });
+
+ it("mentions PostHog for analytics", () => {
+ render();
+ expect(screen.getByText(/PostHog/)).toBeDefined();
+ });
+
+ it("mentions Formspree for contact form", () => {
+ render();
+ expect(screen.getAllByText(/Formspree/).length).toBeGreaterThanOrEqual(1);
+ });
+
+ it("renders the contact email link", () => {
+ render();
+ const emailLink = screen.getByText("contact@snapotter.com");
+ expect(emailLink.closest("a")?.getAttribute("href")).toBe("mailto:contact@snapotter.com");
+ });
+
+ it("states the codebase is open source and inspectable", () => {
+ render();
+ expect(screen.getByText(/inspect the entire codebase/)).toBeDefined();
+ });
+});