Les tests attendaient 5 sections mais le dashboard en affiche 8 (5 thématiques + 3 placeholders DashboardSection). Le heading sr-only "Actions de configuration" manquait pour l'accessibilité.
589 lines
24 KiB
TypeScript
589 lines
24 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { execSync } from 'child_process';
|
|
import { join, dirname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
// Extract port from PLAYWRIGHT_BASE_URL or use default (4173 matches playwright.config.ts)
|
|
const baseUrl = process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:4173';
|
|
const urlMatch = baseUrl.match(/:(\d+)$/);
|
|
const PORT = urlMatch ? urlMatch[1] : '4173';
|
|
const ALPHA_URL = `http://ecole-alpha.classeo.local:${PORT}`;
|
|
|
|
// Test credentials for authenticated tests
|
|
const ADMIN_EMAIL = 'e2e-dashboard-admin@example.com';
|
|
const ADMIN_PASSWORD = 'DashboardTest123';
|
|
|
|
test.describe('Dashboard', () => {
|
|
/**
|
|
* Navigate to the dashboard and wait for SvelteKit hydration.
|
|
* SSR renders the HTML immediately, but event handlers are only
|
|
* attached after client-side hydration completes.
|
|
*/
|
|
async function goToDashboard(page: import('@playwright/test').Page) {
|
|
await page.goto('/dashboard', { waitUntil: 'networkidle' });
|
|
await expect(page.locator('.demo-controls')).toBeVisible({ timeout: 5000 });
|
|
}
|
|
|
|
/**
|
|
* Switch to a demo role with retry logic to handle hydration timing.
|
|
* Retries the click until the button's active class confirms the switch.
|
|
*/
|
|
async function switchToDemoRole(
|
|
page: import('@playwright/test').Page,
|
|
roleName: string | RegExp
|
|
) {
|
|
const button = page.locator('.demo-controls button', { hasText: roleName });
|
|
await expect(async () => {
|
|
await button.click();
|
|
await expect(button).toHaveClass(/active/, { timeout: 1000 });
|
|
}).toPass({ timeout: 10000 });
|
|
}
|
|
|
|
// ============================================================================
|
|
// Demo Mode (unauthenticated) - Role Switcher
|
|
// ============================================================================
|
|
test.describe('Demo Mode', () => {
|
|
test('shows demo role switcher when not authenticated', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
await expect(page).toHaveURL(/\/dashboard/);
|
|
await expect(page.getByText(/Démo - Changer de rôle/i)).toBeVisible();
|
|
});
|
|
|
|
test('page title is set correctly', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
await expect(page).toHaveTitle(/tableau de bord/i);
|
|
});
|
|
|
|
test('demo role switcher has all 4 role buttons', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
const demoControls = page.locator('.demo-controls');
|
|
await expect(demoControls).toBeVisible();
|
|
|
|
await expect(demoControls.getByRole('button', { name: 'Parent' })).toBeVisible();
|
|
await expect(demoControls.getByRole('button', { name: 'Enseignant' })).toBeVisible();
|
|
await expect(demoControls.getByRole('button', { name: /Élève/i })).toBeVisible();
|
|
await expect(demoControls.getByRole('button', { name: 'Admin' })).toBeVisible();
|
|
});
|
|
|
|
test('Parent role is selected by default', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
const parentButton = page.locator('.demo-controls button', { hasText: 'Parent' });
|
|
await expect(parentButton).toHaveClass(/active/);
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// Parent Dashboard View
|
|
// ============================================================================
|
|
test.describe('Parent Dashboard', () => {
|
|
test('shows Score Serenite card', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Parent is the default demo role
|
|
await expect(page.getByText(/score sérénité/i).first()).toBeVisible();
|
|
});
|
|
|
|
test('shows serenity score with numeric value', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// The score card should display a number value
|
|
const scoreCard = page.locator('.serenity-card');
|
|
await expect(scoreCard).toBeVisible();
|
|
|
|
// Should have a numeric value followed by /100
|
|
await expect(scoreCard.locator('.value')).toBeVisible();
|
|
await expect(scoreCard.getByText('/100')).toBeVisible();
|
|
});
|
|
|
|
test('serenity score shows demo badge', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
await expect(page.getByText(/données de démonstration/i)).toBeVisible();
|
|
});
|
|
|
|
test('shows placeholder sections for schedule, notes, and homework', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// These sections show as placeholders since hasRealData is false
|
|
await expect(page.getByRole('heading', { name: /emploi du temps/i })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: /notes récentes/i })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: /devoirs à venir/i })).toBeVisible();
|
|
});
|
|
|
|
test('placeholder sections show informative messages', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
await expect(page.getByText(/l'emploi du temps sera disponible/i)).toBeVisible();
|
|
await expect(page.getByText(/les notes apparaîtront ici/i)).toBeVisible();
|
|
await expect(page.getByText(/les devoirs seront affichés ici/i)).toBeVisible();
|
|
});
|
|
|
|
test('onboarding banner is visible on first login', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// The onboarding banner should be visible (isFirstLogin=true initially)
|
|
await expect(page.getByText(/bienvenue sur classeo/i)).toBeVisible();
|
|
await expect(page.getByText(/score sérénité/i).first()).toBeVisible();
|
|
});
|
|
|
|
test('clicking serenity score opens explainer', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Click the serenity score card
|
|
const scoreCard = page.locator('.serenity-card');
|
|
await expect(scoreCard).toBeVisible();
|
|
await scoreCard.click();
|
|
|
|
// The explainer modal/overlay should appear
|
|
// SerenityScoreExplainer should be visible after click
|
|
await expect(page.getByText(/cliquez pour en savoir plus/i)).toBeVisible();
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// Teacher Dashboard View
|
|
// ============================================================================
|
|
test.describe('Teacher Dashboard', () => {
|
|
test('shows teacher dashboard header', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Switch to teacher
|
|
await switchToDemoRole(page, 'Enseignant');
|
|
|
|
await expect(page.getByRole('heading', { name: /tableau de bord enseignant/i })).toBeVisible();
|
|
await expect(page.getByText(/bienvenue.*voici vos outils du jour/i)).toBeVisible();
|
|
});
|
|
|
|
test('shows quick action cards', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Enseignant');
|
|
|
|
await expect(page.getByText(/faire l'appel/i)).toBeVisible();
|
|
await expect(page.getByText(/saisir des notes/i)).toBeVisible();
|
|
await expect(page.getByText(/créer un devoir/i)).toBeVisible();
|
|
});
|
|
|
|
test('quick action cards are disabled in demo mode', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Enseignant');
|
|
|
|
// First two action cards should be disabled since hasRealData=false
|
|
// "Créer un devoir" navigates to homework page and is always enabled
|
|
const actionCards = page.locator('.action-card');
|
|
const count = await actionCards.count();
|
|
expect(count).toBeGreaterThanOrEqual(3);
|
|
|
|
await expect(actionCards.nth(0)).toBeDisabled();
|
|
await expect(actionCards.nth(1)).toBeDisabled();
|
|
await expect(actionCards.nth(2)).toBeEnabled();
|
|
});
|
|
|
|
test('shows placeholder sections for teacher data', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Enseignant');
|
|
|
|
await expect(page.getByRole('heading', { name: /mes classes aujourd'hui/i })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: /notes à saisir/i })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: /appels du jour/i })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: /statistiques rapides/i })).toBeVisible();
|
|
});
|
|
|
|
test('placeholder sections have informative messages', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Enseignant');
|
|
|
|
await expect(page.getByText(/vos classes apparaîtront ici/i)).toBeVisible();
|
|
await expect(page.getByText(/évaluations en attente de notation/i)).toBeVisible();
|
|
await expect(page.getByText(/les appels à effectuer/i)).toBeVisible();
|
|
await expect(page.getByText(/les statistiques de vos classes/i)).toBeVisible();
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// Student Dashboard View
|
|
// ============================================================================
|
|
test.describe('Student Dashboard', () => {
|
|
test('shows student dashboard header', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Switch to student
|
|
await switchToDemoRole(page, /Élève/i);
|
|
|
|
await expect(page.getByRole('heading', { name: /mon espace/i })).toBeVisible();
|
|
// Student is minor by default, so "ton" instead of "votre"
|
|
await expect(page.getByText(/bienvenue.*voici ton tableau de bord/i)).toBeVisible();
|
|
});
|
|
|
|
test('shows info banner for student in demo mode', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, /Élève/i);
|
|
|
|
await expect(page.getByText(/ton emploi du temps, tes notes et tes devoirs/i)).toBeVisible();
|
|
});
|
|
|
|
test('shows placeholder sections for student data', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, /Élève/i);
|
|
|
|
await expect(page.getByRole('heading', { name: /mon emploi du temps/i })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: /mes notes/i })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: /mes devoirs/i })).toBeVisible();
|
|
});
|
|
|
|
test('placeholder sections show minor-appropriate messages', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, /Élève/i);
|
|
|
|
// Uses "ton/tes" for minors
|
|
await expect(page.getByText(/ton emploi du temps sera bientôt disponible/i)).toBeVisible();
|
|
await expect(page.getByText(/tes notes apparaîtront ici/i)).toBeVisible();
|
|
await expect(page.getByText(/tes devoirs s'afficheront ici/i)).toBeVisible();
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// Admin Dashboard View
|
|
// ============================================================================
|
|
test.describe('Admin Dashboard', () => {
|
|
test('shows admin dashboard header', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Switch to admin
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
await expect(page.getByRole('heading', { name: /administration/i })).toBeVisible();
|
|
});
|
|
|
|
test('shows establishment name', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
// Demo data uses "École Alpha" as establishment name
|
|
await expect(page.getByText(/école alpha/i)).toBeVisible();
|
|
});
|
|
|
|
test('shows quick action links for admin', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
await expect(page.getByText(/gérer les utilisateurs/i)).toBeVisible();
|
|
await expect(page.getByText(/configurer les classes/i)).toBeVisible();
|
|
await expect(page.getByText(/gérer les matières/i)).toBeVisible();
|
|
await expect(page.getByText(/périodes scolaires/i)).toBeVisible();
|
|
await expect(page.getByText(/pédagogie/i)).toBeVisible();
|
|
});
|
|
|
|
test('admin quick action links have correct hrefs', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
// Verify action cards link to correct pages
|
|
const usersLink = page.locator('.action-card[href="/admin/users"]');
|
|
await expect(usersLink).toBeVisible();
|
|
|
|
const classesLink = page.locator('.action-card[href="/admin/classes"]');
|
|
await expect(classesLink).toBeVisible();
|
|
|
|
const subjectsLink = page.locator('.action-card[href="/admin/subjects"]');
|
|
await expect(subjectsLink).toBeVisible();
|
|
|
|
const periodsLink = page.locator('.action-card[href="/admin/academic-year/periods"]');
|
|
await expect(periodsLink).toBeVisible();
|
|
|
|
const pedagogyLink = page.locator('.action-card[href="/admin/pedagogy"]');
|
|
await expect(pedagogyLink).toBeVisible();
|
|
});
|
|
|
|
test('shows import action cards for students and teachers', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
const studentImport = page.getByRole('link', { name: /importer des élèves/i });
|
|
await expect(studentImport).toBeVisible();
|
|
await expect(studentImport).toHaveAttribute('href', '/admin/import/students');
|
|
|
|
const teacherImport = page.getByRole('link', { name: /importer des enseignants/i });
|
|
await expect(teacherImport).toBeVisible();
|
|
await expect(teacherImport).toHaveAttribute('href', '/admin/import/teachers');
|
|
});
|
|
|
|
test('shows placeholder sections for admin stats', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
await expect(page.getByRole('heading', { name: /utilisateurs/i })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: 'Configuration', exact: true })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: /activité récente/i })).toBeVisible();
|
|
});
|
|
|
|
test('shows section titles grouping action cards', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
await expect(page.getByRole('heading', { name: 'Personnes', exact: true })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: 'Organisation', exact: true })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: 'Année scolaire', exact: true })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: 'Paramètres', exact: true })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: 'Imports', exact: true })).toBeVisible();
|
|
});
|
|
|
|
test('groups correct cards within each section', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
// Personnes: Utilisateurs, Invitations parents, Élèves
|
|
const personnes = page.locator('section[aria-labelledby="section-personnes"]');
|
|
await expect(personnes.locator('.action-card')).toHaveCount(3);
|
|
await expect(personnes.locator('.action-card[href="/admin/users"]')).toBeVisible();
|
|
await expect(personnes.locator('.action-card[href="/admin/parent-invitations"]')).toBeVisible();
|
|
await expect(personnes.locator('.action-card[href="/admin/students"]')).toBeVisible();
|
|
|
|
// Organisation: Classes, Matières, Affectations, Remplacements, Emploi du temps
|
|
const organisation = page.locator('section[aria-labelledby="section-organisation"]');
|
|
await expect(organisation.locator('.action-card')).toHaveCount(5);
|
|
await expect(organisation.locator('.action-card[href="/admin/classes"]')).toBeVisible();
|
|
await expect(organisation.locator('.action-card[href="/admin/subjects"]')).toBeVisible();
|
|
await expect(organisation.locator('.action-card[href="/admin/assignments"]')).toBeVisible();
|
|
await expect(organisation.locator('.action-card[href="/admin/replacements"]')).toBeVisible();
|
|
await expect(organisation.locator('.action-card[href="/admin/schedule"]')).toBeVisible();
|
|
|
|
// Année scolaire: Périodes scolaires, Calendrier
|
|
const anneeScolaire = page.locator('section[aria-labelledby="section-annee-scolaire"]');
|
|
await expect(anneeScolaire.locator('.action-card')).toHaveCount(2);
|
|
await expect(anneeScolaire.locator('.action-card[href="/admin/academic-year/periods"]')).toBeVisible();
|
|
await expect(anneeScolaire.locator('.action-card[href="/admin/calendar"]')).toBeVisible();
|
|
|
|
// Paramètres: Droit à l'image, Pédagogie, Identité visuelle, Règles de devoirs
|
|
const parametres = page.locator('section[aria-labelledby="section-parametres"]');
|
|
await expect(parametres.locator('.action-card')).toHaveCount(4);
|
|
await expect(parametres.locator('.action-card[href="/admin/image-rights"]')).toBeVisible();
|
|
await expect(parametres.locator('.action-card[href="/admin/pedagogy"]')).toBeVisible();
|
|
await expect(parametres.locator('.action-card[href="/admin/branding"]')).toBeVisible();
|
|
await expect(parametres.locator('.action-card[href="/admin/homework-rules"]')).toBeVisible();
|
|
|
|
// Imports: Importer des élèves, Importer des enseignants
|
|
const imports = page.locator('section[aria-labelledby="section-imports"]');
|
|
await expect(imports.locator('.action-card')).toHaveCount(2);
|
|
await expect(imports.locator('.action-card[href="/admin/import/students"]')).toBeVisible();
|
|
await expect(imports.locator('.action-card[href="/admin/import/teachers"]')).toBeVisible();
|
|
});
|
|
|
|
test('sections are displayed in the expected order', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
const sectionTitles = page.locator('.dashboard-section .section-title');
|
|
await expect(sectionTitles).toHaveCount(8);
|
|
await expect(sectionTitles.nth(0)).toHaveText('Personnes');
|
|
await expect(sectionTitles.nth(1)).toHaveText('Organisation');
|
|
await expect(sectionTitles.nth(2)).toHaveText('Année scolaire');
|
|
await expect(sectionTitles.nth(3)).toHaveText('Paramètres');
|
|
await expect(sectionTitles.nth(4)).toHaveText('Imports');
|
|
await expect(sectionTitles.nth(5)).toHaveText('Utilisateurs');
|
|
await expect(sectionTitles.nth(6)).toHaveText('Configuration');
|
|
await expect(sectionTitles.nth(7)).toHaveText('Activité récente');
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// Role Switching
|
|
// ============================================================================
|
|
test.describe('Role Switching', () => {
|
|
test('switching from parent to teacher changes dashboard content', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Verify parent view
|
|
await expect(page.getByText(/score sérénité/i).first()).toBeVisible();
|
|
|
|
// Switch to teacher
|
|
await switchToDemoRole(page, 'Enseignant');
|
|
|
|
// Parent content should be gone
|
|
await expect(page.locator('.serenity-card')).not.toBeVisible();
|
|
|
|
// Teacher content should appear
|
|
await expect(page.getByRole('heading', { name: /tableau de bord enseignant/i })).toBeVisible();
|
|
});
|
|
|
|
test('switching from teacher to student changes dashboard content', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Switch to teacher first
|
|
await switchToDemoRole(page, 'Enseignant');
|
|
await expect(page.getByRole('heading', { name: /tableau de bord enseignant/i })).toBeVisible();
|
|
|
|
// Switch to student
|
|
await switchToDemoRole(page, /Élève/i);
|
|
|
|
// Teacher content should be gone
|
|
await expect(page.getByRole('heading', { name: /tableau de bord enseignant/i })).not.toBeVisible();
|
|
|
|
// Student content should appear
|
|
await expect(page.getByRole('heading', { name: /mon espace/i })).toBeVisible();
|
|
});
|
|
|
|
test('switching from student to admin changes dashboard content', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Switch to student first
|
|
await switchToDemoRole(page, /Élève/i);
|
|
await expect(page.getByRole('heading', { name: /mon espace/i })).toBeVisible();
|
|
|
|
// Switch to admin
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
// Student content should be gone
|
|
await expect(page.getByRole('heading', { name: /mon espace/i })).not.toBeVisible();
|
|
|
|
// Admin content should appear
|
|
await expect(page.getByRole('heading', { name: /administration/i })).toBeVisible();
|
|
});
|
|
|
|
test('active role button changes visual state', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Parent should be active initially
|
|
const parentBtn = page.locator('.demo-controls button', { hasText: 'Parent' });
|
|
await expect(parentBtn).toHaveClass(/active/);
|
|
|
|
// Switch to teacher
|
|
await switchToDemoRole(page, 'Enseignant');
|
|
|
|
// Teacher should now be active, parent should not
|
|
const teacherBtn = page.locator('.demo-controls button', { hasText: 'Enseignant' });
|
|
await expect(teacherBtn).toHaveClass(/active/);
|
|
await expect(parentBtn).not.toHaveClass(/active/);
|
|
});
|
|
|
|
test('onboarding banner disappears after switching roles', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
// Onboarding banner is visible initially (isFirstLogin=true)
|
|
await expect(page.getByText(/bienvenue sur classeo/i)).toBeVisible();
|
|
|
|
// Switch role - this calls switchDemoRole which sets isFirstLogin=false
|
|
await switchToDemoRole(page, 'Enseignant');
|
|
|
|
// Switch back to parent
|
|
await switchToDemoRole(page, 'Parent');
|
|
|
|
// Onboarding banner should no longer be visible
|
|
await expect(page.getByText(/bienvenue sur classeo/i)).not.toBeVisible();
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// Admin Dashboard - Navigation from Quick Actions
|
|
// ============================================================================
|
|
test.describe('Admin Quick Action Navigation', () => {
|
|
test.beforeAll(async () => {
|
|
const projectRoot = join(__dirname, '../..');
|
|
const composeFile = join(projectRoot, 'compose.yaml');
|
|
|
|
execSync(
|
|
`docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-user --tenant=ecole-alpha --email=${ADMIN_EMAIL} --password=${ADMIN_PASSWORD} --role=ROLE_ADMIN 2>&1`,
|
|
{ encoding: 'utf-8' }
|
|
);
|
|
});
|
|
|
|
async function loginAsAdmin(page: import('@playwright/test').Page) {
|
|
await page.goto(`${ALPHA_URL}/login`);
|
|
await page.locator('#email').fill(ADMIN_EMAIL);
|
|
await page.locator('#password').fill(ADMIN_PASSWORD);
|
|
await Promise.all([
|
|
page.waitForURL(/\/dashboard/, { timeout: 30000 }),
|
|
page.getByRole('button', { name: /se connecter/i }).click()
|
|
]);
|
|
}
|
|
|
|
test('clicking "Gerer les utilisateurs" navigates to users page', async ({ page }) => {
|
|
await loginAsAdmin(page);
|
|
|
|
// Admin dashboard should show after login (ROLE_ADMIN maps to admin view)
|
|
await expect(page.getByRole('heading', { name: /administration/i })).toBeVisible({ timeout: 10000 });
|
|
|
|
// Click users link
|
|
await page.locator('.action-card[href="/admin/users"]').click();
|
|
await expect(page).toHaveURL(/\/admin\/users/);
|
|
});
|
|
|
|
test('clicking "Configurer les classes" navigates to classes page', async ({ page }) => {
|
|
await loginAsAdmin(page);
|
|
await expect(page.getByRole('heading', { name: /administration/i })).toBeVisible({ timeout: 10000 });
|
|
|
|
await page.locator('.action-card[href="/admin/classes"]').click();
|
|
await expect(page).toHaveURL(/\/admin\/classes/);
|
|
});
|
|
|
|
test('clicking "Gerer les matieres" navigates to subjects page', async ({ page }) => {
|
|
await loginAsAdmin(page);
|
|
await expect(page.getByRole('heading', { name: /administration/i })).toBeVisible({ timeout: 10000 });
|
|
|
|
await page.locator('.action-card[href="/admin/subjects"]').click();
|
|
await expect(page).toHaveURL(/\/admin\/subjects/);
|
|
});
|
|
|
|
test('clicking "Periodes scolaires" navigates to periods page', async ({ page }) => {
|
|
await loginAsAdmin(page);
|
|
await expect(page.getByRole('heading', { name: /administration/i })).toBeVisible({ timeout: 10000 });
|
|
|
|
await page.locator('.action-card[href="/admin/academic-year/periods"]').click();
|
|
await expect(page).toHaveURL(/\/admin\/academic-year\/periods/);
|
|
});
|
|
|
|
test('clicking "Pedagogie" navigates to pedagogy page', async ({ page }) => {
|
|
await loginAsAdmin(page);
|
|
await expect(page.getByRole('heading', { name: /administration/i })).toBeVisible({ timeout: 10000 });
|
|
|
|
await page.locator('.action-card[href="/admin/pedagogy"]').click();
|
|
await expect(page).toHaveURL(/\/admin\/pedagogy/);
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// Accessibility
|
|
// ============================================================================
|
|
test.describe('Accessibility', () => {
|
|
test('serenity score card has accessible label', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
|
|
const scoreCard = page.locator('[aria-label*="Score Sérénité"]');
|
|
await expect(scoreCard).toBeVisible();
|
|
});
|
|
|
|
test('teacher quick actions have a visually hidden heading', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Enseignant');
|
|
|
|
// The "Actions rapides" heading exists but is sr-only
|
|
const actionsHeading = page.getByRole('heading', { name: /actions rapides/i });
|
|
await expect(actionsHeading).toBeAttached();
|
|
});
|
|
|
|
test('admin configuration actions have a visually hidden heading', async ({ page }) => {
|
|
await goToDashboard(page);
|
|
await switchToDemoRole(page, 'Admin');
|
|
|
|
const configHeading = page.getByRole('heading', { name: /actions de configuration/i });
|
|
await expect(configHeading).toBeAttached();
|
|
});
|
|
});
|
|
});
|
|
|
|
test.describe('Dashboard Components', () => {
|
|
test('demo data JSON is valid and accessible', async ({ page }) => {
|
|
// This tests that the demo data file is bundled correctly
|
|
await page.goto('/');
|
|
|
|
// The app should load without errors
|
|
await expect(page.locator('body')).toBeVisible();
|
|
});
|
|
});
|