Les helpers loginAs* utilisaient un pattern séquentiel (click → wait) qui crée une race condition : la navigation peut se terminer avant que le listener soit en place. Firefox sur CI est particulièrement sensible. Le fix remplace ce pattern par Promise.all([waitForURL, click]) dans les 14 fichiers E2E concernés, alignant le code sur le pattern robuste déjà utilisé dans login.spec.ts.
203 lines
7.5 KiB
TypeScript
203 lines
7.5 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}`;
|
|
|
|
const USER_EMAIL = 'e2e-settings-user@example.com';
|
|
const USER_PASSWORD = 'SettingsTest123';
|
|
|
|
function getTenantUrl(path: string): string {
|
|
return `${ALPHA_URL}${path}`;
|
|
}
|
|
|
|
test.describe('Settings Page [P1]', () => {
|
|
// eslint-disable-next-line no-empty-pattern
|
|
test.beforeAll(async ({}, testInfo) => {
|
|
const browserName = testInfo.project.name;
|
|
const projectRoot = join(__dirname, '../..');
|
|
const composeFile = join(projectRoot, 'compose.yaml');
|
|
|
|
// Create a test user (any role works for settings)
|
|
const email = `e2e-settings-${browserName}@example.com`;
|
|
try {
|
|
execSync(
|
|
`docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-user --tenant=ecole-alpha --email=${email} --password=${USER_PASSWORD} 2>&1`,
|
|
{ encoding: 'utf-8' }
|
|
);
|
|
} catch (error) {
|
|
console.error(`[${browserName}] Failed to create settings test user:`, error);
|
|
}
|
|
|
|
// Also create the shared user
|
|
try {
|
|
execSync(
|
|
`docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-user --tenant=ecole-alpha --email=${USER_EMAIL} --password=${USER_PASSWORD} 2>&1`,
|
|
{ encoding: 'utf-8' }
|
|
);
|
|
} catch (error) {
|
|
console.error('Failed to create shared settings test user:', error);
|
|
}
|
|
});
|
|
|
|
function getTestEmail(browserName: string): string {
|
|
return `e2e-settings-${browserName}@example.com`;
|
|
}
|
|
|
|
async function login(page: import('@playwright/test').Page, email: string) {
|
|
await page.goto(getTenantUrl('/login'));
|
|
await page.locator('#email').fill(email);
|
|
await page.locator('#password').fill(USER_PASSWORD);
|
|
await Promise.all([
|
|
page.waitForURL(getTenantUrl('/dashboard'), { timeout: 10000 }),
|
|
page.getByRole('button', { name: /se connecter/i }).click()
|
|
]);
|
|
}
|
|
|
|
// ============================================================================
|
|
// Settings page access
|
|
// ============================================================================
|
|
test('[P1] authenticated user can access /settings page', async ({ page }, testInfo) => {
|
|
const email = getTestEmail(testInfo.project.name);
|
|
await login(page, email);
|
|
|
|
await page.goto(getTenantUrl('/settings'));
|
|
|
|
await expect(page).toHaveURL(/\/settings/);
|
|
await expect(
|
|
page.getByRole('heading', { name: /paramètres/i })
|
|
).toBeVisible({ timeout: 10000 });
|
|
});
|
|
|
|
// ============================================================================
|
|
// Settings page content
|
|
// ============================================================================
|
|
test('[P1] settings page shows description text', async ({ page }, testInfo) => {
|
|
const email = getTestEmail(testInfo.project.name);
|
|
await login(page, email);
|
|
|
|
await page.goto(getTenantUrl('/settings'));
|
|
|
|
await expect(
|
|
page.getByText(/gérez votre compte et vos préférences/i)
|
|
).toBeVisible();
|
|
});
|
|
|
|
test('[P1] settings page shows Sessions navigation card', async ({ page }, testInfo) => {
|
|
const email = getTestEmail(testInfo.project.name);
|
|
await login(page, email);
|
|
|
|
await page.goto(getTenantUrl('/settings'));
|
|
|
|
// The Sessions card should be visible
|
|
await expect(page.getByRole('heading', { name: /mes sessions/i })).toBeVisible();
|
|
await expect(
|
|
page.getByText(/gérez vos sessions actives/i)
|
|
).toBeVisible();
|
|
});
|
|
|
|
// ============================================================================
|
|
// Navigation from settings to sessions
|
|
// ============================================================================
|
|
test('[P1] clicking Sessions card navigates to /settings/sessions', async ({ page, browserName }, testInfo) => {
|
|
// Skip on webkit due to navigation timing issues with SvelteKit
|
|
test.skip(browserName === 'webkit', 'Webkit has navigation timing issues with SvelteKit');
|
|
|
|
const email = getTestEmail(testInfo.project.name);
|
|
await login(page, email);
|
|
|
|
await page.goto(getTenantUrl('/settings'));
|
|
|
|
// Click on the Sessions card (it's a button with heading text)
|
|
await page.getByText(/mes sessions/i).click();
|
|
|
|
await expect(page).toHaveURL(/\/settings\/sessions/);
|
|
await expect(
|
|
page.getByRole('heading', { name: /mes sessions/i })
|
|
).toBeVisible();
|
|
});
|
|
|
|
// ============================================================================
|
|
// Settings layout - header with logo
|
|
// ============================================================================
|
|
test('[P1] settings layout shows header with Classeo logo', async ({ page }, testInfo) => {
|
|
const email = getTestEmail(testInfo.project.name);
|
|
await login(page, email);
|
|
|
|
await page.goto(getTenantUrl('/settings'));
|
|
|
|
// Header should have the Classeo logo text
|
|
await expect(page.locator('.logo-text')).toBeVisible();
|
|
await expect(page.locator('.logo-text')).toHaveText('Classeo');
|
|
});
|
|
|
|
test('[P1] settings layout shows Tableau de bord navigation link', async ({ page }, testInfo) => {
|
|
const email = getTestEmail(testInfo.project.name);
|
|
await login(page, email);
|
|
|
|
await page.goto(getTenantUrl('/settings'));
|
|
|
|
await expect(
|
|
page.getByRole('link', { name: /tableau de bord/i })
|
|
).toBeVisible();
|
|
});
|
|
|
|
test('[P1] settings layout shows Parametres navigation link as active', async ({ page }, testInfo) => {
|
|
const email = getTestEmail(testInfo.project.name);
|
|
await login(page, email);
|
|
|
|
await page.goto(getTenantUrl('/settings'));
|
|
|
|
const parametresLink = page.getByRole('link', { name: /parametres/i });
|
|
await expect(parametresLink).toBeVisible();
|
|
await expect(parametresLink).toHaveClass(/active/);
|
|
});
|
|
|
|
// ============================================================================
|
|
// Logout from settings layout
|
|
// ============================================================================
|
|
test('[P1] logout button on settings layout logs user out', async ({ page, browserName }, testInfo) => {
|
|
// Skip on webkit due to navigation timing issues with SvelteKit
|
|
test.skip(browserName === 'webkit', 'Webkit has navigation timing issues with SvelteKit');
|
|
|
|
const email = getTestEmail(testInfo.project.name);
|
|
await login(page, email);
|
|
|
|
await page.goto(getTenantUrl('/settings'));
|
|
|
|
// Click logout button
|
|
const logoutButton = page.getByRole('button', { name: /d[eé]connexion/i });
|
|
await expect(logoutButton).toBeVisible();
|
|
await logoutButton.click();
|
|
|
|
// Should redirect to login
|
|
await expect(page).toHaveURL(/\/login/, { timeout: 10000 });
|
|
});
|
|
|
|
// ============================================================================
|
|
// Logo click navigates to dashboard
|
|
// ============================================================================
|
|
test('[P1] clicking Classeo logo navigates to dashboard', async ({ page, browserName }, testInfo) => {
|
|
// Skip on webkit due to navigation timing issues with SvelteKit
|
|
test.skip(browserName === 'webkit', 'Webkit has navigation timing issues with SvelteKit');
|
|
|
|
const email = getTestEmail(testInfo.project.name);
|
|
await login(page, email);
|
|
|
|
await page.goto(getTenantUrl('/settings'));
|
|
|
|
// Click the logo button
|
|
await page.locator('.logo-button').click();
|
|
|
|
await expect(page).toHaveURL(/\/dashboard/, { timeout: 10000 });
|
|
});
|
|
});
|