import { readdir } from 'node:fs/promises'; import { join } from 'node:path'; import { PostgreSqlContainer, type StartedPostgreSqlContainer } from '@testcontainers/postgresql'; import { Kysely, Migrator } from 'kysely'; import { createDatabaseDialect } from '../src/db/config.js'; import type { Database } from '../src/db/types.js'; let postgresContainer: StartedPostgreSqlContainer; export async function setup() { console.log('Starting PostgreSQL testcontainer...'); postgresContainer = await new PostgreSqlContainer('postgres:18') .withExposedPorts(5432) .withDatabase('test_db') .withUsername('test_user') .withPassword('test_password') .start(); // Set environment variables for tests to use process.env.DB_TYPE = 'postgres'; process.env.DB_HOST = postgresContainer.getHost(); process.env.DB_PORT = String(postgresContainer.getPort()); process.env.DB_USER = postgresContainer.getUsername(); process.env.DB_PASSWORD = postgresContainer.getPassword(); process.env.DB_NAME = postgresContainer.getDatabase(); console.log(`PostgreSQL container started at ${process.env.DB_HOST}:${process.env.DB_PORT}`); // Run migrations once for all tests console.log('Running database migrations...'); const db = new Kysely({ dialect: createDatabaseDialect({ type: 'postgres', host: postgresContainer.getHost(), port: postgresContainer.getPort(), user: postgresContainer.getUsername(), password: postgresContainer.getPassword(), database: postgresContainer.getDatabase(), }), }); // Dynamically import all migration files from the migrations folder const migrationsDir = join(process.cwd(), 'src/db/migrations'); const files = await readdir(migrationsDir); const migrationFiles = files.filter((file) => file.endsWith('.ts')); // biome-ignore lint/suspicious/noExplicitAny: We need to use any here for dynamic imports const migrations: Record = {}; for (const file of migrationFiles) { const migrationName = file.replace('.ts', ''); const migrationPath = join(migrationsDir, file); const module = await import(migrationPath); migrations[migrationName] = module; } const migrator = new Migrator({ db, provider: { async getMigrations() { return migrations; }, }, }); const { error, results } = await migrator.migrateToLatest(); if (error) { console.error('Migration failed:', error); throw error; } if (results) { for (const result of results) { if (result.status === 'Success') { console.log(`Migration "${result.migrationName}" executed successfully`); } else if (result.status === 'Error') { console.error(`Migration "${result.migrationName}" failed`); } } } await db.destroy(); console.log('Database migrations completed'); } export async function teardown() { console.log('Stopping PostgreSQL testcontainer...'); await postgresContainer?.stop(); console.log('PostgreSQL container stopped'); }