Refine auth, player, tracks, playlists, search, workflows, edge cases, forms, responsive, network errors, error boundary, performance, visual regression, cross-browser, profile, smoke, storybook, chat, and session tests. Add audit test suite (accessibility, ethical, functional, design tokens). Update test helpers and visual snapshots. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
109 lines
4.2 KiB
TypeScript
109 lines
4.2 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { loginViaAPI, navigateTo } from '../helpers';
|
|
import { testModal } from '../helpers/interaction-helpers';
|
|
import { TEST_USERS } from '../design-tokens';
|
|
|
|
test.describe('MODALS & DIALOGS — Ouvrent, ferment, piègent le focus', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, TEST_USERS.listener.email, TEST_USERS.listener.password);
|
|
});
|
|
|
|
test('Settings — les modals de confirmation fonctionnent', async ({ page }) => {
|
|
await navigateTo(page, '/settings');
|
|
|
|
// Chercher les boutons qui ouvrent des modals (delete, danger, etc.)
|
|
const dangerButtons = await page.locator('button:visible').filter({ hasText: /supprimer|delete|effacer|réinitialiser|reset|déconnexion|confirmer/i }).all();
|
|
|
|
for (const btn of dangerButtons.slice(0, 3)) {
|
|
try {
|
|
const text = await btn.textContent().then(t => t?.trim().slice(0, 30) || '').catch(() => '');
|
|
console.log(`[MODAL] Testing trigger: "${text}"`);
|
|
|
|
const result = await testModal(page, btn);
|
|
|
|
if (result.opens) {
|
|
console.log(` Opens: ${result.opens}`);
|
|
console.log(` Backdrop: ${result.hasBackdrop}`);
|
|
console.log(` Escape: ${result.closesOnEscape}`);
|
|
console.log(` Close btn: ${result.closesOnCloseButton}`);
|
|
console.log(` Focus trap: ${result.focusTrapped}`);
|
|
|
|
for (const issue of result.issues) {
|
|
console.log(` [ISSUE] ${issue}`);
|
|
}
|
|
|
|
expect(result.closesOnEscape, `Modal "${text}" ne se ferme pas avec Escape`).toBe(true);
|
|
}
|
|
} catch {
|
|
/* skip */
|
|
}
|
|
}
|
|
});
|
|
|
|
test('Playlists — la modal de création fonctionne', async ({ page }) => {
|
|
await navigateTo(page, '/playlists');
|
|
|
|
// Chercher le bouton "Créer une playlist" ou similaire
|
|
const createBtn = page.getByRole('button', { name: /créer|create|nouvelle|new/i }).first()
|
|
.or(page.locator('[data-testid*="create"]').first());
|
|
|
|
if (!await createBtn.isVisible({ timeout: 5_000 }).catch(() => false)) {
|
|
console.log('[MODAL] Pas de bouton de création de playlist trouvé');
|
|
return;
|
|
}
|
|
|
|
await createBtn.click();
|
|
await page.waitForTimeout(500);
|
|
|
|
const dialog = page.locator('[role="dialog"]').first();
|
|
const isOpen = await dialog.isVisible().catch(() => false);
|
|
|
|
if (isOpen) {
|
|
console.log('[MODAL] Modal de création de playlist ouverte');
|
|
|
|
// Vérifier qu'elle a un titre
|
|
const title = await dialog.locator('h2, h3, [class*="title"]').first().textContent().catch(() => '');
|
|
console.log(` Titre: "${title}"`);
|
|
|
|
// Vérifier qu'elle a un champ input
|
|
const input = dialog.locator('input:visible').first();
|
|
const hasInput = await input.isVisible().catch(() => false);
|
|
expect(hasInput, 'La modal de création devrait avoir un champ input').toBe(true);
|
|
|
|
// Escape ferme
|
|
await page.keyboard.press('Escape');
|
|
await page.waitForTimeout(300);
|
|
const closed = !(await dialog.isVisible().catch(() => false));
|
|
expect(closed, 'La modal ne se ferme pas avec Escape').toBe(true);
|
|
}
|
|
});
|
|
|
|
test('Dialogs — le backdrop bloque les clics sous le modal', async ({ page }) => {
|
|
await navigateTo(page, '/settings');
|
|
|
|
// Ouvrir n'importe quel modal disponible
|
|
const triggerBtn = await page.locator('button:visible').filter({ hasText: /supprimer|delete|logout|déconnexion|modifier|edit/i }).first();
|
|
|
|
if (!await triggerBtn.isVisible({ timeout: 5_000 }).catch(() => false)) return;
|
|
|
|
await triggerBtn.click();
|
|
await page.waitForTimeout(500);
|
|
|
|
const dialog = page.locator('[role="dialog"]').first();
|
|
if (!await dialog.isVisible().catch(() => false)) return;
|
|
|
|
// Vérifier la présence du backdrop
|
|
const hasBackdrop = await page.evaluate(() => {
|
|
return Array.from(document.querySelectorAll('.fixed.inset-0')).some(el => {
|
|
const s = getComputedStyle(el);
|
|
return s.backgroundColor !== 'rgba(0, 0, 0, 0)' || s.backdropFilter !== 'none';
|
|
});
|
|
});
|
|
|
|
console.log(`[MODAL] Backdrop présent: ${hasBackdrop}`);
|
|
expect(hasBackdrop, 'Le modal devrait avoir un backdrop visible').toBe(true);
|
|
|
|
// Nettoyage
|
|
await page.keyboard.press('Escape');
|
|
});
|
|
});
|