import { describe, expect, it } from "vitest"; import { createElement } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { FeaturedCarousel } from "@/components/FeaturedCarousel"; import { TrendingMinnectsRail } from "@/components/TrendingMinnectsRail"; import { DiscoverRailsView } from "@/components/DiscoverRails"; import { fetchDiscover } from "@/lib/discover-client"; import type { DiscoverExpert, DiscoverMinnect } from "@/lib/discover"; const expert = (o: Partial = {}): DiscoverExpert => ({ id: 1, slug: "ann", displayName: "Ann Lee", byline: "Growth coach", pictureUrl: "https://x/a.jpg", rating: 4.8, reviewsCount: 12, available: true, location: { city: null, country: null }, ...o, }); const minnect = (o: Partial = {}): DiscoverMinnect => ({ id: 9, question: "How do I price?", views: 1234, thumbnailUrl: "https://x/t.jpg", media: { kind: "audio", url: "https://x/a.mp3", duration: 30, waveform: null }, expert: { slug: "ann", displayName: "Ann Lee", pictureUrl: null, byline: null, rating: null }, ...o, }); const html = (el: ReturnType) => renderToStaticMarkup(el); describe("FeaturedCarousel (static render)", () => { it("renders the center expert with name, byline, rating and reviews", () => { const out = html(createElement(FeaturedCarousel, { experts: [expert()] })); expect(out).toContain(" { const out = html(createElement(FeaturedCarousel, { experts: [expert({ pictureUrl: null, byline: null, rating: null, reviewsCount: null })], })); expect(out).not.toContain(" { expect(html(createElement(FeaturedCarousel, { experts: [] }))).toBe(""); }); }); describe("TrendingMinnectsRail", () => { it("renders question, views, thumbnail and an audio control", () => { const out = html(createElement(TrendingMinnectsRail, { minnects: [minnect()] })); expect(out).toContain("How do I price?"); expect(out).toContain("1,234 views"); expect(out).toContain(" { const url = "https://valuentainment-quick-questions-prod.s3.amazonaws.com/a.mov?X-Amz-Signature=abc"; const out = html(createElement(TrendingMinnectsRail, { minnects: [minnect({ media: { kind: "video", url, duration: 9, waveform: null } })], })); expect(out).toContain("]*controls/); expect(out).toContain('class="trend-play"'); expect(out).toContain("preload=\"none\""); expect(out).toContain("X-Amz-Signature=abc"); expect(out).toContain('poster="https://x/t.jpg"'); expect(out).not.toContain(" { const out = html(createElement(TrendingMinnectsRail, { minnects: [minnect({ media: null })] })); expect(out).not.toContain(" { const out = html(createElement(TrendingMinnectsRail, { minnects: [minnect({ media: null, thumbnailUrl: null, question: null, views: null })], })); expect(out).not.toContain(" { it("renders both rails from data and nothing when null", () => { const data = { featuredExperts: [expert()], trendingMinnects: [minnect()], categories: [] }; const out = html(createElement(DiscoverRailsView, { data })); expect(out).toContain("Featured experts"); expect(out).toContain("Trending minnects"); expect(html(createElement(DiscoverRailsView, { data: null }))).toBe(""); }); it("fetches /api/discover and tolerates missing arrays", async () => { const f = (async () => new Response(JSON.stringify({ featuredExperts: [expert()] }), { status: 200 })) as typeof fetch; const d = await fetchDiscover(f); expect(d.featuredExperts).toHaveLength(1); expect(d.trendingMinnects).toEqual([]); }); it("throws on a 502", async () => { const f = (async () => new Response("{}", { status: 502 })) as typeof fetch; await expect(fetchDiscover(f)).rejects.toThrow("discover_unavailable"); }); });