Lorsqu'un super-admin crée un établissement via l'interface, le système doit automatiquement créer la base tenant, exécuter les migrations, créer le premier utilisateur admin et envoyer l'invitation — le tout de manière asynchrone pour ne pas bloquer la réponse HTTP. Ce mécanisme rend chaque établissement opérationnel dès sa création sans intervention manuelle sur l'infrastructure.
140 lines
5.2 KiB
TypeScript
140 lines
5.2 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);
|
|
|
|
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}`;
|
|
|
|
const STUDENT_EMAIL = 'e2e-dash-nav-student@example.com';
|
|
const STUDENT_PASSWORD = 'DashNavStudent123';
|
|
|
|
const projectRoot = join(__dirname, '../..');
|
|
const composeFile = join(projectRoot, 'compose.yaml');
|
|
|
|
async function loginAsStudent(page: import('@playwright/test').Page) {
|
|
await page.goto(`${ALPHA_URL}/login`);
|
|
await page.locator('#email').fill(STUDENT_EMAIL);
|
|
await page.locator('#password').fill(STUDENT_PASSWORD);
|
|
await page.getByRole('button', { name: /se connecter/i }).click();
|
|
await page.waitForURL(/\/dashboard/, { timeout: 60000 });
|
|
}
|
|
|
|
test.describe('Dashboard Responsive Navigation', () => {
|
|
test.beforeAll(async () => {
|
|
execSync(
|
|
`docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-user --tenant=ecole-alpha --email=${STUDENT_EMAIL} --password=${STUDENT_PASSWORD} --role=ROLE_ELEVE 2>&1`,
|
|
{ encoding: 'utf-8' }
|
|
);
|
|
});
|
|
|
|
// =========================================================================
|
|
// MOBILE (375x667)
|
|
// =========================================================================
|
|
test.describe('Mobile (375x667)', () => {
|
|
test.use({ viewport: { width: 375, height: 667 } });
|
|
|
|
test('shows hamburger button and hides desktop nav', async ({ page }) => {
|
|
await loginAsStudent(page);
|
|
|
|
const hamburger = page.getByRole('button', { name: /ouvrir le menu/i });
|
|
await expect(hamburger).toBeVisible({ timeout: 10000 });
|
|
|
|
const desktopNav = page.locator('.desktop-nav');
|
|
await expect(desktopNav).not.toBeVisible();
|
|
});
|
|
|
|
test('opens drawer via hamburger and shows nav links', async ({ page }) => {
|
|
await loginAsStudent(page);
|
|
|
|
await page.getByRole('button', { name: /ouvrir le menu/i }).click();
|
|
|
|
const drawer = page.locator('[role="dialog"][aria-modal="true"]');
|
|
await expect(drawer).toBeVisible();
|
|
|
|
// Should show navigation links
|
|
await expect(drawer.getByText('Tableau de bord')).toBeVisible();
|
|
await expect(drawer.getByText('Mon emploi du temps')).toBeVisible();
|
|
await expect(drawer.getByText('Paramètres')).toBeVisible();
|
|
});
|
|
|
|
test('closes drawer via close button', async ({ page }) => {
|
|
await loginAsStudent(page);
|
|
|
|
await page.getByRole('button', { name: /ouvrir le menu/i }).click();
|
|
const drawer = page.locator('[role="dialog"][aria-modal="true"]');
|
|
await expect(drawer).toBeVisible();
|
|
|
|
await page.getByRole('button', { name: /fermer le menu/i }).click();
|
|
await expect(drawer).not.toBeVisible();
|
|
});
|
|
|
|
test('closes drawer on overlay click', async ({ page }) => {
|
|
await loginAsStudent(page);
|
|
|
|
await page.getByRole('button', { name: /ouvrir le menu/i }).click();
|
|
const drawer = page.locator('[role="dialog"][aria-modal="true"]');
|
|
await expect(drawer).toBeVisible();
|
|
|
|
const overlay = page.locator('.mobile-overlay');
|
|
await overlay.click({ position: { x: 350, y: 300 } });
|
|
await expect(drawer).not.toBeVisible();
|
|
});
|
|
|
|
test('navigates via mobile drawer and closes it', async ({ page }) => {
|
|
await loginAsStudent(page);
|
|
|
|
await page.getByRole('button', { name: /ouvrir le menu/i }).click();
|
|
const drawer = page.locator('[role="dialog"][aria-modal="true"]');
|
|
await expect(drawer).toBeVisible();
|
|
|
|
await drawer.getByText('Mon emploi du temps').click();
|
|
|
|
await expect(drawer).not.toBeVisible();
|
|
await expect(page).toHaveURL(/\/dashboard\/schedule/);
|
|
});
|
|
|
|
test('shows logout button in drawer footer', async ({ page }) => {
|
|
await loginAsStudent(page);
|
|
|
|
await page.getByRole('button', { name: /ouvrir le menu/i }).click();
|
|
const drawer = page.locator('[role="dialog"][aria-modal="true"]');
|
|
await expect(drawer).toBeVisible({ timeout: 10000 });
|
|
|
|
const logoutButton = drawer.locator('.mobile-logout');
|
|
await expect(logoutButton).toBeVisible({ timeout: 10000 });
|
|
await expect(logoutButton).toHaveText(/déconnexion/i);
|
|
});
|
|
});
|
|
|
|
// =========================================================================
|
|
// DESKTOP (1280x800)
|
|
// =========================================================================
|
|
test.describe('Desktop (1280x800)', () => {
|
|
test.use({ viewport: { width: 1280, height: 800 } });
|
|
|
|
test('hides hamburger and shows desktop nav', async ({ page }) => {
|
|
await loginAsStudent(page);
|
|
|
|
const hamburger = page.getByRole('button', { name: /ouvrir le menu/i });
|
|
await expect(hamburger).not.toBeVisible();
|
|
|
|
const desktopNav = page.locator('.desktop-nav');
|
|
await expect(desktopNav).toBeVisible({ timeout: 10000 });
|
|
});
|
|
|
|
test('desktop nav shows schedule link for student', async ({ page }) => {
|
|
await loginAsStudent(page);
|
|
|
|
const desktopNav = page.locator('.desktop-nav');
|
|
await expect(desktopNav.getByText('Mon EDT')).toBeVisible({ timeout: 10000 });
|
|
await expect(desktopNav.getByText('Tableau de bord')).toBeVisible();
|
|
});
|
|
});
|
|
});
|