blob: 7d01ac775ef1e5b687e93b1a814aa9d27bbb87f7 [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 = {
Philip Zeyligerd03318d2025-05-08 13:09:12 -07007 state_version: 2,
Sean McCulloughb29f8912025-04-20 15:39:11 -07008 hostname: "test-host",
9 working_dir: "/test/dir",
10 initial_commit: "abcdef1234567890",
11 message_count: 42,
12 os: "linux",
Josh Bleecher Snyder19969a92025-06-05 14:34:02 -070013 slug: "test-session",
Sean McCulloughb29f8912025-04-20 15:39:11 -070014 total_usage: {
15 input_tokens: 1000,
16 output_tokens: 2000,
17 cache_read_input_tokens: 300,
18 cache_creation_input_tokens: 400,
19 total_cost_usd: 0.25,
Sean McCulloughd9f13372025-04-21 15:08:49 -070020 start_time: "",
21 messages: 0,
22 tool_uses: {},
Sean McCulloughb29f8912025-04-20 15:39:11 -070023 },
Philip Zeyliger99a9a022025-04-27 15:15:25 +000024 outstanding_llm_calls: 0,
25 outstanding_tool_calls: [],
Philip Zeyligerc72fff52025-04-29 20:17:54 +000026 session_id: "test-session-id",
27 ssh_available: false,
Philip Zeyliger2c4db092025-04-28 16:57:50 -070028 in_container: true,
29 first_message_index: 0,
Philip Zeyliger64f60462025-06-16 13:57:10 -070030 diff_lines_added: 15,
31 diff_lines_removed: 3,
Sean McCulloughb29f8912025-04-20 15:39:11 -070032};
33
34test("render props", async ({ mount }) => {
35 const component = await mount(SketchContainerStatus, {
36 props: {
37 state: mockCompleteState,
38 },
39 });
40 await expect(component.locator("#hostname")).toContainText(
41 mockCompleteState.hostname,
42 );
43 // Check that all expected elements exist
44 await expect(component.locator("#workingDir")).toContainText(
45 mockCompleteState.working_dir,
46 );
Autoformatter3d040bd2025-06-06 02:35:19 +000047
Josh Bleecher Snyder44f847a2025-06-05 14:33:50 -070048 // Show details to access the popup elements
philip.zeyliger6d3de482025-06-10 19:38:14 -070049 await component.locator(".info-toggle").click();
Autoformatter3d040bd2025-06-06 02:35:19 +000050
Sean McCulloughb29f8912025-04-20 15:39:11 -070051 await expect(component.locator("#initialCommit")).toContainText(
52 mockCompleteState.initial_commit.substring(0, 8),
53 );
54
Autoformatter5c70bfe2025-04-25 21:28:00 +000055 await expect(component.locator("#messageCount")).toContainText(
Sean McCulloughb29f8912025-04-20 15:39:11 -070056 mockCompleteState.message_count + "",
57 );
Josh Bleecher Snyder35889972025-04-24 20:48:16 +000058 const expectedTotalInputTokens =
59 mockCompleteState.total_usage.input_tokens +
60 mockCompleteState.total_usage.cache_read_input_tokens +
61 mockCompleteState.total_usage.cache_creation_input_tokens;
Sean McCulloughb29f8912025-04-20 15:39:11 -070062 await expect(component.locator("#inputTokens")).toContainText(
Josh Bleecher Snydera0801ad2025-04-25 19:34:53 +000063 expectedTotalInputTokens.toLocaleString(),
Sean McCulloughb29f8912025-04-20 15:39:11 -070064 );
65 await expect(component.locator("#outputTokens")).toContainText(
Josh Bleecher Snydera0801ad2025-04-25 19:34:53 +000066 mockCompleteState.total_usage.output_tokens.toLocaleString(),
Sean McCulloughb29f8912025-04-20 15:39:11 -070067 );
Sean McCulloughb29f8912025-04-20 15:39:11 -070068 await expect(component.locator("#totalCost")).toContainText(
69 "$" + mockCompleteState.total_usage.total_cost_usd.toFixed(2),
70 );
71});
72
Sean McCulloughb29f8912025-04-20 15:39:11 -070073test("renders with partial state data", async ({ mount }) => {
74 const partialState: Partial<State> = {
Philip Zeyligerd03318d2025-05-08 13:09:12 -070075 state_version: 2,
Sean McCulloughb29f8912025-04-20 15:39:11 -070076 hostname: "partial-host",
77 message_count: 10,
Sean McCullough86b56862025-04-18 13:04:03 -070078 os: "linux",
Josh Bleecher Snyder19969a92025-06-05 14:34:02 -070079 slug: "partial-test",
Philip Zeyligerc72fff52025-04-29 20:17:54 +000080 session_id: "partial-session",
81 ssh_available: false,
Sean McCullough86b56862025-04-18 13:04:03 -070082 total_usage: {
Sean McCulloughb29f8912025-04-20 15:39:11 -070083 input_tokens: 500,
Sean McCulloughd9f13372025-04-21 15:08:49 -070084 start_time: "",
85 messages: 0,
86 output_tokens: 0,
87 cache_read_input_tokens: 0,
88 cache_creation_input_tokens: 0,
89 total_cost_usd: 0,
90 tool_uses: {},
Sean McCullough71941bd2025-04-18 13:31:48 -070091 },
Sean McCullough86b56862025-04-18 13:04:03 -070092 };
93
Sean McCulloughb29f8912025-04-20 15:39:11 -070094 const component = await mount(SketchContainerStatus, {
95 props: {
96 state: partialState as State,
97 },
Sean McCullough86b56862025-04-18 13:04:03 -070098 });
99
Sean McCulloughb29f8912025-04-20 15:39:11 -0700100 // Check that elements with data are properly populated
101 await expect(component.locator("#hostname")).toContainText("partial-host");
Autoformatter3d040bd2025-06-06 02:35:19 +0000102
Josh Bleecher Snyder44f847a2025-06-05 14:33:50 -0700103 // Show details to access the popup elements
philip.zeyliger6d3de482025-06-10 19:38:14 -0700104 await component.locator(".info-toggle").click();
Sean McCulloughb29f8912025-04-20 15:39:11 -0700105 await expect(component.locator("#messageCount")).toContainText("10");
Josh Bleecher Snyder35889972025-04-24 20:48:16 +0000106
107 const expectedTotalInputTokens =
108 partialState.total_usage.input_tokens +
109 partialState.total_usage.cache_read_input_tokens +
110 partialState.total_usage.cache_creation_input_tokens;
111 await expect(component.locator("#inputTokens")).toContainText(
Josh Bleecher Snydera0801ad2025-04-25 19:34:53 +0000112 expectedTotalInputTokens.toLocaleString(),
Josh Bleecher Snyder35889972025-04-24 20:48:16 +0000113 );
Sean McCullough86b56862025-04-18 13:04:03 -0700114
Sean McCulloughb29f8912025-04-20 15:39:11 -0700115 // Check that elements without data are empty
116 await expect(component.locator("#workingDir")).toContainText("");
117 await expect(component.locator("#initialCommit")).toContainText("");
Josh Bleecher Snyder35889972025-04-24 20:48:16 +0000118 await expect(component.locator("#outputTokens")).toContainText("0");
Josh Bleecher Snyder44f847a2025-06-05 14:33:50 -0700119 // totalCost element should not exist when cost is 0
120 await expect(component.locator("#totalCost")).toHaveCount(0);
Sean McCulloughb29f8912025-04-20 15:39:11 -0700121});
Sean McCulloughc7c2cc12025-06-13 03:21:18 +0000122
123test("formatGitHubRepo handles repository names with dots correctly", async ({
124 mount,
125}) => {
126 // Test repository with dots in name
127 const component = await mount(SketchContainerStatus, {
128 props: {
129 state: {
130 ...mockCompleteState,
131 git_origin: "git@github.com:user/repo.with.dots.git",
132 link_to_github: true,
133 },
134 },
135 });
136
137 // Check that the GitHub link is displayed correctly with dots preserved
138 const githubLink = component.locator("a.github-link");
139 await expect(githubLink).toContainText("user/repo.with.dots");
140 await expect(githubLink).toHaveAttribute(
141 "href",
142 "https://github.com/user/repo.with.dots",
143 );
144 await expect(githubLink).toHaveAttribute(
145 "title",
146 "git@github.com:user/repo.with.dots.git",
147 );
148});
149
150test("formatGitHubRepo handles boldsoftware/sketch.git correctly", async ({
151 mount,
152}) => {
153 // Test the specific case mentioned in the issue
154 const component = await mount(SketchContainerStatus, {
155 props: {
156 state: {
157 ...mockCompleteState,
158 git_origin: "git@github.com:boldsoftware/sketch.git",
159 link_to_github: true,
160 },
161 },
162 });
163
164 // Check that the GitHub link is displayed correctly
165 const githubLink = component.locator("a.github-link");
166 await expect(githubLink).toContainText("boldsoftware/sketch");
167 await expect(githubLink).toHaveAttribute(
168 "href",
169 "https://github.com/boldsoftware/sketch",
170 );
171 await expect(githubLink).toHaveAttribute(
172 "title",
173 "git@github.com:boldsoftware/sketch.git",
174 );
175});