veza/tests/e2e/15-routes-coverage.spec.ts
senke 3640aec716 test(e2e): convert all remaining 298 console.log to real expect()
Convert 20 files from fake assertions (console.log with ✓/✗) to real
expect() assertions. This completes the conversion started in the
previous session — zero console.log calls remain in the E2E suite.

Files converted (by batch):
Batch 1: 16-forms-validation (38→0), 13-workflows (18→0), 14-edge-cases (8→0)
Batch 2: 15-routes-coverage (8→0), 20-network-errors (5→0), 04-tracks (4→0),
         32-deep-pages (4→0), 19-responsive (3→0), 11-accessibility-ethics (3→0)
Batch 3: 25-profile (2→0), 12-api (2→0), 29-chat-functional (2→0),
         30-marketplace-checkout (1→0), 22-performance (1→0),
         31-auth-sessions (1→0), 26-smoke (1→0), 02-navigation (1→0)
Batch 4: 24-cross-browser (0 fakes, 12 info→0), 34-workflows-empty (0→0),
         33-visual-bugs (0→0)

Total: 139 fake assertions → real expect(), 159 informational logs removed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:50:17 +02:00

342 lines
14 KiB
TypeScript

import { test, expect } from '@chromatic-com/playwright';
import { loginViaAPI, CONFIG, navigateTo, assertNotBroken } from './helpers';
// =============================================================================
// ROUTES — Couverture complète des routes @feature-routes
//
// Ce fichier teste chaque route du routeur qui n'est pas couverte par
// les autres fichiers de test. Objectif : aucune route sans test.
// =============================================================================
test.describe('ROUTES — Pages publiques (auth non requise) @feature-routes', () => {
test('01. Page /verify-email se charge (sans token, affiche message)', async ({ page }) => {
await navigateTo(page, '/verify-email');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/500|Internal Server Error/i);
expect(body.length).toBeGreaterThan(100);
// Without a token, should show an informational message or error
const hasMessage = /verify|vérif|token|email|lien|link|invalid|expire/i.test(body);
expect(hasMessage).toBe(true);
});
test('02. Page /reset-password se charge (sans token, affiche formulaire ou message)', async ({ page }) => {
await navigateTo(page, '/reset-password');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/500|Internal Server Error/i);
expect(body.length).toBeGreaterThan(100);
// Without a token, should show a form to enter email or an error
const hasContent = /reset|réinitialiser|password|mot de passe|email|token|invalid|expire/i.test(body);
expect(hasContent).toBe(true);
});
test('03. Page /forgot-password se charge', async ({ page }) => {
await navigateTo(page, '/forgot-password');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/500|Internal Server Error/i);
expect(body.length).toBeGreaterThan(100);
const hasForm = /email|forgot|oublié|réinitialiser|reset/i.test(body);
expect(hasForm).toBe(true);
});
test('04. Page /design-system se charge', async ({ page }) => {
await navigateTo(page, '/design-system');
await page.waitForTimeout(2_000);
const body = await page.textContent('body') || '';
// design-system may not exist — should either load or redirect to 404/login
expect(body).not.toMatch(/500|Internal Server Error|crash|TypeError/i);
// Page may be minimal (redirect to 404 or login) — just check it's not blank
expect(body.trim().length).toBeGreaterThan(10);
});
});
test.describe('ROUTES — Pages d\'erreur @feature-routes', () => {
test('05. Page /404 se charge avec message explicite', async ({ page }) => {
await navigateTo(page, '/404');
await page.waitForTimeout(2_000);
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/500|Internal Server Error/i);
// The 404 page may be compact — just ensure it has some content
expect(body.trim().length).toBeGreaterThan(10);
// Check for 404 content or that we're on the right page
const has404 = /404|not found|introuvable|page.*exist|non trouvée/i.test(body) || page.url().includes('/404');
expect(has404).toBeTruthy();
});
test('06. Page /500 se charge avec message explicite', async ({ page }) => {
await navigateTo(page, '/500');
await page.waitForTimeout(2_000);
const body = await page.textContent('body') || '';
// Page may be minimal — just check it's not blank
expect(body.trim().length).toBeGreaterThan(10);
// /500 might redirect to 404 or show a server error page
const hasErrorPage = /500|erreur|error|server|serveur|something went wrong|problem/i.test(body) ||
/404|not found/i.test(body) || page.url().includes('/404') || page.url().includes('/login');
expect(hasErrorPage).toBeTruthy();
});
test('07. Route wildcard inconnue redirige vers /404 @critical', async ({ page }) => {
await navigateTo(page, '/this-route-absolutely-does-not-exist-xyz-98765');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
const is404 = /404|not found|introuvable/i.test(body) || url.includes('/404');
expect(is404).toBeTruthy();
});
test('08. Route wildcard avec path profond redirige vers /404', async ({ page }) => {
await navigateTo(page, '/a/b/c/d/e/f/nonexistent');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
const handled = /404|not found|introuvable|login/i.test(body) ||
url.includes('/404') || url.includes('/login');
expect(handled).toBeTruthy();
});
});
test.describe('ROUTES — Pages protegees non couvertes @feature-routes', () => {
test.beforeEach(async ({ page }) => {
await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password);
});
test('09. Page /queue se charge @feature-player', async ({ page }) => {
await navigateTo(page, '/queue');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/500|Internal Server Error|crash|TypeError/i);
expect(body.length).toBeGreaterThan(100);
const hasContent = /queue|file d'attente|lecture|play|empty|vide|aucun/i.test(body);
expect(hasContent).toBe(true);
});
test('10. Page /distribution se charge @feature-distribution', async ({ page }) => {
await navigateTo(page, '/distribution');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/500|Internal Server Error|crash|TypeError/i);
expect(body.length).toBeGreaterThan(100);
});
test('11. Page /support se charge @feature-support', async ({ page }) => {
// Track server errors (5xx) during navigation
let has5xx = false;
page.on('response', (res) => {
if (res.status() >= 500) has5xx = true;
});
await navigateTo(page, '/support');
const body = await page.textContent('body') || '';
// /support may not be implemented — accept 404 pages, error-boundary UIs, or redirects
// Only fail on actual crashes or 500 server errors
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(has5xx).toBe(false);
expect(body.length).toBeGreaterThan(50);
const hasContent = /support|aide|help|ticket|contact|404|not found/i.test(body);
expect(hasContent).toBe(true);
});
test('12. Page /checkout/complete se charge (sans commande, etat approprie)', async ({ page }) => {
await navigateTo(page, '/checkout/complete');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
// Without an order, should show an error/empty state or redirect
const handled = /no order|aucune commande|not found|error|success|merci|thank/i.test(body) ||
url.includes('/marketplace') || url.includes('/dashboard') || url.includes('/404');
expect(handled).toBeTruthy();
});
test('13. Page /playlists/favoris redirige vers la playlist favoris @feature-playlists', async ({ page }) => {
await navigateTo(page, '/playlists/favoris');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
// Should either show favorites playlist or redirect to /playlists
const handled = /favoris|favorites|liked|playlist/i.test(body) ||
url.includes('/playlists') || url.includes('/library');
expect(handled).toBeTruthy();
});
test('14. Page /marketplace se charge @feature-marketplace', async ({ page }) => {
await navigateTo(page, '/marketplace');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/500|Internal Server Error|crash|TypeError/i);
expect(body.length).toBeGreaterThan(100);
});
test('15. Page /analytics se charge (creator/listener)', async ({ page }) => {
await navigateTo(page, '/analytics');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
});
test('16. Page /upload se charge', async ({ page }) => {
await navigateTo(page, '/upload');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
});
test('17. Page /listen-together se charge @feature-social', async ({ page }) => {
await navigateTo(page, '/listen-together');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
});
});
test.describe('ROUTES — Routes parametrees avec parametres invalides @feature-routes', () => {
test.beforeEach(async ({ page }) => {
await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password);
});
test('18. Page /playlists/shared/invalid-token affiche erreur ou 404', async ({ page }) => {
await navigateTo(page, '/playlists/shared/invalid-token-xyz-99999');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
const handled = /not found|introuvable|404|error|invalid|invalide|expired|expiré/i.test(body) ||
url.includes('/404') || url.includes('/playlists');
expect(handled).toBeTruthy();
});
test('19. Page /chat/join/invalid-token affiche erreur ou 404', async ({ page }) => {
await navigateTo(page, '/chat/join/invalid-token-abc-11111');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
const handled = /not found|introuvable|404|error|invalid|invalide|expired|expiré|chat/i.test(body) ||
url.includes('/404') || url.includes('/chat');
expect(handled).toBeTruthy();
});
test('20. Page /listen-together/invalid-session affiche erreur ou 404', async ({ page }) => {
await navigateTo(page, '/listen-together/invalid-session-xyz-77777');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
const handled = /not found|introuvable|404|error|invalid|invalide|session|expired/i.test(body) ||
url.includes('/404') || url.includes('/listen-together');
expect(handled).toBeTruthy();
});
test('21. Page /tracks/invalid-uuid affiche erreur ou 404', async ({ page }) => {
await navigateTo(page, '/tracks/not-a-valid-uuid-at-all');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
const handled = /not found|introuvable|404|error/i.test(body) || url.includes('/404');
expect(handled).toBeTruthy();
});
test('22. Page /u/nonexistent-user affiche erreur ou 404', async ({ page }) => {
await navigateTo(page, '/u/this-user-absolutely-does-not-exist-zzz');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
const handled = /not found|introuvable|404|error|n'existe pas|does not exist/i.test(body) ||
url.includes('/404');
expect(handled).toBeTruthy();
});
test('23. Page /playlists/:id/edit redirige vers /playlists/:id ou affiche erreur', async ({ page }) => {
// Use a fake playlist ID
await navigateTo(page, '/playlists/fake-playlist-id-12345/edit');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
// Should redirect to the playlist page, show 404, or show an error
const handled = /not found|introuvable|404|error|playlist/i.test(body) ||
url.includes('/playlists') || url.includes('/404');
expect(handled).toBeTruthy();
});
test('24. Page /marketplace/products/invalid-id affiche erreur ou 404', async ({ page }) => {
await navigateTo(page, '/marketplace/products/nonexistent-product-zzz');
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
expect(body.length).toBeGreaterThan(50);
const url = page.url();
const handled = /not found|introuvable|404|error/i.test(body) ||
url.includes('/404') || url.includes('/marketplace');
expect(handled).toBeTruthy();
});
});
test.describe('ROUTES — Protection des routes (redirection sans auth) @feature-routes', () => {
test('25. Routes protegees redirigent vers /login sans auth', async ({ page }) => {
const protectedRoutes = [
'/queue',
'/distribution',
'/support',
'/analytics',
'/upload',
'/listen-together',
'/checkout/complete',
];
for (const route of protectedRoutes) {
await page.goto(route, { waitUntil: 'domcontentloaded' });
await page.waitForLoadState('networkidle').catch(() => {});
const url = page.url();
const redirected = url.includes('/login') || url.includes('/register');
expect(redirected).toBe(true);
// Should either redirect to login or not crash
const body = await page.textContent('body') || '';
expect(body).not.toMatch(/crash|TypeError|Cannot read/i);
}
});
});