feat: přidání testů – Jest unit testy + Playwright E2E + CI pipeline
Server: - Jest unit testy (88 testů): auth, utils, restaurants, service, voting, pizza - in-memory storage mock pro izolaci testů - oprava race condition při inicializaci Redis (storageReady promise) - dev route dostupná i pro NODE_ENV=test - getStatsMock deterministický (nahrazení Math.random) - exporty interních helperů pro testovatelnost - /api/health endpoint pro Playwright readiness check - tsconfig vylučuje test soubory z produkčního buildu E2E (e2e/): - Playwright s Firefoxem + Chromiem - testy: login, menu, výběr jídla, pizza day životní cyklus, QR/nastavení - trusted-header auth bypass pro testy, video + trace při selhání CI (Woodpecker): - pipeline spouštěna na všech větvích a PR (nejen master) - redis-stack-server service pro E2E – čistý Redis per větev automaticky - kroky: unit testy, build, E2E testy (parallel kde možné) - Docker build zůstává pouze pro master Co-Authored-By: Claude Opus (extra usage) 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
// Tento test záměrně NEPOUŽÍVÁ trusted-header – testuje reálný login formulář.
|
||||
test.use({ extraHTTPHeaders: {} });
|
||||
|
||||
test('uživatel se přihlásí formulářem a uvidí obsah aplikace', async ({ page }) => {
|
||||
// Server běží s HTTP_REMOTE_USER_ENABLED=true, takže POST /api/login vždy vyžaduje
|
||||
// hlavičku remote-user. Zachytíme požadavky z formuláře (mají tělo s polem login)
|
||||
// a přidáme hlavičku; požadavek auto-loginu (bez těla) projde bez hlavičky a selže,
|
||||
// čímž formulář zůstane viditelný.
|
||||
await page.route('**/api/login', async (route) => {
|
||||
const body = route.request().postData();
|
||||
let login: string | undefined;
|
||||
try { login = body ? JSON.parse(body)?.login : undefined; } catch {}
|
||||
await route.continue({
|
||||
headers: login
|
||||
? { ...route.request().headers(), 'remote-user': login }
|
||||
: route.request().headers(),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
// Formulář musí být viditelný – auto-login selhal (nepřišla hlavička)
|
||||
const loginInput = page.locator('#login-input');
|
||||
await expect(loginInput).toBeVisible({ timeout: 10_000 });
|
||||
|
||||
// Vyplnění loginu a odeslání Enterem
|
||||
await loginInput.fill('testuser');
|
||||
await loginInput.press('Enter');
|
||||
|
||||
// Po přihlášení musí zmizet login formulář
|
||||
await expect(loginInput).not.toBeVisible({ timeout: 10_000 });
|
||||
|
||||
// JWT musí být uloženo v localStorage jako 3-dílný token
|
||||
const token = await page.evaluate(() => localStorage.getItem('token'));
|
||||
expect(token).toBeTruthy();
|
||||
expect((token as string).split('.')).toHaveLength(3);
|
||||
});
|
||||
|
||||
test('trusted-header přihlášení proběhne automaticky bez formuláře', async ({ page, context }) => {
|
||||
// Obnoví trusted header (přepíše prázdný extraHTTPHeaders z test.use výše)
|
||||
await context.setExtraHTTPHeaders({ 'remote-user': 'e2e-auto-user' });
|
||||
await page.goto('/');
|
||||
|
||||
// Login formulář by se neměl nikdy zobrazit, nebo se ihned schová
|
||||
await page.waitForLoadState('networkidle');
|
||||
const loginInput = page.locator('#login-input');
|
||||
await expect(loginInput).not.toBeVisible({ timeout: 5_000 });
|
||||
});
|
||||
Reference in New Issue
Block a user