ci(client): lint:format covers the Playwright specs and the client scripts

The check only looked at src/ and tests/, so a new spec under e2e/ or a
new script under scripts/ could land unformatted, and the ratchet scripts
themselves did (fixed in the previous commit). It now walks e2e/ and
scripts/ too and takes .mjs alongside .ts, .tsx and .css. The 58 files
there that were unformatted before this branch (the e2e specs and help
guides, the older build and lint scripts) join the baseline, which keeps
only shrinking; JSON baselines stay out of scope.
This commit is contained in:
Maurice
2026-10-08 12:30:19 +02:00
parent 0344a86aec
commit ead327be73
5 changed files with 94 additions and 7 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ npm run lint:warnings # eslint, failing on any error and on any warning coun
npm run lint:pages # enforce the Page pattern (CI gate)
npm run lint:rtl # physical left/right sides and rtl-lint-disable comments may only shrink per file (CI gate; --list shows them, --update lowers both baselines)
npm run lint:size # no source file or stylesheet past 1000 lines, no test past 2000, counted wrapped at 120 columns; longer ones may only shrink (CI gate; --update lowers the baseline)
npm run lint:format # Prettier: every file outside scripts/format-baseline.json must be formatted, the list only shrinks (CI gate; npx prettier --write <file>, then --update)
npm run lint:format # Prettier: every .ts/.tsx/.mjs/.css file under src/, tests/, e2e/ and scripts/ outside scripts/format-baseline.json must be formatted, the list only shrinks (CI gate; npx prettier --write <file>, then --update)
npm run lint:layers # imports go downwards: components never import pages/ or mobile/, nothing under the views imports a view; per-file counts may only shrink (CI gate; --list, --update)
npm run lint:offline # no view file (components/mobile/pages/hooks) imports src/api/ beyond scripts/offline-baseline.json, which only shrinks (CI gate; --list, --update)
npm run lint:skips # no .only anywhere; skipped/todo/fixme tests per file may only shrink against scripts/skip-baseline.json (CI gate; skipIf/runIf and Playwright's test.skip(condition, 'why') are fine)
+58
View File
@@ -1,4 +1,62 @@
[
"e2e/auth.setup.ts",
"e2e/create-trip.spec.ts",
"e2e/dashboard.spec.ts",
"e2e/dates.ts",
"e2e/help/admin.guide.ts",
"e2e/help/atlas.guide.ts",
"e2e/help/collections.guide.ts",
"e2e/help/dashboard.guide.ts",
"e2e/help/dawarich-track.ts",
"e2e/help/external.ts",
"e2e/help/fixtures.ts",
"e2e/help/guide.ts",
"e2e/help/journey.guide.ts",
"e2e/help/promote.mjs",
"e2e/help/run.mjs",
"e2e/help/settings.guide.ts",
"e2e/help/trip-bookings.guide.ts",
"e2e/help/trip-collab.guide.ts",
"e2e/help/trip-costs.guide.ts",
"e2e/help/trip-day-detail.guide.ts",
"e2e/help/trip-days.guide.ts",
"e2e/help/trip-files.guide.ts",
"e2e/help/trip-lists.guide.ts",
"e2e/help/trip-map.guide.ts",
"e2e/help/trip-place.guide.ts",
"e2e/help/trip-places.guide.ts",
"e2e/help/trip-roadtrip.guide.ts",
"e2e/help/trip-shared.ts",
"e2e/help/trip-transports.guide.ts",
"e2e/help/trip.guide.ts",
"e2e/help/vacay.guide.ts",
"e2e/helpers.ts",
"e2e/ipad-scroll-1432.spec.ts",
"e2e/login.public.spec.ts",
"e2e/mobile-day-swipe-2051.spec.ts",
"e2e/reorder-arrows.spec.ts",
"e2e/screenshots/auth.shot.ts",
"e2e/screenshots/collab.shot.ts",
"e2e/screenshots/detail.shot.ts",
"e2e/screenshots/dialogs.shot.ts",
"e2e/screenshots/pages.shot.ts",
"e2e/screenshots/plan.shot.ts",
"e2e/screenshots/planner.shot.ts",
"e2e/screenshots/promote.mjs",
"e2e/screenshots/seed.setup.ts",
"e2e/screenshots/seed.ts",
"e2e/screenshots/settings.shot.ts",
"e2e/screenshots/shot.ts",
"e2e/screenshots/shots.setup.ts",
"e2e/server-launch.mjs",
"e2e/trip-planner.spec.ts",
"e2e/urlbar-scroll-1809.spec.ts",
"scripts/build-country-shapes.mjs",
"scripts/check-gl-split.mjs",
"scripts/check-page-pattern.mjs",
"scripts/generate-icons.mjs",
"scripts/patch-maplibre.mjs",
"scripts/theme-lint.mjs",
"src/App.test.tsx",
"src/App.tsx",
"src/App.versionHandover.test.tsx",
+1 -1
View File
@@ -8,7 +8,7 @@
* check came in are listed in scripts/format-baseline.json and the list only
* shrinks: every file outside it, a new one in particular, must be formatted,
* and a listed file leaves the list once it has been formatted. The check
* covers .ts, .tsx and .css under src/ and tests/.
* covers .ts, .tsx, .mjs and .css under src/, tests/, e2e/ and scripts/.
*
* npm run lint:format check against the baseline (CI)
* npm run lint:format -- --list print every unformatted file
+3 -2
View File
@@ -16,9 +16,10 @@ import {
writeBaseline,
} from './ratchet.mjs';
export const DIRS = ['src', 'tests'];
/** The app, its tests, the Playwright specs and the client's own tooling. */
export const DIRS = ['src', 'tests', 'e2e', 'scripts'];
export const accepts = (key) => /\.(?:tsx?|css)$/.test(key);
export const accepts = (key) => /\.(?:tsx?|mjs|css)$/.test(key);
/**
* Whether Prettier leaves the file as it is, with the config that applies to
+31 -3
View File
@@ -13,7 +13,14 @@ const FORMATTED = "const a = 'x';\n";
const UNFORMATTED = 'const a = "x"\n';
function run(baseline: string[], files: Record<string, string>, update = false) {
tree = ratchetTree({ ...CONFIG, [BASELINE]: JSON.stringify(baseline), 'tests/keep.ts': FORMATTED, ...files });
tree = ratchetTree({
...CONFIG,
[BASELINE]: JSON.stringify(baseline),
'src/keep.ts': FORMATTED,
'tests/keep.ts': FORMATTED,
'e2e/keep.spec.ts': FORMATTED,
...files,
});
return check({ root: tree.root, baselinePath: tree.path(BASELINE), update, ...tree.out });
}
@@ -58,13 +65,34 @@ describe('lint:format', () => {
expect(JSON.parse(readFileSync(tree.path(BASELINE), 'utf8'))).toEqual([]);
});
it('FORMAT-007: holds the Playwright specs and the client scripts to the same rule', async () => {
const files = {
'e2e/new.spec.ts': UNFORMATTED,
'scripts/new-lint.mjs': UNFORMATTED,
'scripts/data.json': '{"a":1}',
};
expect(await run([], files)).toBe(1);
const errors = tree.error.join('\n');
expect(errors).toMatch(/e2e\/new\.spec\.ts is not formatted/);
expect(errors).toMatch(/scripts\/new-lint\.mjs is not formatted/);
expect(errors).not.toMatch(/data\.json/);
tree.remove();
expect(await run(['e2e/new.spec.ts', 'scripts/new-lint.mjs'], files)).toBe(0);
});
it('FORMAT-006: a missing baseline or Prettier config stops the check', async () => {
tree = ratchetTree({ ...CONFIG, 'src/a.ts': FORMATTED, 'tests/a.ts': FORMATTED });
tree = ratchetTree({
...CONFIG,
'src/a.ts': FORMATTED,
'tests/a.ts': FORMATTED,
'e2e/a.ts': FORMATTED,
'scripts/a.mjs': FORMATTED,
});
await expect(check({ root: tree.root, baselinePath: tree.path(BASELINE), ...tree.out })).rejects.toThrow(
RatchetError
);
tree.remove();
tree = ratchetTree({ [BASELINE]: '[]', 'src/a.ts': FORMATTED, 'tests/a.ts': FORMATTED });
tree = ratchetTree({ [BASELINE]: '[]', 'src/a.ts': FORMATTED, 'tests/a.ts': FORMATTED, 'e2e/a.ts': FORMATTED });
// No config in the tree; the lookup climbs no further than the temp directory's parents,
// which hold none either.
const result = check({ root: tree.root, baselinePath: tree.path(BASELINE), ...tree.out });