Files
grok-build-hud/tests/dashboard.test.ts
T
Redredchen01 df6a9e74d9 Release grok-build-hud v0.3.9: multi-terminal HUD, i18n settings, theme follow
Standalone Grok Build status strip with parallel sessions, width-adaptive
layout, Chinese/English settings UI, and token breakdown. Product copy no
longer references third-party tools.
2026-07-17 16:27:35 +08:00

160 lines
5.1 KiB
TypeScript

import { describe, it } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
import {
titleLine,
refreshDashboard,
runDashboardLoop,
ttyForPid,
} from "../src/dashboard.js";
import { loadSnapshotFromDir } from "../src/session.js";
const pkgRoot = path.join(
path.dirname(fileURLToPath(import.meta.url)),
"..",
"..",
);
const fixtureSession = path.join(pkgRoot, "fixtures", "session");
describe("dashboard", () => {
it("titleLine includes ctx percent", () => {
const snap = loadSnapshotFromDir(fixtureSession)!;
const t = titleLine(snap, {
available: true,
percent: 22,
period: "weekly",
used: 17510,
limit: 150000,
});
assert.match(t, /◆/);
assert.match(t, /37%/);
assert.match(t, /22%|quota/);
});
it("ttyForPid returns null for bogus pid", () => {
assert.equal(ttyForPid(99999999), null);
});
it("refreshDashboard writes status files for fixture home", async () => {
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "hud-dash-"));
const sid = "fixture-session-001";
const dir = path.join(tmp, "sessions", "proj", sid);
fs.mkdirSync(dir, { recursive: true });
for (const f of ["signals.json", "summary.json", "updates.jsonl"]) {
fs.copyFileSync(path.join(fixtureSession, f), path.join(dir, f));
}
fs.writeFileSync(
path.join(tmp, "active_sessions.json"),
JSON.stringify([
{ session_id: sid, pid: process.pid, cwd: "/Users/dex/demo/CoachFlow" },
]),
);
const r = await refreshDashboard({ grokHome: tmp, noUsage: true });
assert.ok(r.session);
assert.match(r.title, /37%/);
assert.ok(fs.existsSync(path.join(tmp, "hud", "status-line.txt")));
assert.ok(fs.existsSync(path.join(tmp, "hud", "tmux-status.txt")));
fs.rmSync(tmp, { recursive: true, force: true });
});
it("after /new: prefers newest active session, not first-listed old 78%", async () => {
// Repro: active_sessions keeps old tab first; new tab second with low/no signals.
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "hud-new-"));
const cwd = "/Users/dex/AI FILM SPACE/0717";
const oldId = "old-session-78pct";
const newId = "new-session-after-new";
const enc = encodeURIComponent(cwd);
const oldDir = path.join(tmp, "sessions", enc, oldId);
const newDir = path.join(tmp, "sessions", enc, newId);
fs.mkdirSync(oldDir, { recursive: true });
fs.mkdirSync(newDir, { recursive: true });
fs.writeFileSync(
path.join(oldDir, "signals.json"),
JSON.stringify({
contextWindowUsage: 78,
contextTokensUsed: 392180,
contextWindowTokens: 500000,
turnCount: 18,
toolCallCount: 344,
primaryModelId: "grok-4.5",
}),
);
fs.writeFileSync(
path.join(oldDir, "summary.json"),
JSON.stringify({
info: { id: oldId, cwd },
last_active_at: "2026-07-17T06:00:00.000Z",
updated_at: "2026-07-17T06:00:00.000Z",
current_model_id: "grok-4.5",
}),
);
// New session often has summary+updates before signals.json exists
fs.writeFileSync(
path.join(newDir, "summary.json"),
JSON.stringify({
info: { id: newId, cwd },
last_active_at: "2026-07-17T07:43:00.000Z",
updated_at: "2026-07-17T07:43:00.000Z",
created_at: "2026-07-17T07:43:00.000Z",
current_model_id: "grok-4.5",
}),
);
fs.writeFileSync(path.join(newDir, "updates.jsonl"), "");
// active list: OLD first (insertion order) — bug used to pick this always
fs.writeFileSync(
path.join(tmp, "active_sessions.json"),
JSON.stringify([
{
session_id: oldId,
pid: process.pid,
cwd,
opened_at: "2026-07-17T04:00:00.000Z",
},
{
session_id: newId,
pid: process.pid,
cwd,
opened_at: "2026-07-17T07:43:00.000Z",
},
]),
);
const r = await refreshDashboard({ grokHome: tmp, noUsage: true });
assert.ok(r.session);
assert.equal(r.session!.sessionId, newId);
assert.ok(
Math.round(r.session!.contextPercent) < 10,
`expected low ctx after /new, got ${r.session!.contextPercent}`,
);
assert.doesNotMatch(r.title, /78%/);
fs.rmSync(tmp, { recursive: true, force: true });
});
it("runDashboardLoop respects maxIterations", async () => {
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "hud-loop-"));
const sid = "fixture-session-001";
const dir = path.join(tmp, "sessions", "proj", sid);
fs.mkdirSync(dir, { recursive: true });
for (const f of ["signals.json", "summary.json", "updates.jsonl"]) {
fs.copyFileSync(path.join(fixtureSession, f), path.join(dir, f));
}
const code = await runDashboardLoop({
grokHome: tmp,
intervalMs: 1,
maxIterations: 2,
noUsage: true,
writePid: true,
sleep: async () => {},
});
assert.equal(code, 0);
fs.rmSync(tmp, { recursive: true, force: true });
});
});