Shuffle/e2e/tests/api/krit09-abmeldung.spec.ts
cschlaefke f302c56904 test(auth): add Playwright project with api tests for KTO-01 (GoTrue, Mailpit, db helper)
Refs #38

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

76 lines
3.3 KiB
TypeScript

import { expect, test } from '@playwright/test';
import { env, errorCodes } from '../../support/auth-config';
import { GoTrueClient, randomEmail, randomPassword } from '../../support/gotrue';
import { extractTokenHash, waitForMail } from '../../support/mailpit';
const gotrue = new GoTrueClient();
async function resetSession(email: string) {
await gotrue.recover(email);
const { tokenHash } = extractTokenHash(await waitForMail(email));
const res = await gotrue.verify(tokenHash, 'recovery');
expect(res.status).toBe(200);
return res.body.access_token as string;
}
test.describe('KTO-01 Kriterium 9: Passwort aendern beendet andere Sitzungen (api)', () => {
test('KTO-01 Kriterium 9: nach Reset sind die Refresh-Tokens anderer Sitzungen ungueltig, die Reset-Sitzung bleibt', async () => {
const email = randomEmail();
const oldPassword = randomPassword();
const newPassword = randomPassword();
await gotrue.createConfirmedUser(email, oldPassword);
const a = (await gotrue.signIn(email, oldPassword)).body;
const b = (await gotrue.signIn(email, oldPassword)).body;
expect(a.refresh_token).not.toBe(b.refresh_token);
const recoveryToken = await resetSession(email);
const update = await gotrue.updateUser(recoveryToken, { password: newPassword });
expect(update.status).toBe(200);
for (const [name, session] of [['A', a], ['B', b]] as const) {
const refreshed = await gotrue.refresh(session.refresh_token);
expect(refreshed.status, `Sitzung ${name}`).toBeGreaterThanOrEqual(400);
expect(['refresh_token_not_found', 'session_not_found']).toContain(
refreshed.body.error_code,
);
}
// Neues Passwort gilt, altes nicht.
expect((await gotrue.signIn(email, newPassword)).status).toBe(200);
expect((await gotrue.signIn(email, oldPassword)).body.error_code).toBe(errorCodes.invalidCredentials);
});
test('KTO-01 Kriterium 9 / R8: GoTrue /user lehnt das Access-Token der beendeten Sitzung ab (PostgREST nicht: bis zu 60 min, F1)', async () => {
const email = randomEmail();
const oldPassword = randomPassword();
await gotrue.createConfirmedUser(email, oldPassword);
const a = (await gotrue.signIn(email, oldPassword)).body;
const recoveryToken = await resetSession(email);
await gotrue.updateUser(recoveryToken, { password: randomPassword() });
const user = await gotrue.getUser(a.access_token);
expect([401, 403]).toContain(user.status);
// Dokumentiert das akzeptierte Restrisiko R8 (AUTH-CFG-14): PostgREST prueft keine Sitzungen.
const rest = await fetch(`${env.supabaseUrl}/rest/v1/profiles?select=id`, {
headers: { apikey: env.anonKey, authorization: `Bearer ${a.access_token}` },
});
expect(rest.status).toBe(200);
});
test('KTO-01 Kriterium 9: gleiches Passwort -> 422 same_password, zu kurzes -> 422 weak_password', async () => {
const email = randomEmail();
const password = randomPassword();
await gotrue.createConfirmedUser(email, password);
const token = await resetSession(email);
const same = await gotrue.updateUser(token, { password });
expect(same.status).toBe(422);
expect(same.body.error_code).toBe(errorCodes.samePassword);
const weak = await gotrue.updateUser(token, { password: 'kurz' });
expect(weak.status).toBe(422);
expect(weak.body.error_code).toBe(errorCodes.weakPassword);
});
});