veza/tests/e2e/audit/pixel-perfect/07-borders-radius-shadows.spec.ts
senke 6fad0ad68d fix: stabilize frontend — 98 TS errors to 0, align API endpoints, optimize bundle
- Fix 98 TypeScript errors across 37 files:
  - Service layer double-unwrapping (subscriptionService, distributionService, gearService)
  - Self-referencing variables in SearchPageResults
  - FeedView/ExploreView .posts→.items alignment
  - useQueueSync Zustand subscribe API
  - AdminAuditLogsView missing interface fields
  - Toast proxy type, interceptor type narrowing
  - 22 unused imports/variables removed
  - 5 storybook mock data fixes

- Align frontend API calls with backend endpoints:
  - Analytics: useAnalyticsView now calls /creator/analytics/dashboard (was /analytics)
  - Chat: chatService uses /conversations (was mock data), WS URL from backend token
  - Dashboard StatsSection: uses real /dashboard API data (was hardcoded zeros)
  - Settings: suppress 2FA toast error when endpoint unavailable

- Fix marketplace products: seed uses 'active' status (was 'published')
- Enrich seed: admin follows all creators (feed has content)

- Optimize bundle: vendor catch-all 793KB→318KB gzip (-60%)
  Split into vendor-charts, vendor-emoji, vendor-swagger, vendor-media, etc.

- Clean repo: remove ~100 orphaned screenshots, audit reports, logs from root

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:18:49 +01:00

115 lines
4.8 KiB
TypeScript

import { test, expect } from '@chromatic-com/playwright';
import { loginViaAPI, navigateTo } from '../helpers';
import { TEST_USERS } from '../design-tokens';
test.describe('BORDURES, ARRONDIS & OMBRES — Cohérence visuelle', () => {
test.beforeEach(async ({ page }) => {
await loginViaAPI(page, TEST_USERS.listener.email, TEST_USERS.listener.password);
});
test('Dashboard — les cards ont des border-radius cohérents', async ({ page }) => {
await navigateTo(page, '/dashboard');
const cardRadii = await page.evaluate(() => {
const cards = document.querySelectorAll('[class*="card"], [class*="Card"], [role="article"]');
const radii: Array<{ selector: string; text: string; borderRadius: string }> = [];
cards.forEach(el => {
const style = getComputedStyle(el);
if (style.display === 'none') return;
const br = style.borderRadius;
if (br === '0px') return;
radii.push({
selector: el.getAttribute('data-testid') || (typeof el.className === 'string' ? el.className : '').split(' ').slice(0, 2).join('.'),
text: el.textContent?.trim().slice(0, 20) || '',
borderRadius: br,
});
});
return radii;
});
if (cardRadii.length < 2) return;
// Vérifier la cohérence : toutes les cards du même type devraient avoir le même radius
const uniqueRadii = [...new Set(cardRadii.map(c => c.borderRadius))];
if (uniqueRadii.length > 2) {
console.log(`[RADIUS] ${uniqueRadii.length} border-radius différents sur les cards du dashboard:`);
for (const card of cardRadii) {
console.log(` ${card.selector}: ${card.borderRadius}`);
}
console.log(` FIX: Uniformiser les cards avec rounded-lg (12px) ou rounded-xl (16px)`);
}
// Tolérance de 2 variantes (ex: rounded-lg pour les cards principales, rounded-xl pour les featured)
expect(uniqueRadii.length,
`Trop de border-radius différents (${uniqueRadii.length}) sur les cards: [${uniqueRadii.join(', ')}]. FIX: Uniformiser.`
).toBeLessThanOrEqual(3);
});
test('Boutons — border-radius cohérent par variante', async ({ page }) => {
await navigateTo(page, '/dashboard');
const buttonRadii = await page.evaluate(() => {
const buttons = document.querySelectorAll('button:not([hidden])');
const radii: Array<{ text: string; borderRadius: string; classes: string }> = [];
buttons.forEach(btn => {
const style = getComputedStyle(btn);
if (style.display === 'none' || style.visibility === 'hidden') return;
radii.push({
text: btn.textContent?.trim().slice(0, 20) || btn.getAttribute('aria-label') || '',
borderRadius: style.borderRadius,
classes: (typeof btn.className === 'string' ? btn.className : '').slice(0, 60),
});
});
return radii;
});
// Les boutons devraient utiliser des radius standard du design system
const validRadii = ['4px', '6px', '8px', '12px', '16px', '9999px', '0px'];
const invalidButtons = buttonRadii.filter(b => {
const allCorners = b.borderRadius.split(' ').map(v => v.trim());
return !allCorners.every(corner => validRadii.includes(corner));
});
if (invalidButtons.length > 0) {
console.log(`[RADIUS] Boutons avec border-radius non-standard:`);
for (const b of invalidButtons) {
console.log(` "${b.text}": ${b.borderRadius} — FIX: utiliser rounded-sm (4px), rounded-md (6px), rounded-lg (12px), ou rounded-full (9999px)`);
}
}
});
test('Inputs — tous les champs ont un border radius d\'au moins 6px', async ({ page }) => {
await navigateTo(page, '/settings');
const inputRadii = await page.evaluate(() => {
const inputs = document.querySelectorAll('input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]), textarea, select');
return Array.from(inputs)
.filter(el => getComputedStyle(el).display !== 'none')
.map(el => ({
type: (el as HTMLInputElement).type || el.tagName.toLowerCase(),
name: (el as HTMLInputElement).name || (el as HTMLInputElement).placeholder?.slice(0, 20) || '',
borderRadius: getComputedStyle(el).borderRadius,
}));
});
const tooSharp = inputRadii.filter(i => {
const px = parseFloat(i.borderRadius);
return !isNaN(px) && px < 6;
});
if (tooSharp.length > 0) {
console.log(`[RADIUS] Inputs avec radius < 6px (design system minimum: 6px / rounded-md):`);
for (const i of tooSharp) {
console.log(` input[type="${i.type}"] "${i.name}": ${i.borderRadius} — FIX: utiliser rounded-lg (12px)`);
}
}
expect(tooSharp.length,
`${tooSharp.length} inputs avec border-radius trop petit:\n${tooSharp.map(i => `input[type="${i.type}"] "${i.name}": ${i.borderRadius}`).join('\n')}`
).toBe(0);
});
});