Files
SnapOtter/tests/integration/new-formats.test.ts
T

148 lines
4.5 KiB
TypeScript
Raw Normal View History

/**
* 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);
}
});
});