import { test } from 'node:test'; import assert from 'node:assert/strict'; import { spawn, spawnSync } from 'node:child_process'; import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { fileURLToPath } from 'node:url'; import { join } from 'node:path'; const root = fileURLToPath(new URL('../../../', import.meta.url)); const script = 'packages/webui/src/cli.mjs'; test('a relative Console launch presents the same-tree absolute parent path to the bus', { timeout: 30000 }, async t => { const env = { ...process.env, MOSAIC_CONFIG: join(process.env.HOME, '.config/mosaic-reltest/config.json'), MOSAIC_AGENT_RUN: 'synthetic-test-marker' }; const setup = spawnSync(join(root, 'scripts/bootstrap.sh'), ['--instance', 'reltest'], { env, encoding: 'utf8' }); assert.equal(setup.status, 0, setup.stderr); const child = spawn(process.execPath, [script, 'serve', '--dev-local-owner', '--port', '0'], { cwd: root, env }); t.after(async () => { if (child.exitCode === null && child.signalCode === null) { const exited = new Promise(resolve => child.once('exit', resolve)); child.kill('SIGTERM'); await exited; } }); let stderr = ''; child.stderr.on('data', chunk => { stderr += chunk; }); await new Promise((resolve, reject) => { let out = ''; const timer = setTimeout(() => reject(Error('Console did not start: ' + stderr)), 20000); child.stdout.on('data', chunk => { out += chunk; if (out.includes('Mosaic Console:')) { clearTimeout(timer); resolve(); } }); child.once('exit', code => { clearTimeout(timer); reject(Error(`Console exited ${code}: ${stderr}`)); }); child.once('error', reject); }); const argv = readFileSync(`/proc/${child.pid}/cmdline`, 'utf8').split('\0'); assert.equal(argv[1], join(root, script)); assert.deepEqual(argv.slice(2, 6), ['serve', '--dev-local-owner', '--port', '0']); // Re-exec must not erase the ancestry marker that makes an agent fail human proof. assert.ok(readFileSync(`/proc/${child.pid}/environ`, 'utf8').split('\0').includes('MOSAIC_AGENT_RUN=synthetic-test-marker')); }); test('Node\'s -- delimiter: an absolute script loads once, a relative one re-execs once', { timeout: 30000 }, () => { const dir = mkdtempSync(join(tmpdir(), 'rl')); const count = join(dir, 'loads'); const preload = join(dir, 'count.cjs'); writeFileSync(preload, `require('node:fs').appendFileSync(${JSON.stringify(count)}, 'x');\n`); const loads = args => { writeFileSync(count, ''); const r = spawnSync(process.execPath, ['--require', preload, '--', ...args, '--help'], { cwd: root, env: process.env, encoding: 'utf8' }); assert.equal(r.status, 0, r.stderr); return readFileSync(count, 'utf8').length; }; assert.equal(loads([join(root, script)]), 1); assert.equal(loads([script]), 2); });