import path from 'node:path' import { fileURLToPath } from 'node:url' import pg from 'pg' import { afterAll, beforeAll, describe, expect, it } from 'vitest' import { runMigrations } from './migrations.js' const { Client } = pg const baseDatabaseUrl = process.env.TEST_DATABASE_URL const suite = baseDatabaseUrl ? describe : describe.skip const databaseName = `osint_test_${process.pid}_${Date.now()}` let adminClient: InstanceType let testDatabaseUrl = '' suite('PostgreSQL migrations', () => { beforeAll(async () => { const adminUrl = new URL(baseDatabaseUrl!) adminUrl.pathname = '/postgres' adminClient = new Client({ connectionString: adminUrl.toString() }) await adminClient.connect() await adminClient.query(`CREATE DATABASE "${databaseName}"`) const testUrl = new URL(baseDatabaseUrl!) testUrl.pathname = `/${databaseName}` testDatabaseUrl = testUrl.toString() }) afterAll(async () => { if (!adminClient) return await adminClient.query(`DROP DATABASE IF EXISTS "${databaseName}"`) await adminClient.end() }) it('applies every migration transactionally and is idempotent', async () => { const migrationsDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'migrations') const firstRun: string[] = [] await runMigrations(testDatabaseUrl, migrationsDir, message => firstRun.push(message)) expect(firstRun.filter(message => message.startsWith('apply '))).toHaveLength(7) const client = new Client({ connectionString: testDatabaseUrl }) await client.connect() const tables = await client.query<{ table_name: string }>(`SELECT table_name FROM information_schema.tables WHERE table_schema = 'osint'`) const tableNames = tables.rows.map(row => row.table_name) expect(tableNames).toEqual(expect.arrayContaining([ 'boards', 'levels', 'level_templates', 'level_template_versions', 'exhibits', 'folder_exhibits', 'document_exhibits', 'folder_memberships', 'exhibit_connections', 'metadata_fields', 'assets', 'schema_migrations', 'party_exhibits', 'person_parties', 'organization_parties', 'brief_concepts', 'level_briefs', ])) expect(tableNames).not.toEqual(expect.arrayContaining(['cases', 'widgets', 'widget_relations', 'playthroughs'])) const ledger = await client.query<{ count: string }>('SELECT COUNT(*)::text AS count FROM osint.schema_migrations') expect(ledger.rows[0].count).toBe('7') await client.end() const secondRun: string[] = [] await runMigrations(testDatabaseUrl, migrationsDir, message => secondRun.push(message)) expect(secondRun.filter(message => message.startsWith('skip '))).toHaveLength(7) expect(secondRun.some(message => message.startsWith('apply '))).toBe(false) }) })