// @vitest-environment jsdom import { act } from "react"; import { createRoot, type Root } from "react-dom/client"; import { renderToStaticMarkup } from "react-dom/server"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; vi.mock("@lingui/react/macro", () => { const t = (parts: TemplateStringsArray, ...values: unknown[]) => parts.reduce( (text, part, index) => text + part + (index < values.length ? values[index] : ""), "", ); return { useLingui: () => ({ t }) }; }); import { MediaPlayer } from "./MediaPlayer"; let container: HTMLDivElement; let root: Root; beforeEach(() => { vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true); container = document.createElement("div"); document.body.append(container); root = createRoot(container); }); afterEach(async () => { await act(async () => root.unmount()); container.remove(); vi.unstubAllGlobals(); }); describe("MediaPlayer", () => { it("loads nothing before it is near the viewport and fits vertical video to the column", () => { const html = renderToStaticMarkup( , ); expect(html).toContain('aria-label="clip.mp4"'); expect(html).not.toContain("src="); expect(html).toContain("width:270px"); expect(html).toContain("aspect-ratio:270 / 480"); }); it("streams video with its poster from the artifact route once visible", async () => { vi.stubGlobal( "IntersectionObserver", class { constructor(private readonly callback: IntersectionObserverCallback) {} observe() { this.callback([{ isIntersecting: true } as IntersectionObserverEntry], this as never); } disconnect() {} }, ); await act(async () => root.render( , ), ); const video = container.querySelector("video")!; expect(video.getAttribute("src")).toBe("/api/artifacts/art-1"); expect(video.getAttribute("poster")).toBe("/api/artifacts/art-2"); expect(video.getAttribute("preload")).toBe("metadata"); expect(video.hasAttribute("controls")).toBe(true); }); it("sizes the frame from the file when the block has no dimensions", async () => { await act(async () => root.render(), ); const frame = container.querySelector('[data-testid="media-video"]')!; expect(frame.style.width).toBe("420px"); const video = container.querySelector("video")!; Object.defineProperty(video, "videoWidth", { value: 1080 }); Object.defineProperty(video, "videoHeight", { value: 1920 }); await act(async () => { video.dispatchEvent(new Event("loadedmetadata")); }); expect(frame.style.width).toBe("270px"); }); it("falls back to a download link when the browser cannot play the file", async () => { await act(async () => root.render(), ); const audio = container.querySelector("audio")!; expect(audio.getAttribute("src")).toBe("/api/artifacts/art-3"); await act(async () => { audio.dispatchEvent(new Event("error")); }); expect(container.querySelector("audio")).toBeNull(); const link = container.querySelector("a")!; expect(link.getAttribute("href")).toBe("/api/artifacts/art-3?download=1"); expect(link.getAttribute("download")).toBe("memo.ogg"); expect(link.getAttribute("aria-label")).toBe("Download memo.ogg"); }); });