Files
frontend-helper/tests/discover-rails.test.ts
T

102 lines
4.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",
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<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("renders a video with poster for video answers, no audio element", () => {
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("<video");
expect(out).toContain("controls");
expect(out).toContain("preload=\"none\"");
expect(out).toContain("X-Amz-Signature=abc");
expect(out).toContain('poster="https://x/t.jpg"');
expect(out).not.toContain("<audio");
expect(out).not.toContain("autoPlay");
});
it("has no media element for a missing url but keeps the thumbnail", () => {
const out = html(createElement(TrendingMinnectsRail, { minnects: [minnect({ media: null })] }));
expect(out).not.toContain("<audio");
expect(out).not.toContain("<video");
expect(out).toContain("minnect-thumb");
});
it("has no audio element or thumbnail when those are missing", () => {
const out = html(createElement(TrendingMinnectsRail, {
minnects: [minnect({ media: 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");
});
});