81 lines
2.7 KiB
TypeScript
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!');
|
|
}
|