92 lines
2.9 KiB
TypeScript

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<Database>({
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<string, any> = {};
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');
}