gm4ebnr3j: Add three-column layout with featured experts and trending minnects rails
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
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");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user