--- phase: 18-api-route-tests plan: 04 type: execute --- Add tests for generate API route covering Replicate and fal.ai provider paths. Purpose: Complete generate route test coverage with external provider mocking. Output: Tests for /api/generate Replicate and fal.ai paths with mocked fetch calls. ~/.claude/get-shit-done/workflows/execute-phase.md ~/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md **Route to test:** @src/app/api/generate/route.ts **Existing tests to extend:** @src/app/api/generate/__tests__/route.test.ts Task 1: Add generate route tests for Replicate provider src/app/api/generate/__tests__/route.test.ts Add tests for /api/generate route Replicate path to existing test file: - POST: Generates image successfully via Replicate - POST: Generates video successfully via Replicate - POST: Returns 401 when Replicate API key missing - POST: Handles rate limit (429) from Replicate - POST: Handles prediction failure - POST: Handles prediction timeout (5 min max) - POST: Polls for prediction completion - POST: Returns video URL for large videos (>20MB) Mock global fetch for Replicate API calls: ```typescript // Model info fetch mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ latest_version: { id: "version123", openapi_schema: {} }, }), }); // Create prediction mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ id: "prediction123", status: "starting", }), }); // Poll prediction (succeeded) mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ id: "prediction123", status: "succeeded", output: ["https://replicate.delivery/output.png"], }), }); // Fetch output media mockFetch.mockResolvedValueOnce({ ok: true, headers: new Headers({ "content-type": "image/png" }), arrayBuffer: () => Promise.resolve(new ArrayBuffer(1024)), }); ``` Test X-Replicate-API-Key header is passed correctly. Test dynamicInputs are passed to prediction input. npm test -- src/app/api/generate/__tests__/route.test.ts --testNamePattern="Replicate" Replicate provider tests pass covering success, polling, and error paths Task 2: Add generate route tests for fal.ai provider src/app/api/generate/__tests__/route.test.ts Add tests for /api/generate route fal.ai path to existing test file: - POST: Generates image successfully via fal.ai (images array response) - POST: Generates video successfully via fal.ai (video object response) - POST: Works without API key (fal.ai allows unauthenticated) - POST: Handles rate limit (429) with and without key - POST: Handles various response formats (image, images, video, output) - POST: Returns video URL for large videos (>20MB) - POST: Filters empty dynamicInputs values Mock global fetch for fal.ai API calls: ```typescript // Sync API call (fal.run) mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ images: [{ url: "https://fal.media/output.png" }], }), }); // Fetch output media mockFetch.mockResolvedValueOnce({ ok: true, headers: new Headers({ "content-type": "image/png" }), arrayBuffer: () => Promise.resolve(new ArrayBuffer(1024)), }); // Video response format mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ video: { url: "https://fal.media/output.mp4" }, }), }); ``` Test X-Fal-API-Key header is passed when provided. Test getFalInputMapping schema parsing (via behavior). npm test -- src/app/api/generate/__tests__/route.test.ts All generate route tests pass covering all three providers Before declaring plan complete: - [ ] `npm test -- src/app/api/generate/__tests__/route.test.ts` passes - [ ] Tests cover Replicate and fal.ai provider paths - [ ] Polling logic tested for Replicate - [ ] Various response formats tested for fal.ai - [ ] No TypeScript errors - All tasks completed - All verification checks pass - All three providers thoroughly tested - Error handling tested for each provider After completion, create `.planning/phases/18-api-route-tests/18-04-SUMMARY.md`