Test fixture updates: - Add toolUseId fields (toolu_read1, toolu_edit1) to tool_use blocks - Add parentToolUseID-linked progress events for read and edit tools - Add orphaned SessionStart progress event (no parent) - Update tool_result references to match new toolUseId values - Add bash_progress and mcp_progress subtypes for subtype derivation session-parser tests (7 new): - toolUseId extraction from tool_use blocks with and without id field - parentToolUseId and progressSubtype extraction from hook_progress - Subtype derivation for bash_progress, mcp_progress, agent_progress - Fallback to "hook" for unknown data types - Undefined parentToolUseId when field is absent progress-grouper tests (7 new): - Partition parented progress into toolProgress map - Remove parented progress from filtered messages array - Keep orphaned progress (no parentToolUseId) in main stream - Keep progress with invalid parentToolUseId (no matching tool_call) - Empty input handling - Sort each group by rawIndex - Multiple tool_call parents tracked independently agent-progress-parser tests (full suite): - Parse user text events with prompt/agentId metadata extraction - Parse tool_use blocks into AgentToolCall events - Parse tool_result blocks with content extraction - Parse text content as text_response with line counting - Handle multiple content blocks in single turn - Post-pass tool_result→tool_call linking (sourceTool, language) - Empty input and malformed JSON → raw_content fallback - stripLineNumbers for cat-n prefixed output - summarizeToolCall for Read, Grep, Glob, Bash, Task, WarpGrep, etc. ProgressBadge component tests: - Collapsed state shows pill counts, hides content - Expanded state shows all event content via markdown - Subtype counting accuracy - Agent-only events route to AgentProgressView AgentProgressView component tests: - Prompt banner rendering with truncation - Agent ID and turn count display - Summary rows with timestamps and tool names - Click-to-expand drill-down content html-exporter tests (8 new): - Collapsible rendering for thinking, tool_call, tool_result - Toggle button and JavaScript inclusion - Non-collapsible messages lack collapse attributes - Diff content detection and highlighting - Progress badge rendering with toolProgress data filters tests (2 new): - hook_progress included/excluded by category toggle Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
158 lines
5.8 KiB
TypeScript
158 lines
5.8 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import type { ParsedMessage, MessageCategory } from "../../src/shared/types.js";
|
|
import { ALL_CATEGORIES, DEFAULT_HIDDEN_CATEGORIES } from "../../src/shared/types.js";
|
|
|
|
// Replicate the filter logic to test it in isolation
|
|
function filterMessages(
|
|
messages: ParsedMessage[],
|
|
enabledCategories: Set<MessageCategory>,
|
|
redactedUuids: Set<string> = new Set()
|
|
): ParsedMessage[] {
|
|
return messages.filter(
|
|
(m) => enabledCategories.has(m.category) && !redactedUuids.has(m.uuid)
|
|
);
|
|
}
|
|
|
|
function makeMsg(uuid: string, category: MessageCategory): ParsedMessage {
|
|
return { uuid, category, content: `Content for ${uuid}`, rawIndex: 0 };
|
|
}
|
|
|
|
describe("filters", () => {
|
|
const messages: ParsedMessage[] = [
|
|
makeMsg("1", "user_message"),
|
|
makeMsg("2", "assistant_text"),
|
|
makeMsg("3", "thinking"),
|
|
makeMsg("4", "tool_call"),
|
|
makeMsg("5", "tool_result"),
|
|
makeMsg("6", "system_message"),
|
|
makeMsg("7", "hook_progress"),
|
|
makeMsg("8", "file_snapshot"),
|
|
makeMsg("9", "summary"),
|
|
];
|
|
|
|
it("correctly includes messages by enabled category", () => {
|
|
const enabled = new Set<MessageCategory>(["user_message", "assistant_text"]);
|
|
const filtered = filterMessages(messages, enabled);
|
|
expect(filtered).toHaveLength(2);
|
|
expect(filtered.map((m) => m.category)).toEqual([
|
|
"user_message",
|
|
"assistant_text",
|
|
]);
|
|
});
|
|
|
|
it("correctly excludes messages by disabled category", () => {
|
|
const enabled = new Set<MessageCategory>(ALL_CATEGORIES);
|
|
enabled.delete("thinking");
|
|
const filtered = filterMessages(messages, enabled);
|
|
expect(filtered).toHaveLength(8);
|
|
expect(filtered.find((m) => m.category === "thinking")).toBeUndefined();
|
|
});
|
|
|
|
it("default filter state hides tool_result, system, hooks, and snapshots", () => {
|
|
const defaultEnabled = new Set(ALL_CATEGORIES);
|
|
for (const cat of DEFAULT_HIDDEN_CATEGORIES) {
|
|
defaultEnabled.delete(cat);
|
|
}
|
|
const filtered = filterMessages(messages, defaultEnabled);
|
|
expect(filtered.find((m) => m.category === "tool_result")).toBeUndefined();
|
|
expect(filtered.find((m) => m.category === "system_message")).toBeUndefined();
|
|
expect(filtered.find((m) => m.category === "hook_progress")).toBeUndefined();
|
|
expect(filtered.find((m) => m.category === "file_snapshot")).toBeUndefined();
|
|
expect(filtered).toHaveLength(5);
|
|
});
|
|
|
|
it("all-off filter returns empty array", () => {
|
|
const filtered = filterMessages(messages, new Set());
|
|
expect(filtered).toEqual([]);
|
|
});
|
|
|
|
it("all-on filter returns all messages", () => {
|
|
const filtered = filterMessages(messages, new Set(ALL_CATEGORIES));
|
|
expect(filtered).toHaveLength(9);
|
|
});
|
|
|
|
it("excludes redacted messages", () => {
|
|
const enabled = new Set(ALL_CATEGORIES);
|
|
const redacted = new Set(["1", "3"]);
|
|
const filtered = filterMessages(messages, enabled, redacted);
|
|
expect(filtered).toHaveLength(7);
|
|
expect(filtered.find((m) => m.uuid === "1")).toBeUndefined();
|
|
expect(filtered.find((m) => m.uuid === "3")).toBeUndefined();
|
|
});
|
|
|
|
it("getMatchCount returns count of messages matching search query", () => {
|
|
const lowerQuery = "content for 1";
|
|
const count = messages.filter((m) =>
|
|
m.content.toLowerCase().includes(lowerQuery)
|
|
).length;
|
|
expect(count).toBe(1);
|
|
});
|
|
|
|
it("getMatchCount returns 0 for empty query", () => {
|
|
const lowerQuery = "";
|
|
const count = lowerQuery
|
|
? messages.filter((m) => m.content.toLowerCase().includes(lowerQuery)).length
|
|
: 0;
|
|
expect(count).toBe(0);
|
|
});
|
|
|
|
it("conversation preset includes only user and assistant messages", () => {
|
|
const preset: MessageCategory[] = ["user_message", "assistant_text"];
|
|
const enabled = new Set(preset);
|
|
const filtered = filterMessages(messages, enabled);
|
|
expect(filtered).toHaveLength(2);
|
|
expect(filtered.every((m) => m.category === "user_message" || m.category === "assistant_text")).toBe(true);
|
|
});
|
|
|
|
it("debug preset includes only tool calls and results", () => {
|
|
const preset: MessageCategory[] = ["tool_call", "tool_result"];
|
|
const enabled = new Set(preset);
|
|
const filtered = filterMessages(messages, enabled);
|
|
expect(filtered).toHaveLength(2);
|
|
expect(filtered.every((m) => m.category === "tool_call" || m.category === "tool_result")).toBe(true);
|
|
});
|
|
|
|
it("hook_progress included when category is enabled", () => {
|
|
const enabled = new Set<MessageCategory>(ALL_CATEGORIES);
|
|
const filtered = filterMessages(messages, enabled);
|
|
expect(filtered.find((m) => m.category === "hook_progress")).toBeDefined();
|
|
});
|
|
|
|
it("hook_progress excluded when category is disabled", () => {
|
|
const enabled = new Set<MessageCategory>(ALL_CATEGORIES);
|
|
enabled.delete("hook_progress");
|
|
const filtered = filterMessages(messages, enabled);
|
|
expect(filtered.find((m) => m.category === "hook_progress")).toBeUndefined();
|
|
});
|
|
|
|
it("category counts are computed correctly", () => {
|
|
const counts: Record<string, number> = {};
|
|
for (const cat of ALL_CATEGORIES) {
|
|
counts[cat] = 0;
|
|
}
|
|
for (const msg of messages) {
|
|
counts[msg.category]++;
|
|
}
|
|
expect(counts["user_message"]).toBe(1);
|
|
expect(counts["assistant_text"]).toBe(1);
|
|
expect(counts["thinking"]).toBe(1);
|
|
expect(Object.values(counts).reduce((a, b) => a + b, 0)).toBe(9);
|
|
});
|
|
|
|
it("category counts exclude redacted messages", () => {
|
|
const redacted = new Set(["1", "2"]);
|
|
const counts: Record<string, number> = {};
|
|
for (const cat of ALL_CATEGORIES) {
|
|
counts[cat] = 0;
|
|
}
|
|
for (const msg of messages) {
|
|
if (!redacted.has(msg.uuid)) {
|
|
counts[msg.category]++;
|
|
}
|
|
}
|
|
expect(counts["user_message"]).toBe(0);
|
|
expect(counts["assistant_text"]).toBe(0);
|
|
expect(Object.values(counts).reduce((a, b) => a + b, 0)).toBe(7);
|
|
});
|
|
});
|