import { describe, it, expect, beforeEach, vi } from "vitest"; import { imageToolHandler } from "../../../src/tools/image"; import { executeSwiftCli, readImageAsBase64 } from "../../../src/utils/peekaboo-cli"; import { resolveImagePath } from "../../../src/utils/image-cli-args"; import { mockSwiftCli } from "../../mocks/peekaboo-cli.mock"; import { pino } from "pino"; // Mock the Swift CLI utility vi.mock("../../../src/utils/peekaboo-cli"); // Mock fs/promises vi.mock("fs/promises"); // Mock image-cli-args module vi.mock("../../../src/utils/image-cli-args", async () => { const actual = await vi.importActual("../../../src/utils/image-cli-args"); return { ...actual, resolveImagePath: vi.fn(), }; }); const mockExecuteSwiftCli = executeSwiftCli as vi.MockedFunction< typeof executeSwiftCli >; const mockResolveImagePath = resolveImagePath as vi.MockedFunction; const mockLogger = pino({ level: "silent" }); const mockContext = { logger: mockLogger }; const MOCK_TEMP_DIR = "/tmp/peekaboo-img-XXXXXX"; const MOCK_SAVED_FILE_PATH = "/tmp/test_invalid_format.png"; describe("Invalid Format Handling", () => { beforeEach(() => { vi.clearAllMocks(); // Mock resolveImagePath to return a temp directory mockResolveImagePath.mockResolvedValue({ effectivePath: MOCK_TEMP_DIR, tempDirUsed: MOCK_TEMP_DIR, }); }); it("should fallback invalid format 'bmp' to 'png' and use correct extension in filename", async () => { // Import schema to test preprocessing const { imageToolSchema } = await import("../../../src/types/index.js"); // Mock Swift CLI response with PNG format (fallback) const mockResponse = mockSwiftCli.captureImage("screen", { path: MOCK_SAVED_FILE_PATH, format: "png", }); // Ensure the saved file has .png extension, not .bmp const savedFileWithCorrectExtension = { ...mockResponse.data.saved_files[0], path: "/tmp/test_invalid_format.png", // Should be .png, not .bmp }; const correctedResponse = { ...mockResponse, data: { ...mockResponse.data, saved_files: [savedFileWithCorrectExtension], }, }; mockExecuteSwiftCli.mockResolvedValue(correctedResponse); // Test with invalid format 'bmp' - schema should preprocess to 'png' const parsedInput = imageToolSchema.parse({ format: "bmp", path: "/tmp/test_invalid_format.bmp" }); // Validate that schema preprocessing worked expect(parsedInput.format).toBe("png"); const result = await imageToolHandler(parsedInput, mockContext); expect(result.isError).toBeUndefined(); // Should have called Swift CLI with PNG format, not BMP expect(mockExecuteSwiftCli).toHaveBeenCalledWith( expect.arrayContaining(["--format", "png"]), mockLogger, expect.objectContaining({ timeout: expect.any(Number) }), ); // The saved file should have .png extension expect(result.saved_files?.[0]?.path).toBe("/tmp/test_invalid_format.png"); expect(result.saved_files?.[0]?.path).not.toContain(".bmp"); // The result should not contain .bmp anywhere const resultText = result.content[0]?.text || ""; expect(resultText).not.toContain(".bmp"); expect(resultText).toContain(".png"); }); it("should handle other invalid formats correctly", async () => { const { imageToolSchema } = await import("../../../src/types/index.js"); const invalidFormats = ["gif", "webp", "tiff", "xyz", "bmp"]; for (const invalidFormat of invalidFormats) { const parsedInput = imageToolSchema.parse({ format: invalidFormat }); // All invalid formats should be preprocessed to 'png' expect(parsedInput.format).toBe("png"); } // Empty string should become undefined (which will use default) const emptyInput = imageToolSchema.parse({ format: "" }); expect(emptyInput.format).toBeUndefined(); }); it("should preserve valid formats", async () => { const { imageToolSchema } = await import("../../../src/types/index.js"); const validFormats = [ { input: "png", expected: "png" }, { input: "PNG", expected: "png" }, // case insensitive { input: "jpg", expected: "jpg" }, { input: "JPG", expected: "jpg" }, // case insensitive { input: "jpeg", expected: "jpg" }, // alias { input: "JPEG", expected: "jpg" }, // alias + case insensitive { input: "data", expected: "data" }, ]; for (const { input, expected } of validFormats) { const parsedInput = imageToolSchema.parse({ format: input }); expect(parsedInput.format).toBe(expected); } }); });