74 lines
2.7 KiB
TypeScript
74 lines
2.7 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { exportFixtures } from "./fixtures";
|
|
import type { WorkerRequest, WorkerResult } from "./types";
|
|
|
|
class TestWorker {
|
|
static instances: TestWorker[] = [];
|
|
requests: WorkerRequest[] = [];
|
|
onmessage?: (event: { data: WorkerResult }) => void;
|
|
onerror?: () => void;
|
|
terminate = vi.fn();
|
|
constructor() {
|
|
TestWorker.instances.push(this);
|
|
}
|
|
postMessage(request: WorkerRequest) {
|
|
this.requests.push(request);
|
|
}
|
|
}
|
|
beforeEach(() => {
|
|
vi.resetModules();
|
|
TestWorker.instances = [];
|
|
vi.stubGlobal("Worker", TestWorker);
|
|
vi.stubGlobal("window", { location: { origin: "http://export.test" } });
|
|
});
|
|
afterEach(() => vi.unstubAllGlobals());
|
|
|
|
describe("export worker client", () => {
|
|
it("reuses one lazy worker and matches replies to concurrent requests", async () => {
|
|
const { renderImage } = await import("./client");
|
|
expect(TestWorker.instances).toHaveLength(0);
|
|
const first = renderImage(exportFixtures[0]);
|
|
const second = renderImage({ ...exportFixtures[0], format: "webp" });
|
|
expect(TestWorker.instances).toHaveLength(1);
|
|
const worker = TestWorker.instances[0];
|
|
const [a, b] = worker.requests;
|
|
worker.onmessage!({
|
|
data: { id: b.id, bytes: new Uint8Array([2]).buffer },
|
|
});
|
|
worker.onmessage!({
|
|
data: { id: a.id, bytes: new Uint8Array([1]).buffer },
|
|
});
|
|
expect((await first).type).toBe("image/png");
|
|
expect((await second).type).toBe("image/webp");
|
|
});
|
|
it("rejects a failed job and permits retry", async () => {
|
|
const { renderImage } = await import("./client");
|
|
const failed = renderImage(exportFixtures[0]);
|
|
const worker = TestWorker.instances[0];
|
|
const rejection = expect(failed).rejects.toThrow("Missing artwork");
|
|
worker.onmessage!({
|
|
data: { id: worker.requests[0].id, error: "Missing artwork" },
|
|
});
|
|
await rejection;
|
|
const retried = renderImage(exportFixtures[0]);
|
|
worker.onmessage!({
|
|
data: { id: worker.requests[1].id, bytes: new ArrayBuffer(1) },
|
|
});
|
|
expect(await retried).toBeInstanceOf(Blob);
|
|
});
|
|
it("clears pending jobs and recreates a crashed worker", async () => {
|
|
const { renderImage } = await import("./client");
|
|
const failed = renderImage(exportFixtures[0]);
|
|
const rejection = expect(failed).rejects.toThrow("Image renderer failed");
|
|
TestWorker.instances[0].onerror!();
|
|
await rejection;
|
|
expect(TestWorker.instances[0].terminate).toHaveBeenCalledOnce();
|
|
const retried = renderImage(exportFixtures[0]);
|
|
const worker = TestWorker.instances[1];
|
|
worker.onmessage!({
|
|
data: { id: worker.requests[0].id, bytes: new ArrayBuffer(1) },
|
|
});
|
|
expect(await retried).toBeInstanceOf(Blob);
|
|
});
|
|
});
|