- Update E2E test credentials to match actual seed users (user@veza.music, artist@veza.music, admin@veza.music, mod@veza.music) - Fix hardcoded "Suggested Accounts" in SuggestionsWidget with i18n key - Replace hardcoded amelie_dubois references with CONFIG.users.creator - Refactor auth, player, upload E2E tests for reliability - Add tmt test plans and scripts for CI integration - Simplify CI workflow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
769 lines
24 KiB
TypeScript
769 lines
24 KiB
TypeScript
// =============================================================================
|
|
// SUMI DESIGN SYSTEM v2.0 — Source de vérité pour les tests audit
|
|
// Extrait de : apps/web/src/index.css + tailwind.config.ts + composants
|
|
// =============================================================================
|
|
|
|
// =============================================================================
|
|
// COULEURS
|
|
// =============================================================================
|
|
|
|
export const COLORS = {
|
|
dark: {
|
|
bg: {
|
|
void: '#0c0c0f',
|
|
base: '#121215',
|
|
raised: '#1a1a1f',
|
|
overlay: '#222228',
|
|
hover: '#2a2a31',
|
|
active: '#32323a',
|
|
wash: '#18181d',
|
|
},
|
|
surface: {
|
|
inset: '#101013',
|
|
subtle: '#1e1e24',
|
|
card: '#1a1a1f',
|
|
elevated: '#242430',
|
|
},
|
|
border: {
|
|
faint: 'rgba(255,255,255, 0.06)',
|
|
default: 'rgba(255,255,255, 0.10)',
|
|
strong: 'rgba(255,255,255, 0.16)',
|
|
focus: 'rgba(139,170,220, 0.50)',
|
|
accent: 'rgba(139,170,220, 0.30)',
|
|
},
|
|
text: {
|
|
primary: '#f0ede8',
|
|
secondary: '#a8a4a0',
|
|
tertiary: '#706c68',
|
|
disabled: '#4a4844',
|
|
inverse: '#121215',
|
|
link: '#8baade',
|
|
},
|
|
accent: {
|
|
DEFAULT: '#7c9dd6',
|
|
hover: '#93afe0',
|
|
active: '#6b8dc6',
|
|
muted: 'rgba(124,157,214, 0.20)',
|
|
subtle: 'rgba(124,157,214, 0.12)',
|
|
emphasis: '#5a7fba',
|
|
},
|
|
vermillion: {
|
|
DEFAULT: '#d4634a',
|
|
hover: '#de7a64',
|
|
subtle: 'rgba(212,99,74, 0.12)',
|
|
},
|
|
sage: {
|
|
DEFAULT: '#7a9e6c',
|
|
hover: '#8eb280',
|
|
subtle: 'rgba(122,158,108, 0.12)',
|
|
},
|
|
gold: {
|
|
DEFAULT: '#c9a84c',
|
|
hover: '#d6b860',
|
|
subtle: 'rgba(201,168,76, 0.12)',
|
|
},
|
|
live: '#e05a5a',
|
|
shadows: {
|
|
xs: '0 1px 2px rgba(0,0,0,0.30)',
|
|
sm: '0 2px 4px rgba(0,0,0,0.25), 0 1px 2px rgba(0,0,0,0.20)',
|
|
md: '0 4px 12px rgba(0,0,0,0.30), 0 2px 4px rgba(0,0,0,0.15)',
|
|
lg: '0 8px 24px rgba(0,0,0,0.35), 0 4px 8px rgba(0,0,0,0.20)',
|
|
xl: '0 16px 48px rgba(0,0,0,0.40), 0 8px 16px rgba(0,0,0,0.20)',
|
|
'2xl': '0 24px 64px rgba(0,0,0,0.50)',
|
|
glow: '0 0 0 3px rgba(124,157,214,0.25)',
|
|
glowLg: '0 0 20px rgba(124,157,214,0.15)',
|
|
},
|
|
glass: {
|
|
bg: 'rgba(18,18,21, 0.80)',
|
|
border: 'rgba(255,255,255, 0.08)',
|
|
blur: '12px',
|
|
},
|
|
scrollbar: {
|
|
track: 'transparent',
|
|
thumb: 'rgba(255,255,255, 0.10)',
|
|
hover: 'rgba(255,255,255, 0.18)',
|
|
},
|
|
},
|
|
light: {
|
|
bg: {
|
|
void: '#f0ece4',
|
|
base: '#f6f3ed',
|
|
raised: '#ffffff',
|
|
overlay: '#ffffff',
|
|
hover: '#ede9e1',
|
|
active: '#e4e0d8',
|
|
wash: '#f8f6f1',
|
|
},
|
|
surface: {
|
|
inset: '#ebe7df',
|
|
subtle: '#f2eee6',
|
|
card: '#ffffff',
|
|
elevated: '#ffffff',
|
|
},
|
|
border: {
|
|
faint: 'rgba(0,0,0, 0.05)',
|
|
default: 'rgba(0,0,0, 0.10)',
|
|
strong: 'rgba(0,0,0, 0.18)',
|
|
focus: 'rgba(80,110,170, 0.45)',
|
|
accent: 'rgba(80,110,170, 0.25)',
|
|
},
|
|
text: {
|
|
primary: '#1a1816',
|
|
secondary: '#5c5854',
|
|
tertiary: '#8a8580',
|
|
disabled: '#b5b0aa',
|
|
inverse: '#f0ede8',
|
|
link: '#4a6fa5',
|
|
},
|
|
accent: {
|
|
DEFAULT: '#4a6fa5',
|
|
hover: '#3a5f95',
|
|
active: '#5a7fb5',
|
|
subtle: 'rgba(74,111,165, 0.12)',
|
|
muted: 'rgba(74,111,165, 0.20)',
|
|
emphasis: '#3d5f90',
|
|
},
|
|
vermillion: {
|
|
DEFAULT: '#b84a35',
|
|
hover: '#a03e2e',
|
|
subtle: 'rgba(184,74,53, 0.12)',
|
|
},
|
|
sage: {
|
|
DEFAULT: '#5a7e4e',
|
|
hover: '#4d6e42',
|
|
subtle: 'rgba(90,126,78, 0.12)',
|
|
},
|
|
gold: {
|
|
DEFAULT: '#9a7d2e',
|
|
hover: '#8a6d20',
|
|
subtle: 'rgba(154,125,46, 0.12)',
|
|
},
|
|
live: '#c84040',
|
|
shadows: {
|
|
xs: '0 1px 2px rgba(0,0,0,0.05)',
|
|
sm: '0 2px 4px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)',
|
|
md: '0 4px 12px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04)',
|
|
lg: '0 8px 24px rgba(0,0,0,0.10), 0 4px 8px rgba(0,0,0,0.05)',
|
|
xl: '0 16px 48px rgba(0,0,0,0.12), 0 8px 16px rgba(0,0,0,0.06)',
|
|
'2xl': '0 24px 64px rgba(0,0,0,0.15)',
|
|
glow: '0 0 0 3px rgba(74,111,165,0.25)',
|
|
},
|
|
glass: {
|
|
bg: 'rgba(255,255,255, 0.85)',
|
|
border: 'rgba(0,0,0, 0.06)',
|
|
},
|
|
scrollbar: {
|
|
thumb: 'rgba(0,0,0, 0.12)',
|
|
hover: 'rgba(0,0,0, 0.22)',
|
|
},
|
|
},
|
|
contextual: {
|
|
graffitiMagenta: '#c840a0',
|
|
gamingGold: '#d4b040',
|
|
terminalGreen: '#3eaa5e',
|
|
sakura: '#e0a0b8',
|
|
},
|
|
charts: {
|
|
1: '#7c9dd6', // accent
|
|
2: '#d4634a', // vermillion
|
|
3: '#7a9e6c', // sage
|
|
4: '#c9a84c', // gold
|
|
5: '#8b7ec8', // purple
|
|
},
|
|
semantic: {
|
|
destructiveForeground: '#ffffff',
|
|
successForeground: '#ffffff',
|
|
primaryForeground: '#121215', // dark theme text-inverse
|
|
},
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// TYPOGRAPHIE
|
|
// =============================================================================
|
|
|
|
export const FONTS = {
|
|
heading: {
|
|
family: 'Space Grotesk',
|
|
fallback: "'Space Grotesk', 'Inter', sans-serif",
|
|
weights: [400, 500, 600, 700] as const,
|
|
},
|
|
body: {
|
|
family: 'Inter',
|
|
fallback: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
weights: [300, 400, 500, 600, 700] as const,
|
|
},
|
|
mono: {
|
|
family: 'JetBrains Mono',
|
|
fallback: "'JetBrains Mono', 'SF Mono', 'Consolas', monospace",
|
|
weights: [400, 500, 600] as const,
|
|
},
|
|
serif: {
|
|
family: 'Noto Serif JP',
|
|
fallback: "'Noto Serif JP', Georgia, serif",
|
|
weights: [400, 600] as const,
|
|
},
|
|
sizes: {
|
|
'4xl': '2.25rem', // 36px
|
|
'3xl': '1.875rem', // 30px
|
|
'2xl': '1.5rem', // 24px
|
|
xl: '1.25rem', // 20px
|
|
lg: '1.125rem', // 18px
|
|
md: '1rem', // 16px
|
|
base: '0.875rem', // 14px
|
|
sm: '0.8125rem', // 13px
|
|
xs: '0.75rem', // 12px
|
|
},
|
|
lineHeights: {
|
|
none: '1',
|
|
tight: '1.25',
|
|
snug: '1.375',
|
|
normal: '1.5',
|
|
relaxed: '1.625',
|
|
loose: '1.75',
|
|
},
|
|
letterSpacing: {
|
|
tighter: '-0.03em',
|
|
tight: '-0.015em',
|
|
normal: '0',
|
|
wide: '0.025em',
|
|
wider: '0.05em',
|
|
widest: '0.1em',
|
|
},
|
|
weights: {
|
|
light: 300,
|
|
regular: 400,
|
|
medium: 500,
|
|
semibold: 600,
|
|
bold: 700,
|
|
},
|
|
// SUMI typography presets — class → expected styles
|
|
presets: {
|
|
'sumi-display': { family: 'Space Grotesk', size: '2.25rem', weight: 700, leading: 1.25, tracking: '-0.03em' },
|
|
'sumi-h1': { family: 'Space Grotesk', size: '1.875rem', weight: 600, leading: 1.25, tracking: '-0.015em' },
|
|
'sumi-h2': { family: 'Space Grotesk', size: '1.5rem', weight: 600, leading: 1.375, tracking: '-0.015em' },
|
|
'sumi-h3': { family: 'Space Grotesk', size: '1.25rem', weight: 500, leading: 1.375, tracking: '0' },
|
|
'sumi-h4': { family: 'Space Grotesk', size: '1.125rem', weight: 500, leading: 1.375, tracking: '0' },
|
|
'sumi-body-lg': { family: 'Inter', size: '1rem', weight: 400, leading: 1.625, tracking: '0' },
|
|
'sumi-body': { family: 'Inter', size: '0.875rem', weight: 400, leading: 1.5, tracking: '0' },
|
|
'sumi-body-sm': { family: 'Inter', size: '0.8125rem', weight: 400, leading: 1.5, tracking: '0' },
|
|
'sumi-caption': { family: 'Inter', size: '0.75rem', weight: 400, leading: 1.5, tracking: '0' },
|
|
'sumi-label': { family: 'Inter', size: '0.75rem', weight: 500, leading: 1.5, tracking: '0.05em' },
|
|
'sumi-mono': { family: 'JetBrains Mono', size: '0.8125rem', weight: 400, leading: 1.5, tracking: '0' },
|
|
},
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// ESPACEMENT
|
|
// =============================================================================
|
|
|
|
export const SPACING = {
|
|
normal: {
|
|
'0.5': '2px',
|
|
'1': '4px',
|
|
'1.5': '6px',
|
|
'2': '8px',
|
|
'2.5': '10px',
|
|
'3': '12px',
|
|
'4': '16px',
|
|
'5': '20px',
|
|
'6': '24px',
|
|
'8': '32px',
|
|
'10': '40px',
|
|
'12': '48px',
|
|
'16': '64px',
|
|
'20': '80px',
|
|
},
|
|
compact: {
|
|
'0.5': '1.5px',
|
|
'1': '3px',
|
|
'1.5': '4.5px',
|
|
'2': '6px',
|
|
'2.5': '7.5px',
|
|
'3': '9px',
|
|
'4': '12px',
|
|
'5': '15px',
|
|
'6': '18px',
|
|
'8': '24px',
|
|
'10': '30px',
|
|
'12': '36px',
|
|
'16': '48px',
|
|
'20': '60px',
|
|
},
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// RAYON DE BORDURE
|
|
// =============================================================================
|
|
|
|
export const BORDER_RADIUS = {
|
|
xs: '2px',
|
|
sm: '4px',
|
|
md: '6px', // --radius default
|
|
lg: '12px',
|
|
xl: '16px',
|
|
'2xl': '20px',
|
|
full: '9999px',
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// TRANSITIONS / MOTION
|
|
// =============================================================================
|
|
|
|
export const MOTION = {
|
|
duration: {
|
|
instant: '75ms',
|
|
fast: '150ms',
|
|
normal: '200ms',
|
|
slow: '300ms',
|
|
slower: '500ms',
|
|
},
|
|
easing: {
|
|
default: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
|
|
out: 'cubic-bezier(0.33, 1, 0.68, 1)',
|
|
in: 'cubic-bezier(0.32, 0, 0.67, 0)',
|
|
inOut: 'cubic-bezier(0.65, 0, 0.35, 1)',
|
|
bounce: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
|
|
spring: 'cubic-bezier(0.175, 0.885, 0.32, 1.1)',
|
|
},
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// Z-INDEX
|
|
// =============================================================================
|
|
|
|
export const Z_INDEX = {
|
|
base: 0,
|
|
raised: 10,
|
|
dropdown: 100,
|
|
sticky: 200,
|
|
overlay: 300,
|
|
modal: 400,
|
|
popover: 500,
|
|
toast: 600,
|
|
tooltip: 700,
|
|
max: 999,
|
|
// Application-specific
|
|
sidebarOverlay: 90,
|
|
sidebar: 95,
|
|
player: 200, // var(--sumi-z-sticky)
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// LAYOUT
|
|
// =============================================================================
|
|
|
|
export const LAYOUT = {
|
|
maxWidth: {
|
|
DEFAULT: '1400px',
|
|
content: '1200px',
|
|
narrow: '800px',
|
|
prose: '65ch',
|
|
layoutContent: '100rem',
|
|
},
|
|
header: {
|
|
height: '4rem', // 64px
|
|
},
|
|
sidebar: {
|
|
widthExpanded: '15rem', // 240px
|
|
widthCollapsed: '5rem', // 80px
|
|
offsetLeft: '1.5rem', // 24px
|
|
offsetTop: '5rem', // 80px
|
|
offsetBottom: '1.5rem', // 24px
|
|
},
|
|
player: {
|
|
height: '80px',
|
|
},
|
|
main: {
|
|
offsetTop: '5rem', // 80px
|
|
offsetBottom: '9rem', // 144px
|
|
marginLeftExpanded: '18rem', // 288px
|
|
marginLeftCollapsed: '7rem', // 112px
|
|
minHeight: 'calc(100vh - 4rem)',
|
|
},
|
|
headerLeft: {
|
|
expanded: '18rem', // 288px
|
|
collapsed: '5rem', // 80px
|
|
},
|
|
gaps: {
|
|
DEFAULT: '1rem', // 16px
|
|
sm: '0.75rem', // 12px
|
|
lg: '1.5rem', // 24px
|
|
},
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// BREAKPOINTS
|
|
// =============================================================================
|
|
|
|
export const BREAKPOINTS = {
|
|
sm: 640,
|
|
md: 768,
|
|
lg: 1024, // Principale — sidebar responsive
|
|
xl: 1280,
|
|
'2xl': 1536,
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// VIEWPORTS DE TEST
|
|
// =============================================================================
|
|
|
|
export const VIEWPORTS = {
|
|
mobileSE: { width: 375, height: 667 },
|
|
mobile14: { width: 390, height: 844 },
|
|
mobilePro: { width: 430, height: 932 },
|
|
tablet: { width: 768, height: 1024 },
|
|
tabletLandscape: { width: 1024, height: 768 },
|
|
laptop: { width: 1280, height: 720 },
|
|
desktop: { width: 1440, height: 900 },
|
|
wide: { width: 1920, height: 1080 },
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// ROUTES
|
|
// =============================================================================
|
|
|
|
interface RouteInfo {
|
|
path: string;
|
|
name: string;
|
|
component: string;
|
|
}
|
|
|
|
export const ROUTES = {
|
|
/** Routes publiques — pas d'auth requise, redirige vers /dashboard si connecté */
|
|
public: [
|
|
{ path: '/login', name: 'Login', component: 'LoginPage' },
|
|
{ path: '/register', name: 'Register', component: 'RegisterPage' },
|
|
{ path: '/forgot-password', name: 'Forgot Password', component: 'ForgotPasswordPage' },
|
|
{ path: '/verify-email', name: 'Verify Email', component: 'VerifyEmailPage' },
|
|
{ path: '/reset-password', name: 'Reset Password', component: 'ResetPasswordPage' },
|
|
] satisfies RouteInfo[],
|
|
|
|
/** Routes publiques standalone — pas de layout dashboard */
|
|
publicStandalone: [
|
|
{ path: '/design-system', name: 'Design System', component: 'DesignSystemDemo' },
|
|
// /u/:username et /playlists/shared/:token nécessitent des params dynamiques — testés séparément
|
|
] satisfies RouteInfo[],
|
|
|
|
/** Routes protégées — auth requise, DashboardLayout */
|
|
listener: [
|
|
{ path: '/dashboard', name: 'Dashboard', component: 'DashboardPage' },
|
|
{ path: '/feed', name: 'Feed', component: 'FeedPage' },
|
|
{ path: '/discover', name: 'Discover', component: 'DiscoverPage' },
|
|
{ path: '/library', name: 'Library', component: 'LibraryPage' },
|
|
{ path: '/queue', name: 'Queue', component: 'QueuePage' },
|
|
{ path: '/search', name: 'Search', component: 'SearchPage' },
|
|
{ path: '/profile', name: 'Profile', component: 'UserProfilePage' },
|
|
{ path: '/settings', name: 'Settings', component: 'SettingsPage' },
|
|
{ path: '/settings/sessions', name: 'Sessions', component: 'SessionsPage' },
|
|
{ path: '/notifications', name: 'Notifications', component: 'NotificationsPage' },
|
|
{ path: '/playlists', name: 'Playlists', component: 'PlaylistListPage' },
|
|
{ path: '/social', name: 'Social', component: 'SocialPage' },
|
|
{ path: '/chat', name: 'Chat', component: 'ChatPage' },
|
|
{ path: '/marketplace', name: 'Marketplace', component: 'MarketplacePage' },
|
|
{ path: '/wishlist', name: 'Wishlist', component: 'WishlistPage' },
|
|
{ path: '/purchases', name: 'Purchases', component: 'PurchasesPage' },
|
|
{ path: '/subscription', name: 'Subscription', component: 'SubscriptionPage' },
|
|
{ path: '/live', name: 'Live', component: 'LivePage' },
|
|
{ path: '/cloud', name: 'Cloud', component: 'CloudPage' },
|
|
{ path: '/education', name: 'Education', component: 'EducationPage' },
|
|
{ path: '/support', name: 'Support', component: 'SupportPage' },
|
|
] satisfies RouteInfo[],
|
|
|
|
/** Routes créateur — auth requise, DashboardLayout */
|
|
creator: [
|
|
{ path: '/analytics', name: 'Analytics', component: 'AnalyticsPage' },
|
|
{ path: '/sell', name: 'Seller Dashboard', component: 'SellerDashboardPage' },
|
|
{ path: '/distribution', name: 'Distribution', component: 'DistributionPage' },
|
|
{ path: '/gear', name: 'Gear', component: 'GearPage' },
|
|
{ path: '/live/go-live', name: 'Go Live', component: 'GoLivePage' },
|
|
{ path: '/developer', name: 'Developer', component: 'DeveloperDashboardPage' },
|
|
{ path: '/webhooks', name: 'Webhooks', component: 'WebhooksPage' },
|
|
] satisfies RouteInfo[],
|
|
|
|
/** Routes admin — auth requise, DashboardLayout (autorisations backend) */
|
|
admin: [
|
|
{ path: '/admin', name: 'Admin Dashboard', component: 'AdminDashboardPage' },
|
|
{ path: '/admin/moderation', name: 'Moderation', component: 'AdminModerationPage' },
|
|
{ path: '/admin/platform', name: 'Platform', component: 'AdminPlatformPage' },
|
|
{ path: '/admin/transfers', name: 'Transfers', component: 'AdminTransfersPage' },
|
|
{ path: '/admin/roles', name: 'Roles', component: 'RolesPage' },
|
|
] satisfies RouteInfo[],
|
|
|
|
/** Routes d'erreur */
|
|
error: [
|
|
{ path: '/404', name: 'Not Found', component: 'NotFoundPage' },
|
|
{ path: '/500', name: 'Server Error', component: 'ServerErrorPage' },
|
|
] satisfies RouteInfo[],
|
|
} as const;
|
|
|
|
/** Toutes les routes protégées (listener + creator + admin) */
|
|
export const ALL_PROTECTED_ROUTES = [
|
|
...ROUTES.listener,
|
|
...ROUTES.creator,
|
|
...ROUTES.admin,
|
|
] as const;
|
|
|
|
/** Toutes les routes (public + protégées + erreur) */
|
|
export const ALL_ROUTES = [
|
|
...ROUTES.public,
|
|
...ROUTES.publicStandalone,
|
|
...ROUTES.listener,
|
|
...ROUTES.creator,
|
|
...ROUTES.admin,
|
|
...ROUTES.error,
|
|
] as const;
|
|
|
|
// =============================================================================
|
|
// COMPOSANTS INTERACTIFS — sélecteurs et états attendus
|
|
// =============================================================================
|
|
|
|
export const INTERACTIVE_COMPONENTS = {
|
|
buttons: {
|
|
default: {
|
|
selector: 'button:not([disabled])',
|
|
description: 'Primary CTA — bg-primary text-primary-foreground',
|
|
expectedHover: { cursor: 'pointer' },
|
|
expectedFocus: { outline: '2px solid', outlineOffset: '2px' },
|
|
expectedDisabled: { opacity: '0.5', pointerEvents: 'none' },
|
|
activeScale: '0.95',
|
|
},
|
|
variants: {
|
|
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
primary: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
|
outline: 'border border-border bg-transparent hover:bg-accent hover:text-accent-foreground',
|
|
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
link: 'text-primary underline-offset-4 hover:underline',
|
|
glass: 'bg-white/10 backdrop-blur-xl border border-white/10 text-white hover:bg-white/15',
|
|
},
|
|
sizes: {
|
|
default: { height: '40px', paddingX: '16px', paddingY: '8px' },
|
|
sm: { height: '36px', paddingX: '16px', borderRadius: '9999px', fontSize: '12px' },
|
|
lg: { height: '48px', paddingX: '32px', borderRadius: '9999px', fontSize: '16px' },
|
|
icon: { height: '40px', width: '40px', borderRadius: '9999px' },
|
|
},
|
|
},
|
|
inputs: {
|
|
text: {
|
|
selector: 'input[type="text"], input[type="email"], input[type="password"], input[type="search"], input[type="number"], input[type="tel"], input[type="url"]',
|
|
height: '44px', // h-11
|
|
borderRadius: '12px', // rounded-xl
|
|
expectedFocus: { ring: '2px', ringColor: 'var(--ring)' },
|
|
expectedError: { borderColor: 'var(--destructive)' },
|
|
expectedDisabled: { opacity: '0.5', cursor: 'not-allowed' },
|
|
},
|
|
textarea: {
|
|
selector: 'textarea',
|
|
minHeight: '96px', // min-h-24
|
|
borderRadius: '8px', // rounded-lg
|
|
},
|
|
checkbox: {
|
|
selector: 'input[type="checkbox"]',
|
|
size: '20px', // w-5 h-5
|
|
},
|
|
select: {
|
|
selector: 'select, [role="listbox"], [role="combobox"]',
|
|
},
|
|
},
|
|
modals: {
|
|
backdrop: {
|
|
selector: '[data-dialog-backdrop], .fixed.inset-0',
|
|
expectedBg: 'rgba(0, 0, 0, 0.6)',
|
|
expectedBlur: 'blur(4px)',
|
|
},
|
|
content: {
|
|
selector: '[role="dialog"]',
|
|
expectedZIndex: Z_INDEX.modal,
|
|
sizes: {
|
|
sm: 'max-w-sm',
|
|
md: 'max-w-md',
|
|
lg: 'max-w-2xl',
|
|
xl: 'max-w-4xl',
|
|
full: 'max-w-full',
|
|
},
|
|
},
|
|
},
|
|
toasts: {
|
|
selector: '[data-testid="toast-alert"]',
|
|
types: {
|
|
success: { icon: 'CheckCircle', colorClass: 'lime' },
|
|
error: { icon: 'XCircle', colorClass: 'vermillion' },
|
|
info: { icon: 'Info', colorClass: 'cyan' },
|
|
},
|
|
animation: 'animate-slide-in-right',
|
|
autoDismiss: 4000,
|
|
minWidth: '288px', // min-w-72
|
|
maxWidth: '448px', // max-w-md
|
|
},
|
|
sidebar: {
|
|
selector: '[data-testid="app-sidebar"]',
|
|
widthExpanded: '240px',
|
|
widthCollapsed: '80px',
|
|
zIndex: 95,
|
|
overlayZIndex: 90,
|
|
responsiveBreakpoint: 1024, // lg
|
|
},
|
|
playerBar: {
|
|
selector: '[data-testid="global-player"]',
|
|
height: '80px',
|
|
zIndex: 200,
|
|
controls: {
|
|
playPause: 'button[aria-label*="Play"], button[aria-label*="Pause"], button[aria-label*="Lire"]',
|
|
previous: 'button[aria-label*="Previous"], button[aria-label*="Précédent"]',
|
|
next: 'button[aria-label*="Next"], button[aria-label*="Suivant"]',
|
|
shuffle: 'button[aria-label*="Shuffle"], button[aria-label*="Aléatoire"]',
|
|
repeat: 'button[aria-label*="Repeat"], button[aria-label*="Répéter"]',
|
|
progress: '[role="slider"][aria-label="Progression"]',
|
|
volume: '[data-testid="volume-control"] [role="slider"]',
|
|
},
|
|
},
|
|
cards: {
|
|
track: {
|
|
selector: '[role="article"]',
|
|
description: 'TrackCard — used in TrackGrid on /feed, /discover',
|
|
},
|
|
generic: {
|
|
selector: '[class*="card"], [data-variant="card"]',
|
|
defaultBorderRadius: '12px', // rounded-lg
|
|
},
|
|
},
|
|
dropdowns: {
|
|
container: {
|
|
selector: '[role="menu"], [role="listbox"]',
|
|
expectedZIndex: Z_INDEX.dropdown,
|
|
borderRadius: '12px', // rounded-xl
|
|
},
|
|
},
|
|
slider: {
|
|
selector: '[role="slider"]',
|
|
trackHeight: '4px', // h-1
|
|
trackHoverHeight: '6px', // group-hover:h-1.5
|
|
thumbSize: '20px', // h-5 w-5
|
|
thumbHiddenUntilHover: true,
|
|
},
|
|
avatar: {
|
|
selector: '[class*="avatar"], img[class*="rounded-full"]',
|
|
sizes: {
|
|
xs: '24px', // w-6 h-6
|
|
sm: '32px', // w-8 h-8
|
|
md: '40px', // w-10 h-10
|
|
lg: '48px', // w-12 h-12
|
|
xl: '64px', // w-16 h-16
|
|
'2xl': '96px', // w-24 h-24
|
|
'3xl': '128px', // w-32 h-32
|
|
},
|
|
},
|
|
badge: {
|
|
selector: '[class*="badge"]',
|
|
variants: ['cyan', 'magenta', 'lime', 'gold'],
|
|
sizes: {
|
|
sm: { paddingX: '8px', paddingY: '2px', fontSize: '12px' },
|
|
md: { paddingX: '10px', paddingY: '2px', fontSize: '12px' },
|
|
lg: { paddingX: '16px', paddingY: '4px', fontSize: '12px' },
|
|
},
|
|
},
|
|
switch: {
|
|
selector: '[role="switch"]',
|
|
width: '44px', // w-11
|
|
height: '24px', // h-6
|
|
thumbSize: '20px', // h-5 w-5
|
|
},
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// ACCESSIBILITÉ — critères WCAG
|
|
// =============================================================================
|
|
|
|
export const WCAG = {
|
|
/** Ratio de contraste minimum (WCAG AA) */
|
|
contrastMinNormal: 4.5,
|
|
/** Ratio de contraste minimum pour grand texte (>= 18px ou >= 14px bold) */
|
|
contrastMinLarge: 3.0,
|
|
/** Taille minimale de cible tactile (WCAG 2.5.8) */
|
|
minTouchTarget: 44,
|
|
/** Focus doit être visible */
|
|
focusVisible: {
|
|
outlineWidth: '2px',
|
|
outlineStyle: 'solid',
|
|
outlineOffset: '2px',
|
|
},
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// SÉLECTEURS DE TEST RÉUTILISABLES
|
|
// =============================================================================
|
|
|
|
export const SELECTORS = {
|
|
// Layout
|
|
sidebar: '[data-testid="app-sidebar"]',
|
|
header: 'header, [data-testid="app-header"], [role="banner"]',
|
|
playerBar: '[data-testid="global-player"]',
|
|
mainContent: 'main, [role="main"]',
|
|
|
|
// Auth
|
|
loginForm: '[data-testid="login-form"]',
|
|
registerForm: '[data-testid="register-form"]',
|
|
loginSubmit: '[data-testid="login-submit"]',
|
|
|
|
// Player
|
|
audioElement: '[data-testid="audio-element"]',
|
|
progressBar: '[role="slider"][aria-label="Progression"]',
|
|
volumeSlider: '[data-testid="volume-control"] [role="slider"]',
|
|
|
|
// Content
|
|
trackCard: '[role="article"]',
|
|
searchInput: '[data-testid="search-input"], [role="search"] input, input[type="search"], input[role="searchbox"]',
|
|
|
|
// Feedback
|
|
toast: '[data-testid="toast-alert"]',
|
|
dialog: '[role="dialog"]',
|
|
alert: '[role="alert"]',
|
|
|
|
// Interactive elements (pour overlap/hover/focus tests)
|
|
allInteractive: 'button, a, input, select, textarea, [role="button"], [role="link"], [role="tab"], [role="switch"], [role="slider"], [tabindex]:not([tabindex="-1"])',
|
|
allButtons: 'button:visible, [role="button"]:visible',
|
|
allLinks: 'a[href]:visible',
|
|
allInputs: 'input:visible, textarea:visible, select:visible',
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// COMPTES DE TEST (seed)
|
|
// =============================================================================
|
|
|
|
export const TEST_USERS = {
|
|
listener: {
|
|
email: 'user@veza.music',
|
|
password: 'User123!',
|
|
username: 'music_fan',
|
|
},
|
|
creator: {
|
|
email: 'artist@veza.music',
|
|
password: 'Artist123!',
|
|
username: 'top_artist',
|
|
},
|
|
admin: {
|
|
email: 'admin@veza.music',
|
|
password: 'Admin123!',
|
|
username: 'admin_veza',
|
|
},
|
|
moderator: {
|
|
email: 'mod@veza.music',
|
|
password: 'Mod123!',
|
|
username: 'mod_veza',
|
|
},
|
|
} as const;
|
|
|
|
// =============================================================================
|
|
// TIMEOUTS POUR LES TESTS
|
|
// =============================================================================
|
|
|
|
export const TIMEOUTS = {
|
|
navigation: 15_000,
|
|
action: 5_000,
|
|
animation: 1_000,
|
|
networkIdle: 10_000,
|
|
hoverTransition: 250,
|
|
focusTransition: 150,
|
|
toastDismiss: 5_000,
|
|
} as const;
|