2025-03-23 04:12:28 +01:00
|
|
|
import { describe, expect, it } from "bun:test";
|
2024-06-29 08:10:02 +02:00
|
|
|
import sharp from "sharp";
|
2025-01-29 17:21:40 +01:00
|
|
|
import { convertImage } from "./image-conversion.ts";
|
2024-06-29 08:10:02 +02:00
|
|
|
|
|
|
|
|
describe("ImageConversionPreprocessor", () => {
|
|
|
|
|
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();
|
|
|
|
|
|
2025-11-21 08:31:02 +01:00
|
|
|
const inputFile = new File([inputBuffer as BlobPart], "test.jpg", {
|
2024-06-29 08:10:02 +02:00
|
|
|
type: "image/jpeg",
|
|
|
|
|
});
|
2025-03-23 04:12:28 +01:00
|
|
|
const result = await convertImage(inputFile, "image/webp");
|
2024-06-29 08:10:02 +02:00
|
|
|
|
2025-01-29 17:21:40 +01:00
|
|
|
expect(result.type).toBe("image/webp");
|
|
|
|
|
expect(result.name).toBe("test.webp");
|
2024-06-29 08:10:02 +02:00
|
|
|
|
2025-01-29 17:21:40 +01:00
|
|
|
const resultBuffer = await result.arrayBuffer();
|
2024-06-29 08:10:02 +02:00
|
|
|
const metadata = await sharp(resultBuffer).metadata();
|
|
|
|
|
expect(metadata.format).toBe("webp");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should not convert SVG when convert_vector is false", async () => {
|
|
|
|
|
const svgContent =
|
|
|
|
|
'<svg xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" fill="red"/></svg>';
|
|
|
|
|
const inputFile = new File([svgContent], "test.svg", {
|
|
|
|
|
type: "image/svg+xml",
|
|
|
|
|
});
|
2025-03-23 04:12:28 +01:00
|
|
|
const result = await convertImage(inputFile, "image/webp");
|
2024-06-29 08:10:02 +02:00
|
|
|
|
2025-01-29 17:21:40 +01:00
|
|
|
expect(result).toBe(inputFile);
|
2024-06-29 08:10:02 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should convert SVG when convert_vector is true", async () => {
|
|
|
|
|
const svgContent =
|
|
|
|
|
'<svg xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" fill="red"/></svg>';
|
|
|
|
|
const inputFile = new File([svgContent], "test.svg", {
|
|
|
|
|
type: "image/svg+xml",
|
|
|
|
|
});
|
2025-03-23 04:12:28 +01:00
|
|
|
const result = await convertImage(inputFile, "image/webp", {
|
|
|
|
|
convertVectors: true,
|
|
|
|
|
});
|
2024-06-29 08:10:02 +02:00
|
|
|
|
2025-01-29 17:21:40 +01:00
|
|
|
expect(result.type).toBe("image/webp");
|
|
|
|
|
expect(result.name).toBe("test.webp");
|
2024-06-29 08:10:02 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should not convert unsupported file types", async () => {
|
|
|
|
|
const inputFile = new File(["test content"], "test.txt", {
|
|
|
|
|
type: "text/plain",
|
|
|
|
|
});
|
2025-03-23 04:12:28 +01:00
|
|
|
const result = await convertImage(inputFile, "image/webp");
|
2024-06-29 08:10:02 +02:00
|
|
|
|
2025-01-29 17:21:40 +01:00
|
|
|
expect(result).toBe(inputFile);
|
2024-06-29 08:10:02 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should throw an error for unsupported output format", async () => {
|
|
|
|
|
const inputBuffer = await sharp({
|
|
|
|
|
create: {
|
|
|
|
|
width: 100,
|
|
|
|
|
height: 100,
|
|
|
|
|
channels: 3,
|
|
|
|
|
background: { r: 255, g: 0, b: 0 },
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
.png()
|
|
|
|
|
.toBuffer();
|
|
|
|
|
|
2025-11-21 08:31:02 +01:00
|
|
|
const inputFile = new File([inputBuffer as BlobPart], "test.png", {
|
2024-06-29 08:10:02 +02:00
|
|
|
type: "image/png",
|
|
|
|
|
});
|
|
|
|
|
|
2025-03-23 04:12:28 +01:00
|
|
|
await expect(convertImage(inputFile, "image/bmp")).rejects.toThrow(
|
2024-06-29 08:10:02 +02:00
|
|
|
"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();
|
|
|
|
|
|
2025-11-21 08:31:02 +01:00
|
|
|
const inputFile = new File([inputBuffer as BlobPart], "animated.gif", {
|
2024-06-29 08:10:02 +02:00
|
|
|
type: "image/gif",
|
|
|
|
|
});
|
2025-03-23 04:12:28 +01:00
|
|
|
const result = await convertImage(inputFile, "image/webp");
|
2024-06-29 08:10:02 +02:00
|
|
|
|
2025-01-29 17:21:40 +01:00
|
|
|
expect(result.type).toBe("image/webp");
|
|
|
|
|
expect(result.name).toBe("animated.webp");
|
2024-06-29 08:10:02 +02:00
|
|
|
|
2025-01-29 17:21:40 +01:00
|
|
|
const resultBuffer = await result.arrayBuffer();
|
2024-06-29 08:10:02 +02:00
|
|
|
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(
|
2025-11-21 08:31:02 +01:00
|
|
|
[inputBuffer as BlobPart],
|
2024-06-29 08:10:02 +02:00
|
|
|
"test image with spaces.png",
|
|
|
|
|
{ type: "image/png" },
|
|
|
|
|
);
|
2025-03-23 04:12:28 +01:00
|
|
|
const result = await convertImage(inputFile, "image/webp");
|
2024-06-29 08:10:02 +02:00
|
|
|
|
2025-01-29 17:21:40 +01:00
|
|
|
expect(result.type).toBe("image/webp");
|
|
|
|
|
expect(result.name).toBe("test image with spaces.webp");
|
2024-06-29 08:10:02 +02:00
|
|
|
});
|
|
|
|
|
});
|