blob: ca1a8f533132505f2cfaf0a7ef8a518f126a1768 [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,
Sean McCulloughb29f8912025-04-20 15:39:11 -070030};
31
32test("render props", async ({ mount }) => {
33 const component = await mount(SketchContainerStatus, {
34 props: {
35 state: mockCompleteState,
36 },
37 });
38 await expect(component.locator("#hostname")).toContainText(
39 mockCompleteState.hostname,
40 );
41 // Check that all expected elements exist
42 await expect(component.locator("#workingDir")).toContainText(
43 mockCompleteState.working_dir,
44 );
Autoformatter3d040bd2025-06-06 02:35:19 +000045
Josh Bleecher Snyder44f847a2025-06-05 14:33:50 -070046 // Show details to access the popup elements
philip.zeyliger6d3de482025-06-10 19:38:14 -070047 await component.locator(".info-toggle").click();
Autoformatter3d040bd2025-06-06 02:35:19 +000048
Sean McCulloughb29f8912025-04-20 15:39:11 -070049 await expect(component.locator("#initialCommit")).toContainText(
50 mockCompleteState.initial_commit.substring(0, 8),
51 );
52
Autoformatter5c70bfe2025-04-25 21:28:00 +000053 await expect(component.locator("#messageCount")).toContainText(
Sean McCulloughb29f8912025-04-20 15:39:11 -070054 mockCompleteState.message_count + "",
55 );
Josh Bleecher Snyder35889972025-04-24 20:48:16 +000056 const expectedTotalInputTokens =
57 mockCompleteState.total_usage.input_tokens +
58 mockCompleteState.total_usage.cache_read_input_tokens +
59 mockCompleteState.total_usage.cache_creation_input_tokens;
Sean McCulloughb29f8912025-04-20 15:39:11 -070060 await expect(component.locator("#inputTokens")).toContainText(
Josh Bleecher Snydera0801ad2025-04-25 19:34:53 +000061 expectedTotalInputTokens.toLocaleString(),
Sean McCulloughb29f8912025-04-20 15:39:11 -070062 );
63 await expect(component.locator("#outputTokens")).toContainText(
Josh Bleecher Snydera0801ad2025-04-25 19:34:53 +000064 mockCompleteState.total_usage.output_tokens.toLocaleString(),
Sean McCulloughb29f8912025-04-20 15:39:11 -070065 );
Sean McCulloughb29f8912025-04-20 15:39:11 -070066 await expect(component.locator("#totalCost")).toContainText(
67 "$" + mockCompleteState.total_usage.total_cost_usd.toFixed(2),
68 );
69});
70
Sean McCulloughb29f8912025-04-20 15:39:11 -070071test("renders with partial state data", async ({ mount }) => {
72 const partialState: Partial<State> = {
Philip Zeyligerd03318d2025-05-08 13:09:12 -070073 state_version: 2,
Sean McCulloughb29f8912025-04-20 15:39:11 -070074 hostname: "partial-host",
75 message_count: 10,
Sean McCullough86b56862025-04-18 13:04:03 -070076 os: "linux",
Josh Bleecher Snyder19969a92025-06-05 14:34:02 -070077 slug: "partial-test",
Philip Zeyligerc72fff52025-04-29 20:17:54 +000078 session_id: "partial-session",
79 ssh_available: false,
Sean McCullough86b56862025-04-18 13:04:03 -070080 total_usage: {
Sean McCulloughb29f8912025-04-20 15:39:11 -070081 input_tokens: 500,
Sean McCulloughd9f13372025-04-21 15:08:49 -070082 start_time: "",
83 messages: 0,
84 output_tokens: 0,
85 cache_read_input_tokens: 0,
86 cache_creation_input_tokens: 0,
87 total_cost_usd: 0,
88 tool_uses: {},
Sean McCullough71941bd2025-04-18 13:31:48 -070089 },
Sean McCullough86b56862025-04-18 13:04:03 -070090 };
91
Sean McCulloughb29f8912025-04-20 15:39:11 -070092 const component = await mount(SketchContainerStatus, {
93 props: {
94 state: partialState as State,
95 },
Sean McCullough86b56862025-04-18 13:04:03 -070096 });
97
Sean McCulloughb29f8912025-04-20 15:39:11 -070098 // Check that elements with data are properly populated
99 await expect(component.locator("#hostname")).toContainText("partial-host");
Autoformatter3d040bd2025-06-06 02:35:19 +0000100
Josh Bleecher Snyder44f847a2025-06-05 14:33:50 -0700101 // Show details to access the popup elements
philip.zeyliger6d3de482025-06-10 19:38:14 -0700102 await component.locator(".info-toggle").click();
Sean McCulloughb29f8912025-04-20 15:39:11 -0700103 await expect(component.locator("#messageCount")).toContainText("10");
Josh Bleecher Snyder35889972025-04-24 20:48:16 +0000104
105 const expectedTotalInputTokens =
106 partialState.total_usage.input_tokens +
107 partialState.total_usage.cache_read_input_tokens +
108 partialState.total_usage.cache_creation_input_tokens;
109 await expect(component.locator("#inputTokens")).toContainText(
Josh Bleecher Snydera0801ad2025-04-25 19:34:53 +0000110 expectedTotalInputTokens.toLocaleString(),
Josh Bleecher Snyder35889972025-04-24 20:48:16 +0000111 );
Sean McCullough86b56862025-04-18 13:04:03 -0700112
Sean McCulloughb29f8912025-04-20 15:39:11 -0700113 // Check that elements without data are empty
114 await expect(component.locator("#workingDir")).toContainText("");
115 await expect(component.locator("#initialCommit")).toContainText("");
Josh Bleecher Snyder35889972025-04-24 20:48:16 +0000116 await expect(component.locator("#outputTokens")).toContainText("0");
Josh Bleecher Snyder44f847a2025-06-05 14:33:50 -0700117 // totalCost element should not exist when cost is 0
118 await expect(component.locator("#totalCost")).toHaveCount(0);
Sean McCulloughb29f8912025-04-20 15:39:11 -0700119});
Sean McCulloughc7c2cc12025-06-13 03:21:18 +0000120
121test("formatGitHubRepo handles repository names with dots correctly", async ({
122 mount,
123}) => {
124 // Test repository with dots in name
125 const component = await mount(SketchContainerStatus, {
126 props: {
127 state: {
128 ...mockCompleteState,
129 git_origin: "git@github.com:user/repo.with.dots.git",
130 link_to_github: true,
131 },
132 },
133 });
134
135 // Check that the GitHub link is displayed correctly with dots preserved
136 const githubLink = component.locator("a.github-link");
137 await expect(githubLink).toContainText("user/repo.with.dots");
138 await expect(githubLink).toHaveAttribute(
139 "href",
140 "https://github.com/user/repo.with.dots",
141 );
142 await expect(githubLink).toHaveAttribute(
143 "title",
144 "git@github.com:user/repo.with.dots.git",
145 );
146});
147
148test("formatGitHubRepo handles boldsoftware/sketch.git correctly", async ({
149 mount,
150}) => {
151 // Test the specific case mentioned in the issue
152 const component = await mount(SketchContainerStatus, {
153 props: {
154 state: {
155 ...mockCompleteState,
156 git_origin: "git@github.com:boldsoftware/sketch.git",
157 link_to_github: true,
158 },
159 },
160 });
161
162 // Check that the GitHub link is displayed correctly
163 const githubLink = component.locator("a.github-link");
164 await expect(githubLink).toContainText("boldsoftware/sketch");
165 await expect(githubLink).toHaveAttribute(
166 "href",
167 "https://github.com/boldsoftware/sketch",
168 );
169 await expect(githubLink).toHaveAttribute(
170 "title",
171 "git@github.com:boldsoftware/sketch.git",
172 );
173});