- 11 tests couvrant le login (3) et la visibilite sidebar par RBAC (8) - 6 personas seedes via la commande app:seed-e2e, miroir cote front dans frontend/tests/e2e/_fixtures/personas.ts - Page Objects (LoginPage, SidebarComponent) avec selecteurs stables par href + loginAs programmatique via cookie BEARER - Targets Makefile : seed-e2e, test-e2e, test-e2e-ui, install-e2e-deps - CLAUDE.md + README.md : workflow E2E + regle d'or "un E2E par bug prod uniquement" pour garder la suite maintenable dans la duree Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
83 lines
3.3 KiB
TypeScript
83 lines
3.3 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
|
import { loginAs } from '../helpers/loginAs'
|
|
import { SidebarComponent } from '../helpers/pages/SidebarComponent'
|
|
import { ALL_ADMIN_LINKS, type PersonaKey, getPersona, personas } from '../_fixtures/personas'
|
|
|
|
/**
|
|
* Test strategique : la matrice persona <-> liens admin visibles.
|
|
*
|
|
* Valide que `SidebarProvider` (back) + `useSidebar` (front) filtrent bien
|
|
* les items admin selon les permissions RBAC de chaque user.
|
|
*
|
|
* Regle d'evolution : ajouter une permission ou un persona = 1 ligne a
|
|
* modifier dans `personas.ts` et cote back (`SeedE2ECommand`) + `sidebar.php`.
|
|
* Ce fichier ne bouge pas.
|
|
*/
|
|
test.describe('Sidebar visibility', () => {
|
|
const personaKeys: PersonaKey[] = [
|
|
'super-admin',
|
|
'user-full',
|
|
'user-readonly',
|
|
'user-users-only',
|
|
'user-audit-only',
|
|
'user-nothing',
|
|
]
|
|
|
|
for (const key of personaKeys) {
|
|
const persona = getPersona(key)
|
|
|
|
test(`${persona.key} ne voit que ses liens admin autorises`, async ({ page, context }) => {
|
|
await loginAs(context, persona.key)
|
|
await page.goto('/')
|
|
|
|
// Attendre que la sidebar soit chargee (le middleware auth fetch /api/sidebar
|
|
// apres login). Les liens presents apparaissent alors ; les absents ne
|
|
// seront jamais attaches au DOM.
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
const sidebar = new SidebarComponent(page)
|
|
|
|
for (const link of ALL_ADMIN_LINKS) {
|
|
const locator = sidebar.adminLink(link)
|
|
const shouldBeVisible = persona.expectedAdminLinks.includes(link)
|
|
|
|
if (shouldBeVisible) {
|
|
await expect(
|
|
locator,
|
|
`${persona.key} doit voir le lien /admin/${link}`,
|
|
).toBeVisible()
|
|
} else {
|
|
await expect(
|
|
locator,
|
|
`${persona.key} ne doit PAS voir le lien /admin/${link}`,
|
|
).toHaveCount(0)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
test('user-nothing voit toujours le dashboard et le logout (section Mon compte sans permission)', async ({
|
|
page,
|
|
context,
|
|
}) => {
|
|
// La section "Mon compte" n'est gardee par aucune permission : tout user
|
|
// authentifie voit le dashboard et peut se deconnecter. Ce test protege
|
|
// contre une regression qui mettrait un gate RBAC par inadvertance
|
|
// dessus — ca bloquerait le logout de users sans permissions.
|
|
await loginAs(context, 'user-nothing')
|
|
await page.goto('/')
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
const sidebar = new SidebarComponent(page)
|
|
await expect(sidebar.accountDashboardLink()).toBeVisible()
|
|
await expect(sidebar.logoutLink()).toBeVisible()
|
|
})
|
|
|
|
test('la liste des personas dans personas.ts couvre toutes les combinaisons admin attendues', () => {
|
|
// Test meta : si quelqu'un ajoute un persona dans personas.ts sans le
|
|
// seeder cote back (SeedE2ECommand), le test sidebar pour ce persona
|
|
// echouera (loginAs 401). Ce test rappelle la coherence attendue.
|
|
expect(Object.keys(personas)).toEqual(personaKeys)
|
|
})
|
|
})
|