Shuffle/e2e/tests/api/config.spec.ts
cschlaefke aa421b12b0
Some checks failed
CI / flutter (pull_request) Successful in 1m15s
CI / web-build (pull_request) Successful in 53s
CI / supabase (pull_request) Successful in 3s
CI / supabase-tests (pull_request) Successful in 30s
CI / e2e (pull_request) Failing after 3m56s
test(auth): address review findings for e2e
Refs #38

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-03 10:55:27 +01:00

84 lines
3.7 KiB
TypeScript

import { expect, test } from '@playwright/test';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { authConfig } from '../../support/auth-config';
const root = resolve(__dirname, '../../..');
const toml = readFileSync(resolve(root, 'supabase/config.toml'), 'utf8');
const doc = readFileSync(resolve(root, 'docs/auth-konfiguration.md'), 'utf8');
/** Aktive (nicht auskommentierte) Zeilen von `config.toml`. */
const active = toml
.split('\n')
.map((l) => l.trim())
.filter((l) => l && !l.startsWith('#'));
function value(key: string, section?: string): string | undefined {
let current = '';
for (const line of active) {
const sec = line.match(/^\[(.+)\]$/);
if (sec) {
current = sec[1];
continue;
}
if (section !== undefined && current !== section) continue;
const kv = line.match(new RegExp(`^${key}\\s*=\\s*(.+)$`));
if (kv) return kv[1].replace(/^"|"$/g, '');
}
return undefined;
}
test.describe('Auth-Konfiguration: auth-config.ts stimmt mit config.toml und Doku ueberein', () => {
test('AUTH-CFG-01: Site-URL', () => {
expect(value('site_url', 'auth')).toBe(authConfig.siteUrl);
});
test('AUTH-CFG-04: E-Mail-Bestaetigung Pflicht', () => {
expect(value('enable_confirmations', 'auth.email')).toBe('true');
});
test('AUTH-CFG-05/-06: Passwort-Mindestlaenge und keine Zeichenklassen', () => {
expect(Number(value('minimum_password_length', 'auth'))).toBe(authConfig.passwordMinLength);
expect(value('password_requirements', 'auth')).toBe('');
});
test('AUTH-CFG-07: Gueltigkeit der Links', () => {
expect(Number(value('otp_expiry', 'auth.email'))).toBe(authConfig.otpExpirySeconds);
});
test('AUTH-CFG-08: Mindestabstand lokal 1 s', () => {
expect(value('max_frequency', 'auth.email')).toBe(`${authConfig.maxFrequencySeconds}s`);
});
test('AUTH-CFG-10: Login-/Token-Refresh-Drosselung (150 je 5 min, Burst 30)', () => {
expect(Number(value('token_refresh', 'auth.rate_limit'))).toBe(150);
expect(authConfig.loginBurst).toBe(30);
});
test('AUTH-CFG-11: Signup/Reset/Resend-Drosselung (30 je 5 min)', () => {
expect(Number(value('sign_in_sign_ups', 'auth.rate_limit'))).toBe(authConfig.otpBurst);
});
test('AUTH-CFG-12: Link-Pruefung (30 je 5 min)', () => {
expect(Number(value('token_verifications', 'auth.rate_limit'))).toBe(30);
});
test('AUTH-CFG-14/-15: JWT-Laufzeit und Refresh-Token-Rotation', () => {
expect(Number(value('jwt_expiry', 'auth'))).toBe(authConfig.jwtExpirySeconds);
expect(value('enable_refresh_token_rotation', 'auth')).toBe('true');
expect(Number(value('refresh_token_reuse_interval', 'auth'))).toBe(authConfig.refreshTokenReuseIntervalSeconds);
});
test('KTO-01 Kriterium 5: AUTH-CFG-16 Sitzungsbegrenzung ist nicht gesetzt (timebox, inactivity_timeout)', () => {
expect(active.some((l) => /^timebox\s*=/.test(l))).toBe(false);
expect(active.some((l) => /^inactivity_timeout\s*=/.test(l))).toBe(false);
expect(active).not.toContain('[auth.sessions]');
});
test('AUTH-CFG-19: alle Benachrichtigungs-Mails aus', () => {
const sections = active.filter((l) => l.startsWith('[auth.email.notification.'));
expect(sections.length).toBeGreaterThan(0);
for (const s of sections) {
expect(value('enabled', s.slice(1, -1)), s).toBe('false');
}
});
test('AUTH-CFG-24: SMS-Autoconfirm aus (enable_confirmations = true), Voraussetzung fuer den Enumerationsschutz', () => {
expect(value('enable_confirmations', 'auth.sms')).toBe('true');
});
test('docs/auth-konfiguration.md fuehrt AUTH-CFG-01 bis -25', () => {
for (let i = 1; i <= 25; i++) {
const id = `AUTH-CFG-${String(i).padStart(2, '0')}`;
expect(doc, id).toContain(`| ${id} |`);
}
});
});