session-status.test.ts 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. import { describe, expect, test, vi } from "vitest";
  2. vi.mock("@/lib/logger", () => ({
  3. logger: {
  4. trace: vi.fn(),
  5. debug: vi.fn(),
  6. info: vi.fn(),
  7. warn: vi.fn(),
  8. error: vi.fn(),
  9. },
  10. }));
  11. import {
  12. getSessionDisplayStatus,
  13. SESSION_DISPLAY_STATUS,
  14. type SessionStatusInput,
  15. } from "@/lib/session-status";
  16. describe("Session Status Logic", () => {
  17. describe("getSessionDisplayStatus", () => {
  18. test("IDLE: concurrentCount is 0 with no requests", () => {
  19. const input: SessionStatusInput = {
  20. concurrentCount: 0,
  21. requestCount: 0,
  22. status: "completed",
  23. };
  24. const result = getSessionDisplayStatus(input);
  25. expect(result.status).toBe(SESSION_DISPLAY_STATUS.IDLE);
  26. expect(result.label).toBe("IDLE");
  27. expect(result.pulse).toBe(false);
  28. expect(result.tooltipKey).toBe("status.idleTooltip");
  29. });
  30. test("IDLE: concurrentCount is 0 with completed requests", () => {
  31. const input: SessionStatusInput = {
  32. concurrentCount: 0,
  33. requestCount: 5,
  34. status: "completed",
  35. };
  36. const result = getSessionDisplayStatus(input);
  37. expect(result.status).toBe(SESSION_DISPLAY_STATUS.IDLE);
  38. expect(result.label).toBe("IDLE");
  39. expect(result.pulse).toBe(false);
  40. });
  41. test("INITIALIZING: first request still running (requestCount=0, concurrentCount>0)", () => {
  42. const input: SessionStatusInput = {
  43. concurrentCount: 1,
  44. requestCount: 0,
  45. status: "in_progress",
  46. };
  47. const result = getSessionDisplayStatus(input);
  48. expect(result.status).toBe(SESSION_DISPLAY_STATUS.INITIALIZING);
  49. expect(result.label).toBe("INIT");
  50. expect(result.pulse).toBe(true);
  51. expect(result.tooltipKey).toBe("status.initializingTooltip");
  52. expect(result.color).toContain("amber");
  53. });
  54. test("INITIALIZING: first request still running (requestCount=1, concurrentCount>0)", () => {
  55. const input: SessionStatusInput = {
  56. concurrentCount: 1,
  57. requestCount: 1,
  58. status: "in_progress",
  59. };
  60. const result = getSessionDisplayStatus(input);
  61. expect(result.status).toBe(SESSION_DISPLAY_STATUS.INITIALIZING);
  62. expect(result.label).toBe("INIT");
  63. expect(result.pulse).toBe(true);
  64. });
  65. test("IN_PROGRESS: has active requests after first (requestCount>1, concurrentCount>0)", () => {
  66. const input: SessionStatusInput = {
  67. concurrentCount: 2,
  68. requestCount: 5,
  69. status: "in_progress",
  70. };
  71. const result = getSessionDisplayStatus(input);
  72. expect(result.status).toBe(SESSION_DISPLAY_STATUS.IN_PROGRESS);
  73. expect(result.label).toBe("BUSY");
  74. expect(result.pulse).toBe(true);
  75. expect(result.tooltipKey).toBe("status.inProgressTooltip");
  76. expect(result.color).toContain("emerald");
  77. });
  78. test("IN_PROGRESS: single active request after first completed", () => {
  79. const input: SessionStatusInput = {
  80. concurrentCount: 1,
  81. requestCount: 2,
  82. status: "in_progress",
  83. };
  84. const result = getSessionDisplayStatus(input);
  85. expect(result.status).toBe(SESSION_DISPLAY_STATUS.IN_PROGRESS);
  86. expect(result.label).toBe("BUSY");
  87. expect(result.pulse).toBe(true);
  88. });
  89. test("ERROR: status is error takes priority", () => {
  90. const input: SessionStatusInput = {
  91. concurrentCount: 1,
  92. requestCount: 3,
  93. status: "error",
  94. };
  95. const result = getSessionDisplayStatus(input);
  96. expect(result.status).toBe(SESSION_DISPLAY_STATUS.IN_PROGRESS);
  97. expect(result.label).toBe("FAIL");
  98. expect(result.pulse).toBe(true);
  99. expect(result.tooltipKey).toBe("status.errorTooltip");
  100. expect(result.color).toContain("rose");
  101. });
  102. test("ERROR: status is error even with no concurrent requests", () => {
  103. const input: SessionStatusInput = {
  104. concurrentCount: 0,
  105. requestCount: 5,
  106. status: "error",
  107. };
  108. const result = getSessionDisplayStatus(input);
  109. expect(result.label).toBe("FAIL");
  110. expect(result.pulse).toBe(true);
  111. });
  112. test("handles undefined values with defaults", () => {
  113. const input: SessionStatusInput = {};
  114. const result = getSessionDisplayStatus(input);
  115. expect(result.status).toBe(SESSION_DISPLAY_STATUS.IDLE);
  116. expect(result.label).toBe("IDLE");
  117. expect(result.pulse).toBe(false);
  118. });
  119. test("handles partial input with only concurrentCount", () => {
  120. const input: SessionStatusInput = {
  121. concurrentCount: 1,
  122. };
  123. const result = getSessionDisplayStatus(input);
  124. expect(result.status).toBe(SESSION_DISPLAY_STATUS.INITIALIZING);
  125. expect(result.label).toBe("INIT");
  126. });
  127. test("handles partial input with only requestCount", () => {
  128. const input: SessionStatusInput = {
  129. requestCount: 10,
  130. };
  131. const result = getSessionDisplayStatus(input);
  132. expect(result.status).toBe(SESSION_DISPLAY_STATUS.IDLE);
  133. expect(result.label).toBe("IDLE");
  134. });
  135. test("high concurrency scenario", () => {
  136. const input: SessionStatusInput = {
  137. concurrentCount: 50,
  138. requestCount: 100,
  139. status: "in_progress",
  140. };
  141. const result = getSessionDisplayStatus(input);
  142. expect(result.status).toBe(SESSION_DISPLAY_STATUS.IN_PROGRESS);
  143. expect(result.label).toBe("BUSY");
  144. expect(result.pulse).toBe(true);
  145. });
  146. });
  147. describe("SESSION_DISPLAY_STATUS constants", () => {
  148. test("constants are uppercase strings", () => {
  149. expect(SESSION_DISPLAY_STATUS.IN_PROGRESS).toBe("IN_PROGRESS");
  150. expect(SESSION_DISPLAY_STATUS.IDLE).toBe("IDLE");
  151. expect(SESSION_DISPLAY_STATUS.INITIALIZING).toBe("INITIALIZING");
  152. });
  153. test("constants are readonly", () => {
  154. expect(Object.isFrozen(SESSION_DISPLAY_STATUS)).toBe(false);
  155. expect(typeof SESSION_DISPLAY_STATUS).toBe("object");
  156. });
  157. });
  158. describe("status transition scenarios", () => {
  159. test("session lifecycle: new -> initializing -> in_progress -> idle", () => {
  160. // New session, no requests yet
  161. const newSession: SessionStatusInput = {
  162. concurrentCount: 0,
  163. requestCount: 0,
  164. };
  165. expect(getSessionDisplayStatus(newSession).status).toBe(SESSION_DISPLAY_STATUS.IDLE);
  166. // First request starts
  167. const initializing: SessionStatusInput = {
  168. concurrentCount: 1,
  169. requestCount: 0,
  170. };
  171. expect(getSessionDisplayStatus(initializing).status).toBe(
  172. SESSION_DISPLAY_STATUS.INITIALIZING
  173. );
  174. // First request completes, second starts
  175. const inProgress: SessionStatusInput = {
  176. concurrentCount: 1,
  177. requestCount: 2,
  178. };
  179. expect(getSessionDisplayStatus(inProgress).status).toBe(SESSION_DISPLAY_STATUS.IN_PROGRESS);
  180. // All requests complete
  181. const idle: SessionStatusInput = {
  182. concurrentCount: 0,
  183. requestCount: 10,
  184. };
  185. expect(getSessionDisplayStatus(idle).status).toBe(SESSION_DISPLAY_STATUS.IDLE);
  186. });
  187. test("error can occur at any stage", () => {
  188. const errorDuringInit: SessionStatusInput = {
  189. concurrentCount: 1,
  190. requestCount: 0,
  191. status: "error",
  192. };
  193. expect(getSessionDisplayStatus(errorDuringInit).label).toBe("FAIL");
  194. const errorDuringProgress: SessionStatusInput = {
  195. concurrentCount: 3,
  196. requestCount: 10,
  197. status: "error",
  198. };
  199. expect(getSessionDisplayStatus(errorDuringProgress).label).toBe("FAIL");
  200. const errorAfterComplete: SessionStatusInput = {
  201. concurrentCount: 0,
  202. requestCount: 5,
  203. status: "error",
  204. };
  205. expect(getSessionDisplayStatus(errorAfterComplete).label).toBe("FAIL");
  206. });
  207. });
  208. });