Files
hyperframes/packages/cli/src/server/studioServer.renderBrowser.test.ts
T
Miguel Ángel 2d8d44151a fix(cli): a Studio render refuses with the browser check's own message (#4176)
* fix(cli): a Studio render refuses with the browser check's own message

* test(cli): the Studio browser refusal test no longer loads the real producer
2026-09-19 12:25:08 -04:00

89 lines
2.9 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { createStudioServer, type StudioServer } from "./studioServer.js";
const mocks = vi.hoisted(() => ({
resolveRenderBrowser: vi.fn(),
createRenderJob: vi.fn(() => ({ id: "job", perfSummary: undefined })),
executeRenderJob: vi.fn(async () => {}),
}));
vi.mock("../browser/preflight.js", async (importOriginal) => ({
...(await importOriginal<typeof import("../browser/preflight.js")>()),
resolveRenderBrowser: mocks.resolveRenderBrowser,
}));
// Under vitest the module is a .ts file, which would take the dev-mode producer load.
vi.mock("../utils/env.js", async (importOriginal) => ({
...(await importOriginal<typeof import("../utils/env.js")>()),
isDevMode: () => false,
}));
// Not importOriginal: loading the real producer takes longer than a wait timeout on a cold Windows runner.
vi.mock("@hyperframes/producer", () => ({
createRenderJob: mocks.createRenderJob,
executeRenderJob: mocks.executeRenderJob,
}));
vi.mock("./studioRenderTelemetry.js", () => ({
emitStudioRenderComplete: vi.fn(),
emitStudioRenderError: vi.fn(),
}));
const dirs: string[] = [];
let server: StudioServer | undefined;
afterEach(() => {
server?.watcher.close();
server = undefined;
delete process.env.PRODUCER_HEADLESS_SHELL_PATH;
vi.clearAllMocks();
for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true });
});
function startStudioRender() {
const dir = mkdtempSync(join(tmpdir(), "hf-studio-render-browser-"));
dirs.push(dir);
server = createStudioServer({ projectDir: dir });
return server.adapter.startRender({
project: { dir, id: "p", title: "p" },
outputPath: join(dir, "out.mp4"),
format: "mp4",
fps: { num: 30, den: 1 },
quality: "draft",
jobId: "job",
} as never);
}
describe("Studio render browser resolution", () => {
it("refuses the render with the resolver's message instead of continuing without a browser", async () => {
mocks.resolveRenderBrowser.mockRejectedValue(
new Error("Chrome not found Chrome Headless Shell is required for local rendering."),
);
const state = startStudioRender();
await vi.waitFor(() => expect(state.status).toBe("failed"), { timeout: 10_000 });
expect(state.error).toBe(
"Chrome not found Chrome Headless Shell is required for local rendering.",
);
expect(mocks.createRenderJob).not.toHaveBeenCalled();
});
it("hands the resolved browser to the producer before the job is created", async () => {
mocks.resolveRenderBrowser.mockResolvedValue({
executablePath: "/opt/chrome",
source: "cache",
});
startStudioRender();
await vi.waitFor(() => expect(mocks.createRenderJob).toHaveBeenCalledTimes(1), {
timeout: 10_000,
});
expect(process.env.PRODUCER_HEADLESS_SHELL_PATH).toBe("/opt/chrome");
});
});