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.5 KiB
TypeScript
112 lines
4.5 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { loginViaAPI, navigateTo } from '../helpers';
|
|
import { TEST_USERS, VIEWPORTS } from '../design-tokens';
|
|
|
|
test.describe('SCROLL — Les conteneurs scrollables fonctionnent', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, TEST_USERS.listener.email, TEST_USERS.listener.password);
|
|
});
|
|
|
|
test('Header reste sticky/fixed au scroll', async ({ page }) => {
|
|
await navigateTo(page, '/dashboard');
|
|
|
|
// Scroller vers le bas
|
|
await page.evaluate(() => window.scrollTo(0, 500));
|
|
await page.waitForTimeout(300);
|
|
|
|
const headerState = await page.evaluate(() => {
|
|
const header = document.querySelector('header, [data-testid="app-header"], [role="banner"]');
|
|
if (!header) return null;
|
|
const rect = header.getBoundingClientRect();
|
|
const style = getComputedStyle(header);
|
|
return {
|
|
top: Math.round(rect.top),
|
|
position: style.position,
|
|
visible: rect.top >= -5 && rect.top < 100,
|
|
};
|
|
});
|
|
|
|
if (headerState) {
|
|
console.log(`[SCROLL] Header après scroll: position=${headerState.position}, top=${headerState.top}px, visible=${headerState.visible}`);
|
|
expect(headerState.visible,
|
|
`ÉLÉMENT: header | PAGE: /dashboard | MESURÉ: top=${headerState.top}px après scroll | ATTENDU: visible (top < 100px) | FIX TAILWIND: Ajouter sticky top-0 z-50 sur le header`
|
|
).toBe(true);
|
|
}
|
|
});
|
|
|
|
test('Sidebar reste fixed au scroll', async ({ page }) => {
|
|
await page.setViewportSize(VIEWPORTS.desktop);
|
|
await navigateTo(page, '/dashboard');
|
|
|
|
await page.evaluate(() => window.scrollTo(0, 500));
|
|
await page.waitForTimeout(300);
|
|
|
|
const sidebarState = await page.evaluate(() => {
|
|
const sidebar = document.querySelector('[data-testid="app-sidebar"]');
|
|
if (!sidebar) return null;
|
|
const rect = sidebar.getBoundingClientRect();
|
|
const style = getComputedStyle(sidebar);
|
|
return {
|
|
top: Math.round(rect.top),
|
|
position: style.position,
|
|
height: Math.round(rect.height),
|
|
visible: rect.height > 200,
|
|
};
|
|
});
|
|
|
|
if (sidebarState) {
|
|
console.log(`[SCROLL] Sidebar après scroll: position=${sidebarState.position}, top=${sidebarState.top}px`);
|
|
expect(sidebarState.visible,
|
|
`ÉLÉMENT: [data-testid="app-sidebar"] | PAGE: /dashboard | MESURÉ: height=${sidebarState.height}px après scroll | ATTENDU: visible (height > 200px) | FIX TAILWIND: Ajouter fixed ou sticky sur le sidebar`
|
|
).toBe(true);
|
|
}
|
|
});
|
|
|
|
test('Scroller tout en bas ne casse pas le layout', async ({ page }) => {
|
|
await navigateTo(page, '/discover');
|
|
|
|
// Scroller tout en bas
|
|
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
|
await page.waitForTimeout(500);
|
|
|
|
// Vérifier que rien n'est cassé
|
|
const layout = await page.evaluate(() => {
|
|
const body = document.body.textContent || '';
|
|
const hasError = /500|Internal Server Error|undefined|null/.test(body);
|
|
const viewportWidth = document.documentElement.clientWidth;
|
|
const scrollWidth = document.documentElement.scrollWidth;
|
|
return {
|
|
hasError,
|
|
horizontalOverflow: scrollWidth > viewportWidth + 5,
|
|
bodyLength: body.length,
|
|
};
|
|
});
|
|
|
|
expect(layout.hasError, 'Erreur visible après scroll tout en bas').toBe(false);
|
|
expect(layout.horizontalOverflow,
|
|
`Scroll horizontal apparu après scroll vertical. scrollWidth=${await page.evaluate(() => document.documentElement.scrollWidth)}px > viewport`
|
|
).toBe(false);
|
|
});
|
|
|
|
test('Sidebar scrollable si contenu dépasse', async ({ page }) => {
|
|
await page.setViewportSize({ width: 1440, height: 600 }); // Hauteur réduite pour forcer le scroll
|
|
await navigateTo(page, '/dashboard');
|
|
|
|
const sidebarScroll = await page.evaluate(() => {
|
|
const sidebar = document.querySelector('[data-testid="app-sidebar"]');
|
|
if (!sidebar) return null;
|
|
const nav = sidebar.querySelector('nav') || sidebar;
|
|
return {
|
|
scrollHeight: nav.scrollHeight,
|
|
clientHeight: nav.clientHeight,
|
|
isScrollable: nav.scrollHeight > nav.clientHeight + 10,
|
|
overflow: getComputedStyle(nav).overflowY,
|
|
};
|
|
});
|
|
|
|
if (sidebarScroll && sidebarScroll.isScrollable) {
|
|
console.log(`[SCROLL] Sidebar nav scrollable: ${sidebarScroll.scrollHeight}px content dans ${sidebarScroll.clientHeight}px container, overflow=${sidebarScroll.overflow}`);
|
|
expect(['auto', 'scroll', 'overlay']).toContain(sidebarScroll.overflow);
|
|
}
|
|
});
|
|
});
|