import { describe, expect, it } from "vitest"; import { createElement, type FC } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { readFileSync } from "node:fs"; import { BottomSheet } from "@/components/BottomSheet"; const css = readFileSync("src/styles/sheet.css", "utf8"); const feed = readFileSync("src/components/MobileFeed.tsx", "utf8"); describe("BottomSheet", () => { const html = renderToStaticMarkup(createElement(BottomSheet as FC<{ title: string; onClose: () => void }>, { title: "New post", onClose: () => {} }, createElement("p", null, "body"))); it("is a modal dialog named by its serif title, with a grab handle, close buttons and a backdrop", () => { expect(html).toContain('role="dialog"'); expect(html).toContain('aria-modal="true"'); expect(html).toMatch(/aria-labelledby="([^"]+)"[\s\S]*

]*type-title[^>]*>New post<\/h2>/); expect(html).toContain("sheet-grab"); expect(html).toContain('class="sheet-bg"'); expect(html.match(/aria-label="Close"/g)?.length).toBe(2); expect(html).toContain("

body

"); }); it("slides up over 450ms and turns the motion off under reduced motion", () => { expect(css).toMatch(/animation: sheet-up \.45s/); expect(css).toMatch(/prefers-reduced-motion: reduce[\s\S]*animation: none/); expect(css).toMatch(/backdrop-filter: blur\(3px\)/); }); it("gives the composer sheet a 150px text area", () => { expect(css).toMatch(/\.sheet-composer \.composer textarea[\s\S]*height: 150px/); }); }); describe("phone feed sheets", () => { it("opens the shared comments section and composer from the dock", () => { expect(feed).toContain('"); }); });