// Rendu headless de chaque écran, avec les données de démonstration // préchargées, pour vérifier que la chaîne API → sélecteurs → rendu ne lève pas. // Lancement : npx tsx --tsconfig tsconfig.app.json scripts/smoke.tsx import { createElement } from 'react'; import { renderToString } from 'react-dom/server'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { RouterProvider, createMemoryRouter } from 'react-router-dom'; import { EDITION_ID, api } from '@/api'; import { queryKeys } from '@/api/hooks'; import { routes } from '@/app/router'; const paths = [ '/grille', '/benevoles', '/publication', '/mobile-benevole', '/mobile-referent', '/configuration', ]; async function prefetch(client: QueryClient) { const e = EDITION_ID; await Promise.all([ client.prefetchQuery({ queryKey: queryKeys.volunteers, queryFn: () => api.volunteers.list(e) }), client.prefetchQuery({ queryKey: queryKeys.positions, queryFn: () => api.positions.list(e) }), client.prefetchQuery({ queryKey: queryKeys.shifts(), queryFn: () => api.shifts.list(e) }), client.prefetchQuery({ queryKey: queryKeys.assignments(), queryFn: () => api.assignments.list(e) }), client.prefetchQuery({ queryKey: queryKeys.matrix, queryFn: () => api.matrix.get(e) }), ]); } async function checkMockApi() { const e = EDITION_ID; const [volunteers, positions, shifts, assignments, matrix] = await Promise.all([ api.volunteers.list(e), api.positions.list(e), api.shifts.list(e), api.assignments.list(e), api.matrix.get(e), ]); const openShift = matrix.positions.flatMap((p) => p.shifts).find((s) => s.confirmed + s.proposed < s.min_staff); const candidate = volunteers.find( (v) => !assignments.some((a) => a.shift_id === openShift?.shift_id && a.volunteer_id === v.id), ); const validation = openShift && candidate ? await api.assignments.validate(e, { volunteer_id: candidate.id, shift_id: openShift.shift_id }) : { blocking: false, violations: [] }; let dupError = 'none'; const existing = assignments[0]; try { await api.assignments.create(e, { volunteer_id: existing.volunteer_id, shift_id: existing.shift_id }); } catch (err) { dupError = err instanceof Error ? err.message : String(err); } console.log( JSON.stringify( { volunteers: volunteers.length, positions: positions.length, shifts: shifts.length, assignments: assignments.length, matrixPositions: matrix.positions.length, matrixShifts: matrix.positions.reduce((n, p) => n + p.shifts.length, 0), sampleValidation: validation.violations.map((v) => v.code), duplicateCreateRejectedWith: dupError, }, null, 2, ), ); } let failures = 0; await checkMockApi().catch((err) => { failures += 1; console.error('FAIL checkMockApi', err); }); for (const path of paths) { try { const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }); await prefetch(client); const router = createMemoryRouter(routes, { initialEntries: [path] }); const html = renderToString( createElement(QueryClientProvider, { client }, createElement(RouterProvider, { router })), ); console.log(`ok ${path.padEnd(20)} ${html.length} octets`); } catch (error) { failures += 1; console.error(`FAIL ${path}`, error); } } process.exit(failures ? 1 : 0);