Files
ECC/tests/scripts/sessions-cli.test.js
T
2026-10-20 17:40:57 -04:00

98 lines
4.2 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { spawnSync } = require('node:child_process');
const { test } = require('node:test');
const { parseArgs } = require('../../scripts/sessions-cli');
const { createStateStore } = require('../../scripts/lib/state-store');
const SCRIPT = path.resolve(__dirname, '../../scripts/sessions-cli.js');
async function withTempHome(fn) {
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-sessions-cli-'));
try {
await fn(homeDir);
} finally {
fs.rmSync(homeDir, { recursive: true, force: true });
}
}
function runCli(homeDir, args) {
return spawnSync(process.execPath, [SCRIPT, ...args], {
cwd: homeDir,
encoding: 'utf8',
env: { ...process.env, HOME: homeDir, USERPROFILE: homeDir },
});
}
test('requires a value for every db and limit option', () => {
for (const flag of ['--db', '--limit']) {
for (const args of [[flag], [flag, '--json'], [flag, '-h'], [flag, 'value', flag]]) {
assert.throws(() => parseArgs(['node', SCRIPT, ...args]), { message: `Missing value for ${flag}` });
}
}
const parsed = parseArgs(['node', SCRIPT, '--db', 'state.db', '--limit', '2', '--json', 'demo']);
assert.equal(parsed.dbPath, 'state.db');
assert.equal(parsed.limit, '2');
assert.equal(parsed.json, true);
assert.equal(parsed.sessionId, 'demo');
});
test('rejects incomplete options without creating a database', async () => {
await withTempHome(async homeDir => {
for (const flag of ['--db', '--limit']) {
for (const args of [[flag], [flag, '--json'], [flag, '-h']]) {
const result = runCli(homeDir, args);
assert.equal(result.status, 1, result.stderr);
assert.match(result.stderr, new RegExp(`Missing value for ${flag}`));
assert.deepEqual(fs.readdirSync(homeDir), []);
}
}
assert.match(runCli(homeDir, ['--help']).stdout, /Usage:/);
assert.deepEqual(fs.readdirSync(homeDir), []);
});
});
test('retains valid database and limit options for listing and inspecting sessions', async () => {
await withTempHome(async homeDir => {
const dbPath = path.join(homeDir, 'state.db');
const empty = runCli(homeDir, ['--db', dbPath]);
assert.equal(empty.status, 0, empty.stderr);
assert.match(empty.stdout, /No sessions found/);
const store = await createStateStore({ dbPath });
try {
store.upsertSession({
id: 'demo', adapterId: 'claude-history', harness: 'claude', state: 'recorded', repoRoot: homeDir,
startedAt: '2026-03-15T08:00:00Z', endedAt: '2026-03-15T09:00:00Z',
snapshot: { workers: [{ id: 'worker', state: 'active', branch: 'main', worktree: homeDir }, {}] },
});
store.upsertSession({ id: 'empty', adapterId: 'claude-history', harness: 'claude', state: 'recorded' });
store.insertSkillRun({
id: 'run', skillId: 'demo-skill', skillVersion: 'v1', sessionId: 'demo', taskDescription: 'A task', outcome: 'success',
});
store.insertDecision({ id: 'choice', sessionId: 'demo', title: 'A choice', rationale: 'A reason', status: 'active' });
} finally {
store.close();
}
const list = runCli(homeDir, ['--db', dbPath, '--limit', '1', '--json']);
assert.equal(list.status, 0, list.stderr);
assert.equal(JSON.parse(list.stdout).sessions.length, 1);
const human = runCli(homeDir, ['--db', dbPath]);
assert.equal(human.status, 0, human.stderr);
assert.match(human.stdout, /Total sessions: 2/);
const detail = runCli(homeDir, ['demo', '--db', dbPath]);
assert.equal(detail.status, 0, detail.stderr);
assert.match(detail.stdout, /Workers: 2/);
assert.match(detail.stdout, /Task: A task/);
assert.match(detail.stdout, /Title: A choice/);
const emptyDetail = runCli(homeDir, ['empty', '--db', dbPath, '--json']);
assert.equal(emptyDetail.status, 0, emptyDetail.stderr);
assert.deepEqual(JSON.parse(emptyDetail.stdout).workers, []);
assert.match(runCli(homeDir, ['empty', '--db', dbPath]).stdout, /Workers: 0/);
assert.match(runCli(homeDir, ['missing', '--db', dbPath]).stderr, /Session not found: missing/);
});
});