mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 17:51:22 +00:00
212 lines
6.7 KiB
TypeScript
212 lines
6.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { HealthSummary } from "./health.js";
|
|
import {
|
|
buildStatusFooterLines,
|
|
buildStatusHealthRows,
|
|
buildStatusPairingRecoveryLines,
|
|
buildStatusPluginCompatibilityLines,
|
|
buildStatusSecurityAuditLines,
|
|
buildStatusSessionsRows,
|
|
buildStatusSystemEventsRows,
|
|
buildStatusSystemEventsTrailer,
|
|
statusHealthColumns,
|
|
} from "./status.command-sections.ts";
|
|
|
|
describe("status.command-sections", () => {
|
|
it("formats security audit lines with finding caps and follow-up commands", () => {
|
|
const lines = buildStatusSecurityAuditLines({
|
|
securityAudit: {
|
|
summary: { critical: 1, warn: 6, info: 2 },
|
|
findings: [
|
|
{
|
|
severity: "warn",
|
|
title: "Warn first",
|
|
detail: "warn detail",
|
|
},
|
|
{
|
|
severity: "critical",
|
|
title: "Critical first",
|
|
detail: "critical\ndetail",
|
|
remediation: "fix it",
|
|
},
|
|
...Array.from({ length: 5 }, (_, index) => ({
|
|
severity: "warn" as const,
|
|
title: `Warn ${index + 2}`,
|
|
detail: `detail ${index + 2}`,
|
|
})),
|
|
],
|
|
},
|
|
theme: {
|
|
error: (value) => `error(${value})`,
|
|
warn: (value) => `warn(${value})`,
|
|
muted: (value) => `muted(${value})`,
|
|
},
|
|
shortenText: (value) => value,
|
|
formatCliCommand: (value) => `cmd:${value}`,
|
|
});
|
|
|
|
expect(lines[0]).toBe("muted(Summary: error(1 critical) · warn(6 warn) · muted(2 info))");
|
|
expect(lines).toContain(" error(CRITICAL) Critical first");
|
|
expect(lines).toContain(" critical detail");
|
|
expect(lines).toContain(" muted(Fix: fix it)");
|
|
expect(lines).toContain("muted(… +1 more)");
|
|
expect(lines.at(-2)).toBe("muted(Full report: cmd:openclaw security audit)");
|
|
expect(lines.at(-1)).toBe("muted(Deep probe: cmd:openclaw security audit --deep)");
|
|
});
|
|
|
|
it("builds verbose sessions rows and empty fallback rows", () => {
|
|
const verboseRows = buildStatusSessionsRows({
|
|
recent: [
|
|
{
|
|
key: "session-key-1234567890",
|
|
kind: "direct",
|
|
updatedAt: 1,
|
|
age: 5_000,
|
|
model: "gpt-5.4",
|
|
totalTokens: null,
|
|
totalTokensFresh: false,
|
|
remainingTokens: null,
|
|
percentUsed: null,
|
|
contextTokens: null,
|
|
flags: [],
|
|
},
|
|
],
|
|
verbose: true,
|
|
shortenText: (value) => value.slice(0, 8),
|
|
formatTimeAgo: (value) => `${value}ms`,
|
|
formatTokensCompact: () => "12k",
|
|
formatPromptCacheCompact: () => "cache ok",
|
|
muted: (value) => `muted(${value})`,
|
|
});
|
|
|
|
expect(verboseRows).toEqual([
|
|
{
|
|
Key: "session-",
|
|
Kind: "direct",
|
|
Age: "5000ms",
|
|
Model: "gpt-5.4",
|
|
Tokens: "12k",
|
|
Cache: "cache ok",
|
|
},
|
|
]);
|
|
|
|
const emptyRows = buildStatusSessionsRows({
|
|
recent: [],
|
|
verbose: true,
|
|
shortenText: (value) => value,
|
|
formatTimeAgo: () => "",
|
|
formatTokensCompact: () => "",
|
|
formatPromptCacheCompact: () => null,
|
|
muted: (value) => `muted(${value})`,
|
|
});
|
|
|
|
expect(emptyRows).toEqual([
|
|
{
|
|
Key: "muted(no sessions yet)",
|
|
Kind: "",
|
|
Age: "",
|
|
Model: "",
|
|
Tokens: "",
|
|
Cache: "",
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("maps health channel detail lines into status rows", () => {
|
|
const rows = buildStatusHealthRows({
|
|
health: { durationMs: 42 } as HealthSummary,
|
|
formatHealthChannelLines: () => [
|
|
"Telegram: OK · ready",
|
|
"Slack: failed · auth",
|
|
"Discord: not configured",
|
|
"Matrix: linked",
|
|
"Signal: not linked",
|
|
],
|
|
ok: (value) => `ok(${value})`,
|
|
warn: (value) => `warn(${value})`,
|
|
muted: (value) => `muted(${value})`,
|
|
});
|
|
|
|
expect(rows).toEqual([
|
|
{ Item: "Gateway", Status: "ok(reachable)", Detail: "42ms" },
|
|
{ Item: "Telegram", Status: "ok(OK)", Detail: "OK · ready" },
|
|
{ Item: "Slack", Status: "warn(WARN)", Detail: "failed · auth" },
|
|
{ Item: "Discord", Status: "muted(OFF)", Detail: "not configured" },
|
|
{ Item: "Matrix", Status: "ok(LINKED)", Detail: "linked" },
|
|
{ Item: "Signal", Status: "warn(UNLINKED)", Detail: "not linked" },
|
|
]);
|
|
});
|
|
|
|
it("builds footer lines from update and reachability state", () => {
|
|
expect(
|
|
buildStatusFooterLines({
|
|
updateHint: "upgrade ready",
|
|
warn: (value) => `warn(${value})`,
|
|
formatCliCommand: (value) => `cmd:${value}`,
|
|
nodeOnlyGateway: null,
|
|
gatewayReachable: false,
|
|
}),
|
|
).toEqual([
|
|
"FAQ: https://docs.openclaw.ai/faq",
|
|
"Troubleshooting: https://docs.openclaw.ai/troubleshooting",
|
|
"",
|
|
"warn(upgrade ready)",
|
|
"Next steps:",
|
|
" Need to share? cmd:openclaw status --all",
|
|
" Need to debug live? cmd:openclaw logs --follow",
|
|
" Fix reachability first: cmd:openclaw gateway probe",
|
|
]);
|
|
});
|
|
|
|
it("builds plugin compatibility lines and pairing recovery guidance", () => {
|
|
expect(
|
|
buildStatusPluginCompatibilityLines({
|
|
notices: [
|
|
{ severity: "warn" as const, message: "legacy" },
|
|
{ severity: "info" as const, message: "heads-up" },
|
|
{ severity: "warn" as const, message: "extra" },
|
|
],
|
|
limit: 2,
|
|
formatNotice: (notice) => String(notice.message),
|
|
warn: (value) => `warn(${value})`,
|
|
muted: (value) => `muted(${value})`,
|
|
}),
|
|
).toEqual([" warn(WARN) legacy", " muted(INFO) heads-up", "muted( … +1 more)"]);
|
|
|
|
expect(
|
|
buildStatusPairingRecoveryLines({
|
|
pairingRecovery: { requestId: "req-123" },
|
|
warn: (value) => `warn(${value})`,
|
|
muted: (value) => `muted(${value})`,
|
|
formatCliCommand: (value) => `cmd:${value}`,
|
|
}),
|
|
).toEqual([
|
|
"warn(Gateway pairing approval required.)",
|
|
"muted(Recovery: cmd:openclaw devices approve req-123)",
|
|
"muted(Fallback: cmd:openclaw devices approve --latest)",
|
|
"muted(Inspect: cmd:openclaw devices list)",
|
|
]);
|
|
});
|
|
|
|
it("builds system event rows and health columns", () => {
|
|
expect(
|
|
buildStatusSystemEventsRows({
|
|
queuedSystemEvents: ["one", "two", "three"],
|
|
limit: 2,
|
|
}),
|
|
).toEqual([{ Event: "one" }, { Event: "two" }]);
|
|
expect(
|
|
buildStatusSystemEventsTrailer({
|
|
queuedSystemEvents: ["one", "two", "three"],
|
|
limit: 2,
|
|
muted: (value) => `muted(${value})`,
|
|
}),
|
|
).toBe("muted(… +1 more)");
|
|
expect(statusHealthColumns).toEqual([
|
|
{ key: "Item", header: "Item", minWidth: 10 },
|
|
{ key: "Status", header: "Status", minWidth: 8 },
|
|
{ key: "Detail", header: "Detail", flex: true, minWidth: 28 },
|
|
]);
|
|
});
|
|
});
|