Update auth, playlists, tracks, search, profile, dashboard, player, settings, and social features. Add e2e audit specs for all major pages. Update ESLint config, vitest config, and route configuration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
159 lines
6.1 KiB
TypeScript
159 lines
6.1 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { navigateTo, assertPageLoads } from './helpers';
|
|
|
|
const PAGE_PATH = '/design-system';
|
|
|
|
test.describe('Démo du design system (/design-system)', () => {
|
|
test.describe('Chargement & Rendu', () => {
|
|
test('la page se charge sans crash', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
await expect(page.locator('main#main-content')).toBeVisible();
|
|
});
|
|
|
|
test('pas d\'erreurs JS dans la console (hors 401 auth)', async ({ page }) => {
|
|
const errors = await assertPageLoads(page, PAGE_PATH);
|
|
const realErrors = errors.filter(
|
|
(e) => !e.includes('/api/v1/auth/me') && !e.includes('401'),
|
|
);
|
|
expect(realErrors).toHaveLength(0);
|
|
});
|
|
|
|
test('tous les éléments visuels sont présents', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
await expect(page.locator('h1')).toBeVisible();
|
|
await expect(page.locator('h1')).not.toBeEmpty();
|
|
// Subtitle paragraph
|
|
await expect(page.locator('header p')).toBeVisible();
|
|
// Under construction message
|
|
await expect(page.locator('section p')).toBeVisible();
|
|
// Back to home link
|
|
await expect(page.locator('a[href="/"]')).toBeVisible();
|
|
});
|
|
|
|
test('document.title est mis à jour', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
await expect(page).toHaveTitle(/Design System/);
|
|
});
|
|
});
|
|
|
|
test.describe('Accessibilité', () => {
|
|
test('le skip-to-content fonctionne (cible #main-content existe)', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
const skipLink = page.locator('a[href="#main-content"]');
|
|
await expect(skipLink).toBeAttached();
|
|
const mainContent = page.locator('#main-content');
|
|
await expect(mainContent).toBeAttached();
|
|
});
|
|
|
|
test('landmark <main> est présent', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
const main = page.locator('main');
|
|
await expect(main).toBeAttached();
|
|
await expect(main).toHaveAttribute('id', 'main-content');
|
|
});
|
|
|
|
test('hiérarchie des headings correcte (h1 unique)', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
const h1s = page.locator('main h1');
|
|
await expect(h1s).toHaveCount(1);
|
|
});
|
|
|
|
test('navigation au clavier logique (Tab order)', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
// First Tab → skip link
|
|
await page.keyboard.press('Tab');
|
|
const skipLink = page.locator('a[href="#main-content"]');
|
|
await expect(skipLink).toBeFocused();
|
|
// Next Tab → "Back to home" link
|
|
await page.keyboard.press('Tab');
|
|
const backLink = page.locator('a[href="/"]');
|
|
await expect(backLink).toBeFocused();
|
|
});
|
|
|
|
test('le lien "Back to home" a un texte accessible', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
const backLink = page.locator('a[href="/"]');
|
|
const text = await backLink.textContent();
|
|
expect(text?.trim().length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
test.describe('i18n', () => {
|
|
test('pas de clés i18n brutes affichées', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
const bodyText = await page.locator('main').textContent();
|
|
// i18n keys look like "designSystem.title" — should not appear as rendered text
|
|
expect(bodyText).not.toMatch(/designSystem\./);
|
|
});
|
|
|
|
test('texte cohérent — pas de mélange avec du texte hardcodé', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
const bodyText = await page.locator('main').textContent();
|
|
// The old hardcoded text should not appear
|
|
expect(bodyText).not.toContain('Component under construction.');
|
|
});
|
|
});
|
|
|
|
test.describe('Responsive', () => {
|
|
test('mobile 375px — pas d\'overflow horizontal', async ({ page }) => {
|
|
await page.setViewportSize({ width: 375, height: 812 });
|
|
await navigateTo(page, PAGE_PATH);
|
|
const hasOverflow = await page.evaluate(
|
|
() => document.documentElement.scrollWidth > document.documentElement.clientWidth,
|
|
);
|
|
expect(hasOverflow).toBe(false);
|
|
});
|
|
|
|
test('tablet 768px — pas d\'overflow horizontal', async ({ page }) => {
|
|
await page.setViewportSize({ width: 768, height: 1024 });
|
|
await navigateTo(page, PAGE_PATH);
|
|
const hasOverflow = await page.evaluate(
|
|
() => document.documentElement.scrollWidth > document.documentElement.clientWidth,
|
|
);
|
|
expect(hasOverflow).toBe(false);
|
|
});
|
|
|
|
test('desktop 1280px — layout correct', async ({ page }) => {
|
|
await page.setViewportSize({ width: 1280, height: 800 });
|
|
await navigateTo(page, PAGE_PATH);
|
|
const main = page.locator('main');
|
|
await expect(main).toBeVisible();
|
|
const hasOverflow = await page.evaluate(
|
|
() => document.documentElement.scrollWidth > document.documentElement.clientWidth,
|
|
);
|
|
expect(hasOverflow).toBe(false);
|
|
});
|
|
});
|
|
|
|
test.describe('Régression', () => {
|
|
test('BUG #1 — #main-content existe pour le skip link', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
await expect(page.locator('#main-content')).toBeAttached();
|
|
});
|
|
|
|
test('BUG #2 — landmark <main> est présent', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
await expect(page.locator('main')).toBeAttached();
|
|
});
|
|
|
|
test('BUG #3 — data-testid est présent', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
await expect(page.locator('[data-testid="design-system-page"]')).toBeAttached();
|
|
});
|
|
|
|
test('BUG #4 — texte traduit via i18n (pas hardcodé)', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
const h1 = await page.locator('h1').textContent();
|
|
// h1 should have actual translated content, not a raw key
|
|
expect(h1).toBeTruthy();
|
|
expect(h1).not.toMatch(/^designSystem\./);
|
|
});
|
|
|
|
test('BUG #5 — document.title est mis à jour', async ({ page }) => {
|
|
await navigateTo(page, PAGE_PATH);
|
|
const title = await page.title();
|
|
expect(title).toContain('Design System');
|
|
expect(title).not.toBe('Veza - Plateforme de streaming musical');
|
|
});
|
|
});
|
|
});
|