summaryrefslogtreecommitdiffhomepage
path: root/src/core/chunks/retry-banner.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/chunks/retry-banner.test.ts')
-rw-r--r--src/core/chunks/retry-banner.test.ts63
1 files changed, 63 insertions, 0 deletions
diff --git a/src/core/chunks/retry-banner.test.ts b/src/core/chunks/retry-banner.test.ts
new file mode 100644
index 0000000..1d8c1cd
--- /dev/null
+++ b/src/core/chunks/retry-banner.test.ts
@@ -0,0 +1,63 @@
+import type { TurnProviderRetryEvent } from "@dispatch/wire";
+import { describe, expect, it } from "vitest";
+import { formatRetryDelay, viewProviderRetry } from "./retry-banner";
+
+const retry = (
+ attempt: number,
+ delayMs: number,
+ message = "HTTP 429: overloaded",
+ code?: string,
+): TurnProviderRetryEvent =>
+ code !== undefined
+ ? {
+ type: "provider-retry",
+ conversationId: "c1",
+ turnId: "t1",
+ attempt,
+ delayMs,
+ message,
+ code,
+ }
+ : { type: "provider-retry", conversationId: "c1", turnId: "t1", attempt, delayMs, message };
+
+describe("formatRetryDelay", () => {
+ it("formats sub-minute delays as seconds", () => {
+ expect(formatRetryDelay(5000)).toBe("5s");
+ expect(formatRetryDelay(10000)).toBe("10s");
+ expect(formatRetryDelay(30000)).toBe("30s");
+ });
+
+ it("formats minute+ delays as minutes", () => {
+ expect(formatRetryDelay(60000)).toBe("1m");
+ expect(formatRetryDelay(300000)).toBe("5m");
+ expect(formatRetryDelay(1800000)).toBe("30m");
+ });
+
+ it("rounds to the nearest whole unit", () => {
+ expect(formatRetryDelay(5500)).toBe("6s"); // 5.5s -> 6s
+ expect(formatRetryDelay(90000)).toBe("2m"); // 1.5m -> 2m
+ });
+});
+
+describe("viewProviderRetry", () => {
+ it("labels the attempt 1-based (attempt 0 = Retry #1)", () => {
+ expect(viewProviderRetry(retry(0, 5000)).attemptLabel).toBe("Retry #1");
+ expect(viewProviderRetry(retry(1, 10000)).attemptLabel).toBe("Retry #2");
+ expect(viewProviderRetry(retry(7, 1800000)).attemptLabel).toBe("Retry #8");
+ });
+
+ it("derives the delay label from delayMs", () => {
+ expect(viewProviderRetry(retry(0, 5000)).delayLabel).toBe("5s");
+ expect(viewProviderRetry(retry(4, 300000)).delayLabel).toBe("5m");
+ });
+
+ it("passes the endpoint error verbatim", () => {
+ const msg = 'HTTP 429: {"error":{"type":"overloaded_error","message":"overloaded"}}';
+ expect(viewProviderRetry(retry(0, 5000, msg)).message).toBe(msg);
+ });
+
+ it("surfaces the code when present, null when absent", () => {
+ expect(viewProviderRetry(retry(0, 5000, "msg", "429")).code).toBe("429");
+ expect(viewProviderRetry(retry(0, 5000, "msg")).code).toBeNull();
+ });
+});