import { test } from 'node:test'; import assert from 'node:assert/strict'; import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, existsSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { spawnSync } from 'node:child_process'; const commands = [ 'go test -timeout=180s ./...', 'go test -race -timeout=180s ./...', 'go vet ./...', 'go build ./...', 'npm --prefix web test', 'npm --prefix web run build', 'node --test image/init-profile.test.mjs', 'node --check scripts/test-panel.mjs', ]; function fixture(t) { const home = mkdtempSync(join(tmpdir(), 'check-trial-')); t.after(() => rmSync(home, { recursive: true, force: true })); const project = join(home, 'project with spaces'); const bin = join(home, 'stubs'); mkdirSync(join(project, 'scripts'), { recursive: true }); mkdirSync(join(project, 'bin')); mkdirSync(bin); writeFileSync(join(project, 'bin', 'existing'), 'keep'); const script = join(project, 'scripts', 'check-trial.sh'); copyFileSync(new URL('./check-trial.sh', import.meta.url), script); for (const tool of ['go', 'npm', 'node']) { writeFileSync(join(bin, tool), `#!/bin/bash command="${tool} $*" printf '%s\t%s\t%s\n' "$command" "$PWD" "$TMPDIR" >> "$COMMAND_LOG" if [[ $command == "$FAIL_COMMAND" ]]; then exit 23; fi `, { mode: 0o755 }); } const log = join(home, 'commands'); return { home, project, run(overrides = {}) { const result = spawnSync('bash', [script], { cwd: home, encoding: 'utf8', env: { ...process.env, PATH: `${bin}:${process.env.PATH}`, COMMAND_LOG: log, FAIL_COMMAND: '', TEST_TMPDIR: '', TMPDIR: home, ...overrides }, }); assert.ifError(result.error); const rows = existsSync(log) ? readFileSync(log, 'utf8').trim().split('\n').map(line => line.split('\t')) : []; assert.equal(readFileSync(join(project, 'bin', 'existing'), 'utf8'), 'keep'); return { ...result, rows }; }, }; } test('runs all checks from the script project and preserves the default temp directory', t => { const f = fixture(t); const result = f.run(); assert.equal(result.status, 0, result.stderr); assert.deepEqual(result.rows, commands.map(command => [command, f.project, f.home])); assert.match(result.stdout, /All acceptance checks passed/); }); for (const [index, command] of commands.entries()) { test(`stops immediately when ${command} fails`, t => { const result = fixture(t).run({ FAIL_COMMAND: command }); assert.equal(result.status, 23); assert.deepEqual(result.rows.map(row => row[0]), commands.slice(0, index + 1)); assert.match(result.stderr, /Acceptance failed/); assert.doesNotMatch(result.stdout, /All acceptance checks passed/); }); } test('accepts an explicit relative TEST_TMPDIR without removing its contents', t => { const f = fixture(t); const temp = join(f.home, 'custom temp'); mkdirSync(temp); writeFileSync(join(temp, 'keep'), 'user data'); const result = f.run({ TEST_TMPDIR: 'custom temp' }); assert.equal(result.status, 0, result.stderr); assert.deepEqual(result.rows.map(row => row[2]), commands.map(() => temp)); assert.equal(readFileSync(join(temp, 'keep'), 'utf8'), 'user data'); }); test('rejects a missing TEST_TMPDIR without creating it or starting checks', t => { const f = fixture(t); const temp = join(f.home, 'missing'); const result = f.run({ TEST_TMPDIR: temp }); assert.notEqual(result.status, 0); assert.deepEqual(result.rows, []); assert.equal(existsSync(temp), false); assert.doesNotMatch(result.stdout, /All acceptance checks passed/); });