/** * Test database setup and teardown utilities for migration tests * Updated for PostgreSQL */ import { PrismaClient } from '@prisma/client' /** * Create a Prisma client instance for testing * Uses DATABASE_URL from environment */ export function createTestPrismaClient(): PrismaClient { return new PrismaClient() } /** * Initialize test database schema * Runs prisma migrate deploy or db push */ export async function initializeTestDatabase(prisma: PrismaClient) { await prisma.$connect() } export async function setupTestEnvironment(): Promise { // no-op — environment is ready via Docker } /** * Cleanup test database * Disconnects Prisma client and cleans all data */ export async function cleanupTestDatabase(prisma: PrismaClient) { try { // Delete in dependency order await prisma.aiFeedback.deleteMany() await prisma.memoryEchoInsight.deleteMany() await prisma.noteShare.deleteMany() await prisma.note.deleteMany() await prisma.label.deleteMany() await prisma.notebook.deleteMany() await prisma.userAISettings.deleteMany() await prisma.systemConfig.deleteMany() await prisma.session.deleteMany() await prisma.account.deleteMany() await prisma.verificationToken.deleteMany() await prisma.subscription.deleteMany() await prisma.user.deleteMany() await prisma.$disconnect() } catch (error) { console.error('Error cleaning up test database:', error) } } /** * Ensure a test user exists with the given ID (upsert by id). * Needed because PostgreSQL enforces FK constraints on Note.userId / Notebook.userId. */ export async function ensureTestUser(prisma: PrismaClient, userId: string): Promise { await prisma.user.upsert({ where: { id: userId }, create: { id: userId, email: `${userId}@test-fixture.internal` }, update: {}, }) } /** * Create sample test data */ export async function createSampleNotes(prisma: PrismaClient, count: number = 10) { const notes = [] const userId = 'test-user-123' await ensureTestUser(prisma, userId) for (let i = 0; i < count; i++) { const note = await prisma.note.create({ data: { title: `Test Note ${i + 1}`, content: `This is test content for note ${i + 1}`, userId, color: `color-${i % 5}`, order: i, isPinned: i % 3 === 0, isArchived: false, type: 'text', size: i % 3 === 0 ? 'small' : 'medium' } }) notes.push(note) } return notes } /** * Create sample AI-enabled notes */ export async function createSampleAINotes(prisma: PrismaClient, count: number = 10) { const notes = [] const userId = 'test-user-ai' await ensureTestUser(prisma, userId) for (let i = 0; i < count; i++) { const note = await prisma.note.create({ data: { title: `AI Test Note ${i + 1}`, content: `This is AI test content for note ${i + 1}`, userId, color: 'default', order: i, autoGenerated: i % 2 === 0, aiProvider: i % 3 === 0 ? 'openai' : 'ollama', aiConfidence: 70 + i * 2, language: i % 2 === 0 ? 'en' : 'fr', languageConfidence: 0.85 + (i * 0.01), lastAiAnalysis: new Date() } }) notes.push(note) } return notes } /** * Measure execution time for a function */ export async function measureExecutionTime(fn: () => Promise): Promise<{ result: T; duration: number }> { const start = performance.now() const result = await fn() const end = performance.now() return { result, duration: end - start } } /** * Verify data integrity after migration */ export async function verifyDataIntegrity(prisma: PrismaClient, expectedNoteCount: number) { const noteCount = await prisma.note.count() if (noteCount !== expectedNoteCount) { throw new Error(`Data integrity check failed: Expected ${expectedNoteCount} notes, found ${noteCount}`) } return true } /** * Check if database table exists (PostgreSQL version) */ export async function verifyTableExists(prisma: PrismaClient, tableName: string): Promise { try { const result = await prisma.$queryRawUnsafe>( `SELECT EXISTS ( SELECT FROM information_schema.tables WHERE table_schema = 'public' AND table_name = $1 )`, tableName ) return result[0]?.exists ?? false } catch (error) { return false } } /** * Check if index exists on a table (PostgreSQL version) */ export async function verifyIndexExists(prisma: PrismaClient, tableName: string, indexName: string): Promise { try { const result = await prisma.$queryRawUnsafe>( `SELECT EXISTS ( SELECT FROM pg_indexes WHERE schemaname = 'public' AND tablename = $1 AND indexname = $2 )`, tableName, indexName ) return result[0]?.exists ?? false } catch (error) { return false } } /** * Check if column exists in table (PostgreSQL version) */ export async function verifyColumnExists(prisma: PrismaClient, tableName: string, columnName: string): Promise { try { const result = await prisma.$queryRawUnsafe>( `SELECT EXISTS ( SELECT FROM information_schema.columns WHERE table_schema = 'public' AND table_name = $1 AND column_name = $2 )`, tableName, columnName ) return result[0]?.exists ?? false } catch (error) { return false } } /** * Get table schema information (PostgreSQL version) */ export async function getTableSchema(prisma: PrismaClient, tableName: string) { try { const result = await prisma.$queryRawUnsafe>( `SELECT column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_schema = 'public' AND table_name = $1 ORDER BY ordinal_position`, tableName ) return result } catch (error) { return null } }