import { test, expect } from '@chromatic-com/playwright'; 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'); }); });