- 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>
99 lines
3.9 KiB
TypeScript
99 lines
3.9 KiB
TypeScript
import { test, expect } from '@chromatic-com/playwright';
|
|
import { loginViaAPI, navigateTo } from '../helpers';
|
|
import { checkAlignment } from '../helpers/visual-helpers';
|
|
import { TEST_USERS, ROUTES } from '../design-tokens';
|
|
|
|
test.describe('SPACING & ALIGNEMENT — Espacement régulier et éléments alignés', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, TEST_USERS.listener.email, TEST_USERS.listener.password);
|
|
});
|
|
|
|
test('Dashboard — les sections sont alignées et espacées', async ({ page }) => {
|
|
await navigateTo(page, '/dashboard');
|
|
|
|
// Trouver les conteneurs de grille
|
|
const gridContainers = await page.locator('main [class*="grid"], main [class*="flex"][class*="gap"]').all();
|
|
|
|
const allIssues: string[] = [];
|
|
for (const container of gridContainers.slice(0, 8)) {
|
|
try {
|
|
const selector = await container.evaluate(el => {
|
|
const testid = el.getAttribute('data-testid');
|
|
if (testid) return `[data-testid="${testid}"]`;
|
|
const classes = (typeof el.className === 'string' ? el.className : '').split(' ').slice(0, 3).join('.');
|
|
return `.${classes}`;
|
|
});
|
|
|
|
const issues = await checkAlignment(page, selector);
|
|
for (const issue of issues) {
|
|
if (issue.issue.includes('Désalignement')) {
|
|
allIssues.push(`${selector}: ${issue.issue}\nFIX: ${issue.fix}`);
|
|
console.log(`[ALIGNMENT] ${selector}: ${issue.issue}`);
|
|
console.log(` FIX: ${issue.fix}`);
|
|
}
|
|
}
|
|
} catch {
|
|
/* skip */
|
|
}
|
|
}
|
|
|
|
expect(allIssues.length,
|
|
`Problèmes d'alignement sur /dashboard:\n${allIssues.join('\n')}`
|
|
).toBe(0);
|
|
});
|
|
|
|
test('Discover — les track cards sont toutes de la même taille', async ({ page }) => {
|
|
await navigateTo(page, '/discover');
|
|
|
|
const cards = await page.locator('[role="article"]').all();
|
|
if (cards.length < 2) {
|
|
console.log('Moins de 2 track cards sur /discover — test non applicable');
|
|
return;
|
|
}
|
|
|
|
const sizes = await Promise.all(cards.slice(0, 20).map(async card => {
|
|
const box = await card.boundingBox();
|
|
return box ? { width: Math.round(box.width), height: Math.round(box.height) } : null;
|
|
}));
|
|
|
|
const validSizes = sizes.filter(Boolean) as { width: number; height: number }[];
|
|
if (validSizes.length < 2) return;
|
|
|
|
const widths = validSizes.map(s => s.width);
|
|
const widthDiff = Math.max(...widths) - Math.min(...widths);
|
|
|
|
expect(widthDiff,
|
|
`Largeurs de cards inconsistantes sur /discover: min=${Math.min(...widths)}px max=${Math.max(...widths)}px diff=${widthDiff}px. ` +
|
|
`FIX: Utiliser grid-cols-* avec fr units pour des largeurs uniformes.`
|
|
).toBeLessThan(5);
|
|
});
|
|
|
|
// Vérifier le padding du contenu principal sur chaque page
|
|
for (const route of ROUTES.listener.slice(0, 10)) {
|
|
test(`${route.name} (${route.path}) — le contenu principal a un padding suffisant`, async ({ page }) => {
|
|
await navigateTo(page, route.path);
|
|
|
|
const mainPadding = await page.evaluate(() => {
|
|
const main = document.querySelector('main, [role="main"]');
|
|
if (!main) return null;
|
|
const style = getComputedStyle(main);
|
|
return {
|
|
top: parseFloat(style.paddingTop),
|
|
right: parseFloat(style.paddingRight),
|
|
bottom: parseFloat(style.paddingBottom),
|
|
left: parseFloat(style.paddingLeft),
|
|
};
|
|
});
|
|
|
|
if (mainPadding) {
|
|
expect(mainPadding.left,
|
|
`Padding gauche insuffisant sur ${route.path}: ${mainPadding.left}px. FIX: Ajouter px-4 (16px) minimum au conteneur principal.`
|
|
).toBeGreaterThanOrEqual(8);
|
|
|
|
expect(mainPadding.right,
|
|
`Padding droite insuffisant sur ${route.path}: ${mainPadding.right}px. FIX: Ajouter px-4 (16px) minimum au conteneur principal.`
|
|
).toBeGreaterThanOrEqual(8);
|
|
}
|
|
});
|
|
}
|
|
});
|