import { es } from '@impuestos/i18n'; import { expect, test, type Page } from '@playwright/test'; import { readAuditActions } from './db'; async function signIn(page: Page, email: string, password: string): Promise { await page.goto('/es/login'); await page.getByLabel(es['auth.register.email']).fill(email); await page.getByLabel(es['auth.login.password']).fill(password); await page.getByRole('button', { name: es['auth.login.submit'] }).click(); // Staff accounts have no taxpayer profile, so they land on setup rather than the // dashboard. Either way, leaving the login screen is what says the session took. // Generous, because the first visit to a route in a dev server compiles it. await expect(page).not.toHaveURL(/\/login$/, { timeout: 20_000 }); } async function openMaria(page: Page): Promise { await page.goto('/es/usuarios'); await page.getByLabel(es['admin.users.searchLabel']).fill('maria@demo.local'); await page.getByRole('button', { name: es['common.search'] }).click(); await page.getByRole('link', { name: 'maria@demo.local' }).click(); } /** Golden path 5 (SPEC.md section 13): admin lookup, then the audit row it wrote. */ test.describe('admin console', () => { test('staff look a user up and the lookup lands in the audit log', async ({ page }) => { await signIn(page, 'staff@demo.local', 'demo-staff-1'); await page.goto('/es/usuarios'); await expect(page.getByRole('heading', { name: es['admin.users.title'] })).toBeVisible(); // The reminder is on the screen before anyone searches anything. await expect(page.getByText(es['admin.users.auditBanner'])).toBeVisible(); const before = readAuditActions('maria@demo.local').filter( (action) => action === 'admin.user_lookup', ).length; // How many rows one view writes is pinned against the API in admin.test.ts, where it // is exactly one. It cannot be pinned here: React strict mode mounts a client // component twice in development, so the browser asks for the overview twice. await page.getByLabel(es['admin.users.searchLabel']).fill('maria@demo.local'); await page.getByRole('button', { name: es['common.search'] }).click(); const row = page.getByRole('link', { name: 'maria@demo.local' }); await expect(row).toBeVisible(); await row.click(); await expect(page.getByRole('heading', { name: 'Maria Gonzalez' })).toBeVisible(); await expect(page.getByText(es['admin.users.counts.documents'])).toBeVisible(); await expect(async () => { const after = readAuditActions('maria@demo.local').filter( (action) => action === 'admin.user_lookup', ).length; expect(after).toBeGreaterThan(before); }).toPass({ timeout: 10_000 }); // And the row is visible on the audit screen, which is where staff would look. await page.goto('/es/auditoria'); await page.getByLabel(es['admin.audit.filterAction']).fill('admin.user_lookup'); await page.getByRole('button', { name: es['admin.audit.apply'] }).click(); await expect(page.locator('tbody tr').first()).toContainText('staff@demo.local'); await expect(page.locator('tbody tr').first()).toContainText('maria@demo.local'); }); test('the error queue shows both sources and expands a row', async ({ page }) => { await signIn(page, 'staff@demo.local', 'demo-staff-1'); await page.goto('/es/errores'); await expect(page.getByRole('heading', { name: es['admin.errors.title'] })).toBeVisible(); const rows = page.locator('tbody tr'); await expect(rows.first()).toBeVisible(); // Expanding a row shows what the failure captured, rather than a stack trace. await rows.first().getByRole('button').click(); await expect(page.locator('pre').first()).toBeVisible(); }); test('a plain user cannot reach the console', async ({ page }) => { await signIn(page, 'maria@demo.local', 'demo-maria-1'); for (const path of ['/es/usuarios', '/es/errores', '/es/auditoria']) { await page.goto(path); await expect(page.getByText(es['admin.forbidden'])).toBeVisible(); } }); test('staff are not offered role management', async ({ page }) => { await signIn(page, 'staff@demo.local', 'demo-staff-1'); await openMaria(page); await expect(page.getByRole('heading', { name: 'Maria Gonzalez' })).toBeVisible(); await expect(page.getByRole('button', { name: es['admin.role.change'] })).toHaveCount(0); }); test('a superadmin is offered role management', async ({ page }) => { await signIn(page, 'superadmin@demo.local', 'demo-superadmin-1'); await openMaria(page); await expect(page.getByRole('button', { name: es['admin.role.change'] })).toBeVisible(); }); });