221 lines
7.2 KiB
TypeScript
221 lines
7.2 KiB
TypeScript
// tests/api/02-flows.ts
|
|
|
|
import { api, log, runTest, saveImage, waitForGeneration, testContext } from './utils';
|
|
import { endpoints } from './config';
|
|
|
|
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);
|