/** * Integration tests for new input/output format support. * * - New output formats: convert PNG to jxl, bmp, ico, jp2, qoi * - SVGZ input: verify compressed SVG decodes correctly * - JXL quality: verify lower quality produces smaller files */ import { readFileSync } from "node:fs"; import { join } from "node:path"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; const FORMATS_DIR = join(__dirname, "..", "fixtures", "formats"); describe("New format support", () => { let testApp: TestApp; let app: TestApp["app"]; let adminToken: string; beforeAll(async () => { testApp = await buildTestApp(); app = testApp.app; adminToken = await loginAsAdmin(app); }, 30_000); afterAll(async () => { await testApp?.cleanup(); }, 10_000); // --------------------------------------------------------------------------- // New output format conversions // --------------------------------------------------------------------------- const NEW_OUTPUT_FORMATS = ["jxl", "bmp", "ico", "jp2", "qoi"]; for (const format of NEW_OUTPUT_FORMATS) { it(`converts PNG to ${format}`, async () => { const fileBuffer = readFileSync(join(FORMATS_DIR, "sample.png")); const { body, contentType } = createMultipartPayload([ { name: "file", filename: "sample.png", contentType: "image/png", content: fileBuffer, }, { name: "settings", content: JSON.stringify({ format, quality: 80 }), }, ]); const res = await app.inject({ method: "POST", url: "/api/v1/tools/convert", headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType, }, body, }); // Accept 200 (success) or 422 (encoder not available in test env) expect([200, 422]).toContain(res.statusCode); if (res.statusCode === 200) { const json = JSON.parse(res.body); expect(json.processedSize).toBeGreaterThan(0); expect(json.downloadUrl).toBeTruthy(); } }); } // --------------------------------------------------------------------------- // SVGZ input decoding // --------------------------------------------------------------------------- it("decodes SVGZ input correctly", async () => { const fileBuffer = readFileSync(join(FORMATS_DIR, "sample.svgz")); const { body, contentType } = createMultipartPayload([ { name: "file", filename: "sample.svgz", contentType: "image/svg+xml", content: fileBuffer, }, { name: "settings", content: JSON.stringify({ format: "png" }), }, ]); const res = await app.inject({ method: "POST", url: "/api/v1/tools/convert", headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType, }, body, }); expect([200, 422]).toContain(res.statusCode); if (res.statusCode === 200) { const json = JSON.parse(res.body); expect(json.processedSize).toBeGreaterThan(0); } }); // --------------------------------------------------------------------------- // JXL quality affects file size // --------------------------------------------------------------------------- it("JXL quality affects file size", async () => { const fileBuffer = readFileSync(join(FORMATS_DIR, "sample.png")); const convert = async (quality: number) => { const { body, contentType } = createMultipartPayload([ { name: "file", filename: "sample.png", contentType: "image/png", content: fileBuffer, }, { name: "settings", content: JSON.stringify({ format: "jxl", quality }), }, ]); return app.inject({ method: "POST", url: "/api/v1/tools/convert", headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType, }, body, }); }; const lowQ = await convert(30); const highQ = await convert(90); // Only compare sizes if both succeeded (JXL encoder may not be available) if (lowQ.statusCode === 200 && highQ.statusCode === 200) { const lowJson = JSON.parse(lowQ.body); const highJson = JSON.parse(highQ.body); expect(lowJson.processedSize).toBeLessThan(highJson.processedSize); } }); });