Files
frontend-helper/tests/video-playback.test.ts
T

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");
});
});