mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 20:23:36 +00:00
test: Add comprehensive tests for platform and utils packages
Added extensive test coverage for previously untested files: Platform package (94.69% coverage, +47 tests): - paths.test.ts: 22 tests for path construction and directory creation - security.test.ts: 25 tests for path validation and security Utils package (94.3% coverage, +109 tests): - logger.test.ts: 23 tests for logging with levels - fs-utils.test.ts: 20 tests for safe file operations - conversation-utils.test.ts: 24 tests for message formatting - image-handler.test.ts: 25 tests for image processing - prompt-builder.test.ts: 17 tests for prompt construction Coverage improvements: - Platform: 63.71% → 94.69% stmts, 40% → 97.14% funcs - Utils: 19.51% → 94.3% stmts, 18.51% → 100% funcs Updated thresholds to enforce high quality: - Platform: 90% lines/stmts, 95% funcs, 75% branches - Utils: 90% lines/stmts, 95% funcs, 85% branches Total new tests: 156 (platform: 47, utils: 109) All tests passing with new coverage thresholds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
250
libs/utils/tests/image-handler.test.ts
Normal file
250
libs/utils/tests/image-handler.test.ts
Normal file
@@ -0,0 +1,250 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import {
|
||||
getMimeTypeForImage,
|
||||
readImageAsBase64,
|
||||
convertImagesToContentBlocks,
|
||||
formatImagePathsForPrompt,
|
||||
} from "../src/image-handler";
|
||||
|
||||
describe("image-handler.ts", () => {
|
||||
let tempDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "image-handler-test-"));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
try {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
} catch (error) {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
});
|
||||
|
||||
describe("getMimeTypeForImage", () => {
|
||||
it("should return correct MIME type for .jpg", () => {
|
||||
expect(getMimeTypeForImage("image.jpg")).toBe("image/jpeg");
|
||||
expect(getMimeTypeForImage("/path/to/image.jpg")).toBe("image/jpeg");
|
||||
});
|
||||
|
||||
it("should return correct MIME type for .jpeg", () => {
|
||||
expect(getMimeTypeForImage("image.jpeg")).toBe("image/jpeg");
|
||||
});
|
||||
|
||||
it("should return correct MIME type for .png", () => {
|
||||
expect(getMimeTypeForImage("image.png")).toBe("image/png");
|
||||
});
|
||||
|
||||
it("should return correct MIME type for .gif", () => {
|
||||
expect(getMimeTypeForImage("image.gif")).toBe("image/gif");
|
||||
});
|
||||
|
||||
it("should return correct MIME type for .webp", () => {
|
||||
expect(getMimeTypeForImage("image.webp")).toBe("image/webp");
|
||||
});
|
||||
|
||||
it("should be case-insensitive", () => {
|
||||
expect(getMimeTypeForImage("image.JPG")).toBe("image/jpeg");
|
||||
expect(getMimeTypeForImage("image.PNG")).toBe("image/png");
|
||||
expect(getMimeTypeForImage("image.GIF")).toBe("image/gif");
|
||||
});
|
||||
|
||||
it("should default to image/png for unknown extensions", () => {
|
||||
expect(getMimeTypeForImage("file.xyz")).toBe("image/png");
|
||||
expect(getMimeTypeForImage("file.txt")).toBe("image/png");
|
||||
expect(getMimeTypeForImage("file")).toBe("image/png");
|
||||
});
|
||||
|
||||
it("should handle filenames with multiple dots", () => {
|
||||
expect(getMimeTypeForImage("my.file.name.jpg")).toBe("image/jpeg");
|
||||
});
|
||||
});
|
||||
|
||||
describe("readImageAsBase64", () => {
|
||||
it("should read image and return base64 data", async () => {
|
||||
const imagePath = path.join(tempDir, "test.png");
|
||||
const imageContent = Buffer.from("fake png data");
|
||||
await fs.writeFile(imagePath, imageContent);
|
||||
|
||||
const result = await readImageAsBase64(imagePath);
|
||||
|
||||
expect(result.base64).toBe(imageContent.toString("base64"));
|
||||
expect(result.mimeType).toBe("image/png");
|
||||
expect(result.filename).toBe("test.png");
|
||||
expect(result.originalPath).toBe(imagePath);
|
||||
});
|
||||
|
||||
it("should handle different image formats", async () => {
|
||||
const formats = [
|
||||
{ ext: "jpg", mime: "image/jpeg" },
|
||||
{ ext: "png", mime: "image/png" },
|
||||
{ ext: "gif", mime: "image/gif" },
|
||||
{ ext: "webp", mime: "image/webp" },
|
||||
];
|
||||
|
||||
for (const format of formats) {
|
||||
const imagePath = path.join(tempDir, `image.${format.ext}`);
|
||||
await fs.writeFile(imagePath, Buffer.from("data"));
|
||||
|
||||
const result = await readImageAsBase64(imagePath);
|
||||
|
||||
expect(result.mimeType).toBe(format.mime);
|
||||
expect(result.filename).toBe(`image.${format.ext}`);
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw error if file doesn't exist", async () => {
|
||||
const imagePath = path.join(tempDir, "nonexistent.png");
|
||||
|
||||
await expect(readImageAsBase64(imagePath)).rejects.toThrow();
|
||||
});
|
||||
|
||||
it("should handle binary image data correctly", async () => {
|
||||
const imagePath = path.join(tempDir, "binary.png");
|
||||
const binaryData = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a]);
|
||||
await fs.writeFile(imagePath, binaryData);
|
||||
|
||||
const result = await readImageAsBase64(imagePath);
|
||||
|
||||
expect(result.base64).toBe(binaryData.toString("base64"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("convertImagesToContentBlocks", () => {
|
||||
it("should convert single image to content block", async () => {
|
||||
const imagePath = path.join(tempDir, "test.png");
|
||||
await fs.writeFile(imagePath, Buffer.from("image data"));
|
||||
|
||||
const result = await convertImagesToContentBlocks([imagePath]);
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toMatchObject({
|
||||
type: "image",
|
||||
source: {
|
||||
type: "base64",
|
||||
media_type: "image/png",
|
||||
},
|
||||
});
|
||||
expect(result[0].source.data).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should convert multiple images", async () => {
|
||||
const image1 = path.join(tempDir, "image1.jpg");
|
||||
const image2 = path.join(tempDir, "image2.png");
|
||||
|
||||
await fs.writeFile(image1, Buffer.from("jpg data"));
|
||||
await fs.writeFile(image2, Buffer.from("png data"));
|
||||
|
||||
const result = await convertImagesToContentBlocks([image1, image2]);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].source.media_type).toBe("image/jpeg");
|
||||
expect(result[1].source.media_type).toBe("image/png");
|
||||
});
|
||||
|
||||
it("should resolve relative paths with workDir", async () => {
|
||||
const image = "test.png";
|
||||
const imagePath = path.join(tempDir, image);
|
||||
await fs.writeFile(imagePath, Buffer.from("data"));
|
||||
|
||||
const result = await convertImagesToContentBlocks([image], tempDir);
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].type).toBe("image");
|
||||
});
|
||||
|
||||
it("should handle absolute paths without workDir", async () => {
|
||||
const imagePath = path.join(tempDir, "absolute.png");
|
||||
await fs.writeFile(imagePath, Buffer.from("data"));
|
||||
|
||||
const result = await convertImagesToContentBlocks([imagePath]);
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("should skip images that fail to load", async () => {
|
||||
const validImage = path.join(tempDir, "valid.png");
|
||||
const invalidImage = path.join(tempDir, "nonexistent.png");
|
||||
|
||||
await fs.writeFile(validImage, Buffer.from("data"));
|
||||
|
||||
const result = await convertImagesToContentBlocks([
|
||||
validImage,
|
||||
invalidImage,
|
||||
]);
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].source.media_type).toBe("image/png");
|
||||
});
|
||||
|
||||
it("should return empty array for empty input", async () => {
|
||||
const result = await convertImagesToContentBlocks([]);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it("should preserve order of images", async () => {
|
||||
const images = ["img1.jpg", "img2.png", "img3.gif"];
|
||||
|
||||
for (const img of images) {
|
||||
await fs.writeFile(path.join(tempDir, img), Buffer.from("data"));
|
||||
}
|
||||
|
||||
const result = await convertImagesToContentBlocks(images, tempDir);
|
||||
|
||||
expect(result).toHaveLength(3);
|
||||
expect(result[0].source.media_type).toBe("image/jpeg");
|
||||
expect(result[1].source.media_type).toBe("image/png");
|
||||
expect(result[2].source.media_type).toBe("image/gif");
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatImagePathsForPrompt", () => {
|
||||
it("should return empty string for empty array", () => {
|
||||
const result = formatImagePathsForPrompt([]);
|
||||
expect(result).toBe("");
|
||||
});
|
||||
|
||||
it("should format single image path", () => {
|
||||
const result = formatImagePathsForPrompt(["/path/to/image.png"]);
|
||||
expect(result).toBe("\n\nAttached images:\n- /path/to/image.png\n");
|
||||
});
|
||||
|
||||
it("should format multiple image paths", () => {
|
||||
const result = formatImagePathsForPrompt([
|
||||
"/path/image1.png",
|
||||
"/path/image2.jpg",
|
||||
"/path/image3.gif",
|
||||
]);
|
||||
|
||||
expect(result).toBe(
|
||||
"\n\nAttached images:\n" +
|
||||
"- /path/image1.png\n" +
|
||||
"- /path/image2.jpg\n" +
|
||||
"- /path/image3.gif\n"
|
||||
);
|
||||
});
|
||||
|
||||
it("should handle relative paths", () => {
|
||||
const result = formatImagePathsForPrompt([
|
||||
"relative/path/image.png",
|
||||
"another/image.jpg",
|
||||
]);
|
||||
|
||||
expect(result).toContain("- relative/path/image.png");
|
||||
expect(result).toContain("- another/image.jpg");
|
||||
});
|
||||
|
||||
it("should start with newlines", () => {
|
||||
const result = formatImagePathsForPrompt(["/image.png"]);
|
||||
expect(result.startsWith("\n\n")).toBe(true);
|
||||
});
|
||||
|
||||
it("should include header text", () => {
|
||||
const result = formatImagePathsForPrompt(["/image.png"]);
|
||||
expect(result).toContain("Attached images:");
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user