import { describe, expect, test } from "bun:test"; import { AiEventRequestSchema } from "@/lib/types"; // --------------------------------------------------------------------------- // AiEventRequestSchema – behavioral validation tests // // The schema is the contract between the client and the API route. // Tests verify what the schema ALLOWS and what it REJECTS. // --------------------------------------------------------------------------- const VALID_PNG = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="; const VALID_JPEG = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAACf/EABQQAQAAAAAAAAAAAAAAAAAAAAD/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AJQAB/9k="; describe("AiEventRequestSchema – images array", () => { test("accepts a prompt with no images", () => { const result = AiEventRequestSchema.safeParse({ prompt: "Team standup every Monday at 9am" }); expect(result.success).toBe(true); }); test("accepts images array with one valid base64 image", () => { const result = AiEventRequestSchema.safeParse({ prompt: "What events are on this flyer?", images: [VALID_PNG], }); expect(result.success).toBe(true); }); test("accepts images array with multiple valid base64 images", () => { const result = AiEventRequestSchema.safeParse({ images: [VALID_PNG, VALID_JPEG], }); expect(result.success).toBe(true); if (result.success) { expect(result.data.images).toHaveLength(2); } }); test("accepts request with images only (no prompt)", () => { const result = AiEventRequestSchema.safeParse({ images: [VALID_PNG] }); expect(result.success).toBe(true); }); test("rejects request with neither prompt nor images", () => { const result = AiEventRequestSchema.safeParse({}); expect(result.success).toBe(false); }); test("rejects images array containing an invalid data URL", () => { const result = AiEventRequestSchema.safeParse({ images: ["not-a-data-url"], }); expect(result.success).toBe(false); }); test("rejects images array containing a non-image data URL (e.g. PDF)", () => { const result = AiEventRequestSchema.safeParse({ images: ["data:application/pdf;base64,abc123"], }); expect(result.success).toBe(false); }); test("rejects empty images array (must have at least one image OR a prompt)", () => { // An empty images array with no prompt should fail the 'prompt or images' refinement const result = AiEventRequestSchema.safeParse({ images: [] }); expect(result.success).toBe(false); }); test("returns data.images as string[] when images are valid", () => { const result = AiEventRequestSchema.safeParse({ images: [VALID_PNG, VALID_JPEG], }); expect(result.success).toBe(true); if (result.success) { expect(Array.isArray(result.data.images)).toBe(true); for (const img of result.data.images ?? []) { expect(typeof img).toBe("string"); } } }); }); describe("AiEventRequestSchema – prompt validation", () => { test("accepts a plain text prompt with no images", () => { const result = AiEventRequestSchema.safeParse({ prompt: "Birthday party Saturday" }); expect(result.success).toBe(true); }); test("rejects a prompt that exceeds 2000 characters", () => { const longPrompt = "a".repeat(2001); const result = AiEventRequestSchema.safeParse({ prompt: longPrompt }); expect(result.success).toBe(false); }); test("accepts a prompt of exactly 2000 characters", () => { const maxPrompt = "a".repeat(2000); const result = AiEventRequestSchema.safeParse({ prompt: maxPrompt }); expect(result.success).toBe(true); }); });