83 lines
3.8 KiB
TypeScript
83 lines
3.8 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { createElement } from "react";
|
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
import { FeaturedExpertsRail } from "@/components/FeaturedExpertsRail";
|
|
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> = {}): 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> = {}): DiscoverMinnect => ({
|
|
id: 9, question: "How do I price?", views: 1234, thumbnailUrl: "https://x/t.jpg",
|
|
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<typeof createElement>) => renderToStaticMarkup(el);
|
|
|
|
describe("FeaturedExpertsRail", () => {
|
|
it("renders a card with name, byline, rating and reviews", () => {
|
|
const out = html(createElement(FeaturedExpertsRail, { experts: [expert()] }));
|
|
expect(out).toContain("<h2");
|
|
expect(out).toContain("Ann Lee");
|
|
expect(out).toContain("Growth coach");
|
|
expect(out).toContain("4.8");
|
|
expect(out).toContain("12 reviews");
|
|
expect(out).toContain("<img");
|
|
});
|
|
it("falls back to initials and omits missing fields", () => {
|
|
const out = html(createElement(FeaturedExpertsRail, {
|
|
experts: [expert({ pictureUrl: null, byline: null, rating: null, reviewsCount: null })],
|
|
}));
|
|
expect(out).not.toContain("<img");
|
|
expect(out).toContain("AL");
|
|
expect(out).not.toContain("review");
|
|
});
|
|
it("renders nothing when empty", () => {
|
|
expect(html(createElement(FeaturedExpertsRail, { 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("<audio");
|
|
expect(out).toContain("controls");
|
|
expect(out).toContain('src="https://x/a.mp3"');
|
|
expect(out).toContain("t.jpg");
|
|
});
|
|
it("has no audio element or thumbnail when those are missing", () => {
|
|
const out = html(createElement(TrendingMinnectsRail, {
|
|
minnects: [minnect({ audio: { url: null, duration: null, waveform: null }, thumbnailUrl: null, question: null, views: null })],
|
|
}));
|
|
expect(out).not.toContain("<audio");
|
|
expect(out).not.toContain("minnect-thumb");
|
|
expect(out).toContain("Ann Lee");
|
|
});
|
|
});
|
|
|
|
describe("DiscoverRailsView / fetchDiscover", () => {
|
|
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");
|
|
});
|
|
});
|