import { test, expect } from '@chromatic-com/playwright'; import { loginViaAPI, CONFIG, navigateTo } from './helpers'; test.describe('PLAYLISTS — CRUD', () => { test.beforeEach(async ({ page }) => { await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password); }); test('01. Page /playlists se charge et affiche la liste @critical', async ({ page }) => { await navigateTo(page, '/playlists'); const body = await page.textContent('body') || ''; expect(body).not.toMatch(/500|Internal Server Error|crash|TypeError|Unhandled/i); const playlistCards = page.locator('[role="article"][aria-label^="Playlist:"]'); expect(await playlistCards.count()).toBeGreaterThan(0); const createBtn = page.getByRole('button', { name: /créer|create|nouvelle|new/i }) .or(page.getByRole('link', { name: /créer|create|nouvelle|new/i })); await expect(createBtn.first()).toBeVisible(); }); test('02. Créer une nouvelle playlist @critical', async ({ page }) => { await navigateTo(page, '/playlists'); const createBtn = page.getByRole('button', { name: /créer|create|nouvelle|new/i }) .or(page.getByRole('link', { name: /créer|create|nouvelle|new/i })) .first(); await expect(createBtn).toBeVisible(); await createBtn.click(); await page.waitForTimeout(500); const nameInput = page.getByLabel(/nom|name|titre|title/i) .or(page.getByPlaceholder(/nom|name|titre/i)) .first(); await expect(nameInput).toBeVisible(); const playlistName = `E2E Playlist ${Date.now()}`; await nameInput.fill(playlistName); const descInput = page.getByLabel(/description/i).first(); if (await descInput.isVisible().catch(() => false)) { await descInput.fill('Créée par les tests E2E'); } const dialog = page.locator('[role="dialog"], [role="alertdialog"], dialog, [data-state="open"]').first(); const dialogVisible = await dialog.isVisible().catch(() => false); let saved = false; if (dialogVisible) { const dialogSaveBtn = dialog.getByRole('button', { name: /créer|create|sauvegarder|save|ok/i }).first(); if (await dialogSaveBtn.isVisible().catch(() => false)) { await dialogSaveBtn.click(); saved = true; } } if (!saved) { const allSaveBtns = page.getByRole('button', { name: /créer|create|sauvegarder|save|ok/i }); const count = await allSaveBtns.count(); if (count > 0) { await allSaveBtns.nth(count - 1).click(); } } await page.waitForTimeout(2_000); const newCard = page.locator(`[role="article"][aria-label="Playlist: ${playlistName}"]`); const exists = await newCard.isVisible().catch(() => page.getByText(playlistName).isVisible().catch(() => false) ); expect(exists).toBeTruthy(); }); test('03. Ouvrir une playlist existante affiche ses tracks', async ({ page }) => { await navigateTo(page, '/playlists'); const playlistLink = page.locator('a[href*="/playlists/"]').first(); await expect(playlistLink).toBeVisible(); await playlistLink.click(); await page.waitForLoadState('networkidle'); expect(page.url()).toMatch(/\/playlists\//); const body = await page.textContent('body') || ''; expect(body.length).toBeGreaterThan(100); expect(body).not.toContain('undefined'); }); test('04. Modifier le nom d\'une playlist', async ({ page }) => { await navigateTo(page, '/playlists'); const playlistLink = page.locator('a[href*="/playlists/"]').first(); await expect(playlistLink).toBeVisible(); await playlistLink.click(); await page.waitForLoadState('networkidle'); const editBtn = page.getByRole('button', { name: /edit|modifier|éditer/i }).first() .or(page.locator('[data-action="edit"]').first()) .or(page.locator('button:has(svg.lucide-edit), button:has(svg.lucide-pencil)').first()); await expect(editBtn).toBeVisible(); await editBtn.click(); }); test('05. Supprimer une playlist', async ({ page }) => { await navigateTo(page, '/playlists'); const playlistLink = page.locator('a[href*="/playlists/"]').first(); await expect(playlistLink).toBeVisible(); await playlistLink.click(); await page.waitForLoadState('networkidle'); const deleteBtn = page.getByRole('button', { name: /supprimer|delete|remove/i }).first() .or(page.locator('[data-action="delete"]').first()); await expect(deleteBtn).toBeVisible(); }); }); test.describe('PLAYLISTS — Collaboration', () => { test.beforeEach(async ({ page }) => { await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password); }); test('06. Option d\'invitation de collaborateurs', async ({ page }) => { await navigateTo(page, '/playlists'); const playlistLink = page.locator('a[href*="/playlists/"]').first(); await expect(playlistLink).toBeVisible(); await playlistLink.click(); await page.waitForLoadState('networkidle'); const collabBtn = page.getByRole('button', { name: /collabor|inviter|invite|partager|share/i }).first() .or(page.locator('button:has(svg.lucide-share-2), button:has(svg.lucide-share)').first()); await expect(collabBtn).toBeVisible(); }); test('07. Export playlist (JSON/CSV/M3U)', async ({ page }) => { await navigateTo(page, '/playlists'); const playlistLink = page.locator('a[href*="/playlists/"]').first(); await expect(playlistLink).toBeVisible(); await playlistLink.click(); await page.waitForLoadState('networkidle'); // ExportPlaylistButton renders as a standalone button with Download icon + "Export" text // It opens a DropdownMenu with JSON/CSV/M3U items on click const exportBtn = page.getByRole('button', { name: /export|télécharger|download/i }).first(); await expect(exportBtn).toBeVisible(); await exportBtn.click(); await page.waitForTimeout(500); // DropdownMenuItem renders with role="menuitem" (Radix UI) const exportOptions = page.getByRole('menuitem', { name: /json|csv|m3u/i }); expect(await exportOptions.count()).toBeGreaterThanOrEqual(1); }); }); test.describe('PLAYLISTS — Drag & Drop', () => { test('08. Réordonner les tracks par drag & drop', async ({ page }) => { await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password); await navigateTo(page, '/playlists'); const playlistLink = page.locator('a[href*="/playlists/"]').first(); await expect(playlistLink).toBeVisible(); await playlistLink.click(); await page.waitForLoadState('networkidle'); const dragHandles = page.locator('[class*="drag"], [data-testid="drag-handle"], [class*="grip"], [class*="cursor-grab"]'); expect(await dragHandles.count()).toBeGreaterThan(0); }); });