Зачем: 156 зелёных тестов на fakeDatabase не поймали, что ключевые сценарии (создание сотрудника, подтверждение смены, расчёт зарплаты) всегда падают на реальной PostgreSQL. Нужен приёмочный стенд, который проверяет продукт как чёрный ящик: настоящий процесс сервера, настоящая БД, роли как в pilot, но с минимальными привилегиями. - tests/e2e/harness/global-setup.ts: создаёт БД и роли через scripts/test/provision-pg.mjs, применяет миграции ролью krona_migrator (NOSUPERUSER), поднимает `tsx src/server.ts` под krona_staff_app с токенами/VAPID из crypto.randomBytes; три процесса: с токенами, без токенов (как корневой compose.yaml) и отдельный для проверки rate limit; логи серверов пишутся в tests/e2e/evidence/. - *.e2e.ts и отдельный vitest.e2e.config.ts: e2e не попадают в `npm test`, поэтому `npm run check` не требует БД и не краснеет от известных дефектов. - [HARNESS]/[CTRL] — позитивные контроли (версия PG >= 17, атрибуты ролей, app-роль не видит schema_migrations, RBAC, уволенный теряет доступ): если они красные, красные дефектные сценарии ничего не доказывают. - scripts/test/run-e2e.mjs: «храповик» известных дефектов по tests/e2e/known-defects.json (новый красный или исправленный-но-не- вычеркнутый ID = exit 1), таблица e2e-table.md и проверка, что в evidence нет ничего похожего на секреты стенда. Логи названы *.txt, т.к. *.log в .gitignore.
41 lines
1.2 KiB
TypeScript
41 lines
1.2 KiB
TypeScript
import { randomBytes } from 'node:crypto';
|
|
|
|
export interface E2EContext {
|
|
baseUrl: string;
|
|
openBaseUrl: string;
|
|
rateLimitBaseUrl: string;
|
|
managerToken: string;
|
|
terminalToken: string;
|
|
tenantId: string;
|
|
actorId: string;
|
|
terminalActorId: string;
|
|
appDatabaseUrl: string;
|
|
migrationDatabaseUrl: string;
|
|
}
|
|
|
|
declare module 'vitest' {
|
|
export interface ProvidedContext {
|
|
e2e: E2EContext;
|
|
}
|
|
}
|
|
|
|
const crockford = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
|
|
|
/** Случайный ULID (время + crypto.randomBytes), чтобы не зависеть от src/. */
|
|
export function randomUlid(): string {
|
|
let time = Date.now();
|
|
let timePart = '';
|
|
for (let i = 0; i < 10; i += 1) {
|
|
timePart = crockford[time % 32]! + timePart;
|
|
time = Math.floor(time / 32);
|
|
}
|
|
const bytes = randomBytes(16);
|
|
let randomPart = '';
|
|
for (let i = 0; i < 16; i += 1) randomPart += crockford[bytes[i]! % 32]!;
|
|
return timePart + randomPart;
|
|
}
|
|
|
|
/** Синтетическая метка для данных тестов: очевидно не реальные люди/суммы. */
|
|
export function synthetic(label: string): string {
|
|
return `E2E-${label}-${randomBytes(3).toString('hex')}`;
|
|
}
|