session-list-item.test.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /**
  2. * @vitest-environment happy-dom
  3. */
  4. import type { ReactNode } from "react";
  5. import { renderToStaticMarkup } from "react-dom/server";
  6. import { describe, expect, test, vi } from "vitest";
  7. import { SessionListItem } from "@/components/customs/session-list-item";
  8. import type { CurrencyCode } from "@/lib/utils/currency";
  9. import type { ActiveSessionInfo } from "@/types/session";
  10. vi.mock("@/i18n/routing", () => ({
  11. Link: ({
  12. href,
  13. children,
  14. ...rest
  15. }: {
  16. href: string;
  17. children: ReactNode;
  18. className?: string;
  19. }) => (
  20. <a href={href} {...rest}>
  21. {children}
  22. </a>
  23. ),
  24. }));
  25. vi.mock("@/lib/utils/currency", async () => {
  26. const actual =
  27. await vi.importActual<typeof import("@/lib/utils/currency")>("@/lib/utils/currency");
  28. return {
  29. ...actual,
  30. formatCurrency: () => "__COST__",
  31. };
  32. });
  33. const UP_ARROW = "\u2191";
  34. const DOWN_ARROW = "\u2193";
  35. const COST_SENTINEL = "__COST__";
  36. type SessionListItemProps = {
  37. session: ActiveSessionInfo;
  38. currencyCode?: CurrencyCode;
  39. showTokensCost?: boolean;
  40. };
  41. const SessionListItemTest = SessionListItem as unknown as (
  42. props: SessionListItemProps
  43. ) => JSX.Element;
  44. const baseSession: ActiveSessionInfo = {
  45. sessionId: "session-1",
  46. userName: "alice",
  47. userId: 1,
  48. keyId: 2,
  49. keyName: "key-1",
  50. providerId: 3,
  51. providerName: "openai",
  52. model: "gpt-4.1",
  53. apiType: "chat",
  54. startTime: 1700000000000,
  55. status: "completed",
  56. durationMs: 1500,
  57. inputTokens: 100,
  58. outputTokens: 50,
  59. costUsd: "0.0123",
  60. };
  61. function renderTextContent(options?: {
  62. showTokensCost?: boolean;
  63. sessionOverrides?: Partial<ActiveSessionInfo>;
  64. }) {
  65. const session = { ...baseSession, ...(options?.sessionOverrides ?? {}) };
  66. const html = renderToStaticMarkup(
  67. <SessionListItemTest session={session} showTokensCost={options?.showTokensCost} />
  68. );
  69. const container = document.createElement("div");
  70. container.innerHTML = html;
  71. return container.textContent ?? "";
  72. }
  73. describe("SessionListItem showTokensCost", () => {
  74. test("hides tokens and cost when disabled but keeps core fields", () => {
  75. const text = renderTextContent({ showTokensCost: false });
  76. expect(text).not.toContain(`${UP_ARROW}100`);
  77. expect(text).not.toContain(`${DOWN_ARROW}50`);
  78. expect(text).not.toContain(COST_SENTINEL);
  79. expect(text).toContain("alice");
  80. expect(text).toContain("key-1");
  81. expect(text).toContain("gpt-4.1");
  82. expect(text).toContain("@ openai");
  83. expect(text).toContain("1.5s");
  84. });
  85. test("shows tokens and cost by default", () => {
  86. const text = renderTextContent();
  87. expect(text).toContain(`${UP_ARROW}100`);
  88. expect(text).toContain(`${DOWN_ARROW}50`);
  89. expect(text).toContain(COST_SENTINEL);
  90. });
  91. });