import { expect, test } from '@playwright/test'; import type { BrowserContext } from '@playwright/test'; import { contextForUser } from './helpers'; const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:5173'; /** * Site-Admin quota override management (issue #58): an override set through the * admin UI takes effect immediately — a user at their `additional_ponds` limit * can create one more shared pond once the override is raised above their * current usage. Written to be independent of pre-existing state. */ async function userId(ctx: BrowserContext): Promise { return ((await (await ctx.request.get('/api/v1/auth/me')).json()) as { id: string }).id; } test('a quota override set in the admin UI takes effect immediately', async ({ browser }) => { const admin = await contextForUser(browser, BASE_URL, 'fixture-admin'); const user = await contextForUser(browser, BASE_URL, 'fixture-editor'); const uid = await userId(user); const override = `/api/v1/admin/quotas/user/${uid}/additional_ponds`; // Baseline: no override → the default (0) applies, so the user is at/over // limit and cannot create another shared pond. await admin.request.delete(override); const owned = ( (await (await admin.request.get(`/api/v1/admin/quotas/user/${uid}`)).json()) as { lines: { key: string; usage: number | null }[]; } ).lines.find((l) => l.key === 'additional_ponds')!.usage!; const before = await user.request.post('/api/v1/ponds', { data: { name: `Q ${Date.now()}` } }); expect(before.status()).toBe(403); const page = await admin.newPage(); await page.goto('/admin'); await page.locator('.quota-manager__type').selectOption('user'); await page.locator('.quota-manager__query').fill('fixture-editor'); await page.getByRole('button', { name: /find|suchen/i }).click(); const row = page.locator('.quota-row[data-key="additional_ponds"]'); await expect(row).toBeVisible(); await row.locator('.quota-row__input').fill(String(owned + 1)); // room for exactly one more await row.getByRole('button', { name: /^(set|setzen)$/i }).click(); await expect(row.locator('.quota-row__effective')).toHaveText(String(owned + 1)); try { const after = await user.request.post('/api/v1/ponds', { data: { name: `Q ${Date.now()}` } }); expect(after.status()).toBe(201); const pond = (await after.json()) as { id: string }; await user.request.delete(`/api/v1/ponds/${pond.id}`); } finally { await admin.request.delete(override); // repeatable await admin.close(); await user.close(); } });