Backend :
- AuditLogWriter::stripSensitive rendu reellement recursif (matche doc).
- Tests GET /api/permissions/{id} non-admin pour chaque branche OR (gap Codex).
- Gardes non-regression UserRbacProcessor : PATCH /rbac sans clef sites ne
doit ni auto-selectionner currentSite ni exiger sites.manage.
Frontend :
- useAuditLog : renomme export trompeur fetchLogs -> fetchLogsCached, le
nom reflete desormais le comportement (cache pollue sinon).
- RoleDrawer / UserRbacDrawer : catch explicite + message d'erreur +
bouton save disabled si le chargement des referentiels a echoue (evite
un ecrasement silencieux des droits).
- AuditTimeline / AuditLogDetail : `oui`/`non` passent par common.yes/no.
- AuditTimeline : Intl.RelativeTimeFormat et toLocaleString suivent la
locale i18n courante (plus de hardcode 'fr').
E2E :
- sidebar-visibility.spec : remplace waitForLoadState('networkidle')
fragile par attente semantique sur accountDashboardLink (stable en CI).
Tests : 237/237 green, eslint clean, php-cs-fixer clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
85 lines
3.5 KiB
TypeScript
85 lines
3.5 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('/')
|
|
|
|
const sidebar = new SidebarComponent(page)
|
|
|
|
// Attente semantique : on ancre sur un lien toujours present pour
|
|
// tout user authentifie (Mon compte > Tableau de bord). Remplace
|
|
// `networkidle` qui est reconnu instable en CI (SPAs avec polling
|
|
// ou HMR peuvent ne jamais quitter cet etat).
|
|
await expect(sidebar.accountDashboardLink()).toBeVisible({ timeout: 10000 })
|
|
|
|
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('/')
|
|
|
|
const sidebar = new SidebarComponent(page)
|
|
// Meme strategie que ci-dessus : ancrage semantique plutot que
|
|
// `networkidle` pour eviter les faux timeouts en CI.
|
|
await expect(sidebar.accountDashboardLink()).toBeVisible({ timeout: 10000 })
|
|
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)
|
|
})
|
|
})
|