veza/tests/e2e/global-setup.ts
senke 4a6a6293e3 fix(e2e): hard-fail global-setup when rate limiting detected
Previously the rate-limit probe emitted a warning box when it
detected active rate limiting (implying the backend was started
without DISABLE_RATE_LIMIT_FOR_TESTS=true) but let the test run
proceed. The flaky 401s on 02-navigation.spec.ts:77 (and sibling
specs using loginViaAPI in beforeEach) all trace to this silent
failure mode — seed users get progressively locked out as each
spec fires rapid login attempts against the real rate limiter.

Replace console.error(box) with throw new Error(), pointing the
developer at `make dev-e2e`. Preserves fast-iteration when the
setup is correct — only blocks misconfigured runs.

Root cause trace:
- tests/e2e/playwright.config.ts:139 uses reuseExistingServer=true,
  so env vars declared in webServer.env (DISABLE_RATE_LIMIT_FOR_TESTS,
  APP_ENV=test, RATE_LIMIT_LIMIT=10000, ACCOUNT_LOCKOUT_EXEMPT_EMAILS)
  are IGNORED if a non-test-mode backend already owns port 18080.
- Previous global-setup warn path emitted a console box but kept
  running — lockout appeared later, looking like a random flake.

Refactored the try/catch: probe stays wrapped (API-down still OK),
got429 sentinel lifted outside so the throw isn't swallowed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 19:15:39 +02:00

88 lines
3.4 KiB
TypeScript

import { request } from '@playwright/test';
import { CONFIG } from './helpers';
/**
* Global Setup — Crée les comptes de test et vérifie la santé des services.
* S'exécute une seule fois avant toute la suite.
*
* NOTE: globalSetup exporte une fonction async, pas des appels à test().
*/
export default async function globalSetup() {
const ctx = await request.newContext({ baseURL: CONFIG.baseURL });
// ── Créer les comptes de test ──────────────────────────────────
const users = [CONFIG.users.listener, CONFIG.users.creator, CONFIG.users.admin];
for (const user of users) {
try {
const response = await ctx.post('/api/v1/auth/register', {
data: {
email: user.email,
password: user.password,
username: user.username,
password_confirmation: user.password,
},
});
if (response.ok()) {
console.log(` ✓ Compte créé: ${user.email}`);
} else if (response.status() === 409 || response.status() === 422) {
console.log(` ⊘ Compte existant: ${user.email}`);
} else {
const body = await response.text().catch(() => '');
console.warn(` ⚠ Échec création ${user.email}: ${response.status()} ${body.slice(0, 120)}`);
}
} catch (e) {
console.warn(` ⚠ API indisponible pour ${user.email}: ${e}`);
}
}
// ── Vérification santé des services ────────────────────────────
try {
const health = await ctx.get('/api/v1/health');
console.log(` Backend API: ${health.ok() ? '✓ OK' : '✗ DOWN'} (${health.status()})`);
} catch {
console.error(' ✗ Backend API inaccessible');
}
// ── Vérification que le rate limiting est désactivé ────────────
// Le backend doit être démarré avec APP_ENV=test ou DISABLE_RATE_LIMIT_FOR_TESTS=true
// Utiliser `make dev-e2e` pour démarrer correctement.
//
// Historique : avant 2026-04-23, ce bloc se contentait d'un console.error
// encadré quand la probe détectait un 429. Les tests continuaient quand
// même, ce qui masquait un lockout progressif des seed users sur
// loginViaAPI (ex. 02-navigation.spec.ts:77 flake). Maintenant on
// hard-fail : si le backend n'est pas en mode test, on abort tout de suite.
let rateLimitActive = false;
try {
for (let i = 0; i < 10; i++) {
const r = await ctx.post('/api/v1/auth/login', {
data: { email: 'rate-limit-probe@test.invalid', password: 'x' },
});
if (r.status() === 429) { rateLimitActive = true; break; }
}
} catch {
// Probe failure (API down, network) : on laisse filer, le health check
// ci-dessus aura déjà signalé le problème.
}
if (rateLimitActive) {
throw new Error(
'E2E aborted: rate limiting is ACTIVE on the backend. ' +
'Stop the current backend and restart with `make dev-e2e` ' +
'(sets APP_ENV=test + DISABLE_RATE_LIMIT_FOR_TESTS=true). ' +
'Full env set : tests/e2e/playwright.config.ts webServer.env.',
);
}
console.log(' Rate limiting: ✓ disabled (test mode)');
try {
const health = await ctx.get(`${CONFIG.streamURL}/health`);
console.log(` Stream Server: ${health.ok() ? '✓ OK' : '✗ DOWN'} (${health.status()})`);
} catch {
console.error(' ✗ Stream Server inaccessible (non bloquant)');
}
await ctx.dispose();
}