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>
112 lines
4.2 KiB
TypeScript
112 lines
4.2 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { loginViaAPI, navigateTo } from '../helpers';
|
|
import { testDropdown } from '../helpers/interaction-helpers';
|
|
import { TEST_USERS } from '../design-tokens';
|
|
|
|
test.describe('DROPDOWNS & MENUS — Tous s\'ouvrent, se ferment, et ne débordent pas', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, TEST_USERS.listener.email, TEST_USERS.listener.password);
|
|
});
|
|
|
|
test('Sidebar — les dropdowns de navigation fonctionnent', async ({ page }) => {
|
|
await navigateTo(page, '/dashboard');
|
|
|
|
// Chercher les triggers de dropdown dans le sidebar
|
|
const sidebar = page.locator('[data-testid="app-sidebar"]');
|
|
if (!await sidebar.isVisible({ timeout: 5_000 }).catch(() => false)) return;
|
|
|
|
const dropdownTriggers = await sidebar.locator('button[aria-expanded], button[aria-haspopup]').all();
|
|
|
|
for (const trigger of dropdownTriggers.slice(0, 5)) {
|
|
try {
|
|
const text = await trigger.textContent().then(t => t?.trim().slice(0, 20) || '').catch(() => '');
|
|
console.log(`[DROPDOWN] Testing sidebar trigger: "${text}"`);
|
|
|
|
await trigger.click();
|
|
await page.waitForTimeout(300);
|
|
|
|
// Vérifier qu'un menu apparaît
|
|
const expanded = await trigger.getAttribute('aria-expanded');
|
|
if (expanded === 'true') {
|
|
// Escape ferme
|
|
await page.keyboard.press('Escape');
|
|
await page.waitForTimeout(200);
|
|
const closedAfterEscape = await trigger.getAttribute('aria-expanded');
|
|
expect(closedAfterEscape, `Dropdown "${text}" ne se ferme pas avec Escape`).not.toBe('true');
|
|
}
|
|
} catch {
|
|
/* skip detached elements */
|
|
}
|
|
}
|
|
});
|
|
|
|
test('Settings — les select/dropdown de préférences fonctionnent', async ({ page }) => {
|
|
await navigateTo(page, '/settings');
|
|
|
|
// Chercher les selects et dropdowns
|
|
const selects = await page.locator('select:visible, [role="combobox"]:visible, [role="listbox"]:visible').all();
|
|
|
|
for (const select of selects.slice(0, 5)) {
|
|
try {
|
|
const box = await select.boundingBox();
|
|
if (!box) continue;
|
|
|
|
await select.click();
|
|
await page.waitForTimeout(300);
|
|
|
|
// Vérifier que les options sont affichées
|
|
const options = page.locator('[role="option"]:visible, option:visible');
|
|
const optionCount = await options.count().catch(() => 0);
|
|
console.log(`[SELECT] ${optionCount} options visibles`);
|
|
|
|
// Fermer
|
|
await page.keyboard.press('Escape');
|
|
await page.waitForTimeout(200);
|
|
} catch {
|
|
/* skip */
|
|
}
|
|
}
|
|
});
|
|
|
|
test('Header — le menu utilisateur fonctionne', async ({ page }) => {
|
|
await navigateTo(page, '/dashboard');
|
|
|
|
// Chercher le menu utilisateur dans le header
|
|
const userMenu = page.locator('header button[aria-haspopup], header [data-testid*="user-menu"], header [data-testid*="profile"]').first();
|
|
if (!await userMenu.isVisible({ timeout: 5_000 }).catch(() => false)) {
|
|
console.log('[DROPDOWN] Pas de menu utilisateur trouvé dans le header');
|
|
return;
|
|
}
|
|
|
|
await userMenu.click();
|
|
await page.waitForTimeout(400);
|
|
|
|
const menuContent = page.locator('[role="menu"]:visible, [role="dialog"]:visible').first();
|
|
const menuVisible = await menuContent.isVisible().catch(() => false);
|
|
|
|
if (menuVisible) {
|
|
// Escape ferme
|
|
await page.keyboard.press('Escape');
|
|
await page.waitForTimeout(200);
|
|
const closed = !(await menuContent.isVisible().catch(() => false));
|
|
expect(closed, 'Le menu utilisateur ne se ferme pas avec Escape').toBe(true);
|
|
}
|
|
});
|
|
|
|
test('Discover — les filtres/genre buttons fonctionnent', async ({ page }) => {
|
|
await navigateTo(page, '/discover');
|
|
|
|
// Les boutons de genre sont des boutons qui filtre les tracks
|
|
const genreButtons = await page.locator('button').filter({ has: page.locator('.font-heading') }).all();
|
|
|
|
if (genreButtons.length > 0) {
|
|
const firstGenre = genreButtons[0];
|
|
await firstGenre.click();
|
|
await page.waitForTimeout(1_000);
|
|
|
|
// Après le clic, la page devrait afficher des tracks ou un état vide
|
|
const body = await page.textContent('body');
|
|
expect(body).not.toMatch(/500|Internal Server Error/i);
|
|
}
|
|
});
|
|
});
|