Files
fitcrm/e2e/global-setup.ts
root accfa61e08
Some checks failed
CI / Lint & Format (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Build All Apps (push) Has been cancelled
CI / E2E Tests (Playwright) (push) Has been cancelled
CI / Deploy to Production (push) Has been cancelled
fix: E2E тесты — 143/143 passed, 0 failed
- Global setup: единый логин всех пользователей перед тестами (без rate limit)
- Playwright проекты: testMatch привязка файлов к проектам (убрал 5x дублирование)
- LP порт: 3004 → 3050 (реальный порт из ecosystem.config)
- Theme тесты: мок API через page.route() (предотвращение 401→logout)
- Web UI тесты: защита response?.status() ?? 200 от undefined
- getCachedTokens(): чтение токенов из файла вместо loginAs в каждом beforeAll

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:40:39 +00:00

70 lines
2.3 KiB
TypeScript

import { request } from '@playwright/test';
import { writeFileSync } from 'fs';
import { join } from 'path';
const API_URL = process.env.E2E_API_URL || 'http://localhost:3000';
const TEST_USERS = {
trainer: { phone: '+70000000010', password: 'trainer123' },
coordinator: { phone: '+70000000003', password: 'admin123' },
manager: { phone: '+70000000003', password: 'admin123' },
receptionist: { phone: '+70000000004', password: 'admin123' },
clubAdmin: { phone: '+70000000002', password: 'admin123' },
superAdmin: { phone: '+70000000001', password: 'admin123' },
};
async function loginWithRetry(
ctx: Awaited<ReturnType<typeof request.newContext>>,
phone: string,
password: string,
): Promise<{ accessToken: string; refreshToken: string }> {
for (let attempt = 0; attempt < 8; attempt++) {
const response = await ctx.post(`${API_URL}/v1/auth/login`, {
data: { phone, password },
});
if (response.status() === 429) {
const delay = (attempt + 1) * 12_000;
await new Promise((r) => setTimeout(r, delay));
continue;
}
if (!response.ok()) {
throw new Error(`Login failed for ${phone}: ${response.status()}`);
}
const body = await response.json();
return { accessToken: body.accessToken, refreshToken: body.refreshToken };
}
throw new Error(`Login rate limited after 8 retries for ${phone}`);
}
export default async function globalSetup() {
const ctx = await request.newContext();
// Login all unique users (coordinator and manager share same credentials)
const uniqueLogins = [
{ key: 'superAdmin', ...TEST_USERS.superAdmin },
{ key: 'clubAdmin', ...TEST_USERS.clubAdmin },
{ key: 'coordinator', ...TEST_USERS.coordinator },
{ key: 'receptionist', ...TEST_USERS.receptionist },
{ key: 'trainer', ...TEST_USERS.trainer },
];
const tokens: Record<string, { accessToken: string; refreshToken: string }> = {};
for (const user of uniqueLogins) {
tokens[user.key] = await loginWithRetry(ctx, user.phone, user.password);
}
// manager shares tokens with coordinator
tokens.manager = tokens.coordinator;
// Save to file for test consumption
const tokenPath = join(__dirname, '.auth-tokens.json');
writeFileSync(tokenPath, JSON.stringify(tokens, null, 2));
await ctx.dispose();
}