Plan UI premium 6–8 semaines (design system, shell, Storybook, a11y): - Design system: DESIGN_TOKENS.md, APP_SHELL.md, FULL_LAYOUT_PAGE.md. Single source for layout/shell (index.css), shadows (design-system.css), durations/easing. - Tokens: shadow-cover-depth, shadow-gold-glow, shadow-fab-glow; layout max-height (max-h-layout-drawer, max-h-layout-panel, max-h-layout-list). All duration-200/300/500 replaced by --duration-fast/normal/slow. Arbitrary shadows replaced by token classes. - Shell & player: Sidebar, Header, GlobalPlayer, MiniPlayer, PlayerQueue, PlayerControls, AudioPlayer use tokens; focus-visible on Sidebar, PlayerQueue, DropdownMenuTrigger/Item, TabsTrigger. Typography: text-[10px]/[9px] → text-xs where applicable. - ESLint: no-restricted-syntax (warn) for w-/h-/rounded-/shadow-/text-/spacing arbitrary. - Scripts: report-arbitrary-values.mjs, capture/compare/generate visual; visual-complete.spec.ts. - Stories full layout: Dashboard, Playlists, Library, Settings, Profile in DashboardLayout.stories. - .cursorrules + README: DESIGN_TOKENS, APP_SHELL, visual commands, no arbitrary without justification. - apps/web/.gitignore: e2e test artifacts (test-results-visual, playwright-report-visual). Co-authored-by: Cursor <cursoragent@cursor.com>
78 lines
2.2 KiB
TypeScript
78 lines
2.2 KiB
TypeScript
import { defineConfig, devices } from '@playwright/test';
|
||
import path from 'path';
|
||
|
||
/**
|
||
* Playwright config for pixel-perfect visual regression (capture & compare).
|
||
*
|
||
* - Viewport fixe 1280×720, dark mode forcé, reduced motion.
|
||
* - Désactivation des animations CSS via inject-style (fixture / beforeEach).
|
||
* - Sortie : visual-tests/current/ (capture) ou visual-tests/baselines/ (update).
|
||
*
|
||
* Usage:
|
||
* npm run visual:capture → écrit dans visual-tests/current/
|
||
* npm run visual:update → écrit dans visual-tests/baselines/
|
||
* npm run visual:compare → script generate-visual-report.mjs (baselines vs current)
|
||
*/
|
||
const VIEWPORT = { width: 1280, height: 720 };
|
||
const THEME = 'dark';
|
||
const VIEWPORT_LABEL = 'desktop';
|
||
|
||
export const visualOutputDir = process.env.VISUAL_UPDATE_BASELINES
|
||
? path.join(process.cwd(), 'visual-tests', 'baselines')
|
||
: path.join(process.cwd(), 'visual-tests', 'current');
|
||
|
||
export function screenshotName(screenName: string): string {
|
||
return `${screenName}-${VIEWPORT_LABEL}-${THEME}.png`;
|
||
}
|
||
|
||
export default defineConfig({
|
||
testDir: './e2e',
|
||
testMatch: /visual-complete\.spec\.ts/,
|
||
fullyParallel: false,
|
||
forbidOnly: !!process.env.CI,
|
||
retries: process.env.CI ? 1 : 0,
|
||
workers: 1,
|
||
timeout: 45000,
|
||
|
||
outputDir: 'e2e/test-results-visual',
|
||
reporter: [
|
||
['html', { outputFolder: 'e2e/playwright-report-visual', open: 'never' }],
|
||
['list'],
|
||
],
|
||
|
||
use: {
|
||
baseURL: process.env.PLAYWRIGHT_BASE_URL || process.env.VITE_FRONTEND_URL || 'http://localhost:5173',
|
||
trace: 'on-first-retry',
|
||
screenshot: 'only-on-failure',
|
||
video: 'off',
|
||
viewport: VIEWPORT,
|
||
deviceScaleFactor: 1,
|
||
isMobile: false,
|
||
hasTouch: false,
|
||
locale: 'en-US',
|
||
timezoneId: 'Europe/Paris',
|
||
reducedMotion: 'reduce',
|
||
colorScheme: 'dark',
|
||
storageState: process.env.VISUAL_NO_AUTH ? undefined : 'e2e/.auth/user.json',
|
||
},
|
||
|
||
projects: [
|
||
{
|
||
name: 'chromium-desktop',
|
||
use: {
|
||
...devices['Desktop Chrome'],
|
||
viewport: VIEWPORT,
|
||
deviceScaleFactor: 1,
|
||
reducedMotion: 'reduce',
|
||
colorScheme: 'dark',
|
||
},
|
||
},
|
||
],
|
||
|
||
webServer: {
|
||
command: 'npm run dev',
|
||
url: 'http://localhost:5173',
|
||
reuseExistingServer: true,
|
||
timeout: 120_000,
|
||
},
|
||
});
|