Files
hyperframes/packages/studio/vite.browser.test.ts

90 lines
3.1 KiB
TypeScript

import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const browserMocks = vi.hoisted(() => {
const newPage = vi.fn(async () => ({
setViewport: vi.fn(async () => {}),
goto: vi.fn(async () => {}),
evaluate: vi.fn(async () => undefined),
waitForFunction: vi.fn(async () => undefined),
addScriptTag: vi.fn(async () => undefined),
screenshot: vi.fn(async () => Buffer.from("thumbnail")),
close: vi.fn(async () => {}),
}));
const launch = vi.fn(async () => ({ connected: true, newPage }));
return { launch, newPage };
});
vi.mock("puppeteer-core", () => ({ default: { launch: browserMocks.launch } }));
import { generateThumbnail, type GenerateThumbnailOptions } from "./vite.browser";
const originalExecutable = process.env.PUPPETEER_EXECUTABLE_PATH;
function options(signal = new AbortController().signal): GenerateThumbnailOptions {
return {
project: { dir: process.cwd() },
compPath: "index.html",
seekTime: 1,
previewUrl: "http://localhost/preview",
width: 1920,
height: 1080,
outputWidth: 240,
outputHeight: 135,
format: "jpeg",
signal,
};
}
describe("generateThumbnail", () => {
beforeAll(() => {
process.env.PUPPETEER_EXECUTABLE_PATH = process.execPath;
});
beforeEach(() => {
browserMocks.newPage.mockClear();
});
afterAll(() => {
if (originalExecutable == null) delete process.env.PUPPETEER_EXECUTABLE_PATH;
else process.env.PUPPETEER_EXECUTABLE_PATH = originalExecutable;
});
it("retries browser launch after a transient failure", async () => {
browserMocks.launch.mockClear();
browserMocks.launch.mockRejectedValueOnce(new Error("launch failed"));
await expect(generateThumbnail(options())).rejects.toThrow("launch failed");
await expect(generateThumbnail(options())).resolves.toEqual(Buffer.from("thumbnail"));
expect(browserMocks.launch).toHaveBeenCalledTimes(2);
});
it("captures at the route-provided physical output size", async () => {
await expect(generateThumbnail(options())).resolves.toEqual(Buffer.from("thumbnail"));
const result = browserMocks.newPage.mock.results[0];
if (!result) throw new Error("page was not created");
const page = await result.value;
expect(page.setViewport).toHaveBeenCalledWith({
width: 1920,
height: 1080,
deviceScaleFactor: 0.125,
});
expect(page.close).toHaveBeenCalledTimes(1);
});
it("lets the route own dedupe and closes browser work on cancellation", async () => {
const controller = new AbortController();
const cancelled = generateThumbnail(options(controller.signal));
await vi.waitFor(() => expect(browserMocks.newPage).toHaveBeenCalledTimes(1));
controller.abort();
await expect(cancelled).resolves.toBeNull();
const cancelledResult = browserMocks.newPage.mock.results[0];
if (!cancelledResult) throw new Error("cancelled page was not created");
expect((await cancelledResult.value).close).toHaveBeenCalled();
browserMocks.newPage.mockClear();
await Promise.all([generateThumbnail(options()), generateThumbnail(options())]);
expect(browserMocks.newPage).toHaveBeenCalledTimes(2);
});
});