paperclip/server/src/__tests__/heartbeat-run-summary.test.ts
HenkDz 14d59da316 feat(adapters): external adapter plugin system with dynamic UI parser
- Plugin loader: install/reload/remove/reinstall external adapters
  from npm packages or local directories
- Plugin store persisted at ~/.paperclip/adapter-plugins.json
- Self-healing UI parser resolution with version caching
- UI: Adapter Manager page, dynamic loader, display registry
  with humanized names for unknown adapter types
- Dev watch: exclude adapter-plugins dir from tsx watcher
  to prevent mid-request server restarts during reinstall
- All consumer fallbacks use getAdapterLabel() for consistent display
- AdapterTypeDropdown uses controlled open state for proper close behavior
- Remove hermes-local from built-in UI (externalized to plugin)
- Add docs for external adapters and UI parser contract
2026-04-03 21:11:20 +01:00

57 lines
1.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
summarizeHeartbeatRunResultJson,
buildHeartbeatRunIssueComment,
} from "../services/heartbeat-run-summary.js";
describe("summarizeHeartbeatRunResultJson", () => {
it("truncates text fields and preserves cost aliases", () => {
const summary = summarizeHeartbeatRunResultJson({
summary: "a".repeat(600),
result: "ok",
message: "done",
error: "failed",
total_cost_usd: 1.23,
cost_usd: 0.45,
costUsd: 0.67,
nested: { ignored: true },
});
expect(summary).toEqual({
summary: "a".repeat(500),
result: "ok",
message: "done",
error: "failed",
total_cost_usd: 1.23,
cost_usd: 0.45,
costUsd: 0.67,
});
});
it("returns null for non-object and irrelevant payloads", () => {
expect(summarizeHeartbeatRunResultJson(null)).toBeNull();
expect(summarizeHeartbeatRunResultJson(["nope"] as unknown as Record<string, unknown>)).toBeNull();
expect(summarizeHeartbeatRunResultJson({ nested: { only: "ignored" } })).toBeNull();
});
});
describe("buildHeartbeatRunIssueComment", () => {
it("uses the final summary text for issue comments on successful runs", () => {
const comment = buildHeartbeatRunIssueComment({
summary: "## Summary\n\n- fixed deploy config\n- posted issue update",
});
expect(comment).toContain("## Summary");
expect(comment).toContain("- fixed deploy config");
expect(comment).not.toContain("Run summary");
});
it("falls back to result or message when summary is missing", () => {
expect(buildHeartbeatRunIssueComment({ result: "done" })).toBe("done");
expect(buildHeartbeatRunIssueComment({ message: "completed" })).toBe("completed");
});
it("returns null when there is no usable final text", () => {
expect(buildHeartbeatRunIssueComment({ costUsd: 1.2 })).toBeNull();
});
});