blob: b5e625d5469c13d54a171239b8ba351b447dab6d [file] [log] [blame]
Sean McCulloughb29f8912025-04-20 15:39:11 -07001import { test, expect } from "@sand4rt/experimental-ct-web";
2import { SketchContainerStatus } from "./sketch-container-status";
Sean McCullough86b56862025-04-18 13:04:03 -07003import { State } from "../types";
4
Sean McCulloughb29f8912025-04-20 15:39:11 -07005// Mock complete state for testing
6const mockCompleteState: State = {
7 hostname: "test-host",
8 working_dir: "/test/dir",
9 initial_commit: "abcdef1234567890",
10 message_count: 42,
11 os: "linux",
12 title: "Test Session",
13 total_usage: {
14 input_tokens: 1000,
15 output_tokens: 2000,
16 cache_read_input_tokens: 300,
17 cache_creation_input_tokens: 400,
18 total_cost_usd: 0.25,
Sean McCulloughd9f13372025-04-21 15:08:49 -070019 start_time: "",
20 messages: 0,
21 tool_uses: {},
Sean McCulloughb29f8912025-04-20 15:39:11 -070022 },
Philip Zeyliger99a9a022025-04-27 15:15:25 +000023 outstanding_llm_calls: 0,
24 outstanding_tool_calls: [],
Sean McCulloughb29f8912025-04-20 15:39:11 -070025};
26
27test("render props", async ({ mount }) => {
28 const component = await mount(SketchContainerStatus, {
29 props: {
30 state: mockCompleteState,
31 },
32 });
33 await expect(component.locator("#hostname")).toContainText(
34 mockCompleteState.hostname,
35 );
36 // Check that all expected elements exist
37 await expect(component.locator("#workingDir")).toContainText(
38 mockCompleteState.working_dir,
39 );
40 await expect(component.locator("#initialCommit")).toContainText(
41 mockCompleteState.initial_commit.substring(0, 8),
42 );
43
Autoformatter5c70bfe2025-04-25 21:28:00 +000044 await expect(component.locator("#messageCount")).toContainText(
Sean McCulloughb29f8912025-04-20 15:39:11 -070045 mockCompleteState.message_count + "",
46 );
Josh Bleecher Snyder35889972025-04-24 20:48:16 +000047 const expectedTotalInputTokens =
48 mockCompleteState.total_usage.input_tokens +
49 mockCompleteState.total_usage.cache_read_input_tokens +
50 mockCompleteState.total_usage.cache_creation_input_tokens;
Sean McCulloughb29f8912025-04-20 15:39:11 -070051 await expect(component.locator("#inputTokens")).toContainText(
Josh Bleecher Snydera0801ad2025-04-25 19:34:53 +000052 expectedTotalInputTokens.toLocaleString(),
Sean McCulloughb29f8912025-04-20 15:39:11 -070053 );
54 await expect(component.locator("#outputTokens")).toContainText(
Josh Bleecher Snydera0801ad2025-04-25 19:34:53 +000055 mockCompleteState.total_usage.output_tokens.toLocaleString(),
Sean McCulloughb29f8912025-04-20 15:39:11 -070056 );
Sean McCulloughb29f8912025-04-20 15:39:11 -070057 await expect(component.locator("#totalCost")).toContainText(
58 "$" + mockCompleteState.total_usage.total_cost_usd.toFixed(2),
59 );
60});
61
62test("renders with undefined state", async ({ mount }) => {
63 const component = await mount(SketchContainerStatus, {});
64
65 // Elements should exist but be empty
66 await expect(component.locator("#hostname")).toContainText("");
67 await expect(component.locator("#workingDir")).toContainText("");
68 await expect(component.locator("#initialCommit")).toContainText("");
69 await expect(component.locator("#messageCount")).toContainText("");
Josh Bleecher Snyder35889972025-04-24 20:48:16 +000070 await expect(component.locator("#inputTokens")).toContainText("0");
Sean McCulloughb29f8912025-04-20 15:39:11 -070071 await expect(component.locator("#outputTokens")).toContainText("");
72 await expect(component.locator("#totalCost")).toContainText("$0.00");
73});
74
75test("renders with partial state data", async ({ mount }) => {
76 const partialState: Partial<State> = {
77 hostname: "partial-host",
78 message_count: 10,
Sean McCullough86b56862025-04-18 13:04:03 -070079 os: "linux",
Sean McCulloughb29f8912025-04-20 15:39:11 -070080 title: "Partial Test",
Sean McCullough86b56862025-04-18 13:04:03 -070081 total_usage: {
Sean McCulloughb29f8912025-04-20 15:39:11 -070082 input_tokens: 500,
Sean McCulloughd9f13372025-04-21 15:08:49 -070083 start_time: "",
84 messages: 0,
85 output_tokens: 0,
86 cache_read_input_tokens: 0,
87 cache_creation_input_tokens: 0,
88 total_cost_usd: 0,
89 tool_uses: {},
Sean McCullough71941bd2025-04-18 13:31:48 -070090 },
Sean McCullough86b56862025-04-18 13:04:03 -070091 };
92
Sean McCulloughb29f8912025-04-20 15:39:11 -070093 const component = await mount(SketchContainerStatus, {
94 props: {
95 state: partialState as State,
96 },
Sean McCullough86b56862025-04-18 13:04:03 -070097 });
98
Sean McCulloughb29f8912025-04-20 15:39:11 -070099 // Check that elements with data are properly populated
100 await expect(component.locator("#hostname")).toContainText("partial-host");
101 await expect(component.locator("#messageCount")).toContainText("10");
Josh Bleecher Snyder35889972025-04-24 20:48:16 +0000102
103 const expectedTotalInputTokens =
104 partialState.total_usage.input_tokens +
105 partialState.total_usage.cache_read_input_tokens +
106 partialState.total_usage.cache_creation_input_tokens;
107 await expect(component.locator("#inputTokens")).toContainText(
Josh Bleecher Snydera0801ad2025-04-25 19:34:53 +0000108 expectedTotalInputTokens.toLocaleString(),
Josh Bleecher Snyder35889972025-04-24 20:48:16 +0000109 );
Sean McCullough86b56862025-04-18 13:04:03 -0700110
Sean McCulloughb29f8912025-04-20 15:39:11 -0700111 // Check that elements without data are empty
112 await expect(component.locator("#workingDir")).toContainText("");
113 await expect(component.locator("#initialCommit")).toContainText("");
Josh Bleecher Snyder35889972025-04-24 20:48:16 +0000114 await expect(component.locator("#outputTokens")).toContainText("0");
Sean McCulloughb29f8912025-04-20 15:39:11 -0700115 await expect(component.locator("#totalCost")).toContainText("$0.00");
116});
Sean McCullough86b56862025-04-18 13:04:03 -0700117
Sean McCulloughb29f8912025-04-20 15:39:11 -0700118test("handles cost formatting correctly", async ({ mount }) => {
119 // Test with different cost values
120 const testCases = [
121 { cost: 0, expected: "$0.00" },
122 { cost: 0.1, expected: "$0.10" },
123 { cost: 1.234, expected: "$1.23" },
124 { cost: 10.009, expected: "$10.01" },
125 ];
126
127 for (const testCase of testCases) {
128 const stateWithCost = {
129 ...mockCompleteState,
Sean McCullough86b56862025-04-18 13:04:03 -0700130 total_usage: {
Sean McCulloughb29f8912025-04-20 15:39:11 -0700131 ...mockCompleteState.total_usage,
132 total_cost_usd: testCase.cost,
Sean McCullough71941bd2025-04-18 13:31:48 -0700133 },
Sean McCullough86b56862025-04-18 13:04:03 -0700134 };
135
Sean McCulloughb29f8912025-04-20 15:39:11 -0700136 const component = await mount(SketchContainerStatus, {
137 props: {
138 state: stateWithCost,
139 },
140 });
141 await expect(component.locator("#totalCost")).toContainText(
142 testCase.expected,
143 );
144 await component.unmount();
145 }
146});
Sean McCullough86b56862025-04-18 13:04:03 -0700147
Sean McCulloughb29f8912025-04-20 15:39:11 -0700148test("truncates commit hash to 8 characters", async ({ mount }) => {
149 const stateWithLongCommit = {
150 ...mockCompleteState,
151 initial_commit: "1234567890abcdef1234567890abcdef12345678",
152 };
Sean McCullough71941bd2025-04-18 13:31:48 -0700153
Sean McCulloughb29f8912025-04-20 15:39:11 -0700154 const component = await mount(SketchContainerStatus, {
155 props: {
156 state: stateWithLongCommit,
157 },
Sean McCullough86b56862025-04-18 13:04:03 -0700158 });
159
Sean McCulloughb29f8912025-04-20 15:39:11 -0700160 await expect(component.locator("#initialCommit")).toContainText("12345678");
161});
Sean McCullough86b56862025-04-18 13:04:03 -0700162
Sean McCulloughb29f8912025-04-20 15:39:11 -0700163test("has correct link elements", async ({ mount }) => {
164 const component = await mount(SketchContainerStatus, {
165 props: {
166 state: mockCompleteState,
167 },
Sean McCullough86b56862025-04-18 13:04:03 -0700168 });
169
Sean McCulloughb29f8912025-04-20 15:39:11 -0700170 // Check for logs link
171 const logsLink = component.locator("a").filter({ hasText: "Logs" });
172 await expect(logsLink).toHaveAttribute("href", "logs");
Sean McCullough86b56862025-04-18 13:04:03 -0700173
Sean McCulloughb29f8912025-04-20 15:39:11 -0700174 // Check for download link
175 const downloadLink = component.locator("a").filter({ hasText: "Download" });
176 await expect(downloadLink).toHaveAttribute("href", "download");
Sean McCullough86b56862025-04-18 13:04:03 -0700177});