Shuffle/e2e/tests/web/krit09-abmeldung.spec.ts
cschlaefke d390b60bd6 test(auth): add web E2E tests for KTO-01 criteria 1-10 against the Flutter web build
Refs #38

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

61 lines
2.9 KiB
TypeScript

import { expect, test } from '@playwright/test';
import { GoTrueClient, randomEmail, randomPassword } from '../../support/gotrue';
import { extractTokenHash, waitForMail } from '../../support/mailpit';
import { enableSemantics, expectSignedIn, expectSignedInViaLoginRedirect, login, readAuthStorage, shiftBrowserClock } from '../../support/web';
const gotrue = new GoTrueClient();
test.describe('KTO-01 Kriterium 9 (web): Passwort-Reset beendet andere Sitzungen', () => {
test('KTO-01 Kriterium 9: zweiter Browser-Kontext ist nach dem Reset und dem naechsten (erzwungenen) Refresh abgemeldet', async ({
page,
browser,
}) => {
const email = randomEmail();
const oldPassword = randomPassword();
await gotrue.createConfirmedUser(email, oldPassword);
// Sitzung B: ein zweites Geraet in eigenem Kontext.
await login(page, email, oldPassword);
await expectSignedIn(page);
// Reset ueber Sitzung A (API): neues Passwort setzen beendet alle anderen Sitzungen.
await gotrue.recover(email);
const { tokenHash } = extractTokenHash(await waitForMail(email));
const recovery = await gotrue.verify(tokenHash, 'recovery');
const update = await gotrue.updateUser(recovery.body.access_token, { password: randomPassword() });
expect(update.status).toBe(200);
// Der Access-Token laeuft erst nach jwt_expiry (AUTH-CFG-14, bis 60 min, F1) ab: Der Test
// erzwingt den Refresh, indem er die Browser-Uhr um 2 h vorstellt.
await shiftBrowserClock(page, 2 * 60 * 60 * 1000);
await page.reload();
await enableSemantics(page);
// Der Refresh scheitert (refresh_token_not_found): supabase_flutter loescht die Sitzung.
await expect.poll(async () => Object.keys(await readAuthStorage(page)), { timeout: 15_000 }).toEqual([]);
// Abgemeldet: /login leitet nicht mehr auf die Startseite (Gegenprobe zu Krit. 5).
await page.goto('/login');
await enableSemantics(page);
await page.waitForTimeout(1_000);
await expect(page).toHaveURL(/\/login$/);
await expect(page.getByRole('button', { name: 'Sign in', exact: true })).toBeVisible();
});
test('KTO-01 Kriterium 9: Gegenprobe ohne Reset und mit abgelaufenem Access-Token bleibt die Sitzung bestehen (Refresh klappt)', async ({
page,
}) => {
const email = randomEmail();
const password = randomPassword();
await gotrue.createConfirmedUser(email, password);
await login(page, email, password);
await expectSignedIn(page);
await shiftBrowserClock(page, 2 * 60 * 60 * 1000);
const before = JSON.parse(Object.values(await readAuthStorage(page))[0]).access_token;
await page.reload();
await expectSignedInViaLoginRedirect(page);
// Der Refresh lief wirklich: neues Access-Token im Storage.
await expect
.poll(async () => JSON.parse(Object.values(await readAuthStorage(page))[0] ?? '{}').access_token)
.not.toBe(before);
});
});