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 projectRoot = join(__dirname, '../..'); const composeFile = join(projectRoot, 'compose.yaml'); // 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}`; const SA_PASSWORD = 'SuperAdmin123'; const REGULAR_PASSWORD = 'TestPassword123'; function getSuperAdminEmail(browserName: string): string { return `e2e-sadmin-${browserName}@test.com`; } function getRegularUserEmail(browserName: string): string { return `e2e-sadmin-regular-${browserName}@example.com`; } // eslint-disable-next-line no-empty-pattern test.beforeAll(async ({}, testInfo) => { const browserName = testInfo.project.name; const saEmail = getSuperAdminEmail(browserName); const regularEmail = getRegularUserEmail(browserName); try { // Create a test super admin const saResult = execSync( `docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-super-admin --email=${saEmail} --password=${SA_PASSWORD} 2>&1`, { encoding: 'utf-8' } ); console.warn( `[${browserName}] Super admin created or exists:`, saResult.includes('already exists') ? 'exists' : 'created' ); // Create a regular user (for access control test) const userResult = execSync( `docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-user --email=${regularEmail} --password=${REGULAR_PASSWORD} 2>&1`, { encoding: 'utf-8' } ); console.warn( `[${browserName}] Regular user created or exists:`, userResult.includes('already exists') ? 'exists' : 'created' ); } catch (error) { console.error(`[${browserName}] Failed to create test users:`, error); } }); async function loginAsSuperAdmin( page: import('@playwright/test').Page, email: string ) { await page.goto(`${ALPHA_URL}/login`); await expect(page.getByRole('heading', { name: /connexion/i })).toBeVisible(); await page.locator('#email').fill(email); await page.locator('#password').fill(SA_PASSWORD); const submitButton = page.getByRole('button', { name: /se connecter/i }); await Promise.all([ page.waitForURL('**/super-admin/dashboard', { timeout: 30000 }), submitButton.click() ]); } test.describe('Super Admin', () => { test.describe('Login & Redirect', () => { test('super admin login redirects to /super-admin/dashboard', async ({ page }, testInfo) => { const email = getSuperAdminEmail(testInfo.project.name); await loginAsSuperAdmin(page, email); await expect(page).toHaveURL(/\/super-admin\/dashboard/); }); }); test.describe('Dashboard', () => { test('dashboard displays stats cards', async ({ page }, testInfo) => { const email = getSuperAdminEmail(testInfo.project.name); await loginAsSuperAdmin(page, email); // The dashboard should show stat cards await expect(page.locator('.stat-card').first()).toBeVisible({ timeout: 10000 }); // Verify dashboard heading await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible(); }); }); test.describe('Navigation', () => { test('navigates to establishments page', async ({ page }, testInfo) => { const email = getSuperAdminEmail(testInfo.project.name); await loginAsSuperAdmin(page, email); const etablissementsLink = page.getByRole('link', { name: /établissements/i }); await Promise.all([ page.waitForURL('**/super-admin/establishments', { timeout: 10000 }), etablissementsLink.click() ]); await expect(page).toHaveURL(/\/super-admin\/establishments/); await expect( page.getByRole('heading', { name: /établissements/i }) ).toBeVisible(); }); test('establishments page has create button', async ({ page }, testInfo) => { const email = getSuperAdminEmail(testInfo.project.name); await loginAsSuperAdmin(page, email); // Navigate via SPA link (page.goto would reload and lose in-memory token) const etablissementsLink = page.getByRole('link', { name: /établissements/i }); await Promise.all([ page.waitForURL('**/super-admin/establishments', { timeout: 10000 }), etablissementsLink.click() ]); await expect(page.getByRole('heading', { name: /établissements/i })).toBeVisible({ timeout: 10000 }); // Check "Nouvel établissement" button/link await expect( page.getByRole('link', { name: /nouvel établissement/i }) ).toBeVisible(); }); }); test.describe('Create Establishment Form', () => { test('new establishment form has required fields', async ({ page }, testInfo) => { const email = getSuperAdminEmail(testInfo.project.name); await loginAsSuperAdmin(page, email); // Navigate via SPA links (page.goto would reload and lose in-memory token) const etablissementsLink = page.getByRole('link', { name: /établissements/i }); await Promise.all([ page.waitForURL('**/super-admin/establishments', { timeout: 10000 }), etablissementsLink.click() ]); const newLink = page.getByRole('link', { name: /nouvel établissement/i }); await expect(newLink).toBeVisible({ timeout: 10000 }); await Promise.all([ page.waitForURL('**/super-admin/establishments/new', { timeout: 10000 }), newLink.click() ]); // Verify form fields await expect(page.locator('#name')).toBeVisible({ timeout: 10000 }); await expect(page.locator('#subdomain')).toBeVisible(); await expect(page.locator('#adminEmail')).toBeVisible(); // Submit button should be disabled when empty const submitButton = page.getByRole('button', { name: /créer l'établissement/i }); await expect(submitButton).toBeDisabled(); // Fill in the form await page.locator('#name').fill('École Test E2E'); await page.locator('#adminEmail').fill('admin-e2e@test.com'); // Subdomain should be auto-generated await expect(page.locator('#subdomain')).not.toHaveValue(''); // Submit button should be enabled await expect(submitButton).toBeEnabled(); }); }); test.describe('Access Control', () => { test('regular user is redirected away from /super-admin', async ({ page }, testInfo) => { const regularEmail = getRegularUserEmail(testInfo.project.name); // Login as regular user on alpha tenant await page.goto(`${ALPHA_URL}/login`); await page.locator('#email').fill(regularEmail); await page.locator('#password').fill(REGULAR_PASSWORD); const submitButton = page.getByRole('button', { name: /se connecter/i }); await Promise.all([ page.waitForURL('**/dashboard', { timeout: 30000 }), submitButton.click() ]); // Try to navigate to super-admin area await page.goto(`${ALPHA_URL}/super-admin/dashboard`); // Should be redirected away (to /dashboard since not super admin) await expect(page).not.toHaveURL(/\/super-admin/, { timeout: 10000 }); }); }); });