banatie-service/tests/api/test-05-edge-cases.ts

381 lines
11 KiB
TypeScript

// tests/api/05-edge-cases.ts
import { join } from 'path';
import { api, log, runTest, uploadFile } from './utils';
import { config, endpoints } from './config';
async function main() {
log.section('EDGE CASES & VALIDATION TESTS');
// Test 1: Invalid alias format
await runTest('Invalid alias format', async () => {
const result = await api(endpoints.generations, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: 'Test image',
assignAlias: 'invalid-no-at-sign',
}),
expectError: true,
});
if (result.status !== 400 && result.status !== 422) {
throw new Error(`Expected 400/422, got ${result.status}`);
}
log.detail('Status', result.status);
log.detail('Error', result.data.error || result.data.message);
});
// Test 2: Reserved technical alias
await runTest('Reserved technical alias', async () => {
const fixturePath = join(__dirname, config.fixturesDir, 'test-image.png');
try {
await uploadFile(fixturePath, {
alias: '@last', // Reserved
});
throw new Error('Should have failed with reserved alias');
} catch (error) {
log.detail('Correctly rejected', '@last is reserved');
}
});
// Test 3: Duplicate project alias
await runTest('Duplicate project alias', async () => {
const fixturePath = join(__dirname, config.fixturesDir, 'test-image.png');
// First upload
await uploadFile(fixturePath, {
alias: '@duplicate-test',
});
// Try duplicate
const result = await api(endpoints.images + '/upload', {
method: 'POST',
body: (() => {
const formData = new FormData();
formData.append('alias', '@duplicate-test');
return formData;
})(),
expectError: true,
});
if (result.status !== 409) {
throw new Error(`Expected 409 Conflict, got ${result.status}`);
}
log.detail('Status', '409 Conflict');
log.detail('Message', result.data.message);
});
// Test 4: Missing prompt
await runTest('Missing required prompt', async () => {
const result = await api(endpoints.generations, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
aspectRatio: '16:9',
// No prompt
}),
expectError: true,
});
if (result.status !== 400 && result.status !== 422) {
throw new Error(`Expected 400/422, got ${result.status}`);
}
log.detail('Status', result.status);
log.detail('Validation error', 'prompt is required');
});
// Test 5: Invalid aspect ratio format
await runTest('Invalid aspect ratio format', async () => {
const result = await api(endpoints.generations, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: 'Test image',
aspectRatio: 'invalid',
}),
expectError: true,
});
if (result.status !== 400 && result.status !== 422) {
throw new Error(`Expected 400/422, got ${result.status}`);
}
log.detail('Status', result.status);
log.detail('Error', 'Invalid aspect ratio format');
});
// Test 6: Non-existent reference image
await runTest('Non-existent reference image', async () => {
const result = await api(endpoints.generations, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: 'Test with invalid reference',
referenceImages: ['@non-existent-alias'],
}),
expectError: true,
});
if (result.status !== 404) {
throw new Error(`Expected 404, got ${result.status}`);
}
log.detail('Status', '404 Not Found');
log.detail('Error', 'Reference image not found');
});
// Test 7: Invalid flow ID
await runTest('Invalid flow ID', async () => {
const result = await api(endpoints.generations, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: 'Test image',
flowId: '00000000-0000-0000-0000-000000000000',
}),
expectError: true,
});
if (result.status !== 404) {
throw new Error(`Expected 404, got ${result.status}`);
}
log.detail('Status', '404 Not Found');
log.detail('Error', 'Flow not found');
});
// Test 8: assignFlowAlias without flowId
await runTest('Flow alias without flow ID', async () => {
const result = await api(endpoints.generations, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: 'Test image',
assignFlowAlias: '@test', // No flowId provided
}),
expectError: true,
});
if (result.status !== 400 && result.status !== 422) {
throw new Error(`Expected 400/422, got ${result.status}`);
}
log.detail('Status', result.status);
log.detail('Error', 'assignFlowAlias requires flowId');
});
// Test 9: Empty prompt
await runTest('Empty prompt', async () => {
const result = await api(endpoints.generations, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: '',
}),
expectError: true,
});
if (result.status !== 400 && result.status !== 422) {
throw new Error(`Expected 400/422, got ${result.status}`);
}
log.detail('Status', result.status);
log.detail('Error', 'Prompt cannot be empty');
});
// Test 10: Extremely long prompt (over 2000 chars)
await runTest('Prompt too long', async () => {
const longPrompt = 'A'.repeat(2001);
const result = await api(endpoints.generations, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: longPrompt,
}),
expectError: true,
});
if (result.status !== 400 && result.status !== 422) {
throw new Error(`Expected 400/422, got ${result.status}`);
}
log.detail('Status', result.status);
log.detail('Error', 'Prompt exceeds max length');
});
// Test 11: Dimensions out of range
await runTest('Invalid dimensions', async () => {
const result = await api(endpoints.generations, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: 'Test image',
width: 10000, // Over max
height: 10000,
}),
expectError: true,
});
if (result.status !== 400 && result.status !== 422) {
throw new Error(`Expected 400/422, got ${result.status}`);
}
log.detail('Status', result.status);
log.detail('Error', 'Dimensions exceed max 8192');
});
// Test 12: Invalid image ID
await runTest('Non-existent image ID', async () => {
const result = await api(`${endpoints.images}/00000000-0000-0000-0000-000000000000`, {
expectError: true,
});
if (result.status !== 404) {
throw new Error(`Expected 404, got ${result.status}`);
}
log.detail('Status', '404 Not Found');
});
// Test 13: Update non-existent image
await runTest('Update non-existent image', async () => {
const result = await api(`${endpoints.images}/00000000-0000-0000-0000-000000000000`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
description: 'Updated',
}),
expectError: true,
});
if (result.status !== 404) {
throw new Error(`Expected 404, got ${result.status}`);
}
log.detail('Status', '404 Not Found');
});
// Test 14: Delete non-existent flow
await runTest('Delete non-existent flow', async () => {
const result = await api(`${endpoints.flows}/00000000-0000-0000-0000-000000000000`, {
method: 'DELETE',
expectError: true,
});
if (result.status !== 404) {
throw new Error(`Expected 404, got ${result.status}`);
}
log.detail('Status', '404 Not Found');
});
// Test 15: Invalid pagination params
await runTest('Invalid pagination params', async () => {
const result = await api(`${endpoints.images}?limit=1000`, {
expectError: true,
});
if (result.status !== 400 && result.status !== 422) {
throw new Error(`Expected 400/422, got ${result.status}`);
}
log.detail('Status', result.status);
log.detail('Error', 'Limit exceeds max 100');
});
// Test 16: Missing API key
await runTest('Missing API key', async () => {
const url = `${config.baseURL}${endpoints.images}`;
const response = await fetch(url); // No API key header
if (response.status !== 401) {
throw new Error(`Expected 401, got ${response.status}`);
}
log.detail('Status', '401 Unauthorized');
});
// Test 17: Invalid API key
await runTest('Invalid API key', async () => {
const url = `${config.baseURL}${endpoints.images}`;
const response = await fetch(url, {
headers: {
'X-API-Key': 'invalid_key_123',
},
});
if (response.status !== 401) {
throw new Error(`Expected 401, got ${response.status}`);
}
log.detail('Status', '401 Unauthorized');
});
// Test 18: Retry non-failed generation
await runTest('Retry non-failed generation', async () => {
// Create a successful generation first
const genResult = await api(endpoints.generations, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: 'Test for retry',
aspectRatio: '1:1',
}),
});
// Try to retry it (should fail)
const retryResult = await api(`${endpoints.generations}/${genResult.data.generation.id}/retry`, {
method: 'POST',
expectError: true,
});
if (retryResult.status !== 422) {
throw new Error(`Expected 422, got ${retryResult.status}`);
}
log.detail('Status', '422 Unprocessable Entity');
log.detail('Error', 'Can only retry failed generations');
});
// Test 19: Resolve alias without context
await runTest('Resolve flow alias without flow context', async () => {
// Try to resolve a flow-only alias without flowId
const result = await api(`${endpoints.images}/resolve/@temp-logo`, {
expectError: true,
});
if (result.status !== 404) {
throw new Error(`Expected 404, got ${result.status}`);
}
log.detail('Status', '404 Not Found');
log.detail('Error', 'Alias requires flow context');
});
// Test 20: Live endpoint without prompt
await runTest('Live endpoint without prompt', async () => {
const result = await api(`${endpoints.live}?aspectRatio=16:9`, {
expectError: true,
});
if (result.status !== 400) {
throw new Error(`Expected 400, got ${result.status}`);
}
log.detail('Status', '400 Bad Request');
log.detail('Error', 'Prompt is required');
});
log.section('EDGE CASES TESTS COMPLETED');
}
main().catch(console.error);