import { beforeEach, describe, expect, it } from "bun:test";
import sharp from "sharp";
import type { Config } from "~/packages/config-manager/config.type";
import { ImageConversionPreprocessor } from "./image-conversion.ts";
describe("ImageConversionPreprocessor", () => {
let preprocessor: ImageConversionPreprocessor;
let mockConfig: Config;
beforeEach(() => {
mockConfig = {
media: {
conversion: {
convert_images: true,
convert_to: "image/webp",
convert_vector: false,
},
},
} as Config;
preprocessor = new ImageConversionPreprocessor(mockConfig);
});
it("should convert a JPEG image to WebP", async () => {
const inputBuffer = await sharp({
create: {
width: 100,
height: 100,
channels: 3,
background: { r: 255, g: 0, b: 0 },
},
})
.jpeg()
.toBuffer();
const inputFile = new File([inputBuffer], "test.jpg", {
type: "image/jpeg",
});
const result = await preprocessor.process(inputFile);
expect(result.file.type).toBe("image/webp");
expect(result.file.name).toBe("test.webp");
const resultBuffer = await result.file.arrayBuffer();
const metadata = await sharp(resultBuffer).metadata();
expect(metadata.format).toBe("webp");
});
it("should not convert SVG when convert_vector is false", async () => {
const svgContent =
'';
const inputFile = new File([svgContent], "test.svg", {
type: "image/svg+xml",
});
const result = await preprocessor.process(inputFile);
expect(result.file).toBe(inputFile);
});
it("should convert SVG when convert_vector is true", async () => {
mockConfig.media.conversion.convert_vector = true;
preprocessor = new ImageConversionPreprocessor(mockConfig);
const svgContent =
'';
const inputFile = new File([svgContent], "test.svg", {
type: "image/svg+xml",
});
const result = await preprocessor.process(inputFile);
expect(result.file.type).toBe("image/webp");
expect(result.file.name).toBe("test.webp");
});
it("should not convert unsupported file types", async () => {
const inputFile = new File(["test content"], "test.txt", {
type: "text/plain",
});
const result = await preprocessor.process(inputFile);
expect(result.file).toBe(inputFile);
});
it("should throw an error for unsupported output format", async () => {
mockConfig.media.conversion.convert_to = "image/bmp";
preprocessor = new ImageConversionPreprocessor(mockConfig);
const inputBuffer = await sharp({
create: {
width: 100,
height: 100,
channels: 3,
background: { r: 255, g: 0, b: 0 },
},
})
.png()
.toBuffer();
const inputFile = new File([inputBuffer], "test.png", {
type: "image/png",
});
await expect(preprocessor.process(inputFile)).rejects.toThrow(
"Unsupported output format: image/bmp",
);
});
it("should convert animated GIF to WebP while preserving animation", async () => {
// Create a simple animated GIF
const inputBuffer = await sharp({
create: {
width: 100,
height: 100,
channels: 4,
background: { r: 255, g: 0, b: 0, alpha: 1 },
},
})
.gif()
.toBuffer();
const inputFile = new File([inputBuffer], "animated.gif", {
type: "image/gif",
});
const result = await preprocessor.process(inputFile);
expect(result.file.type).toBe("image/webp");
expect(result.file.name).toBe("animated.webp");
const resultBuffer = await result.file.arrayBuffer();
const metadata = await sharp(resultBuffer).metadata();
expect(metadata.format).toBe("webp");
});
it("should handle files with spaces in the name", async () => {
const inputBuffer = await sharp({
create: {
width: 100,
height: 100,
channels: 3,
background: { r: 255, g: 0, b: 0 },
},
})
.png()
.toBuffer();
const inputFile = new File(
[inputBuffer],
"test image with spaces.png",
{ type: "image/png" },
);
const result = await preprocessor.process(inputFile);
expect(result.file.type).toBe("image/webp");
expect(result.file.name).toBe("test image with spaces.webp");
});
});