/** * Entity Submission & Validation Integration Tests * * Tests for submission validation, schema validation, and entity creation. */ import { supabase } from '@/lib/supabaseClient'; import type { TestSuite, TestResult } from '../testRunner'; import { TestDataTracker } from '../TestDataTracker'; export const submissionTestSuite: TestSuite = { id: 'submission', name: 'Entity Submission & Validation', description: 'Tests for entity submission workflows and validation schemas', tests: [ { id: 'submission-001', name: 'Park Creation Validation', description: 'Validates park submission and creation', run: async (): Promise => { const startTime = Date.now(); const tracker = new TestDataTracker(); let parkId: string | null = null; try { const parkSlug = `test-park-submit-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; // Create park with valid data const { data: park, error: createError } = await supabase .from('parks') .insert({ name: 'Test Park Submission', slug: parkSlug, park_type: 'theme_park', status: 'operating', description: 'Test park for submission validation' }) .select('id, name, slug, park_type, status') .single(); if (createError) throw new Error(`Park creation failed: ${createError.message}`); if (!park) throw new Error('Park not returned after creation'); parkId = park.id; // Validate created park has correct data if (park.name !== 'Test Park Submission') { throw new Error(`Expected name "Test Park Submission", got "${park.name}"`); } if (park.slug !== parkSlug) { throw new Error(`Expected slug "${parkSlug}", got "${park.slug}"`); } if (park.park_type !== 'theme_park') { throw new Error(`Expected park_type "theme_park", got "${park.park_type}"`); } // Test slug uniqueness constraint const { error: duplicateError } = await supabase .from('parks') .insert({ name: 'Duplicate Slug Park', slug: parkSlug, // Same slug park_type: 'theme_park', status: 'operating' }); if (!duplicateError) { throw new Error('Duplicate slug was allowed (uniqueness constraint failed)'); } const duration = Date.now() - startTime; return { id: 'submission-001', name: 'Park Creation Validation', suite: 'Entity Submission & Validation', status: 'pass', duration, timestamp: new Date().toISOString(), details: { parkId, parkSlug, validationsPassed: ['name', 'slug', 'park_type', 'uniqueness_constraint'] } }; } catch (error) { return { id: 'submission-001', name: 'Park Creation Validation', suite: 'Entity Submission & Validation', status: 'fail', duration: Date.now() - startTime, error: error instanceof Error ? error.message : String(error), timestamp: new Date().toISOString() }; } finally { await tracker.cleanup(); const remaining = await tracker.verifyCleanup(); if (remaining.length > 0) { console.warn('submission-001 cleanup incomplete:', remaining); } } } }, { id: 'submission-002', name: 'Ride Creation with Dependencies', description: 'Validates ride submission requires valid park_id', run: async (): Promise => { const startTime = Date.now(); const tracker = new TestDataTracker(); let parkId: string | null = null; let rideId: string | null = null; try { // First create a park const parkSlug = `test-park-ride-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const { data: park, error: parkError } = await supabase .from('parks') .insert({ name: 'Test Park for Ride', slug: parkSlug, park_type: 'theme_park', status: 'operating', is_test_data: true }) .select('id') .single(); if (parkError) throw new Error(`Park creation failed: ${parkError.message}`); parkId = park.id; // Try to create ride with invalid park_id (should fail) const invalidParkId = '00000000-0000-0000-0000-000000000000'; const { error: invalidError } = await supabase .from('rides') .insert({ name: 'Test Ride Invalid Park', slug: `test-ride-invalid-${Date.now()}`, park_id: invalidParkId, category: 'roller_coaster', status: 'operating' }); if (!invalidError) { throw new Error('Ride with invalid park_id was allowed (foreign key constraint failed)'); } // Create ride with valid park_id (should succeed) const rideSlug = `test-ride-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const { data: ride, error: rideError } = await supabase .from('rides') .insert({ name: 'Test Ride Valid Park', slug: rideSlug, park_id: parkId, category: 'roller_coaster', status: 'operating' }) .select('id, name, park_id') .single(); if (rideError) throw new Error(`Ride creation failed: ${rideError.message}`); if (!ride) throw new Error('Ride not returned after creation'); rideId = ride.id; if (ride.park_id !== parkId) { throw new Error(`Expected park_id "${parkId}", got "${ride.park_id}"`); } const duration = Date.now() - startTime; return { id: 'submission-002', name: 'Ride Creation with Dependencies', suite: 'Entity Submission & Validation', status: 'pass', duration, timestamp: new Date().toISOString(), details: { parkId, rideId, validationsPassed: ['foreign_key_constraint', 'valid_dependency'] } }; } catch (error) { return { id: 'submission-002', name: 'Ride Creation with Dependencies', suite: 'Entity Submission & Validation', status: 'fail', duration: Date.now() - startTime, error: error instanceof Error ? error.message : String(error), timestamp: new Date().toISOString() }; } finally { await tracker.cleanup(); const remaining = await tracker.verifyCleanup(); if (remaining.length > 0) { console.warn('submission-002 cleanup incomplete:', remaining); } } } }, { id: 'submission-003', name: 'Company Creation All Types', description: 'Validates company creation for all company types', run: async (): Promise => { const startTime = Date.now(); const tracker = new TestDataTracker(); const companyIds: string[] = []; try { const companyTypes = ['manufacturer', 'operator', 'designer', 'property_owner'] as const; for (const companyType of companyTypes) { const slug = `test-company-${companyType}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const { data: company, error: createError } = await supabase .from('companies') .insert({ name: `Test ${companyType} Company`, slug, company_type: companyType, description: `Test company of type ${companyType}` }) .select('id, company_type') .single(); if (createError) { throw new Error(`${companyType} creation failed: ${createError.message}`); } if (!company) { throw new Error(`${companyType} not returned after creation`); } companyIds.push(company.id); tracker.track('companies', company.id); if (company.company_type !== companyType) { throw new Error(`Expected company_type "${companyType}", got "${company.company_type}"`); } } const duration = Date.now() - startTime; return { id: 'submission-003', name: 'Company Creation All Types', suite: 'Entity Submission & Validation', status: 'pass', duration, timestamp: new Date().toISOString(), details: { companiesCreated: companyIds.length, companyTypes: companyTypes, companyIds } }; } catch (error) { return { id: 'submission-003', name: 'Company Creation All Types', suite: 'Entity Submission & Validation', status: 'fail', duration: Date.now() - startTime, error: error instanceof Error ? error.message : String(error), timestamp: new Date().toISOString() }; } finally { await tracker.cleanup(); const remaining = await tracker.verifyCleanup(); if (remaining.length > 0) { console.warn('submission-003 cleanup incomplete:', remaining); } } } }, { id: 'submission-004', name: 'Ride Model with Images', description: 'Validates ride model creation with image fields', run: async (): Promise => { const startTime = Date.now(); let manufacturerId: string | null = null; let modelId: string | null = null; try { // Create manufacturer first const mfgSlug = `test-mfg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const { data: manufacturer, error: mfgError } = await supabase .from('companies') .insert({ name: 'Test Manufacturer', slug: mfgSlug, company_type: 'manufacturer' }) .select('id') .single(); if (mfgError) throw new Error(`Manufacturer creation failed: ${mfgError.message}`); manufacturerId = manufacturer.id; // Create ride model with images const modelSlug = `test-model-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const testImageUrl = 'https://imagedelivery.net/test-account/test-image-id/public'; const testImageId = 'test-image-id'; const { data: model, error: modelError } = await supabase .from('ride_models') .insert({ name: 'Test Ride Model', slug: modelSlug, manufacturer_id: manufacturerId, category: 'roller_coaster', ride_type: 'steel_coaster', banner_image_url: testImageUrl, banner_image_id: testImageId, card_image_url: testImageUrl, card_image_id: testImageId }) .select('id, banner_image_url, banner_image_id, card_image_url, card_image_id') .single(); if (modelError) throw new Error(`Ride model creation failed: ${modelError.message}`); if (!model) throw new Error('Ride model not returned after creation'); modelId = model.id; // Validate image fields if (model.banner_image_url !== testImageUrl) { throw new Error(`banner_image_url mismatch: expected "${testImageUrl}", got "${model.banner_image_url}"`); } if (model.banner_image_id !== testImageId) { throw new Error(`banner_image_id mismatch: expected "${testImageId}", got "${model.banner_image_id}"`); } if (model.card_image_url !== testImageUrl) { throw new Error(`card_image_url mismatch`); } if (model.card_image_id !== testImageId) { throw new Error(`card_image_id mismatch`); } // Verify version was created with images let version: any = null; const pollStart = Date.now(); while (!version && Date.now() - pollStart < 5000) { const { data } = await supabase .from('ride_model_versions') .select('banner_image_url, banner_image_id, card_image_url, card_image_id') .eq('ride_model_id', modelId) .eq('version_number', 1) .single(); if (data) { version = data; break; } await new Promise(resolve => setTimeout(resolve, 100)); } if (!version) throw new Error('Version not created after 5s timeout'); if (version.banner_image_url !== testImageUrl) { throw new Error('Version missing banner_image_url'); } const duration = Date.now() - startTime; return { id: 'submission-004', name: 'Ride Model with Images', suite: 'Entity Submission & Validation', status: 'pass', duration, timestamp: new Date().toISOString(), details: { modelId, manufacturerId, imageFieldsValidated: ['banner_image_url', 'banner_image_id', 'card_image_url', 'card_image_id'], versionCreated: true } }; } catch (error) { return { id: 'submission-004', name: 'Ride Model with Images', suite: 'Entity Submission & Validation', status: 'fail', duration: Date.now() - startTime, error: error instanceof Error ? error.message : String(error), timestamp: new Date().toISOString() }; } finally { if (modelId) { await supabase.from('ride_models').delete().eq('id', modelId); } if (manufacturerId) { await supabase.from('companies').delete().eq('id', manufacturerId); } } } } ] };