// tests/api/02-flows.ts import { api, log, runTest, saveImage, waitForGeneration, testContext } from './utils'; import { endpoints } from './config'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); async function main() { log.section('FLOW TESTS'); // Test 1: Create flow await runTest('Create flow', async () => { const result = await api(endpoints.flows, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ meta: { purpose: 'test-flow', description: 'Testing flow functionality' }, }), }); if (!result.data.flow || !result.data.flow.id) { throw new Error('No flow returned'); } testContext.flowId = result.data.flow.id; log.detail('Flow ID', result.data.flow.id); log.detail('Aliases', JSON.stringify(result.data.flow.aliases)); }); // Test 2: List flows await runTest('List flows', async () => { const result = await api(endpoints.flows); if (!result.data.flows || !Array.isArray(result.data.flows)) { throw new Error('No flows array returned'); } log.detail('Total flows', result.data.flows.length); log.detail('Has pagination', !!result.data.pagination); }); // Test 3: Generate in flow (first generation) await runTest('Generate in flow (first)', async () => { const result = await api(endpoints.generations, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: 'A red sports car on a mountain road', aspectRatio: '16:9', flowId: testContext.flowId, }), }); if (!result.data.generation) { throw new Error('No generation returned'); } log.detail('Generation ID', result.data.generation.id); log.detail('Flow ID', result.data.generation.flowId); // Wait for completion log.info('Waiting for generation to complete...'); const generation = await waitForGeneration(result.data.generation.id); if (generation.status !== 'success') { throw new Error(`Generation failed: ${generation.errorMessage}`); } log.detail('Output image', generation.outputImageId); // Save image if (generation.outputImageId) { const imageResult = await api(`${endpoints.images}/${generation.outputImageId}`); const imageUrl = imageResult.data.image.storageUrl; const imageResponse = await fetch(imageUrl); const imageBuffer = await imageResponse.arrayBuffer(); await saveImage(imageBuffer, 'flow-gen-1.png'); } }); // Test 4: Generate in flow (second generation) with @last reference await runTest('Generate in flow with @last', async () => { const result = await api(endpoints.generations, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: 'Same as @last but make it blue instead of red', aspectRatio: '16:9', flowId: testContext.flowId, referenceImages: ['@last'], }), }); if (!result.data.generation) { throw new Error('No generation returned'); } log.detail('Generation ID', result.data.generation.id); log.detail('Referenced @last', result.data.generation.referencedImages?.some((r: any) => r.alias === '@last')); // Wait for completion log.info('Waiting for generation to complete...'); const generation = await waitForGeneration(result.data.generation.id); if (generation.status !== 'success') { throw new Error(`Generation failed: ${generation.errorMessage}`); } // Save image if (generation.outputImageId) { const imageResult = await api(`${endpoints.images}/${generation.outputImageId}`); const imageUrl = imageResult.data.image.storageUrl; const imageResponse = await fetch(imageUrl); const imageBuffer = await imageResponse.arrayBuffer(); await saveImage(imageBuffer, 'flow-gen-2-with-last.png'); } }); // Test 5: Get flow details await runTest('Get flow details', async () => { const result = await api(`${endpoints.flows}/${testContext.flowId}`); if (!result.data.flow) { throw new Error('Flow not found'); } log.detail('Flow ID', result.data.flow.id); log.detail('Generations count', result.data.generations?.length || 0); log.detail('Images count', result.data.images?.length || 0); log.detail('Resolved aliases', Object.keys(result.data.resolvedAliases || {}).length); }); // Test 6: Update flow aliases await runTest('Update flow aliases', async () => { // First, get the latest generation's image ID const flowResult = await api(`${endpoints.flows}/${testContext.flowId}`); const lastGeneration = flowResult.data.generations[flowResult.data.generations.length - 1]; if (!lastGeneration.outputImageId) { throw new Error('No output image for alias assignment'); } const result = await api(`${endpoints.flows}/${testContext.flowId}/aliases`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ aliases: { '@hero': lastGeneration.outputImageId, '@featured': lastGeneration.outputImageId, }, }), }); if (!result.data.flow) { throw new Error('Flow not returned'); } log.detail('Updated aliases', JSON.stringify(result.data.flow.aliases)); }); // Test 7: Generate with flow-scoped alias await runTest('Generate with flow-scoped alias', async () => { const result = await api(endpoints.generations, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: 'A poster design featuring @hero image', aspectRatio: '9:16', flowId: testContext.flowId, referenceImages: ['@hero'], }), }); if (!result.data.generation) { throw new Error('No generation returned'); } log.detail('Generation ID', result.data.generation.id); log.detail('Referenced @hero', result.data.generation.referencedImages?.some((r: any) => r.alias === '@hero')); // Wait for completion log.info('Waiting for generation to complete...'); const generation = await waitForGeneration(result.data.generation.id); if (generation.status !== 'success') { throw new Error(`Generation failed: ${generation.errorMessage}`); } // Save image if (generation.outputImageId) { const imageResult = await api(`${endpoints.images}/${generation.outputImageId}`); const imageUrl = imageResult.data.image.storageUrl; const imageResponse = await fetch(imageUrl); const imageBuffer = await imageResponse.arrayBuffer(); await saveImage(imageBuffer, 'flow-gen-with-hero.png'); } }); // Test 8: Delete flow alias await runTest('Delete flow alias', async () => { await api(`${endpoints.flows}/${testContext.flowId}/aliases/@featured`, { method: 'DELETE', }); // Verify it's deleted const result = await api(`${endpoints.flows}/${testContext.flowId}`); const hasFeatureAlias = '@featured' in result.data.flow.aliases; if (hasFeatureAlias) { throw new Error('Alias was not deleted'); } log.detail('Remaining aliases', JSON.stringify(result.data.flow.aliases)); }); log.section('FLOW TESTS COMPLETED'); } main().catch(console.error);