#!/usr/bin/env node // scripts/test.mjs —— 合并到默认分支(main / master)前的测试闸门。 // 顺序:detect → setup-db → build → lint → unit+integration → e2e // (不在尾部 reset:下次跑的 setup-db 会 DROP+CREATE,重复清库无意义) // 由 coding.mjs 的 test-gate stage(通过子会话)调用。 // // 跨平台:所有命令经 child_process.spawnSync(cmd, { shell:true }) 执行, // 在 Windows 走 cmd.exe,在 *nix 走 /bin/sh,无需 WSL / Git-Bash。 // 命令字符串来自 docs/04 §零(构建/lint/单测/e2e)——由 skeleton-gen 在 Plan 期填充。 import { spawnSync } from 'node:child_process' import { existsSync } from 'node:fs' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' const PROJECT_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..') // 在指定子目录下跑一条 shell 命令;非零退出码即终止整个闸门并透传该码。 function run(label, command, cwd = PROJECT_ROOT) { console.log(`[test.mjs] ${label}: ${command}`) const res = spawnSync(command, { cwd, shell: true, stdio: 'inherit' }) if (res.error) { console.error(`[test.mjs] FATAL: 无法执行 (${label}): ${res.error.message}`) process.exit(1) } if (res.status !== 0) { console.error(`[test.mjs] FAIL (${label}) exit=${res.status}`) process.exit(res.status === null ? 1 : res.status) } } // Stack detection (runtime, mode-agnostic) const hasBackend = existsSync(join(PROJECT_ROOT, 'backend')) const hasFrontend = existsSync(join(PROJECT_ROOT, 'frontend')) if (!hasBackend && !hasFrontend) { console.error('[test.mjs] FATAL: neither backend/ nor frontend/ exists') process.exit(1) } const backendDir = join(PROJECT_ROOT, 'backend') const frontendDir = join(PROJECT_ROOT, 'frontend') console.log('[test.mjs] 1/5 setup test db') run('setup-test-db', `node ${JSON.stringify(join('scripts', 'setup-test-db.mjs'))}`) console.log('[test.mjs] 2/5 build') if (hasBackend) run('backend build', '{{backend_build}}', backendDir) else console.log('[test.mjs] skip backend build') if (hasFrontend) run('frontend build', '{{frontend_build}}', frontendDir) else console.log('[test.mjs] skip frontend build') console.log('[test.mjs] 3/5 lint') if (hasBackend) run('backend lint', '{{backend_lint}}', backendDir) else console.log('[test.mjs] skip backend lint') if (hasFrontend) run('frontend lint', '{{frontend_lint}}', frontendDir) else console.log('[test.mjs] skip frontend lint') console.log('[test.mjs] 4/5 unit + integration') if (hasBackend) run('backend test', '{{backend_test}}', backendDir) else console.log('[test.mjs] skip backend test') if (hasFrontend) run('frontend test', '{{frontend_test}}', frontendDir) else console.log('[test.mjs] skip frontend test') console.log('[test.mjs] 5/5 E2E') run('e2e', '{{e2e_cmd}}') console.log('[test.mjs] GREEN')