import { describe, it, expect, vi, beforeEach } from "vitest"; import { screen, within } from "@testing-library/react"; import { renderWithProviders as render } from "../utils/test-utils"; import LearnPage from "../../app/(marketing)/learn/page"; vi.mock("../../lib/content", () => ({ getAllBlogPosts: vi.fn(), })); vi.mock("../../app/components/sections/AskOrganizer", () => ({ default: ({ title, subtitle, buttonText, }: { title: string; subtitle: string; buttonText: string; }) => (

{title}

{subtitle}

), })); const mockPosts = [ { slug: "resolving-active-conflicts", frontmatter: { title: "Resolving Active Conflicts", description: "Practical steps for resolving conflicts", author: "CommunityRule", date: "2025-04-15", thumbnail: { vertical: "resolving-active-conflicts-vertical.svg", horizontal: "resolving-active-conflicts-horizontal.svg", }, }, content: "", htmlContent: "", filePath: "resolving-active-conflicts.md", lastModified: new Date(), }, { slug: "operational-security-mutual-aid", frontmatter: { title: "Operational Security for Mutual Aid", description: "Tactics to protect members", author: "CommunityRule", date: "2025-04-10", thumbnail: { vertical: "operational-security-mutual-aid-vertical.svg", horizontal: "operational-security-mutual-aid-horizontal.svg", }, }, content: "", htmlContent: "", filePath: "operational-security-mutual-aid.md", lastModified: new Date(), }, ]; describe("LearnPage", () => { beforeEach(async () => { vi.clearAllMocks(); const { getAllBlogPosts } = await import("../../lib/content"); vi.mocked(getAllBlogPosts).mockReturnValue(mockPosts); }); it("renders the learn sections, with the guide first and the FAQ open", () => { render(); expect( screen.getByRole("heading", { name: /See how groups use/ }), ).toBeInTheDocument(); expect( screen.getByRole("link", { name: "View Boulder Street Medics use case" }), ).toHaveAttribute("href", "/use-cases/boulder-county-street-medics"); expect( screen.getByRole("heading", { name: "Who is this for?" }), ).toBeInTheDocument(); expect(screen.getByText("Organizing is hard")).toBeInTheDocument(); expect( screen.getByText( /Find answers to your questions and see how other communities/, ), ).toBeInTheDocument(); const guideLinks = screen.getAllByRole("link", { name: "Read the guide" }); expect(guideLinks.length).toBeGreaterThan(0); for (const link of guideLinks) { expect(link).toHaveAttribute("href", "/how-it-works"); } expect( screen.getByRole("heading", { name: "Why horizontal communities need CommunityRule", }), ).toBeInTheDocument(); expect( screen.getByText("Transparent, inclusive decisions"), ).toBeInTheDocument(); const faq = screen.getByRole("region", { name: "Get answers to your questions", }); expect(faq).toHaveAttribute("id", "faq"); expect( within(faq).getByRole("button", { name: "Do we have to start from a blank page?", }), ).toHaveAttribute("aria-expanded", "true"); expect(screen.getByTestId("ask-organizer")).toBeInTheDocument(); expect(screen.getByText("Still have questions?")).toBeInTheDocument(); }); it("renders the guide and one card per post, without a duplicate grid", () => { render(); const grid = screen.getByTestId("learn-article-grid"); expect(grid).toHaveClass("md:justify-center", "md:flex-wrap"); expect(grid).toHaveClass( "lg:[&>*]:w-[calc((100%-2*var(--space-400))/3)]", ); expect(grid).toHaveClass( "xl:[&>*]:w-[calc((100%-3*var(--space-400))/4)]", ); expect(grid.className).not.toContain("/5)]"); const links = within(grid).getAllByRole("link"); expect(links).toHaveLength(mockPosts.length + 1); expect(links[0]).toHaveAttribute("href", "/how-it-works"); expect(links[1]).toHaveAttribute( "href", "/blog/resolving-active-conflicts", ); expect(links[2]).toHaveAttribute( "href", "/blog/operational-security-mutual-aid", ); expect(within(grid).queryByText("April 15, 2025")).not.toBeInTheDocument(); const sources = grid.querySelectorAll( "picture source[media='(min-width: 640px)']", ); expect(sources.length).toBe(mockPosts.length + 1); const icons = grid.querySelectorAll("img"); for (const icon of icons) { expect(icon).toHaveAttribute("alt", ""); } }); });