import { test, expect } from '@playwright/test'; import { loginViaAPI, CONFIG, navigateTo, playFirstTrack } from './helpers'; /** * WORKFLOWS COMPLETS & EMPTY STATES */ test.describe('WORKFLOW — Parcours listener complet @critical @workflow', () => { test('Login → Discover → Play → Like → Playlist → Search → Follow → Logout', async ({ page }) => { // 1. Login await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password); // Verify login succeeded if (page.url().includes('/login')) { console.log(' Login failed — skipping'); return; } // 2. Discover await navigateTo(page, '/discover'); const discoverContent = page.locator('text=/discover|découvrir|genre/i').first(); const hasDiscover = await discoverContent.isVisible({ timeout: 10_000 }).catch(() => false); if (!hasDiscover) { // Page loaded but may not have the expected text — check it didn't crash const body = await page.textContent('body') || ''; expect(body).not.toMatch(/500|Internal Server Error/); expect(body.length).toBeGreaterThan(50); } // 3. Play a track await playFirstTrack(page); await page.waitForTimeout(2000); // 4. Like (if heart button visible) const likeBtn = page.locator('button[aria-label*="Like"]').first() .or(page.locator('button').filter({ has: page.locator('[class*="Heart"]') }).first()); if (await likeBtn.isVisible({ timeout: 3000 }).catch(() => false)) { await likeBtn.click(); await page.waitForTimeout(500); } // 5. Navigate to playlists await navigateTo(page, '/playlists'); await page.waitForTimeout(1000); // 6. Search await navigateTo(page, '/search'); const searchInput = page.locator('[role="search"] input').first() .or(page.locator('input[type="search"]').first()); if (await searchInput.isVisible({ timeout: 5000 }).catch(() => false)) { await searchInput.fill('test'); await page.waitForTimeout(1000); } // 7. Navigate to social/follow await navigateTo(page, '/social'); await page.waitForTimeout(1000); // 8. Logout const userMenu = page.getByTestId('user-menu').or(page.locator('[data-testid="user-menu"]')); if (await userMenu.isVisible({ timeout: 3000 }).catch(() => false)) { await userMenu.click(); await page.waitForTimeout(300); const logoutBtn = page.getByRole('menuitem', { name: /logout|déconnexion/i }).first() .or(page.locator('text=/logout|déconnexion/i').first()); if (await logoutBtn.isVisible().catch(() => false)) { await logoutBtn.click(); await page.waitForURL(/login/, { timeout: 5000 }).catch(() => {}); } } }); }); test.describe('WORKFLOW — Parcours créateur @critical @workflow', () => { test('Login créateur → Library → Analytics → Sell @critical', async ({ page }) => { await loginViaAPI(page, CONFIG.users.creator.email, CONFIG.users.creator.password); // Library await navigateTo(page, '/library'); await page.waitForTimeout(1000); const libraryContent = await page.textContent('body'); expect(libraryContent!.length).toBeGreaterThan(100); // Analytics await navigateTo(page, '/analytics'); await page.waitForTimeout(1000); const analyticsContent = await page.textContent('body'); expect(analyticsContent!.length).toBeGreaterThan(100); // Sell await navigateTo(page, '/sell'); await page.waitForTimeout(1000); const sellContent = await page.textContent('body'); expect(sellContent!.length).toBeGreaterThan(100); }); }); test.describe('WORKFLOW — Parcours admin @critical @workflow', () => { test('Login admin → Dashboard → Modération → Platform @critical', async ({ page }) => { await loginViaAPI(page, CONFIG.users.admin.email, CONFIG.users.admin.password); // Verify login succeeded if (page.url().includes('/login')) { console.log(' Admin login failed — skipping'); return; } // Admin dashboard await navigateTo(page, '/admin'); await page.waitForTimeout(1000); const adminContent = page.locator('text=/admin|dashboard/i').first(); const hasAdmin = await adminContent.isVisible({ timeout: 10_000 }).catch(() => false); console.log(` Admin dashboard: ${hasAdmin ? 'visible' : 'not found'}`); // Moderation await navigateTo(page, '/admin/moderation'); await page.waitForTimeout(1000); const modContent = page.locator('text=/moderation|queue/i').first(); const hasMod = await modContent.isVisible({ timeout: 10_000 }).catch(() => false); console.log(` Moderation: ${hasMod ? 'visible' : 'not found'}`); // Platform await navigateTo(page, '/admin/platform'); await page.waitForTimeout(1000); const platformContent = page.locator('text=/platform|metrics/i').first(); const hasPlatform = await platformContent.isVisible({ timeout: 10_000 }).catch(() => false); console.log(` Platform: ${hasPlatform ? 'visible' : 'not found'}`); }); }); test.describe('WORKFLOW — Parcours acheteur @critical @workflow', () => { test('Browse marketplace → Filtrer → Voir produit → Panier @critical', async ({ page }) => { await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password); // Browse await navigateTo(page, '/marketplace'); await page.waitForTimeout(2000); // Search/filter const searchInput = page.locator('input[placeholder*="Search" i]').first(); if (await searchInput.isVisible({ timeout: 3000 }).catch(() => false)) { await searchInput.fill('beat'); await page.waitForTimeout(1000); } // Click product const productCard = page.locator('[aria-label^="Product:"]').first(); if (await productCard.isVisible({ timeout: 5000 }).catch(() => false)) { // Hover and add to cart await productCard.hover(); await page.waitForTimeout(300); const addToCartBtn = productCard.getByRole('button', { name: /add to cart|ajouter/i }).first() .or(productCard.locator('button[class*="outline"]').first()); if (await addToCartBtn.isVisible({ timeout: 3000 }).catch(() => false)) { await addToCartBtn.click(); await page.waitForTimeout(500); } // Open cart const cartBtn = page.getByRole('button', { name: /cart|panier/i }).first(); if (await cartBtn.isVisible({ timeout: 3000 }).catch(() => false)) { await cartBtn.click(); await page.waitForTimeout(500); const cartDialog = page.locator('[role="dialog"]').first(); await expect(cartDialog).toBeVisible({ timeout: 3000 }); } } }); }); test.describe('EMPTY STATES — Premier usage @empty-state', () => { // Use listener account (likely has less data) test.beforeEach(async ({ page }) => { await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password); }); test('Notifications vides → message approprié @empty-state', async ({ page }) => { await navigateTo(page, '/notifications'); await page.waitForTimeout(2000); const content = await page.textContent('body'); // Should have either notifications or empty state message expect(content!.length).toBeGreaterThan(50); }); test('Queue vide → message @empty-state', async ({ page }) => { await navigateTo(page, '/queue'); await page.waitForTimeout(2000); // Check the page loaded without crash const body = await page.textContent('body') || ''; expect(body).not.toMatch(/500|Internal Server Error/); expect(body.length).toBeGreaterThan(50); const emptyState = page.locator('text=/empty|vide|aucun|queue/i').first(); const hasQueue = page.locator('[role="list"], [role="table"]').first(); const isEmpty = await emptyState.isVisible({ timeout: 3000 }).catch(() => false); const hasContent = await hasQueue.isVisible({ timeout: 3000 }).catch(() => false); console.log(` Queue page: empty=${isEmpty}, content=${hasContent}`); }); test('Chat sans conversation → message + CTA @empty-state', async ({ page }) => { await navigateTo(page, '/chat'); await page.waitForTimeout(2000); const content = await page.textContent('body'); expect(content!.length).toBeGreaterThan(50); }); test('Wishlist vide → message + CTA browse @empty-state', async ({ page }) => { await navigateTo(page, '/wishlist'); await page.waitForTimeout(2000); const content = await page.textContent('body'); expect(content!.length).toBeGreaterThan(50); }); test('Purchases vides → message @empty-state', async ({ page }) => { await navigateTo(page, '/purchases'); await page.waitForTimeout(2000); const content = await page.textContent('body'); expect(content!.length).toBeGreaterThan(50); }); test('Cloud vide → message + bouton upload @empty-state', async ({ page }) => { await navigateTo(page, '/cloud'); await page.waitForTimeout(2000); const content = await page.textContent('body'); expect(content!.length).toBeGreaterThan(50); }); test('Gear vide → message + bouton ajouter @empty-state', async ({ page }) => { await navigateTo(page, '/gear'); await page.waitForTimeout(2000); const content = await page.textContent('body'); expect(content!.length).toBeGreaterThan(50); }); });