import { isValidElement } from 'react'; import { Navigate } from 'react-router'; import { expect, it } from 'vitest'; import { routes } from './routes'; // scripts/shot.mjs keeps ITS OWN list of routes — Node cannot load TSX without a build, // and that is a deliberate trade for simplicity. The price of the trade: a new screen forgotten // in shot.mjs is neither photographed nor checked by axe, while `npm run shot` still returns // success. A lock is cheaper than discipline: a divergence of the two lists fails as a test. const shot = Object.values( import.meta.glob('../scripts/shot.mjs', { query: '?raw', eager: true, import: 'default' }), )[0] as string; it('the list of routes in scripts/shot.mjs matches routes.tsx', () => { const declared = /const KNOWN_ROUTES = \[(.*?)\];/s.exec(shot)?.[1]; expect(declared, 'KNOWN_ROUTES not found in scripts/shot.mjs').toBeDefined(); const known = [...(declared as string).matchAll(/'([^']+)'/g)].map((m) => m[1]); // There is nothing to photograph in a redirect: it has no screen of its own. const screens = routes .filter((route) => !(isValidElement(route.element) && route.element.type === Navigate)) .map((route) => route.path) .filter((path) => path !== undefined); expect(known.toSorted()).toEqual(screens.toSorted()); });