Skip to content

Commit 3bc52ca

Browse files
AutoLTXamanape
andauthored
[FrontEnd] Display API cost and token usage in frontend (#7099)
Co-authored-by: amanape <[email protected]>
1 parent ce26f1c commit 3bc52ca

File tree

9 files changed

+411
-137
lines changed

9 files changed

+411
-137
lines changed

frontend/__tests__/components/features/conversation-panel/conversation-card.test.tsx

+98-21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render, screen, within } from "@testing-library/react";
1+
import { screen, within } from "@testing-library/react";
22
import {
33
afterAll,
44
afterEach,
@@ -10,6 +10,7 @@ import {
1010
vi,
1111
} from "vitest";
1212
import userEvent from "@testing-library/user-event";
13+
import { renderWithProviders } from "test-utils";
1314
import { formatTimeDelta } from "#/utils/format-time-delta";
1415
import { ConversationCard } from "#/components/features/conversation-panel/conversation-card";
1516
import { clickOnEditButton } from "./utils";
@@ -20,7 +21,11 @@ describe("ConversationCard", () => {
2021
const onChangeTitle = vi.fn();
2122

2223
beforeAll(() => {
23-
vi.stubGlobal("window", { open: vi.fn() });
24+
vi.stubGlobal("window", {
25+
open: vi.fn(),
26+
addEventListener: vi.fn(),
27+
removeEventListener: vi.fn(),
28+
});
2429
});
2530

2631
afterEach(() => {
@@ -32,7 +37,7 @@ describe("ConversationCard", () => {
3237
});
3338

3439
it("should render the conversation card", () => {
35-
render(
40+
renderWithProviders(
3641
<ConversationCard
3742
onDelete={onDelete}
3843
onChangeTitle={onChangeTitle}
@@ -51,7 +56,7 @@ describe("ConversationCard", () => {
5156
});
5257

5358
it("should render the selectedRepository if available", () => {
54-
const { rerender } = render(
59+
const { rerender } = renderWithProviders(
5560
<ConversationCard
5661
onDelete={onDelete}
5762
onChangeTitle={onChangeTitle}
@@ -82,7 +87,7 @@ describe("ConversationCard", () => {
8287

8388
it("should toggle a context menu when clicking the ellipsis button", async () => {
8489
const user = userEvent.setup();
85-
render(
90+
renderWithProviders(
8691
<ConversationCard
8792
onDelete={onDelete}
8893
onChangeTitle={onChangeTitle}
@@ -107,7 +112,7 @@ describe("ConversationCard", () => {
107112

108113
it("should call onDelete when the delete button is clicked", async () => {
109114
const user = userEvent.setup();
110-
render(
115+
renderWithProviders(
111116
<ConversationCard
112117
onDelete={onDelete}
113118
isActive
@@ -131,7 +136,7 @@ describe("ConversationCard", () => {
131136

132137
test("clicking the selectedRepository should not trigger the onClick handler", async () => {
133138
const user = userEvent.setup();
134-
render(
139+
renderWithProviders(
135140
<ConversationCard
136141
onDelete={onDelete}
137142
isActive
@@ -152,7 +157,7 @@ describe("ConversationCard", () => {
152157

153158
test("conversation title should call onChangeTitle when changed and blurred", async () => {
154159
const user = userEvent.setup();
155-
render(
160+
renderWithProviders(
156161
<ConversationCard
157162
onDelete={onDelete}
158163
isActive
@@ -181,7 +186,7 @@ describe("ConversationCard", () => {
181186

182187
it("should reset title and not call onChangeTitle when the title is empty", async () => {
183188
const user = userEvent.setup();
184-
render(
189+
renderWithProviders(
185190
<ConversationCard
186191
onDelete={onDelete}
187192
isActive
@@ -205,7 +210,7 @@ describe("ConversationCard", () => {
205210

206211
test("clicking the title should trigger the onClick handler", async () => {
207212
const user = userEvent.setup();
208-
render(
213+
renderWithProviders(
209214
<ConversationCard
210215
onClick={onClick}
211216
onDelete={onDelete}
@@ -225,7 +230,7 @@ describe("ConversationCard", () => {
225230

226231
test("clicking the title should not trigger the onClick handler if edit mode", async () => {
227232
const user = userEvent.setup();
228-
render(
233+
renderWithProviders(
229234
<ConversationCard
230235
onDelete={onDelete}
231236
isActive
@@ -246,7 +251,7 @@ describe("ConversationCard", () => {
246251

247252
test("clicking the delete button should not trigger the onClick handler", async () => {
248253
const user = userEvent.setup();
249-
render(
254+
renderWithProviders(
250255
<ConversationCard
251256
onDelete={onDelete}
252257
isActive
@@ -268,11 +273,80 @@ describe("ConversationCard", () => {
268273
expect(onClick).not.toHaveBeenCalled();
269274
});
270275

276+
it("should show display cost button only when showDisplayCostOption is true", async () => {
277+
const user = userEvent.setup();
278+
const { rerender } = renderWithProviders(
279+
<ConversationCard
280+
onDelete={onDelete}
281+
onChangeTitle={onChangeTitle}
282+
isActive
283+
title="Conversation 1"
284+
selectedRepository={null}
285+
lastUpdatedAt="2021-10-01T12:00:00Z"
286+
/>,
287+
);
288+
289+
const ellipsisButton = screen.getByTestId("ellipsis-button");
290+
await user.click(ellipsisButton);
291+
292+
// Wait for context menu to appear
293+
const menu = await screen.findByTestId("context-menu");
294+
expect(
295+
within(menu).queryByTestId("display-cost-button"),
296+
).not.toBeInTheDocument();
271297

298+
// Close menu
299+
await user.click(ellipsisButton);
300+
301+
rerender(
302+
<ConversationCard
303+
onDelete={onDelete}
304+
onChangeTitle={onChangeTitle}
305+
showDisplayCostOption
306+
isActive
307+
title="Conversation 1"
308+
selectedRepository={null}
309+
lastUpdatedAt="2021-10-01T12:00:00Z"
310+
/>,
311+
);
312+
313+
// Open menu again
314+
await user.click(ellipsisButton);
315+
316+
// Wait for context menu to appear and check for display cost button
317+
const newMenu = await screen.findByTestId("context-menu");
318+
within(newMenu).getByTestId("display-cost-button");
319+
});
320+
321+
it("should show metrics modal when clicking the display cost button", async () => {
322+
const user = userEvent.setup();
323+
renderWithProviders(
324+
<ConversationCard
325+
onDelete={onDelete}
326+
isActive
327+
onChangeTitle={onChangeTitle}
328+
title="Conversation 1"
329+
selectedRepository={null}
330+
lastUpdatedAt="2021-10-01T12:00:00Z"
331+
showDisplayCostOption
332+
/>,
333+
);
334+
335+
const ellipsisButton = screen.getByTestId("ellipsis-button");
336+
await user.click(ellipsisButton);
337+
338+
const menu = screen.getByTestId("context-menu");
339+
const displayCostButton = within(menu).getByTestId("display-cost-button");
340+
341+
await user.click(displayCostButton);
342+
343+
// Verify if metrics modal is displayed by checking for the modal content
344+
expect(screen.getByText("Metrics Information")).toBeInTheDocument();
345+
});
272346

273347
it("should not display the edit or delete options if the handler is not provided", async () => {
274348
const user = userEvent.setup();
275-
const { rerender } = render(
349+
const { rerender } = renderWithProviders(
276350
<ConversationCard
277351
onClick={onClick}
278352
onChangeTitle={onChangeTitle}
@@ -285,8 +359,9 @@ describe("ConversationCard", () => {
285359
const ellipsisButton = screen.getByTestId("ellipsis-button");
286360
await user.click(ellipsisButton);
287361

288-
expect(screen.queryByTestId("edit-button")).toBeInTheDocument();
289-
expect(screen.queryByTestId("delete-button")).not.toBeInTheDocument();
362+
const menu = await screen.findByTestId("context-menu");
363+
expect(within(menu).queryByTestId("edit-button")).toBeInTheDocument();
364+
expect(within(menu).queryByTestId("delete-button")).not.toBeInTheDocument();
290365

291366
// toggle to hide the context menu
292367
await user.click(ellipsisButton);
@@ -302,13 +377,15 @@ describe("ConversationCard", () => {
302377
);
303378

304379
await user.click(ellipsisButton);
305-
306-
expect(screen.queryByTestId("edit-button")).not.toBeInTheDocument();
307-
expect(screen.queryByTestId("delete-button")).toBeInTheDocument();
380+
const newMenu = await screen.findByTestId("context-menu");
381+
expect(
382+
within(newMenu).queryByTestId("edit-button"),
383+
).not.toBeInTheDocument();
384+
expect(within(newMenu).queryByTestId("delete-button")).toBeInTheDocument();
308385
});
309386

310387
it("should not render the ellipsis button if there are no actions", () => {
311-
const { rerender } = render(
388+
const { rerender } = renderWithProviders(
312389
<ConversationCard
313390
onClick={onClick}
314391
onDelete={onDelete}
@@ -347,7 +424,7 @@ describe("ConversationCard", () => {
347424

348425
describe("state indicator", () => {
349426
it("should render the 'STOPPED' indicator by default", () => {
350-
render(
427+
renderWithProviders(
351428
<ConversationCard
352429
onDelete={onDelete}
353430
isActive
@@ -362,7 +439,7 @@ describe("ConversationCard", () => {
362439
});
363440

364441
it("should render the other indicators when provided", () => {
365-
render(
442+
renderWithProviders(
366443
<ConversationCard
367444
onDelete={onDelete}
368445
isActive

0 commit comments

Comments
 (0)