80 lines
3.5 KiB
TypeScript
80 lines
3.5 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { createElement } from "react";
|
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
import { PostCard } from "@/components/PostCard";
|
|
import { toCardPosts } from "@/lib/feed-model";
|
|
import { choosePlayback, supportsNativeHls } from "@/lib/video-playback";
|
|
|
|
const MP4 = "https://cdn.feed.sharedservices.vt.com/v.mp4";
|
|
const HLS = "https://stream.mux.com/abc.m3u8";
|
|
const item = (media: Record<string, unknown>) => ({
|
|
type: "post",
|
|
publishedAt: "2026-10-19T10:00:00Z",
|
|
post: { id: "1", content: "hi", author: { displayName: "Ann" }, mediaItems: [media] },
|
|
});
|
|
const html = (media: Record<string, unknown>) =>
|
|
renderToStaticMarkup(createElement(PostCard, { post: toCardPosts([item(media)])[0] }));
|
|
|
|
describe("choosePlayback", () => {
|
|
it("no hlsUrl means no player", () => {
|
|
expect(choosePlayback(null, { nativeHls: true, hlsJsSupported: true })).toBe("none");
|
|
expect(choosePlayback(undefined, { nativeHls: false, hlsJsSupported: true })).toBe("none");
|
|
});
|
|
it("prefers hls.js whenever it is supported, even if native HLS is reported", () => {
|
|
expect(choosePlayback(HLS, { nativeHls: true, hlsJsSupported: true })).toBe("hlsjs");
|
|
expect(choosePlayback(HLS, { nativeHls: false, hlsJsSupported: true })).toBe("hlsjs");
|
|
});
|
|
it("uses native HLS only when hls.js is unsupported", () => {
|
|
expect(choosePlayback(HLS, { nativeHls: true, hlsJsSupported: false })).toBe("native");
|
|
});
|
|
it("falls back to none when neither is available", () => {
|
|
expect(choosePlayback(HLS, { nativeHls: false, hlsJsSupported: false })).toBe("none");
|
|
});
|
|
it("detects native HLS from canPlayType", () => {
|
|
expect(supportsNativeHls({ canPlayType: () => "maybe" })).toBe(true);
|
|
expect(supportsNativeHls({ canPlayType: () => "" })).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("video media in the card", () => {
|
|
const video = { mediaType: "video", thumbnailUrl: "https://i/v.jpg" };
|
|
it("hlsUrl present renders an accessible controls player with the poster", () => {
|
|
const out = html({ ...video, hlsUrl: HLS });
|
|
expect(out).toContain("<video");
|
|
expect(out).toContain("controls");
|
|
expect(out).toContain('poster="https://i/v.jpg"');
|
|
expect(out).toContain('aria-label="Video from Ann"');
|
|
expect(out).not.toContain("autoplay");
|
|
});
|
|
it("hlsUrl absent shows the thumbnail only, no player", () => {
|
|
const out = html(video);
|
|
expect(out).not.toContain("<video");
|
|
expect(out).toContain('src="https://i/v.jpg"');
|
|
});
|
|
it("rejects an hlsUrl not on stream.mux.com", () => {
|
|
const out = html({ ...video, hlsUrl: "https://evil.example/x.m3u8" });
|
|
expect(out).not.toContain("<video");
|
|
expect(out).toContain('src="https://i/v.jpg"');
|
|
});
|
|
it("prefers mp4Url: plain video source, no hls.js needed", () => {
|
|
const out = html({ ...video, hlsUrl: HLS, mp4Url: MP4 });
|
|
expect(out).toContain("<video");
|
|
expect(out).toContain(`src="${MP4}"`);
|
|
expect(out).toContain('poster="https://i/v.jpg"');
|
|
expect(out).not.toContain("m3u8");
|
|
expect(out).not.toContain("autoplay");
|
|
});
|
|
it("mp4Url alone renders the player", () => {
|
|
expect(html({ ...video, mp4Url: MP4 })).toContain(`src="${MP4}"`);
|
|
});
|
|
it("hls-only video renders a video without a src (hls.js attaches it)", () => {
|
|
const out = html({ ...video, hlsUrl: HLS });
|
|
expect(out).toContain("<video");
|
|
expect(out).not.toContain(`src="${HLS}"`);
|
|
});
|
|
it("rejects an mp4Url off the feed CDN", () => {
|
|
const out = html({ ...video, mp4Url: "https://evil.example/v.mp4" });
|
|
expect(out).not.toContain("<video");
|
|
});
|
|
});
|