Files
Antigravity 8283c4e140
Some checks failed
CI / Lint, Test & Build (push) Successful in 12m12s
Deploy to Production / Build and Deploy (push) Has been cancelled
fix(ci): tests unitaires Vitest uniquement, sans Playwright ni migrations
Les tests migration exigent un schéma aligné via db push (hors scope CI).
Trois fichiers unitaires importaient @playwright/test par erreur.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 09:01:27 +00:00

251 lines
7.2 KiB
TypeScript

/**
* 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<void> {
// no-op — environment is ready via Docker
}
/**
* Cleanup test database
* Disconnects Prisma client and cleans all data
*/
async function deleteManyIfTableExists(
prisma: PrismaClient,
tableName: string,
deleteFn: () => Promise<unknown>
) {
if (await verifyTableExists(prisma, tableName)) {
await deleteFn()
}
}
export async function cleanupTestDatabase(prisma: PrismaClient) {
try {
await deleteManyIfTableExists(prisma, 'AiFeedback', () => prisma.aiFeedback.deleteMany())
await deleteManyIfTableExists(prisma, 'MemoryEchoInsight', () => prisma.memoryEchoInsight.deleteMany())
await deleteManyIfTableExists(prisma, 'NoteShare', () => prisma.noteShare.deleteMany())
await deleteManyIfTableExists(prisma, 'Note', () => prisma.note.deleteMany())
await deleteManyIfTableExists(prisma, 'Label', () => prisma.label.deleteMany())
await deleteManyIfTableExists(prisma, 'Notebook', () => prisma.notebook.deleteMany())
await deleteManyIfTableExists(prisma, 'UserAISettings', () => prisma.userAISettings.deleteMany())
await deleteManyIfTableExists(prisma, 'SystemConfig', () => prisma.systemConfig.deleteMany())
await deleteManyIfTableExists(prisma, 'Session', () => prisma.session.deleteMany())
await deleteManyIfTableExists(prisma, 'Account', () => prisma.account.deleteMany())
await deleteManyIfTableExists(prisma, 'VerificationToken', () => prisma.verificationToken.deleteMany())
await deleteManyIfTableExists(prisma, 'Subscription', () => prisma.subscription.deleteMany())
await deleteManyIfTableExists(prisma, 'User', () => 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<void> {
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<T>(fn: () => Promise<T>): 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<boolean> {
try {
const result = await prisma.$queryRawUnsafe<Array<{ exists: boolean }>>(
`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<boolean> {
try {
const result = await prisma.$queryRawUnsafe<Array<{ exists: boolean }>>(
`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<boolean> {
try {
const result = await prisma.$queryRawUnsafe<Array<{ exists: boolean }>>(
`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)
*/
/** Approximate DB size in bytes (PostgreSQL). */
export async function getDatabaseSize(prisma: PrismaClient): Promise<number> {
const rows = await prisma.$queryRaw<Array<{ size: bigint }>>`
SELECT pg_database_size(current_database()) AS size
`
return Number(rows[0]?.size ?? 0)
}
export async function getTableSchema(prisma: PrismaClient, tableName: string) {
try {
const result = await prisma.$queryRawUnsafe<Array<{
column_name: string
data_type: string
is_nullable: string
column_default: string | null
}>>(
`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
}
}