Download server/src/__tests__/lib/image-normalize-no-sharp.test.ts from automindy/fokemal: direct link, hf CLI and curl.
- Browser
- Download file 2.79 kB
-
https://huggingface.co/spaces/automindy/fokemal/resolve/main/server/src/__tests__/lib/image-normalize-no-sharp.test.ts
- Command line
-
hf download hf://spaces/automindy/fokemal/server/src/__tests__/lib/image-normalize-no-sharp.test.ts
-
curl -L -o image-normalize-no-sharp.test.ts https://huggingface.co/spaces/automindy/fokemal/resolve/main/server/src/__tests__/lib/image-normalize-no-sharp.test.ts
2.79 kB
| import { describe, it, expect, vi } from 'vitest'; | |
| import type { ChatMessage } from '@freellmapi/shared/types.js'; | |
| // sharp is a NATIVE module. It is loaded with a dynamic import precisely so a | |
| // missing or mismatched prebuilt libvips cannot take the gateway down at | |
| // import time — the desktop build only electron-rebuilds better-sqlite3, and | |
| // slim/musl containers routinely ship without the matching binary. This is the | |
| // degraded path: images must ride through untouched and the request must still | |
| // be served. | |
| // | |
| // Own file because the resolved module is cached in module state after the | |
| // first call; vitest isolates the registry per file, so the failure is only | |
| // observable from a file that has never loaded the real sharp. | |
| vi.mock('sharp', () => ({ | |
| get default(): never { | |
| throw new Error( | |
| "Could not load the 'sharp' module using the linux-x64 runtime", | |
| ); | |
| }, | |
| })); | |
| const { normalizeMessageImages } = await import('../../lib/image-normalize.js'); | |
| // A data URL big enough to clear every threshold — it must survive byte-for-byte. | |
| const BIG_IMAGE = `data:image/png;base64,${'A'.repeat(2_000_000)}`; | |
| function imageTurn(url: string): ChatMessage[] { | |
| return [{ | |
| role: 'user', | |
| content: [ | |
| { type: 'text', text: 'what is this?' }, | |
| { type: 'image_url', image_url: { url } }, | |
| ], | |
| } as any]; | |
| } | |
| describe('inbound image normalization without sharp', () => { | |
| it('passes images through untouched instead of throwing', async () => { | |
| const messages = imageTurn(BIG_IMAGE); | |
| const summary = await normalizeMessageImages(messages, { thresholdBytes: 0 }); | |
| expect(summary.normalized).toBe(0); | |
| expect(summary.bytesBefore).toBe(0); | |
| expect(summary.bytesAfter).toBe(0); | |
| // Same array, same bytes: the request is served exactly as it was before | |
| // this module existed. | |
| expect(summary.messages).toBe(messages); | |
| expect((messages[0].content as any[])[1].image_url.url).toBe(BIG_IMAGE); | |
| }); | |
| it('warns once, not once per image', async () => { | |
| const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); | |
| try { | |
| await normalizeMessageImages(imageTurn(BIG_IMAGE), { thresholdBytes: 0 }); | |
| await normalizeMessageImages(imageTurn(BIG_IMAGE), { thresholdBytes: 0 }); | |
| // The failed load is remembered, so a busy gateway does not reprint the | |
| // warning (or retry the import) on every vision request. | |
| expect(warn).not.toHaveBeenCalled(); | |
| } finally { | |
| warn.mockRestore(); | |
| } | |
| }); | |
| it('still honours the disable switch', async () => { | |
| const messages = imageTurn(BIG_IMAGE); | |
| const summary = await normalizeMessageImages(messages, { enabled: false }); | |
| expect(summary.normalized).toBe(0); | |
| expect(summary.messages).toBe(messages); | |
| }); | |
| }); | |