mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(studio): a media preview retries after its file or project changes (#6451)
Co-authored-by: lorenzozanee <wyz0707@proton.me>
This commit is contained in:
co-authored by
lorenzozanee
parent
25e5ab733b
commit
15367a9f62
@@ -0,0 +1,69 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { act } from "react";
|
||||
import { createRoot, type Root } from "react-dom/client";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { MediaPreview } from "./MediaPreview";
|
||||
|
||||
(globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
let root: Root | null = null;
|
||||
let host: HTMLDivElement | null = null;
|
||||
|
||||
afterEach(() => {
|
||||
if (root) act(() => root?.unmount());
|
||||
root = null;
|
||||
host = null;
|
||||
document.body.replaceChildren();
|
||||
});
|
||||
|
||||
async function renderPreview(projectId: string, filePath: string): Promise<HTMLDivElement> {
|
||||
if (!root) {
|
||||
host = document.createElement("div");
|
||||
document.body.append(host);
|
||||
root = createRoot(host);
|
||||
}
|
||||
await act(async () => {
|
||||
root?.render(<MediaPreview projectId={projectId} filePath={filePath} />);
|
||||
});
|
||||
return host as HTMLDivElement;
|
||||
}
|
||||
|
||||
describe("MediaPreview", () => {
|
||||
it("retries a repaired file after visiting another media source", async () => {
|
||||
const host = await renderPreview("test", "broken.png");
|
||||
const failedImage = host.querySelector("img");
|
||||
expect(failedImage).not.toBeNull();
|
||||
|
||||
await act(async () => {
|
||||
failedImage?.dispatchEvent(new Event("error"));
|
||||
});
|
||||
expect(host.textContent).toContain("Couldn't load this file");
|
||||
|
||||
await renderPreview("test", "healthy.png");
|
||||
expect(host.querySelector("img")?.getAttribute("src")).toContain("healthy.png");
|
||||
|
||||
await renderPreview("test", "broken.png");
|
||||
expect(host.querySelector("img")?.getAttribute("src")).toContain("broken.png");
|
||||
});
|
||||
|
||||
it("resets failure state when the project changes, but preserves a current failure", async () => {
|
||||
const host = await renderPreview("first", "broken.png");
|
||||
const image = host.querySelector("img");
|
||||
await act(async () => {
|
||||
image?.dispatchEvent(new Event("error"));
|
||||
});
|
||||
expect(host.textContent).toContain("Couldn't load this file");
|
||||
|
||||
await renderPreview("second", "broken.png");
|
||||
expect(host.querySelector("img")?.getAttribute("src")).toContain("/second/preview/broken.png");
|
||||
|
||||
const secondImage = host.querySelector("img");
|
||||
await act(async () => {
|
||||
secondImage?.dispatchEvent(new Event("error"));
|
||||
});
|
||||
expect(host.textContent).toContain("Couldn't load this file");
|
||||
|
||||
await renderPreview("second", "broken.png");
|
||||
expect(host.querySelector("img")).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { buildProjectApiPath } from "../utils/projectRouting";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { IMAGE_EXT, VIDEO_EXT, AUDIO_EXT } from "../utils/mediaTypes";
|
||||
import { encodeUrlPath } from "@hyperframes/parsers";
|
||||
|
||||
@@ -32,10 +32,15 @@ function MediaErrorPanel({ name, filePath }: { name: string; filePath: string })
|
||||
export function MediaPreview({ projectId, filePath }: { projectId: string; filePath: string }) {
|
||||
const serveUrl = buildProjectApiPath(projectId, `/preview/${encodeUrlPath(filePath)}`);
|
||||
const name = filePath.split("/").pop() ?? filePath;
|
||||
// Keyed by path so switching to another file clears a previous failure.
|
||||
const [failedPath, setFailedPath] = useState<string | null>(null);
|
||||
const failed = failedPath === filePath;
|
||||
const setFailed = () => setFailedPath(filePath);
|
||||
const [failure, setFailure] = useState<{ source: string; failed: boolean }>({
|
||||
source: serveUrl,
|
||||
failed: false,
|
||||
});
|
||||
useEffect(() => {
|
||||
setFailure({ source: serveUrl, failed: false });
|
||||
}, [serveUrl]);
|
||||
const failed = failure.source === serveUrl && failure.failed;
|
||||
const setFailed = () => setFailure({ source: serveUrl, failed: true });
|
||||
|
||||
if (failed) return <MediaErrorPanel name={name} filePath={filePath} />;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user