lotr-sut/tests/e2e/support/globalSetup.ts
Fellowship Scholar f6a5823439 init commit
2026-03-29 20:07:56 +00:00

81 lines
2.7 KiB
TypeScript

import { spawnSync } from 'child_process';
import * as fs from 'fs';
import * as http from 'http';
import * as path from 'path';
const ROOT_DIR = path.resolve(__dirname, '../../../');
const MAX_STARTUP_TIME = 180000; // 3 minutes
async function waitForUrl(url: string, timeout: number = MAX_STARTUP_TIME): Promise<void> {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
try {
const httpUrl = new URL(url);
const response = await new Promise<http.IncomingMessage>((resolve, reject) => {
const req = http.get(httpUrl, (res) => {
resolve(res);
});
req.on('error', reject);
req.setTimeout(5000);
});
if (response.statusCode && response.statusCode < 500) {
console.log(`✓ Service ready at ${url}`);
return;
}
} catch (e) {
// Service not ready, continue waiting
}
await new Promise((resolve) => setTimeout(resolve, 2000));
}
throw new Error(`Timeout waiting for service at ${url}`);
}
function runComposeCommand(args: string[]): void {
try {
// Use docker compose (modern Docker CLI syntax)
const result = spawnSync('docker', ['compose', ...args], {
cwd: ROOT_DIR,
stdio: 'inherit',
shell: false
});
if (result.error) {
throw result.error;
}
} catch (e) {
throw new Error(`Failed to run docker compose: ${(e as Error).message}`);
}
}
export default async function globalSetup(): Promise<void> {
console.log('🚀 Starting global test setup...');
// Load environment
const envFile = process.env.ENV_FILE || '.env';
const envPath = path.join(ROOT_DIR, envFile);
if (fs.existsSync(envPath)) {
require('dotenv').config({ path: envPath });
} else {
console.warn(`⚠ ENV file not found at ${envPath}, using defaults`);
}
// Check if we should use real stack or mocks
const useMocks = process.env.FELLOWSHIP_USE_MOCKS?.toLowerCase() === 'true';
if (useMocks) {
console.log('✓ Using mocks for tests (FELLOWSHIP_USE_MOCKS=true)');
return;
}
console.log('🐳 Starting Fellowship SUT stack via docker compose...');
// Start (or restart) containers without recreating — images are rebuilt only when
// Dockerfiles/sources change. Per-test DB state is cleaned up via the
// /api/shop/test-reset endpoint called in each test's beforeEach hook.
runComposeCommand(['up', '-d', '--build']);
console.log('📍 Waiting for services to be ready...');
await waitForUrl('http://localhost/api/health', MAX_STARTUP_TIME);
await waitForUrl('http://localhost/login', MAX_STARTUP_TIME);
await waitForUrl('http://localhost:3000', MAX_STARTUP_TIME);
console.log('✓ All services are ready!');
}