/** * Global setup for E2E tests. * Runs once before all tests. */ import { existsSync, mkdirSync } from 'node:fs' import { join, dirname } from 'node:path' import { fileURLToPath } from 'node:url' import { execSync } from 'node:child_process' const _dirname = dirname(fileURLToPath(import.meta.url)) const projectRoot = join(_dirname, '../../..') const devCertsDir = join(projectRoot, '.dev-certs') const devKey = join(devCertsDir, 'key.pem') const devCert = join(devCertsDir, 'cert.pem') // Import server modules (ES modules) const { getDb } = await import('../../server/utils/db.js') const { hashPassword } = await import('../../server/utils/password.js') const { TEST_ADMIN } = await import('./fixtures/users.js') function ensureDevCerts() { if (existsSync(devKey) && existsSync(devCert)) { return // Certs already exist } // Create .dev-certs directory mkdirSync(devCertsDir, { recursive: true }) // Generate self-signed cert for localhost/127.0.0.1 const SAN = 'subjectAltName=IP:127.0.0.1,DNS:localhost' try { execSync( `openssl req -x509 -newkey rsa:2048 -keyout "${devKey}" -out "${devCert}" -days 365 -nodes -subj "/CN=localhost" -addext "${SAN}"`, { cwd: projectRoot, stdio: 'inherit' }, ) console.log('[test] Generated .dev-certs/key.pem and .dev-certs/cert.pem') } catch (error) { throw new Error(`Failed to generate dev certificates: ${error.message}`) } } async function globalSetup() { ensureDevCerts() let retries = 3 let lastError = null while (retries > 0) { try { const { get, run } = await getDb() const existingUser = await get('SELECT id FROM users WHERE identifier = ?', [TEST_ADMIN.identifier]) if (!existingUser) { const id = crypto.randomUUID() const now = new Date().toISOString() await run( 'INSERT INTO users (id, identifier, password_hash, role, created_at, auth_provider, oidc_issuer, oidc_sub) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [id, TEST_ADMIN.identifier, hashPassword(TEST_ADMIN.password), TEST_ADMIN.role, now, 'local', null, null], ) console.log(`[test] Created test admin user: ${TEST_ADMIN.identifier}`) } else { console.log(`[test] Test admin user already exists: ${TEST_ADMIN.identifier}`) } return } catch (error) { lastError = error if (error.message?.includes('SQLITE_BUSY') || error.message?.includes('database is locked')) { retries-- if (retries > 0) { await new Promise(resolve => setTimeout(resolve, 100 * (4 - retries))) continue } } throw error } } throw lastError } export default globalSetup