Web: add HEIC media regression and doc fix (#38294)

* Web: add HEIC media normalization regression

* Docs: list HEIC input_image MIME types

* Update src/web/media.test.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
Vincent Koc
2026-03-06 22:49:38 -05:00
committed by GitHub
parent 1a022a31de
commit 6017b738b1
2 changed files with 30 additions and 1 deletions

View File

@@ -161,7 +161,7 @@ Supports base64 or URL sources:
}
```
Allowed MIME types (current): `image/jpeg`, `image/png`, `image/gif`, `image/webp`.
Allowed MIME types (current): `image/jpeg`, `image/png`, `image/gif`, `image/webp`, `image/heic`, `image/heif`.
Max size (current): 10MB.
## Files (`input_file`)

View File

@@ -16,6 +16,17 @@ import {
optimizeImageToJpeg,
} from "./media.js";
const convertHeicToJpegMock = vi.fn();
vi.mock("../media/image-ops.js", async () => {
const actual =
await vi.importActual<typeof import("../media/image-ops.js")>("../media/image-ops.js");
return {
...actual,
convertHeicToJpeg: (...args: unknown[]) => convertHeicToJpegMock(...args),
};
});
let fixtureRoot = "";
let fixtureFileCount = 0;
let largeJpegBuffer: Buffer;
@@ -23,6 +34,7 @@ let largeJpegFile = "";
let tinyPngBuffer: Buffer;
let tinyPngFile = "";
let tinyPngWrongExtFile = "";
let fakeHeicFile = "";
let alphaPngBuffer: Buffer;
let alphaPngFile = "";
let fallbackPngBuffer: Buffer;
@@ -76,6 +88,7 @@ beforeAll(async () => {
.toBuffer();
tinyPngFile = await writeTempFile(tinyPngBuffer, ".png");
tinyPngWrongExtFile = await writeTempFile(tinyPngBuffer, ".bin");
fakeHeicFile = await writeTempFile(Buffer.from("fake-heic"), ".heic");
alphaPngBuffer = await sharp({
create: {
width: 64,
@@ -178,6 +191,22 @@ describe("web media loading", () => {
expect(result.contentType).toBe("image/jpeg");
});
it("normalizes HEIC local files to JPEG output", async () => {
convertHeicToJpegMock.mockResolvedValueOnce(tinyPngBuffer);
const result = await loadWebMedia(fakeHeicFile, 1024 * 1024);
expect(convertHeicToJpegMock).toHaveBeenCalledTimes(1);
expect(result.kind).toBe("image");
expect(result.contentType).toBe("image/jpeg");
expect(result.fileName).toBe(path.basename(fakeHeicFile, ".heic") + ".jpg");
expect(result.buffer.length).toBeGreaterThan(0);
expect(result.buffer.equals(tinyPngBuffer)).toBe(false);
// Confirm the output is actually JPEG (magic bytes 0xFF 0xD8)
expect(result.buffer[0]).toBe(0xff);
expect(result.buffer[1]).toBe(0xd8);
});
it("includes URL + status in fetch errors", async () => {
const fetchMock = vi.spyOn(globalThis, "fetch").mockResolvedValueOnce({
ok: false,