Files
lemonspace_app/components/canvas/__tests__/canvas-media-utils.test.ts

77 lines
2.4 KiB
TypeScript

// @vitest-environment jsdom
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { createCompressedImagePreview } from "@/components/canvas/canvas-media-utils";
class MockImage {
onload: (() => void) | null = null;
onerror: (() => void) | null = null;
naturalWidth = 0;
naturalHeight = 0;
set src(_value: string) {
queueMicrotask(() => {
this.naturalWidth = 4000;
this.naturalHeight = 2000;
this.onload?.();
});
}
}
describe("createCompressedImagePreview", () => {
const originalImage = globalThis.Image;
const originalCreateObjectURL = URL.createObjectURL;
const originalRevokeObjectURL = URL.revokeObjectURL;
const drawImage = vi.fn();
const toBlob = vi.fn();
beforeEach(() => {
vi.stubGlobal("Image", MockImage);
URL.createObjectURL = vi.fn(() => "blob:preview") as typeof URL.createObjectURL;
URL.revokeObjectURL = vi.fn() as typeof URL.revokeObjectURL;
vi.spyOn(HTMLCanvasElement.prototype, "getContext").mockReturnValue({
drawImage,
} as unknown as CanvasRenderingContext2D);
vi.spyOn(HTMLCanvasElement.prototype, "toBlob").mockImplementation(
(callback) => {
toBlob();
callback(new Blob(["preview"], { type: "image/webp" }));
},
);
});
afterEach(() => {
vi.restoreAllMocks();
drawImage.mockReset();
toBlob.mockReset();
vi.stubGlobal("Image", originalImage);
URL.createObjectURL = originalCreateObjectURL;
URL.revokeObjectURL = originalRevokeObjectURL;
});
it("clamps dimensions to the configured max edge", async () => {
const file = new File(["bytes"], "photo.jpg", { type: "image/jpeg" });
const preview = await createCompressedImagePreview(file);
expect(preview.width).toBe(640);
expect(preview.height).toBe(320);
expect(preview.blob.type).toBe("image/webp");
expect(drawImage).toHaveBeenCalledTimes(1);
expect(toBlob).toHaveBeenCalledTimes(1);
});
it("returns fallback mime type when encoder does not produce webp", async () => {
vi.spyOn(HTMLCanvasElement.prototype, "toBlob").mockImplementation((callback) => {
callback(new Blob(["preview"], { type: "image/png" }));
});
const file = new File(["bytes"], "photo.jpg", { type: "image/jpeg" });
const preview = await createCompressedImagePreview(file);
expect(preview.blob.type).toBe("image/png");
});
});