fix: add 120s timeout to all HEIF/HEIC integration tests for CI

Comprehensively adds { timeout: 120_000 } to every HEIF/HEIC
integration test across 40 test files. HEIF decoding on CI runners
is significantly slower than local, causing sporadic timeouts at
the default 5s or previous 60s limits.
This commit is contained in:
SnapOtter
2026-05-01 19:51:47 +08:00
parent 6a44c455a3
commit d1f2f63453
42 changed files with 465 additions and 361 deletions
+5 -3
View File
@@ -484,7 +484,7 @@ describe("Barcode Read", () => {
// ── Branch coverage: HEIC input (lines 49-152, ensureSharpCompat) ───
it("reads barcodes from a HEIC image", async () => {
it("reads barcodes from a HEIC image", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -581,7 +581,7 @@ describe("Barcode Read", () => {
// ── Branch coverage: portrait HEIC (with exif orientation) ──────────
it("reads barcodes from portrait HEIC image", async () => {
it("reads barcodes from portrait HEIC image", { timeout: 120_000 }, async () => {
const HEIC_PORTRAIT = readFileSync(join(FIXTURES, "test-portrait.heic"));
const { body, contentType } = createMultipartPayload([
{
@@ -680,7 +680,9 @@ describe("Barcode Read", () => {
// ── Branch coverage: HEIF content format input ─────────────────────
it("reads barcodes from portrait HEIC image (additional format)", async () => {
it("reads barcodes from portrait HEIC image (additional format)", {
timeout: 120_000,
}, async () => {
const HEIC_PORTRAIT = readFileSync(join(FIXTURES, "test-portrait.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo2.heic", contentType: "image/heic", content: HEIC_PORTRAIT },
+18 -13
View File
@@ -107,21 +107,26 @@ describe("blur-faces", () => {
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
it("handles HEIC input (202 or 501)", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"handles HEIC input (202 or 501)",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/blur-faces",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/blur-faces",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
expect([202, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input (200, 422, or 501)", async () => {
const { body, contentType } = createMultipartPayload([
+1 -1
View File
@@ -551,7 +551,7 @@ describe("Border", () => {
expect(meta.height).toBe(150 + padding * 2);
});
it("handles HEIC input", async () => {
it("handles HEIC input", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
+1 -1
View File
@@ -572,7 +572,7 @@ describe("Bulk Rename", () => {
// ── HEIC file handling in rename ────────────────────────────────
it("renames HEIC files preserving extension", async () => {
it("renames HEIC files preserving extension", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
+2 -2
View File
@@ -776,7 +776,7 @@ describe("Collage", () => {
expect(result.processedSize).toBeGreaterThan(0);
});
it("handles HEIC input images", async () => {
it("handles HEIC input images", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "f1", filename: "a.heic", contentType: "image/heic", content: HEIC },
@@ -1429,7 +1429,7 @@ describe("Collage", () => {
// ── Branch coverage: HEIF content format input ─────────────────────
it("handles portrait HEIC input images", async () => {
it("handles portrait HEIC input images", { timeout: 120_000 }, async () => {
const HEIC_PORTRAIT = readFileSync(join(FIXTURES, "test-portrait.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "f1", filename: "a.heic", contentType: "image/heic", content: HEIC_PORTRAIT },
+19 -14
View File
@@ -352,7 +352,7 @@ describe("Exposure adjustments", () => {
// ── HEIC input ──────────────────────────────────────────────────
describe("HEIC input", () => {
it("processes HEIC input with brightness adjustment", async () => {
it("processes HEIC input with brightness adjustment", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const res = await postTool(
"adjust-colors",
@@ -540,19 +540,24 @@ describe("No-op effect", () => {
// ── HEIF input ──────────────────────────────────────────────────
describe("HEIF input", () => {
it("processes HEIF input (motorcycle.heif)", async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const res = await postTool(
"adjust-colors",
{ brightness: 20 },
HEIF,
"photo.heif",
"image/heif",
);
expect(res.statusCode).toBe(200);
const result = JSON.parse(res.body);
expect(result.downloadUrl).toBeDefined();
}, 60_000);
it(
"processes HEIF input (motorcycle.heif)",
{ timeout: 120_000 },
async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const res = await postTool(
"adjust-colors",
{ brightness: 20 },
HEIF,
"photo.heif",
"image/heif",
);
expect(res.statusCode).toBe(200);
const result = JSON.parse(res.body);
expect(result.downloadUrl).toBeDefined();
},
60_000,
);
});
// ── Animated GIF input ──────────────────────────────────────────
+1 -1
View File
@@ -197,7 +197,7 @@ describe("Multipart error handling", () => {
// ── HEIC input handling ─────────────────────────────────────────
describe("HEIC input", () => {
it("extracts palette from HEIC image", async () => {
it("extracts palette from HEIC image", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body: payload, contentType } = makeFilePayload(HEIC, "photo.heic", "image/heic");
const res = await app.inject({
+18 -13
View File
@@ -145,21 +145,26 @@ describe("colorize", () => {
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
it("handles HEIC input (202 or 501)", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"handles HEIC input (202 or 501)",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/colorize",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/colorize",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
expect([202, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input (200, 422, or 501)", async () => {
const { body, contentType } = createMultipartPayload([
+4 -4
View File
@@ -270,7 +270,7 @@ describe("Compare", () => {
expect(result.similarity).toBeLessThanOrEqual(100);
});
it("compares HEIC vs PNG", async () => {
it("compares HEIC vs PNG", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "a.heic", contentType: "image/heic", content: HEIC },
@@ -293,7 +293,7 @@ describe("Compare", () => {
expect(result.dimensions).toBeDefined();
});
it("compares two HEIC images (same file)", async () => {
it("compares two HEIC images (same file)", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "a.heic", contentType: "image/heic", content: HEIC },
@@ -567,7 +567,7 @@ describe("Compare", () => {
// ── Branch coverage: HEIC vs HEIC (portrait) ───────────────────────
it("compares HEIC portrait with standard HEIC", async () => {
it("compares HEIC portrait with standard HEIC", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const HEIC_PORTRAIT = readFileSync(join(FIXTURES, "test-portrait.heic"));
const { body, contentType } = createMultipartPayload([
@@ -674,7 +674,7 @@ describe("Compare", () => {
// ── Branch coverage: HEIF content format input ─────────────────────
it("compares portrait HEIC image with PNG", async () => {
it("compares portrait HEIC image with PNG", { timeout: 120_000 }, async () => {
const HEIC_PORTRAIT = readFileSync(join(FIXTURES, "test-portrait.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "a.heic", contentType: "image/heic", content: HEIC_PORTRAIT },
+4 -4
View File
@@ -509,7 +509,7 @@ describe("Compose", () => {
expect(res.statusCode).toBe(200);
});
it("handles HEIC base image", async () => {
it("handles HEIC base image", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "base.heic", contentType: "image/heic", content: HEIC },
@@ -532,7 +532,7 @@ describe("Compose", () => {
expect(result.downloadUrl).toBeDefined();
});
it("handles HEIC overlay image", async () => {
it("handles HEIC overlay image", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "base.png", contentType: "image/png", content: PNG },
@@ -778,7 +778,7 @@ describe("Compose", () => {
// ── Branch coverage: HEIC overlay with opacity ──────────────────────
it("applies opacity with HEIC overlay", async () => {
it("applies opacity with HEIC overlay", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "base.png", contentType: "image/png", content: PNG },
@@ -871,7 +871,7 @@ describe("Compose", () => {
// ── Branch coverage: HEIF content format input ─────────────────────
it("handles portrait HEIC base image", async () => {
it("handles portrait HEIC base image", { timeout: 120_000 }, async () => {
const HEIC_PORTRAIT = readFileSync(join(FIXTURES, "test-portrait.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "base.heic", contentType: "image/heic", content: HEIC_PORTRAIT },
+26 -21
View File
@@ -320,30 +320,35 @@ describe("Content-Aware Resize", () => {
expect(result.error).toMatch(/invalid image/i);
});
it("handles HEIC input (decodes before processing)", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "test.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({ width: 150, protectFaces: false }) },
]);
it(
"handles HEIC input (decodes before processing)",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "test.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({ width: 150, protectFaces: false }) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/content-aware-resize",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/content-aware-resize",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
// HEIC decode or caire may not be available
expect([200, 422]).toContain(res.statusCode);
// HEIC decode or caire may not be available
expect([200, 422]).toContain(res.statusCode);
if (res.statusCode === 200) {
const resBody = JSON.parse(res.body);
expect(resBody.downloadUrl).toBeDefined();
}
}, 60_000);
if (res.statusCode === 200) {
const resBody = JSON.parse(res.body);
expect(resBody.downloadUrl).toBeDefined();
}
},
60_000,
);
it("processes both width and height simultaneously", async () => {
const { body, contentType } = createMultipartPayload([
+1 -1
View File
@@ -164,7 +164,7 @@ describe("Crop", () => {
expect(meta.height).toBe(50);
});
it("handles HEIC input", async () => {
it("handles HEIC input", { timeout: 120_000 }, async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{
+4 -4
View File
@@ -498,7 +498,7 @@ describe("Error handling", () => {
// ── HEIC handling ──────────────────────────────────────────────
describe("HEIC format handling", () => {
it("generates preview for HEIC output", async () => {
it("generates preview for HEIC output", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const res = await postTool({ artist: "HEIC Author" }, HEIC, "test.heic", "image/heic");
// 422 when exiftool is not installed or heic decode fails
@@ -560,7 +560,7 @@ describe("Comprehensive field writing", () => {
// ── HEIC format handling (extended) ──────────────────────────────
describe("HEIC format handling (extended)", () => {
it("edits metadata on HEIC input with GPS coordinates", async () => {
it("edits metadata on HEIC input with GPS coordinates", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const res = await postTool(
{
@@ -578,7 +578,7 @@ describe("HEIC format handling (extended)", () => {
expect(result.downloadUrl).toBeDefined();
});
it("edits metadata on HEIC and verifies preview generation", async () => {
it("edits metadata on HEIC and verifies preview generation", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const res = await postTool(
{ copyright: "HEIC Preview Test" },
@@ -751,7 +751,7 @@ describe("Inspect endpoint edge cases", () => {
expect(res.statusCode).toBe(400);
});
it("inspect returns correct filename for HEIC input", async () => {
it("inspect returns correct filename for HEIC input", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body: payload, contentType } = createMultipartPayload([
{
+18 -13
View File
@@ -145,21 +145,26 @@ describe("enhance-faces", () => {
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
it("handles HEIC input (202 or 501)", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"handles HEIC input (202 or 501)",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/enhance-faces",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/enhance-faces",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
expect([202, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input (200, 422, or 501)", async () => {
const { body, contentType } = createMultipartPayload([
+18 -13
View File
@@ -107,21 +107,26 @@ describe("erase-object", () => {
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
it("handles HEIC image input (202 or 501)", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "mask", filename: "mask.png", contentType: "image/png", content: MASK },
]);
it(
"handles HEIC image input (202 or 501)",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "mask", filename: "mask.png", contentType: "image/png", content: MASK },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/erase-object",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/erase-object",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
expect([202, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel image input (200, 422, or 501)", async () => {
const { body, contentType } = createMultipartPayload([
+2 -2
View File
@@ -240,7 +240,7 @@ describe("favicon", () => {
});
// ── Additional coverage: HEIC input ────────────────────────────
it("generates favicons from HEIC input", async () => {
it("generates favicons from HEIC input", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -466,7 +466,7 @@ describe("favicon", () => {
// ── Portrait HEIC input ───────────────────────────────────────────
it("generates favicons from portrait HEIC", async () => {
it("generates favicons from portrait HEIC", { timeout: 120_000 }, async () => {
const HEIC_PORTRAIT = readFileSync(join(FIXTURES, "test-portrait.heic"));
const { body, contentType } = createMultipartPayload([
{
+28 -23
View File
@@ -413,7 +413,7 @@ describe("Find Duplicates", () => {
}
});
it("handles HEIC input images", async () => {
it("handles HEIC input images", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "a.heic", contentType: "image/heic", content: HEIC },
@@ -775,7 +775,7 @@ describe("Find Duplicates", () => {
// ── Branch coverage: HEIF content format input ─────────────────────
it("handles portrait HEIC images in duplicate detection", async () => {
it("handles portrait HEIC images in duplicate detection", { timeout: 120_000 }, async () => {
const HEIC_PORTRAIT = readFileSync(join(FIXTURES, "test-portrait.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "a.heic", contentType: "image/heic", content: HEIC_PORTRAIT },
@@ -965,29 +965,34 @@ describe("Find Duplicates", () => {
// ── HEIF format input ─────────────────────────────────────────────
it("handles HEIF input images in duplicate detection", async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "a.heif", contentType: "image/heif", content: HEIF },
{ name: "file", filename: "b.heif", contentType: "image/heif", content: HEIF },
]);
it(
"handles HEIF input images in duplicate detection",
{ timeout: 120_000 },
async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "a.heif", contentType: "image/heif", content: HEIF },
{ name: "file", filename: "b.heif", contentType: "image/heif", content: HEIF },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/find-duplicates",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/find-duplicates",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
expect(res.statusCode).toBe(200);
const result = JSON.parse(res.body);
expect(result.totalImages).toBe(2);
expect(result.duplicateGroups).toHaveLength(1);
expect(result.duplicateGroups[0].files).toHaveLength(2);
}, 60_000);
expect(res.statusCode).toBe(200);
const result = JSON.parse(res.body);
expect(result.totalImages).toBe(2);
expect(result.duplicateGroups).toHaveLength(1);
expect(result.duplicateGroups[0].files).toHaveLength(2);
},
60_000,
);
// ── Animated GIF input ────────────────────────────────────────────
+3 -3
View File
@@ -438,7 +438,7 @@ describe("Error handling", () => {
// ── Analyze endpoint HEIC handling ─────────────────────────────
describe("Analyze endpoint HEIC handling", () => {
it("analyze decodes HEIC input before analysis", async () => {
it("analyze decodes HEIC input before analysis", { timeout: 120_000 }, async () => {
const { body: payload, contentType } = createMultipartPayload([
{ name: "file", filename: "test.heic", contentType: "image/heic", content: HEIC },
]);
@@ -509,7 +509,7 @@ describe("Analyze endpoint invalid image", () => {
// ── HEIC input enhancement ──────────────────────────────────────
describe("HEIC input enhancement", () => {
it("enhances HEIC input image", async () => {
it("enhances HEIC input image", { timeout: 120_000 }, async () => {
const res = await postTool({ mode: "auto" }, HEIC, "test.heic", "image/heic");
expect([200, 422]).toContain(res.statusCode);
if (res.statusCode === 200) {
@@ -519,7 +519,7 @@ describe("HEIC input enhancement", () => {
}
});
it("enhances HEIC in portrait mode", async () => {
it("enhances HEIC in portrait mode", { timeout: 120_000 }, async () => {
const res = await postTool(
{ mode: "portrait", intensity: 60 },
HEIC,
+24 -19
View File
@@ -318,7 +318,7 @@ describe("image-to-base64", () => {
});
// ── HEIC input gets converted to JPEG in original mode ───────────
it("converts HEIC to JPEG in original mode", async () => {
it("converts HEIC to JPEG in original mode", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -534,7 +534,7 @@ describe("image-to-base64", () => {
// ── HEIC with resize ──────────────────────────────────────────────
it("converts HEIC to JPEG with resize applied", async () => {
it("converts HEIC to JPEG with resize applied", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -556,7 +556,7 @@ describe("image-to-base64", () => {
// ── HEIC with explicit format conversion ──────────────────────────
it("converts HEIC to PNG when outputFormat is png", async () => {
it("converts HEIC to PNG when outputFormat is png", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -711,24 +711,29 @@ describe("image-to-base64", () => {
// ── HEIF input (alternative extension) ───────────────────────────
it("converts HEIF to JPEG in original mode", async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heif", contentType: "image/heif", content: HEIF },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"converts HEIF to JPEG in original mode",
{ timeout: 120_000 },
async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heif", contentType: "image/heif", content: HEIF },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/image-to-base64",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/image-to-base64",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
expect(res.statusCode).toBe(200);
const json = JSON.parse(res.body);
expect(json.results[0].mimeType).toBe("image/jpeg");
}, 60_000);
expect(res.statusCode).toBe(200);
const json = JSON.parse(res.body);
expect(json.results[0].mimeType).toBe("image/jpeg");
},
60_000,
);
// ── Quality=1 minimum ────────────────────────────────────────────
+23 -18
View File
@@ -237,7 +237,7 @@ describe("image-to-pdf", () => {
// ── HEIC input handling ───────────────────────────────────────────
it("converts HEIC image to PDF", async () => {
it("converts HEIC image to PDF", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -741,25 +741,30 @@ describe("image-to-pdf", () => {
// ── HEIF input ────────────────────────────────────────────────────
it("converts HEIF image to PDF", async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heif", contentType: "image/heif", content: HEIF },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"converts HEIF image to PDF",
{ timeout: 120_000 },
async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heif", contentType: "image/heif", content: HEIF },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/image-to-pdf",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/image-to-pdf",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
expect(res.statusCode).toBe(200);
const json = JSON.parse(res.body);
expect(json.pages).toBe(1);
expect(json.processedSize).toBeGreaterThan(0);
}, 60_000);
expect(res.statusCode).toBe(200);
const json = JSON.parse(res.body);
expect(json.pages).toBe(1);
expect(json.processedSize).toBeGreaterThan(0);
},
60_000,
);
// ── Animated GIF input ──────────────────────────────────────────
+1 -1
View File
@@ -271,7 +271,7 @@ describe("Info", () => {
// ── HEIC format info ──────────────────────────────────────────
it("returns correct metadata for HEIC image", async () => {
it("returns correct metadata for HEIC image", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "test.heic", contentType: "image/heic", content: HEIC },
+18 -13
View File
@@ -152,21 +152,26 @@ describe("noise-removal", () => {
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
it("handles HEIC input (202 or 501)", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"handles HEIC input (202 or 501)",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/noise-removal",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/noise-removal",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
expect([202, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input (200, 422, or 501)", async () => {
const { body, contentType } = createMultipartPayload([
+18 -13
View File
@@ -146,21 +146,26 @@ describe("ocr", () => {
expect([200, 501]).toContain(res.statusCode);
}, 60_000);
it("handles HEIC input (200 or 501)", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"handles HEIC input (200 or 501)",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/ocr",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/ocr",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
expect([200, 501]).toContain(res.statusCode);
}, 60_000);
expect([200, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input (200, 422, or 501)", async () => {
const { body, contentType } = createMultipartPayload([
+3 -3
View File
@@ -478,7 +478,7 @@ describe("Preview endpoint SVG handling", () => {
// ── Preview endpoint: HEIC decoding ────────────────────────────
describe("Preview endpoint HEIC handling", () => {
it("preview decodes and processes HEIC input", async () => {
it("preview decodes and processes HEIC input", { timeout: 120_000 }, async () => {
const { body: payload, contentType } = createMultipartPayload([
{ name: "file", filename: "test.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({ format: "webp", quality: 60 }) },
@@ -603,7 +603,7 @@ describe("Preview endpoint validation", () => {
// ── HEIC input handling ─────────────────────────────────────────
describe("HEIC input", () => {
it("optimizes HEIC input to webp", async () => {
it("optimizes HEIC input to webp", { timeout: 120_000 }, async () => {
const res = await postTool({ format: "webp" }, HEIC, "test.heic", "image/heic");
// HEIC decode may not be available
expect([200, 422]).toContain(res.statusCode);
@@ -614,7 +614,7 @@ describe("HEIC input", () => {
}
});
it("optimizes HEIC input to jpeg", async () => {
it("optimizes HEIC input to jpeg", { timeout: 120_000 }, async () => {
const res = await postTool({ format: "jpeg" }, HEIC, "test.heic", "image/heic");
expect([200, 422]).toContain(res.statusCode);
if (res.statusCode === 200) {
+17 -12
View File
@@ -76,20 +76,25 @@ describe("passport-photo/analyze", () => {
}
}, 60_000);
it("handles HEIC input (200, 422, or 501)", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
]);
it(
"handles HEIC input (200, 422, or 501)",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/passport-photo/analyze",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/passport-photo/analyze",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
expect([200, 422, 501]).toContain(res.statusCode);
}, 60_000);
expect([200, 422, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input (200, 422, or 501)", async () => {
const { body, contentType } = createMultipartPayload([
+21 -16
View File
@@ -147,24 +147,29 @@ describe("Red Eye Removal", () => {
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
it("handles HEIC input", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"handles HEIC input",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/red-eye-removal",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/red-eye-removal",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
expect([202, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input", async () => {
const { body, contentType } = createMultipartPayload([
+21 -16
View File
@@ -182,24 +182,29 @@ describe("Remove Background", () => {
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
it("handles HEIC input", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"handles HEIC input",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/remove-background",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/remove-background",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
expect([202, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input", async () => {
const { body, contentType } = createMultipartPayload([
+18 -13
View File
@@ -261,7 +261,7 @@ describe("Alpha format fallback", () => {
// ── HEIC input handling ─────────────────────────────────────────
describe("HEIC input", () => {
it("processes HEIC image", async () => {
it("processes HEIC image", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const res = await postTool(
{ sourceColor: "#808080", targetColor: "#FF0000", tolerance: 50 },
@@ -423,18 +423,23 @@ describe("Target color validation", () => {
// ── HEIF input ─────────────────────────────────────────────────
describe("HEIF input", () => {
it("processes HEIF image (motorcycle.heif)", async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const res = await postTool(
{ sourceColor: "#808080", targetColor: "#FF0000", tolerance: 50 },
HEIF,
"photo.heif",
"image/heif",
);
expect(res.statusCode).toBe(200);
const result = JSON.parse(res.body);
expect(result.downloadUrl).toBeDefined();
}, 60_000);
it(
"processes HEIF image (motorcycle.heif)",
{ timeout: 120_000 },
async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const res = await postTool(
{ sourceColor: "#808080", targetColor: "#FF0000", tolerance: 50 },
HEIF,
"photo.heif",
"image/heif",
);
expect(res.statusCode).toBe(200);
const result = JSON.parse(res.body);
expect(result.downloadUrl).toBeDefined();
},
60_000,
);
});
// ── Animated GIF input ─────────────────────────────────────────
+1 -1
View File
@@ -157,7 +157,7 @@ describe("Resize", () => {
expect(meta.height).toBe(25); // 50x50 -> 25x25
});
it("handles HEIC input", async () => {
it("handles HEIC input", { timeout: 120_000 }, async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({ width: 100 }) },
+21 -16
View File
@@ -183,24 +183,29 @@ describe("Restore Photo", () => {
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
it("handles HEIC input", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"handles HEIC input",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/restore-photo",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/restore-photo",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
expect([202, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input", async () => {
const { body, contentType } = createMultipartPayload([
+1 -1
View File
@@ -162,7 +162,7 @@ describe("Rotate", () => {
expect(meta.height).toBe(100);
});
it("handles HEIC input", async () => {
it("handles HEIC input", { timeout: 120_000 }, async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({ angle: 90 }) },
+17 -12
View File
@@ -455,18 +455,23 @@ describe("HEIC with different methods", () => {
// ── HEIF input ──────────────────────────────────────────────────
describe("HEIF input", () => {
it("processes HEIF image (motorcycle.heif)", async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const res = await postTool(
{ method: "adaptive", sigma: 2.0 },
HEIF,
"photo.heif",
"image/heif",
);
expect(res.statusCode).toBe(200);
const result = JSON.parse(res.body);
expect(result.downloadUrl).toBeDefined();
}, 120_000);
it(
"processes HEIF image (motorcycle.heif)",
{ timeout: 120_000 },
async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const res = await postTool(
{ method: "adaptive", sigma: 2.0 },
HEIF,
"photo.heif",
"image/heif",
);
expect(res.statusCode).toBe(200);
const result = JSON.parse(res.body);
expect(result.downloadUrl).toBeDefined();
},
120_000,
);
});
// ── Animated GIF input ──────────────────────────────────────────
+24 -19
View File
@@ -274,27 +274,32 @@ describe("Smart Crop", () => {
}
}, 60_000);
it("handles HEIC input", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{
name: "settings",
content: JSON.stringify({ mode: "subject", width: 100, height: 100 }),
},
]);
it(
"handles HEIC input",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{
name: "settings",
content: JSON.stringify({ mode: "subject", width: 100, height: 100 }),
},
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/smart-crop",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/smart-crop",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
expect([200, 501]).toContain(res.statusCode);
}, 60_000);
expect([200, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input", async () => {
const { body, contentType } = createMultipartPayload([
+6 -4
View File
@@ -603,7 +603,7 @@ describe("Split", () => {
}
});
it("splits a HEIC input image", async () => {
it("splits a HEIC input image", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -751,7 +751,9 @@ describe("Split", () => {
// ── Branch coverage: HEIC with grid split (lines 59-165) ────────────
it("splits a HEIC image into a grid without format conversion", async () => {
it("splits a HEIC image into a grid without format conversion", {
timeout: 120_000,
}, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -779,7 +781,7 @@ describe("Split", () => {
// ── Branch coverage: custom tile dimensions with HEIC ───────────────
it("splits HEIC image using fixed tile dimensions", async () => {
it("splits HEIC image using fixed tile dimensions", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -1058,7 +1060,7 @@ describe("Split", () => {
// ── Branch coverage: HEIC split with webp output ────────────────────
it("splits HEIC image with webp output format", async () => {
it("splits HEIC image with webp output format", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
+2 -2
View File
@@ -927,7 +927,7 @@ describe("Stitch", () => {
expect(meta.format).toBe("heif");
});
it("handles HEIC input", async () => {
it("handles HEIC input", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "f1", filename: "a.heic", contentType: "image/heic", content: HEIC },
@@ -1459,7 +1459,7 @@ describe("Stitch", () => {
// ── Branch coverage: HEIF content format input ─────────────────────
it("handles portrait HEIC input in stitching", async () => {
it("handles portrait HEIC input in stitching", { timeout: 120_000 }, async () => {
const HEIC_PORTRAIT = readFileSync(join(FIXTURES, "test-portrait.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "f1", filename: "a.heic", contentType: "image/heic", content: HEIC_PORTRAIT },
+2 -2
View File
@@ -598,7 +598,7 @@ describe("Inspect endpoint: ICC and XMP parsing", () => {
// ── HEIC format handling ────────────────────────────────────────
describe("HEIC format handling", () => {
it("strips metadata from HEIC input", async () => {
it("strips metadata from HEIC input", { timeout: 120_000 }, async () => {
const heic = readFileSync(join(FIXTURES, "test-200x150.heic"));
const res = await postTool({ stripAll: true }, heic, "test.heic", "image/heic");
// HEIC decode may not be available
@@ -610,7 +610,7 @@ describe("HEIC format handling", () => {
}
});
it("strips selective metadata from HEIC input", async () => {
it("strips selective metadata from HEIC input", { timeout: 120_000 }, async () => {
const heic = readFileSync(join(FIXTURES, "test-200x150.heic"));
const res = await postTool(
{ stripAll: false, stripExif: true, stripGps: true },
+3 -3
View File
@@ -717,7 +717,7 @@ describe("svg-to-raster", () => {
// ── Branch coverage: HEIF output with preview (line 363, 404) ───────
it("converts to heif format and generates a preview", async () => {
it("converts to heif format and generates a preview", { timeout: 120_000 }, async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "test.svg", contentType: "image/svg+xml", content: SVG },
{ name: "settings", content: JSON.stringify({ outputFormat: "heif" }) },
@@ -997,7 +997,7 @@ describe("svg-to-raster", () => {
// ── Branch coverage: batch with heif output ────────────────────────
it("batch converts SVGs to heif format", async () => {
it("batch converts SVGs to heif format", { timeout: 120_000 }, async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "a.svg", contentType: "image/svg+xml", content: SVG },
{ name: "file", filename: "b.svg", contentType: "image/svg+xml", content: SVG },
@@ -1063,7 +1063,7 @@ describe("svg-to-raster", () => {
// ── Branch coverage: heif + background color combination ───────────
it("converts to heif format with background color applied", async () => {
it("converts to heif format with background color applied", { timeout: 120_000 }, async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "test.svg", contentType: "image/svg+xml", content: SVG },
{
+2 -2
View File
@@ -238,7 +238,7 @@ describe("text-overlay", () => {
// ── HEIC input handling ───────────────────────────────────────────
it("handles HEIC input", async () => {
it("handles HEIC input", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -534,7 +534,7 @@ describe("text-overlay", () => {
it(
"handles HEIF input (motorcycle.heif)",
{ timeout: 60_000 },
{ timeout: 120_000 },
async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const { body, contentType } = createMultipartPayload([
+21 -16
View File
@@ -200,24 +200,29 @@ describe("Upscale", () => {
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
it("handles HEIC input", async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
it(
"handles HEIC input",
{ timeout: 120_000 },
async () => {
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
{ name: "settings", content: JSON.stringify({}) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/upscale",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/upscale",
headers: {
authorization: `Bearer ${adminToken}`,
"content-type": contentType,
},
body,
});
expect([202, 501]).toContain(res.statusCode);
}, 60_000);
expect([202, 501]).toContain(res.statusCode);
},
60_000,
);
it("handles 1x1 pixel input", async () => {
const { body, contentType } = createMultipartPayload([
+1 -1
View File
@@ -390,7 +390,7 @@ describe("vectorize", () => {
expect(res.statusCode).toBe(401);
});
it("works with HEIC input after decoding", async () => {
it("works with HEIC input after decoding", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "test.heic", contentType: "image/heic", content: HEIC },
+25 -20
View File
@@ -233,7 +233,7 @@ describe("watermark-image", () => {
// ── HEIC input handling ───────────────────────────────────────────
it("processes HEIC main image", async () => {
it("processes HEIC main image", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -381,7 +381,7 @@ describe("watermark-image", () => {
// ── HEIC watermark image ─────────────────────────────────────────
it("processes HEIC watermark image", async () => {
it("processes HEIC watermark image", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "main.png", contentType: "image/png", content: PNG },
@@ -485,26 +485,31 @@ describe("watermark-image", () => {
// ── HEIF input ────────────────────────────────────────────────────
it("processes HEIF main image (motorcycle.heif)", async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heif", contentType: "image/heif", content: HEIF },
{ name: "watermark", filename: "wm.png", contentType: "image/png", content: SMALL_PNG },
{ name: "settings", content: JSON.stringify({ scale: 10 }) },
]);
it(
"processes HEIF main image (motorcycle.heif)",
{ timeout: 120_000 },
async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heif", contentType: "image/heif", content: HEIF },
{ name: "watermark", filename: "wm.png", contentType: "image/png", content: SMALL_PNG },
{ name: "settings", content: JSON.stringify({ scale: 10 }) },
]);
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/watermark-image",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
const res = await app.inject({
method: "POST",
url: "/api/v1/tools/watermark-image",
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
body,
});
expect(res.statusCode).toBe(200);
const json = JSON.parse(res.body);
expect(json.downloadUrl).toBeDefined();
expect(json.processedSize).toBeGreaterThan(0);
}, 60_000);
expect(res.statusCode).toBe(200);
const json = JSON.parse(res.body);
expect(json.downloadUrl).toBeDefined();
expect(json.processedSize).toBeGreaterThan(0);
},
60_000,
);
// ── Animated GIF input ──────────────────────────────────────────
+2 -2
View File
@@ -254,7 +254,7 @@ describe("watermark-text", () => {
// ── HEIC input handling ───────────────────────────────────────────
it("handles HEIC input", async () => {
it("handles HEIC input", { timeout: 120_000 }, async () => {
const HEIC = readFileSync(join(FIXTURES, "test-200x150.heic"));
const { body, contentType } = createMultipartPayload([
{ name: "file", filename: "photo.heic", contentType: "image/heic", content: HEIC },
@@ -522,7 +522,7 @@ describe("watermark-text", () => {
it(
"handles HEIF input (motorcycle.heif)",
{ timeout: 60_000 },
{ timeout: 120_000 },
async () => {
const HEIF = readFileSync(join(FIXTURES, "content", "motorcycle.heif"));
const { body, contentType } = createMultipartPayload([