From 5c6ca444d9755b5d518ffa695db5ccce905626ac Mon Sep 17 00:00:00 2001 From: implementer Date: Fri, 28 Aug 2026 22:56:48 +0000 Subject: [PATCH] test: lock in root build/test/typecheck commands (E00-S01-T12) --- tests/root-commands.test.mjs | 125 +++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 tests/root-commands.test.mjs diff --git a/tests/root-commands.test.mjs b/tests/root-commands.test.mjs new file mode 100644 index 0000000..90b45fb --- /dev/null +++ b/tests/root-commands.test.mjs @@ -0,0 +1,125 @@ +// Root commands test — locks in the [E00-S01-T12] root build/test/typecheck +// commands for the workspace. +// +// Acceptance criteria covered (each test fails without the committed config): +// - "a root build command exists" → the root `package.json` declares +// `scripts.build` as the workspace-recursive build command +// (`pnpm -r run build`). +// - "a root test command exists" → the root `package.json` declares +// `scripts.test` as the `node --test` runner over `tests/**/*.test.mjs`. +// - "a root typecheck command exists" → the root `package.json` declares +// `scripts.typecheck` as the workspace-recursive typecheck command +// (`pnpm -r run typecheck`). +// - "invoke each root command and confirm it runs" → each command is +// actually executed at the workspace root and must exit 0: `pnpm run +// build` compiles every workspace package, `pnpm run typecheck` +// type-checks every package (`tsc --noEmit`), and `pnpm run test` runs +// the whole `node --test` suite under `tests/`. +// +// Run: `node --test tests/root-commands.test.mjs` +// (node:test — built into Node >= 18; no dependencies, lockfile untouched.) + +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { spawnSync } from 'node:child_process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); + +const read = (relPath) => readFileSync(path.join(REPO_ROOT, relPath), 'utf8'); + +/** The exact root scripts committed in the root package.json (E00-S01-T05/T12). */ +const EXPECTED_SCRIPTS = { + build: 'pnpm -r run build', + test: 'node --test "tests/**/*.test.mjs"', + typecheck: 'pnpm -r run typecheck', +}; + +// Recursion guard. This suite is itself part of the `tests/**/*.test.mjs` +// set that the root test command runs, so the "root test command runs" +// probe must not re-invoke `pnpm run test` endlessly. The probe spawns the +// root command with EPPP_ROOT_COMMANDS_SKIP_INVOKE=1; a nested run of this +// file then skips the invocation probes (the declaration probes still run) +// while the outer probe still proves the command executes and exits 0. +const SKIP_INVOKE = process.env.EPPP_ROOT_COMMANDS_SKIP_INVOKE === '1'; + +/** + * Runs a root script via the pinned pnpm (corepack), the same way CI and + * developers invoke it, and returns the spawn result. + */ +function runRootScript(script, env = {}) { + return spawnSync('corepack', ['pnpm', 'run', script], { + cwd: REPO_ROOT, + encoding: 'utf8', + timeout: 600_000, + env: { ...process.env, ...env }, + }); +} + +// --------------------------------------------------------------------------- +// Declaration tests — a root command exists +// --------------------------------------------------------------------------- + +test('a root build command exists in package.json', () => { + const scripts = JSON.parse(read('package.json')).scripts ?? {}; + assert.equal( + scripts.build, + EXPECTED_SCRIPTS.build, + `root package.json must declare scripts.build exactly as "${EXPECTED_SCRIPTS.build}" ` + + `(got "${scripts.build}") so the whole workspace builds from the root`, + ); +}); + +test('a root test command exists in package.json', () => { + const scripts = JSON.parse(read('package.json')).scripts ?? {}; + assert.equal( + scripts.test, + EXPECTED_SCRIPTS.test, + `root package.json must declare scripts.test exactly as "${EXPECTED_SCRIPTS.test}" ` + + `(got "${scripts.test}") so the whole test suite runs from the root`, + ); +}); + +test('a root typecheck command exists in package.json', () => { + const scripts = JSON.parse(read('package.json')).scripts ?? {}; + assert.equal( + scripts.typecheck, + EXPECTED_SCRIPTS.typecheck, + `root package.json must declare scripts.typecheck exactly as "${EXPECTED_SCRIPTS.typecheck}" ` + + `(got "${scripts.typecheck}") so every workspace package type-checks from the root`, + ); +}); + +// --------------------------------------------------------------------------- +// Invocation tests — invoke each root command and confirm it runs +// --------------------------------------------------------------------------- + +test('the root build command runs successfully (pnpm run build)', { skip: SKIP_INVOKE }, () => { + const result = runRootScript('build'); + assert.equal( + result.status, + 0, + `"pnpm run build" must exit 0:\n${(result.stderr || result.stdout || '').trim()}`, + ); +}); + +test('the root typecheck command runs successfully (pnpm run typecheck)', { skip: SKIP_INVOKE }, () => { + const result = runRootScript('typecheck'); + assert.equal( + result.status, + 0, + `"pnpm run typecheck" must exit 0:\n${(result.stderr || result.stdout || '').trim()}`, + ); +}); + +test('the root test command runs successfully (pnpm run test)', { skip: SKIP_INVOKE }, () => { + const result = runRootScript('test', { EPPP_ROOT_COMMANDS_SKIP_INVOKE: '1' }); + assert.equal( + result.status, + 0, + `"pnpm run test" must exit 0 (the whole node:test suite must pass):\n` + + `${(result.stderr || result.stdout || '').trim()}`, + ); +});