import { expect, test } from '@playwright/test'; const groupes = [ { id: 'groupe-alpha', nom: 'Groupe Alpha', district: '87-16', adresse_local: '123 rue Principale, Saint-Bruno', jour_reunion: 'mardi', heure_reunion: '19:30', assemblee_affaires_ordre: 'premiere', format_reunion: 'Discussion ouverte', }, { id: 'groupe-demo', nom: 'Groupe Démonstration', district: '87-16', adresse_local: 'Salle de démonstration', jour_reunion: 'samedi', heure_reunion: '20:00', assemblee_affaires_ordre: 'derniere', format_reunion: 'Formation', }, ]; async function mockPublicApi(page) { await page.route('**/api/auth/groupes', async (route) => { await route.fulfill({ json: groupes }); }); } async function mockSysadminApi(page) { await page.route('**/api/admin/sysadmin-login', async (route) => { const body = route.request().postDataJSON(); if (body.pin !== '0000') { await route.fulfill({ status: 401, json: { detail: 'PIN Sysadmin invalide' } }); return; } await route.fulfill({ json: { access_token: 'instance-admin-token', token_type: 'bearer', sysadmin_instance: true, membre: { id: 'admin-id', prenom: 'Sysadmin', courriel: 'sysadmin', groupe_id: null, date_abstinence: null, is_sysadmin: true, }, }, }); }); await page.route('**/api/admin/groupes', async (route) => { await route.fulfill({ json: groupes.map((groupe, index) => ({ ...groupe, lien_aa87: 'https://aa87.org', tenant_schema: `grp_${index}`, cree_le: '2026-01-01T00:00:00Z', membres: index === 0 ? 12 : 14, reunions: index === 0 ? 52 : 52, traces: index === 0 ? 120 : 180, demo: groupe.nom === 'Groupe Démonstration', protege: groupe.nom === 'Groupe Démonstration', })), }); }); await page.route('**/api/admin/sysadmin-pin', async (route) => { const body = route.request().postDataJSON(); if (body.pin_actuel !== '0000') { await route.fulfill({ status: 401, json: { detail: 'PIN actuel invalide' } }); return; } await route.fulfill({ json: { message: 'PIN sysadmin mis à jour' } }); }); } test.beforeEach(async ({ page }) => { await page.addInitScript(() => { localStorage.clear(); sessionStorage.clear(); }); await mockPublicApi(page); }); test('la page publique liste les groupes en tuiles fermées et expose les liens publics', async ({ page }) => { await page.goto('/'); await expect(page.getByRole('heading', { name: 'Choisir un groupe' })).toBeVisible(); await expect(page.getByRole('button', { name: /Groupe Alpha/ })).toBeVisible(); await expect(page.getByText('123 rue Principale')).toBeHidden(); await expect(page.getByRole('button', { name: 'Sysadmin' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Charte' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Confidentialité' })).toBeVisible(); await expect(page.getByRole('link', { name: 'Découvrir' })).toBeVisible(); await page.getByRole('button', { name: /Groupe Alpha/ }).click(); await expect(page.getByText('123 rue Principale')).toBeVisible(); await expect(page.getByPlaceholder('Adresse courriel ou identifiant')).toBeVisible(); await expect(page.getByPlaceholder('PIN')).toHaveAttribute('type', 'password'); }); test('les pages publiques Charte et Confidentialité restent accessibles sans connexion', async ({ page }) => { await page.goto('/'); await page.getByRole('button', { name: 'Charte' }).click(); await expect(page.getByRole('heading', { name: /Charte|Principes/ })).toBeVisible(); await page.goto('/'); await page.getByRole('button', { name: 'Confidentialité' }).click(); await expect(page.getByRole('heading', { name: /Confidentialité/ })).toBeVisible(); }); test('le sysadmin d’instance ouvre la gestion des groupes sans contexte de groupe', async ({ page }) => { await mockSysadminApi(page); await page.goto('/'); await page.getByRole('button', { name: 'Sysadmin' }).click(); await page.getByPlaceholder('PIN sysadmin').fill('0000'); await page.getByRole('button', { name: 'Ouvrir' }).click(); await expect(page.getByRole('heading', { name: 'Gestion des groupes' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Créer un groupe' })).toBeVisible(); await expect(page.getByRole('button', { name: /Groupe Alpha/ })).toBeVisible(); await expect(page.getByRole('button', { name: /Groupe Démonstration/ })).toBeVisible(); await expect(page.getByText('Instance · Bonjour Sysadmin')).toBeVisible(); await expect(page.getByText(/Groupe Alpha · Bonjour Sysadmin/)).not.toBeVisible(); }); test('le changement de PIN sysadmin masque les saisies et exige une confirmation', async ({ page }) => { await mockSysadminApi(page); await page.goto('/'); await page.getByRole('button', { name: 'Sysadmin' }).click(); await page.getByPlaceholder('PIN sysadmin').fill('0000'); await page.getByRole('button', { name: 'Ouvrir' }).click(); await page.getByRole('button', { name: 'Changer le PIN sysadmin' }).click(); await expect(page.getByPlaceholder('PIN actuel')).toHaveAttribute('type', 'password'); await expect(page.getByPlaceholder('Nouveau PIN', { exact: true })).toHaveAttribute('type', 'password'); await expect(page.getByPlaceholder('Confirmer le nouveau PIN')).toHaveAttribute('type', 'password'); await page.getByPlaceholder('PIN actuel').fill('0000'); await page.getByPlaceholder('Nouveau PIN', { exact: true }).fill('1234'); await page.getByPlaceholder('Confirmer le nouveau PIN').fill('4321'); await page.getByRole('button', { name: 'Enregistrer' }).click(); await expect(page.getByText('La confirmation ne correspond pas')).toBeVisible(); await page.getByPlaceholder('Confirmer le nouveau PIN').fill('1234'); await page.getByRole('button', { name: 'Enregistrer' }).click(); await expect(page.getByText('PIN sysadmin mis à jour')).toBeVisible(); });