mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 14:50:02 +00:00
144 lines
4.1 KiB
TypeScript
144 lines
4.1 KiB
TypeScript
// @vitest-environment happy-dom
|
|
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import {
|
|
applyCachedSourceDurations,
|
|
getMediaProbeDiagnostics,
|
|
probeMediaUrl,
|
|
probeMissingSourceDurations,
|
|
resetMediaProbeRegistry,
|
|
} from "./mediaProbe";
|
|
|
|
const dispose = vi.fn();
|
|
const getDurationFromMetadata = vi.fn(async () => 5);
|
|
const requestedSources: string[] = [];
|
|
|
|
vi.mock("mediabunny", () => ({
|
|
ALL_FORMATS: {},
|
|
UrlSource: class {
|
|
constructor(readonly url: string) {
|
|
requestedSources.push(url);
|
|
}
|
|
},
|
|
Input: class {
|
|
getDurationFromMetadata = getDurationFromMetadata;
|
|
getPrimaryVideoTrack = vi.fn(async () => ({ displayWidth: 640, displayHeight: 360 }));
|
|
getAudioTracks = vi.fn(async () => []);
|
|
dispose = dispose;
|
|
},
|
|
}));
|
|
|
|
beforeEach(() => {
|
|
resetMediaProbeRegistry();
|
|
vi.clearAllMocks();
|
|
requestedSources.length = 0;
|
|
getDurationFromMetadata.mockResolvedValue(5);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
describe("media probe registry", () => {
|
|
it("deduplicates and caches successful probes", async () => {
|
|
const [first, second] = await Promise.all([
|
|
probeMediaUrl("/video.mp4"),
|
|
probeMediaUrl("/video.mp4"),
|
|
]);
|
|
expect(first).toEqual(second);
|
|
expect(getDurationFromMetadata).toHaveBeenCalledTimes(1);
|
|
expect(dispose).toHaveBeenCalledTimes(1);
|
|
expect(getMediaProbeDiagnostics()).toEqual({ cached: 1, failed: 0, inflight: 0 });
|
|
});
|
|
|
|
it("bounds retained successes to the configured registry count", async () => {
|
|
for (let index = 0; index < 513; index++) {
|
|
await probeMediaUrl(`/video-${index}.mp4`);
|
|
}
|
|
expect(getMediaProbeDiagnostics().cached).toBe(512);
|
|
});
|
|
|
|
it("limits concurrent metadata probes and drains the queue", async () => {
|
|
const resolvers: Array<(duration: number) => void> = [];
|
|
getDurationFromMetadata.mockImplementation(
|
|
() => new Promise<number>((resolve) => resolvers.push(resolve)),
|
|
);
|
|
|
|
const probes = Array.from({ length: 5 }, (_, index) => probeMediaUrl(`/queued-${index}.mp4`));
|
|
await Promise.resolve();
|
|
await Promise.resolve();
|
|
expect(getDurationFromMetadata).toHaveBeenCalledTimes(4);
|
|
|
|
resolvers[0]?.(5);
|
|
await vi.waitFor(() => expect(getDurationFromMetadata).toHaveBeenCalledTimes(5));
|
|
|
|
for (const resolve of resolvers.slice(1)) resolve(5);
|
|
await expect(Promise.all(probes)).resolves.toHaveLength(5);
|
|
expect(getMediaProbeDiagnostics()).toEqual({ cached: 5, failed: 0, inflight: 0 });
|
|
});
|
|
|
|
it("retries failures only after the failure TTL", async () => {
|
|
vi.useFakeTimers();
|
|
getDurationFromMetadata.mockRejectedValue(new Error("bad source"));
|
|
await expect(probeMediaUrl("/bad.mp4")).resolves.toBeNull();
|
|
await expect(probeMediaUrl("/bad.mp4")).resolves.toBeNull();
|
|
expect(getDurationFromMetadata).toHaveBeenCalledTimes(1);
|
|
|
|
vi.advanceTimersByTime(30_001);
|
|
await expect(probeMediaUrl("/bad.mp4")).resolves.toBeNull();
|
|
expect(getDurationFromMetadata).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it("probes same-origin rooted media through the active project preview", async () => {
|
|
const apply = vi.fn();
|
|
await probeMissingSourceDurations(
|
|
[
|
|
{
|
|
id: "clip",
|
|
tag: "video",
|
|
src: `${window.location.origin}/assets/clip.mp4`,
|
|
},
|
|
],
|
|
"project-a",
|
|
apply,
|
|
);
|
|
|
|
expect(requestedSources).toEqual([
|
|
`${window.location.origin}/api/projects/project-a/preview/assets/clip.mp4`,
|
|
]);
|
|
expect(apply).toHaveBeenCalledWith("clip", 5);
|
|
expect(
|
|
applyCachedSourceDurations(
|
|
[
|
|
{
|
|
id: "clip",
|
|
tag: "video",
|
|
src: `${window.location.origin}/assets/clip.mp4`,
|
|
},
|
|
],
|
|
"project-a",
|
|
),
|
|
).toEqual([
|
|
{
|
|
id: "clip",
|
|
tag: "video",
|
|
src: `${window.location.origin}/assets/clip.mp4`,
|
|
sourceDuration: 5,
|
|
},
|
|
]);
|
|
|
|
await probeMissingSourceDurations(
|
|
[
|
|
{
|
|
id: "clip",
|
|
tag: "video",
|
|
src: `${window.location.origin}/assets/clip.mp4`,
|
|
},
|
|
],
|
|
"project-a",
|
|
apply,
|
|
);
|
|
expect(requestedSources).toHaveLength(1);
|
|
});
|
|
});
|