From a12478f24bd668cb31ebafb3efc1016f60dde7e1 Mon Sep 17 00:00:00 2001 From: Julian Tabel Date: Fri, 20 Feb 2026 20:19:17 +0100 Subject: [PATCH] Fix e2e tests for ESM and podman-compose compatibility Replace __dirname with import.meta.url (required by "type": "module"). Replace --wait flag with manual health polling (unsupported by podman-compose). Use explicit -p project name to isolate test containers from dev environment. Co-Authored-By: Claude Opus 4.6 --- frontend/e2e/fixtures.ts | 5 ++++- frontend/e2e/global-setup.ts | 40 +++++++++++++++++++++++---------- frontend/e2e/global-teardown.ts | 7 ++++-- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/frontend/e2e/fixtures.ts b/frontend/e2e/fixtures.ts index e03974b..0c7e5d6 100644 --- a/frontend/e2e/fixtures.ts +++ b/frontend/e2e/fixtures.ts @@ -1,5 +1,8 @@ import { readFileSync } from 'node:fs' -import { resolve } from 'node:path' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' + +const __dirname = dirname(fileURLToPath(import.meta.url)) interface Fixtures { gameId: number diff --git a/frontend/e2e/global-setup.ts b/frontend/e2e/global-setup.ts index 49eb03b..68ee9cd 100644 --- a/frontend/e2e/global-setup.ts +++ b/frontend/e2e/global-setup.ts @@ -1,9 +1,12 @@ import { execSync } from 'node:child_process' import { writeFileSync } from 'node:fs' -import { resolve } from 'node:path' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +const __dirname = dirname(fileURLToPath(import.meta.url)) const API_BASE = 'http://localhost:8000/api/v1' const COMPOSE_FILE = resolve(__dirname, '../../docker-compose.test.yml') +const COMPOSE = `docker compose -p nuzlocke-test -f ${COMPOSE_FILE}` const FIXTURES_PATH = resolve(__dirname, '.fixtures.json') function run(cmd: string): string { @@ -11,6 +14,19 @@ function run(cmd: string): string { return execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'inherit'] }) } +async function waitForApi(url: string, maxAttempts = 30): Promise { + for (let i = 0; i < maxAttempts; i++) { + try { + const res = await fetch(url) + if (res.ok) return + } catch { + // not ready yet + } + await new Promise((r) => setTimeout(r, 2000)) + } + throw new Error(`API at ${url} not ready after ${maxAttempts} attempts`) +} + async function api( path: string, options?: RequestInit, @@ -28,19 +44,19 @@ async function api( export default async function globalSetup() { // 1. Start test DB + API - run(`docker compose -f ${COMPOSE_FILE} up -d --wait`) + run(`${COMPOSE} up -d --build`) - // 2. Run migrations - run( - `docker compose -f ${COMPOSE_FILE} exec -T test-api alembic -c /app/alembic.ini upgrade head`, - ) + // 2. Wait for API to be healthy + console.log('[setup] Waiting for API to be ready...') + await waitForApi('http://localhost:8000/') - // 3. Seed reference data (run from /app/src where the app package lives) - run( - `docker compose -f ${COMPOSE_FILE} exec -T -w /app/src test-api python -m app.seeds`, - ) + // 3. Run migrations + run(`${COMPOSE} exec -T test-api alembic -c /app/alembic.ini upgrade head`) - // 4. Create test fixtures via API + // 4. Seed reference data (run from /app/src where the app package lives) + run(`${COMPOSE} exec -T -w /app/src test-api python -m app.seeds`) + + // 5. Create test fixtures via API const games = await api>('/games') const game = games[0] if (!game) throw new Error('No games found after seeding') @@ -96,7 +112,7 @@ export default async function globalSetup() { }), }) - // 5. Write fixtures file + // 6. Write fixtures file const fixtures = { gameId: game.id, runId: testRun.id, diff --git a/frontend/e2e/global-teardown.ts b/frontend/e2e/global-teardown.ts index 723639d..5742f01 100644 --- a/frontend/e2e/global-teardown.ts +++ b/frontend/e2e/global-teardown.ts @@ -1,13 +1,16 @@ import { execSync } from 'node:child_process' import { rmSync } from 'node:fs' -import { resolve } from 'node:path' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +const __dirname = dirname(fileURLToPath(import.meta.url)) const COMPOSE_FILE = resolve(__dirname, '../../docker-compose.test.yml') +const COMPOSE = `docker compose -p nuzlocke-test -f ${COMPOSE_FILE}` const FIXTURES_PATH = resolve(__dirname, '.fixtures.json') export default async function globalTeardown() { console.log('[teardown] Stopping test containers...') - execSync(`docker compose -f ${COMPOSE_FILE} down -v`, { + execSync(`${COMPOSE} down -v --remove-orphans`, { encoding: 'utf-8', stdio: 'inherit', })