66 lines
3.4 KiB
TypeScript
66 lines
3.4 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { test } from "node:test";
|
|
import { goalDisplay, goalDetails } from "../lib/display.ts";
|
|
import { initialState, setGoal, pauseGoal, blockGoal, resumeGoal, completeGoal, clearGoal } from "../lib/state.ts";
|
|
import { saveState, loadState } from "../lib/store.ts";
|
|
|
|
const text = "Long goal\n" + "Full acceptance criteria, never truncate. ".repeat(100) + "\nEND-OF-GOAL";
|
|
|
|
test("footer maps each lifecycle state to text and a theme role", () => {
|
|
const active = setGoal(initialState(), text);
|
|
for (const [state, label, color] of [
|
|
[initialState(), "None", "muted"],
|
|
[active, "Active", "accent"],
|
|
[{ ...active, activeWait: { owner: "reviewer" } }, "Waiting", "warning"],
|
|
[{ ...active, activeWait: { owner: "reviewer", wakeSent: true } }, "Active", "accent"],
|
|
[pauseGoal(active, "operator stop"), "Paused", "warning"],
|
|
[pauseGoal(active, "blocked: legacy reason"), "Blocked", "error"],
|
|
[blockGoal(active, "missing permission"), "Blocked", "error"],
|
|
[completeGoal(active, "verified"), "Complete", "success"],
|
|
] as const) assert.deepEqual(goalDisplay(state), { label, color });
|
|
});
|
|
|
|
test("full multiline goal survives completion, persistence, and read-only recall", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "goal-display-"));
|
|
try {
|
|
const active = setGoal(initialState(), text);
|
|
const complete = completeGoal(active, "verified ".repeat(300));
|
|
assert.equal(complete.lastOutcome?.text, text);
|
|
assert.equal(complete.lastOutcome?.evidence.length, 1000);
|
|
assert.equal(complete.status, "none");
|
|
assert.deepEqual(resumeGoal(complete), complete);
|
|
const path = join(dir, "state.json");
|
|
saveState(complete, path);
|
|
assert.deepEqual(loadState(path), complete);
|
|
for (const state of [active, blockGoal(active, "denied"), pauseGoal(active, "stop"), loadState(path)]) {
|
|
const before = JSON.stringify(state);
|
|
assert.ok(goalDetails(state).includes(text));
|
|
assert.equal(JSON.stringify(state), before);
|
|
}
|
|
assert.equal(goalDisplay(clearGoal(complete)).label, "None");
|
|
assert.equal(setGoal(complete, "replacement").lastOutcome, undefined);
|
|
assert.equal(resumeGoal(blockGoal(active, "denied")).status, "active");
|
|
} finally { rmSync(dir, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test("old records and malformed outcome fields are safe to recall", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "goal-display-"));
|
|
const path = join(dir, "state.json");
|
|
try {
|
|
const old = pauseGoal(setGoal(initialState(), text), "blocked: legacy");
|
|
saveState(old, path);
|
|
assert.equal(goalDisplay(loadState(path)).label, "Blocked");
|
|
for (const lastOutcome of [null, {}, { status: "complete", text: 123 }, { status: "complete", text, evidence: "yes", at: "invalid" }]) {
|
|
saveState({ ...initialState(), lastOutcome } as any, path);
|
|
assert.equal(goalDisplay(loadState(path)).label, "None");
|
|
assert.doesNotThrow(() => goalDetails(loadState(path)));
|
|
}
|
|
saveState({ ...old, pausedReason: {} } as any, path);
|
|
assert.doesNotThrow(() => goalDetails(loadState(path)));
|
|
assert.doesNotThrow(() => goalDetails({ ...setGoal(initialState(), text), activeWait: { owner: "test", deadlineAt: 1e100 } }));
|
|
} finally { rmSync(dir, { recursive: true, force: true }); }
|
|
});
|