test(commands): share status test fixtures

This commit is contained in:
Vincent Koc
2026-04-12 03:29:17 +01:00
parent 8ba50aa23e
commit cdfde7e0b9
4 changed files with 270 additions and 278 deletions

View File

@@ -3,94 +3,14 @@ import {
buildStatusAllOverviewRows,
buildStatusCommandOverviewRows,
} from "./status-overview-rows.ts";
import {
baseStatusOverviewSurface,
createStatusCommandOverviewRowsParams,
} from "./status.test-support.ts";
describe("status-overview-rows", () => {
it("builds command overview rows from the shared surface", () => {
expect(
buildStatusCommandOverviewRows({
opts: { deep: true },
surface: {
cfg: { update: { channel: "stable" }, gateway: { bind: "loopback" } },
update: {
installKind: "git",
git: {
branch: "main",
tag: "v1.2.3",
upstream: "origin/main",
behind: 2,
ahead: 0,
dirty: false,
fetchOk: true,
},
registry: { latestVersion: "2026.4.10" },
} as never,
tailscaleMode: "serve",
tailscaleDns: "box.tail.ts.net",
tailscaleHttpsUrl: "https://box.tail.ts.net",
gatewayMode: "remote",
remoteUrlMissing: false,
gatewayConnection: { url: "wss://gateway.example.com", urlSource: "config" },
gatewayReachable: true,
gatewayProbe: { connectLatencyMs: 42, error: null },
gatewayProbeAuth: { token: "tok" },
gatewayProbeAuthWarning: "warn-text",
gatewaySelf: { host: "gateway", version: "1.2.3" },
gatewayService: {
label: "LaunchAgent",
installed: true,
managedByOpenClaw: true,
loadedText: "loaded",
runtimeShort: "running",
},
nodeService: {
label: "node",
installed: true,
loadedText: "loaded",
runtime: { status: "running", pid: 42 },
},
nodeOnlyGateway: null,
},
osLabel: "macOS",
summary: {
tasks: { total: 3, active: 1, failures: 0, byStatus: { queued: 1, running: 1 } },
taskAudit: { errors: 1, warnings: 0 },
heartbeat: {
agents: [{ agentId: "main", enabled: true, everyMs: 60_000, every: "1m" }],
},
queuedSystemEvents: ["one", "two"],
sessions: {
count: 2,
paths: ["store.json"],
defaults: { model: "gpt-5.4", contextTokens: 12_000 },
},
},
health: { durationMs: 42 },
lastHeartbeat: {
ts: Date.now() - 30_000,
status: "ok",
channel: "discord",
accountId: "acct",
},
agentStatus: {
defaultId: "main",
bootstrapPendingCount: 1,
totalSessions: 2,
agents: [{ id: "main", lastActiveAgeMs: 60_000 }],
},
memory: { files: 1, chunks: 2, vector: {}, fts: {}, cache: {} },
memoryPlugin: { enabled: true, slot: "memory" },
pluginCompatibility: [{ pluginId: "a", severity: "warn", message: "legacy" }],
ok: (value: string) => `ok(${value})`,
warn: (value: string) => `warn(${value})`,
muted: (value: string) => `muted(${value})`,
formatTimeAgo: (value: number) => `${value}ms`,
formatKTokens: (value: number) => `${Math.round(value / 1000)}k`,
resolveMemoryVectorState: () => ({ state: "ready", tone: "ok" }),
resolveMemoryFtsState: () => ({ state: "ready", tone: "warn" }),
resolveMemoryCacheSummary: () => ({ text: "cache warm", tone: "muted" }),
updateValue: "available · custom update",
} as unknown as Parameters<typeof buildStatusCommandOverviewRows>[0]),
).toEqual(
expect(buildStatusCommandOverviewRows(createStatusCommandOverviewRowsParams())).toEqual(
expect.arrayContaining([
{ Item: "OS", Value: `macOS · node ${process.versions.node}` },
{
@@ -108,36 +28,10 @@ describe("status-overview-rows", () => {
expect(
buildStatusAllOverviewRows({
surface: {
cfg: { update: { channel: "stable" }, gateway: { bind: "loopback" } },
update: {
installKind: "git",
git: { branch: "main", tag: "v1.2.3", upstream: "origin/main" },
} as never,
...baseStatusOverviewSurface,
tailscaleMode: "off",
tailscaleDns: "box.tail.ts.net",
tailscaleHttpsUrl: null,
gatewayMode: "remote",
remoteUrlMissing: false,
gatewayConnection: { url: "wss://gateway.example.com", urlSource: "config" },
gatewayReachable: true,
gatewayProbe: { connectLatencyMs: 42, error: null },
gatewayProbeAuth: { token: "tok" },
gatewayProbeAuthWarning: "warn-text",
gatewaySelf: { host: "gateway", version: "1.2.3" },
gatewayService: {
label: "LaunchAgent",
installed: true,
managedByOpenClaw: true,
loadedText: "loaded",
runtimeShort: "running",
},
nodeService: {
label: "node",
installed: true,
loadedText: "loaded",
runtime: { status: "running", pid: 42 },
},
nodeOnlyGateway: null,
},
osLabel: "macOS",
configPath: "/tmp/openclaw.json",
@@ -148,7 +42,7 @@ describe("status-overview-rows", () => {
agents: [{ id: "main", lastActiveAgeMs: 60_000 }],
},
tailscaleBackendState: "Running",
} as unknown as Parameters<typeof buildStatusAllOverviewRows>[0]),
}),
).toEqual(
expect.arrayContaining([
{ Item: "Version", Value: expect.any(String) },

View File

@@ -5,86 +5,47 @@ import {
buildStatusOverviewSurfaceFromOverview,
buildStatusOverviewSurfaceFromScan,
} from "./status-overview-surface.ts";
const baseCfg = { update: { channel: "stable" }, gateway: { bind: "loopback" } } as const;
const baseUpdate = { installKind: "git", git: { branch: "main", tag: "v1.2.3" } } as never;
const baseGatewaySnapshot = {
gatewayMode: "remote",
remoteUrlMissing: false,
gatewayConnection: {
url: "wss://gateway.example.com",
urlSource: "config",
message: "Gateway target: wss://gateway.example.com",
},
gatewayReachable: true,
gatewayProbe: { connectLatencyMs: 42, error: null } as never,
gatewayProbeAuth: { token: "tok" },
gatewayProbeAuthWarning: "warn-text",
gatewaySelf: { host: "gateway", version: "1.2.3" },
} as const;
const baseScanFields = {
cfg: baseCfg,
update: baseUpdate,
tailscaleMode: "serve",
tailscaleDns: "box.tail.ts.net",
tailscaleHttpsUrl: "https://box.tail.ts.net",
...baseGatewaySnapshot,
};
const baseGatewayService = {
label: "LaunchAgent",
installed: true,
managedByOpenClaw: true,
loadedText: "loaded",
runtimeShort: "running",
};
const baseNodeService = {
label: "node",
installed: true,
loadedText: "loaded",
runtime: { status: "running", pid: 42 },
};
const baseServices = {
gatewayService: baseGatewayService,
nodeService: baseNodeService,
nodeOnlyGateway: null,
};
const baseOverviewSurface = {
...baseScanFields,
...baseServices,
};
import {
baseStatusCfg,
baseStatusGatewaySnapshot,
baseStatusOverviewScanFields,
baseStatusOverviewSurface,
baseStatusServices,
baseStatusUpdate,
} from "./status.test-support.ts";
describe("status-overview-surface", () => {
it("builds the shared overview surface from a status scan result", () => {
expect(
buildStatusOverviewSurfaceFromScan({
scan: baseScanFields,
...baseServices,
scan: baseStatusOverviewScanFields,
...baseStatusServices,
}),
).toEqual(baseOverviewSurface);
).toEqual(baseStatusOverviewSurface);
});
it("builds the shared overview surface from scan overview data", () => {
expect(
buildStatusOverviewSurfaceFromOverview({
overview: {
cfg: baseCfg,
update: baseUpdate,
cfg: baseStatusCfg,
update: baseStatusUpdate,
tailscaleMode: "serve",
tailscaleDns: "box.tail.ts.net",
tailscaleHttpsUrl: "https://box.tail.ts.net",
gatewaySnapshot: baseGatewaySnapshot,
gatewaySnapshot: baseStatusGatewaySnapshot,
} as never,
...baseServices,
...baseStatusServices,
}),
).toEqual(baseOverviewSurface);
).toEqual(baseStatusOverviewSurface);
});
it("builds overview rows from the shared surface bundle", () => {
expect(
buildStatusOverviewRowsFromSurface({
surface: {
...baseOverviewSurface,
cfg: baseCfg,
...baseStatusOverviewSurface,
cfg: baseStatusCfg,
update: {
installKind: "git",
git: {

View File

@@ -1,118 +1,33 @@
import { describe, expect, it } from "vitest";
import { buildStatusCommandReportData } from "./status.command-report-data.ts";
import { createStatusCommandReportDataParams } from "./status.test-support.ts";
describe("buildStatusCommandReportData", () => {
it("builds report inputs from shared status surfaces", async () => {
const result = await buildStatusCommandReportData({
opts: { deep: true, verbose: true },
surface: {
cfg: { update: { channel: "stable" }, gateway: { bind: "loopback" } },
update: {
installKind: "git",
git: {
branch: "main",
tag: "v1.2.3",
upstream: "origin/main",
behind: 2,
ahead: 0,
dirty: false,
fetchOk: true,
const baseParams = createStatusCommandReportDataParams();
const result = await buildStatusCommandReportData(
createStatusCommandReportDataParams({
surface: {
...baseParams.surface,
gatewayProbe: { connectLatencyMs: 123, error: null },
},
summary: {
...baseParams.summary,
sessions: {
...baseParams.summary.sessions,
recent: [
{
key: "session-key",
kind: "direct",
updatedAt: 1,
age: 5_000,
model: "gpt-5.4",
},
],
},
registry: { latestVersion: "2026.4.10" },
} as never,
tailscaleMode: "serve",
tailscaleDns: "box.tail.ts.net",
tailscaleHttpsUrl: "https://box.tail.ts.net",
gatewayMode: "remote",
remoteUrlMissing: false,
gatewayConnection: { url: "wss://gateway.example.com", urlSource: "config" },
gatewayReachable: true,
gatewayProbe: { connectLatencyMs: 123, error: null },
gatewayProbeAuth: { token: "tok" },
gatewayProbeAuthWarning: "warn-text",
gatewaySelf: { host: "gateway", version: "1.2.3" },
gatewayService: {
label: "LaunchAgent",
installed: true,
managedByOpenClaw: true,
loadedText: "loaded",
runtimeShort: "running",
},
nodeService: {
label: "node",
installed: true,
loadedText: "loaded",
runtime: { status: "running", pid: 42 },
},
nodeOnlyGateway: null,
},
osSummary: { label: "macOS" },
summary: {
tasks: { total: 3, active: 1, failures: 0, byStatus: { queued: 1, running: 1 } },
taskAudit: { errors: 1, warnings: 0 },
heartbeat: { agents: [{ agentId: "main", enabled: true, everyMs: 60_000, every: "1m" }] },
queuedSystemEvents: ["one", "two"],
sessions: {
count: 2,
paths: ["store.json"],
defaults: { model: "gpt-5.4", contextTokens: 12_000 },
recent: [
{ key: "session-key", kind: "chat", updatedAt: 1, age: 5_000, model: "gpt-5.4" },
],
},
},
securityAudit: {
summary: { critical: 0, warn: 1, info: 0 },
findings: [{ severity: "warn", title: "Warn first", detail: "warn detail" }],
},
health: { durationMs: 42 },
usageLines: ["usage line"],
lastHeartbeat: {
ts: Date.now() - 30_000,
status: "ok",
channel: "discord",
accountId: "acct",
},
agentStatus: {
defaultId: "main",
bootstrapPendingCount: 1,
totalSessions: 2,
agents: [{ id: "main", lastActiveAgeMs: 60_000 }],
},
channels: {
rows: [{ id: "discord", label: "Discord", enabled: true, state: "ok", detail: "ready" }],
},
channelIssues: [{ channel: "discord", message: "warn msg" }],
memory: { files: 1, chunks: 2, vector: {}, fts: {}, cache: {} },
memoryPlugin: { enabled: true, slot: "memory" },
pluginCompatibility: [{ pluginId: "a", severity: "warn", message: "legacy" }],
pairingRecovery: { requestId: "req-1" },
tableWidth: 120,
ok: (value: string) => `ok(${value})`,
warn: (value: string) => `warn(${value})`,
muted: (value: string) => `muted(${value})`,
shortenText: (value: string) => value,
formatCliCommand: (value: string) => `cmd:${value}`,
formatTimeAgo: (value: number) => `${value}ms`,
formatKTokens: (value: number) => `${Math.round(value / 1000)}k`,
formatTokensCompact: () => "12k",
formatPromptCacheCompact: () => "cache ok",
formatHealthChannelLines: () => ["Discord: OK · ready"],
formatPluginCompatibilityNotice: (notice: { message?: unknown }) => String(notice.message),
formatUpdateAvailableHint: () => "update available",
resolveMemoryVectorState: () => ({ state: "ready", tone: "ok" }),
resolveMemoryFtsState: () => ({ state: "ready", tone: "warn" }),
resolveMemoryCacheSummary: () => ({ text: "cache warm", tone: "muted" }),
accentDim: (value: string) => `accent(${value})`,
theme: {
heading: (value: string) => `# ${value}`,
muted: (value: string) => `muted(${value})`,
warn: (value: string) => `warn(${value})`,
error: (value: string) => `error(${value})`,
},
renderTable: ({ rows }: { rows: Array<Record<string, string>> }) => `table:${rows.length}`,
updateValue: "available · custom update",
} as unknown as Parameters<typeof buildStatusCommandReportData>[0]);
}),
);
expect(result.overviewRows[0]).toEqual({
Item: "OS",

View File

@@ -0,0 +1,222 @@
import type { HeartbeatEventPayload } from "../infra/heartbeat-events.js";
import type { Tone } from "../memory-host-sdk/status.js";
import type { PluginCompatibilityNotice } from "../plugins/status.js";
import type { buildStatusCommandOverviewRows } from "./status-overview-rows.ts";
import type { StatusOverviewSurface } from "./status-overview-surface.ts";
import type { AgentLocalStatus } from "./status.agent-local.js";
import type { buildStatusCommandReportData } from "./status.command-report-data.ts";
import type { MemoryPluginStatus, MemoryStatusSnapshot } from "./status.scan.shared.js";
import type { StatusSummary } from "./status.types.js";
type StatusCommandOverviewRowsParams = Parameters<typeof buildStatusCommandOverviewRows>[0];
type StatusCommandReportDataParams = Parameters<typeof buildStatusCommandReportData>[0];
export const baseStatusCfg = {
update: { channel: "stable" },
gateway: { bind: "loopback" },
} as const;
export const baseStatusUpdate = {
installKind: "git",
git: {
branch: "main",
tag: "v1.2.3",
upstream: "origin/main",
behind: 2,
ahead: 0,
dirty: false,
fetchOk: true,
},
registry: { latestVersion: "2026.4.10" },
} as never;
export const baseStatusGatewaySnapshot = {
gatewayMode: "remote",
remoteUrlMissing: false,
gatewayConnection: {
url: "wss://gateway.example.com",
urlSource: "config",
message: "Gateway target: wss://gateway.example.com",
},
gatewayReachable: true,
gatewayProbe: { connectLatencyMs: 42, error: null } as never,
gatewayProbeAuth: { token: "tok" },
gatewayProbeAuthWarning: "warn-text",
gatewaySelf: { host: "gateway", version: "1.2.3" },
} as const;
export const baseStatusOverviewScanFields = {
cfg: baseStatusCfg,
update: baseStatusUpdate,
tailscaleMode: "serve",
tailscaleDns: "box.tail.ts.net",
tailscaleHttpsUrl: "https://box.tail.ts.net",
...baseStatusGatewaySnapshot,
};
export const baseStatusGatewayService = {
label: "LaunchAgent",
installed: true,
managedByOpenClaw: true,
loadedText: "loaded",
runtimeShort: "running",
};
export const baseStatusNodeService = {
label: "node",
installed: true,
loadedText: "loaded",
runtime: { status: "running", pid: 42 },
};
export const baseStatusServices = {
gatewayService: baseStatusGatewayService,
nodeService: baseStatusNodeService,
nodeOnlyGateway: null,
};
export const baseStatusOverviewSurface = {
...baseStatusOverviewScanFields,
...baseStatusServices,
} as unknown as StatusOverviewSurface;
export const baseStatusSummary = {
tasks: { total: 3, active: 1, failures: 0, byStatus: { queued: 1, running: 1 } },
taskAudit: { errors: 1, warnings: 0 },
heartbeat: {
defaultAgentId: "main",
agents: [{ agentId: "main", enabled: true, everyMs: 60_000, every: "1m" }],
},
channelSummary: [],
queuedSystemEvents: ["one", "two"],
sessions: {
count: 2,
paths: ["store.json"],
defaults: { model: "gpt-5.4", contextTokens: 12_000 },
recent: [{ key: "session-key", kind: "direct", updatedAt: 1, age: 5_000, model: "gpt-5.4" }],
byAgent: [],
},
} as unknown as StatusSummary;
export const baseStatusAgentStatus = {
defaultId: "main",
bootstrapPendingCount: 1,
totalSessions: 2,
agents: [{ id: "main", lastActiveAgeMs: 60_000 }] as AgentLocalStatus[],
};
export const baseStatusMemory = {
agentId: "main",
files: 1,
chunks: 2,
vector: {},
fts: {},
cache: {},
} as unknown as MemoryStatusSnapshot;
export const baseStatusMemoryPlugin = {
enabled: true,
slot: "memory",
} as const satisfies MemoryPluginStatus;
export const baseStatusPluginCompatibility = [
{ pluginId: "a", severity: "warn", message: "legacy" },
] as PluginCompatibilityNotice[];
export function createStatusLastHeartbeat(): HeartbeatEventPayload {
return {
ts: Date.now() - 30_000,
status: "ok",
channel: "discord",
accountId: "acct",
};
}
export const statusTestDecorators = {
ok: (value: string) => `ok(${value})`,
warn: (value: string) => `warn(${value})`,
muted: (value: string) => `muted(${value})`,
accentDim: (value: string) => `accent(${value})`,
};
export const statusTestFormatting = {
shortenText: (value: string) => value,
formatCliCommand: (value: string) => `cmd:${value}`,
formatTimeAgo: (value: number) => `${value}ms`,
formatKTokens: (value: number) => `${Math.round(value / 1000)}k`,
formatTokensCompact: () => "12k",
formatPromptCacheCompact: () => "cache ok",
formatHealthChannelLines: () => ["Discord: OK · ready"],
formatPluginCompatibilityNotice: (notice: { message?: unknown }) => String(notice.message),
formatUpdateAvailableHint: () => "update available",
};
export const statusTestMemoryResolvers = {
resolveMemoryVectorState: () => ({ state: "ready", tone: "ok" as Tone }),
resolveMemoryFtsState: () => ({ state: "ready", tone: "warn" as Tone }),
resolveMemoryCacheSummary: () => ({ text: "cache warm", tone: "muted" as Tone }),
};
export const statusTestTheme = {
heading: (value: string) => `# ${value}`,
muted: (value: string) => `muted(${value})`,
warn: (value: string) => `warn(${value})`,
error: (value: string) => `error(${value})`,
};
export function createStatusCommandOverviewRowsParams(
overrides: Partial<StatusCommandOverviewRowsParams> = {},
): StatusCommandOverviewRowsParams {
return {
opts: { deep: true },
surface: baseStatusOverviewSurface,
osLabel: "macOS",
summary: baseStatusSummary,
health: { durationMs: 42 },
lastHeartbeat: createStatusLastHeartbeat(),
agentStatus: baseStatusAgentStatus,
memory: baseStatusMemory,
memoryPlugin: baseStatusMemoryPlugin,
pluginCompatibility: baseStatusPluginCompatibility,
...statusTestDecorators,
...statusTestFormatting,
...statusTestMemoryResolvers,
updateValue: "available · custom update",
...overrides,
};
}
export function createStatusCommandReportDataParams(
overrides: Partial<StatusCommandReportDataParams> = {},
): StatusCommandReportDataParams {
return {
opts: { deep: true, verbose: true },
surface: baseStatusOverviewSurface,
osSummary: { label: "macOS" } as never,
summary: baseStatusSummary,
securityAudit: {
summary: { critical: 0, warn: 1, info: 0 },
findings: [{ severity: "warn", title: "Warn first", detail: "warn detail" }],
},
health: { durationMs: 42 },
usageLines: ["usage line"],
lastHeartbeat: createStatusLastHeartbeat(),
agentStatus: baseStatusAgentStatus,
channels: {
rows: [{ id: "discord", label: "Discord", enabled: true, state: "ok", detail: "ready" }],
},
channelIssues: [{ channel: "discord", message: "warn msg" }],
memory: baseStatusMemory,
memoryPlugin: baseStatusMemoryPlugin,
pluginCompatibility: baseStatusPluginCompatibility,
pairingRecovery: { requestId: "req-1" },
tableWidth: 120,
...statusTestDecorators,
...statusTestFormatting,
...statusTestMemoryResolvers,
theme: statusTestTheme,
renderTable: ({ rows }: { rows: Array<Record<string, string>> }) => `table:${rows.length}`,
updateValue: "available · custom update",
...overrides,
};
}