From eecb36eff4d4a2dd3ec8b8bc096154439c74d509 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 4 Apr 2026 03:51:59 +0900 Subject: [PATCH] fix(ci): stabilize zero-delay retry and slack interaction tests --- extensions/discord/src/api.test.ts | 2 +- .../src/monitor/events/interactions.test.ts | 23 ++++++------------- src/infra/retry.test.ts | 13 +++++++++++ src/infra/retry.ts | 4 +++- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/extensions/discord/src/api.test.ts b/extensions/discord/src/api.test.ts index 8ccd840e382..b9604f766ab 100644 --- a/extensions/discord/src/api.test.ts +++ b/extensions/discord/src/api.test.ts @@ -67,7 +67,7 @@ describe("fetchDiscord", () => { "/users/@me/guilds", "test", fetcher, - { retry: { attempts: 2, minDelayMs: 0, maxDelayMs: 0 } }, + { retry: { attempts: 2, minDelayMs: 0, maxDelayMs: 0, jitter: 0 } }, ); expect(result).toHaveLength(1); diff --git a/extensions/slack/src/monitor/events/interactions.test.ts b/extensions/slack/src/monitor/events/interactions.test.ts index 1b3a2b4074d..c13a5943867 100644 --- a/extensions/slack/src/monitor/events/interactions.test.ts +++ b/extensions/slack/src/monitor/events/interactions.test.ts @@ -358,17 +358,8 @@ describe("registerSlackInteractionEvents", () => { expect.objectContaining({ channel: "slack", data: "codex:approve:thread-1", - interactionId: "U123:C1:100.200:123.trigger:codex:approve:thread-1", - ctx: expect.objectContaining({ - accountId: ctx.accountId, - conversationId: "C1", - interactionId: "U123:C1:100.200:123.trigger:codex:approve:thread-1", - threadId: "100.100", - interaction: expect.objectContaining({ - actionId: "codex", - value: "approve:thread-1", - }), - }), + dedupeId: "U123:C1:100.200:123.trigger:codex:approve:thread-1", + invoke: expect.any(Function), }), ); expect(enqueueSystemEventMock).not.toHaveBeenCalled(); @@ -491,17 +482,17 @@ describe("registerSlackInteractionEvents", () => { const calls = dispatchPluginInteractiveHandlerMock.mock.calls as unknown[][]; const firstCall = calls[0]?.[0] as | { - interactionId?: string; + dedupeId?: string; } | undefined; const secondCall = calls[1]?.[0] as | { - interactionId?: string; + dedupeId?: string; } | undefined; - expect(firstCall?.interactionId).toContain(":trigger-1:"); - expect(secondCall?.interactionId).toContain(":trigger-2:"); - expect(firstCall?.interactionId).not.toBe(secondCall?.interactionId); + expect(firstCall?.dedupeId).toContain(":trigger-1:"); + expect(secondCall?.dedupeId).toContain(":trigger-2:"); + expect(firstCall?.dedupeId).not.toBe(secondCall?.dedupeId); }); it("resolves plugin binding approvals from shared interactive Slack actions", async () => { diff --git a/src/infra/retry.test.ts b/src/infra/retry.test.ts index 49ae2534d67..f7e554cb485 100644 --- a/src/infra/retry.test.ts +++ b/src/infra/retry.test.ts @@ -162,6 +162,19 @@ describe("retryAsync", () => { ); }); + it("retries immediately when the resolved delay is zero", async () => { + const fn = vi.fn().mockRejectedValueOnce(new Error("boom")).mockResolvedValueOnce("ok"); + await expect( + retryAsync(fn, { + attempts: 2, + minDelayMs: 0, + maxDelayMs: 0, + jitter: 0, + }), + ).resolves.toBe("ok"); + expect(fn).toHaveBeenCalledTimes(2); + }); + it("clamps attempts to at least 1", async () => { const fn = vi.fn().mockRejectedValue(new Error("boom")); await expect(retryAsync(fn, { attempts: 0, minDelayMs: 0, maxDelayMs: 0 })).rejects.toThrow( diff --git a/src/infra/retry.ts b/src/infra/retry.ts index dab49eaf33c..8eaf76513c7 100644 --- a/src/infra/retry.ts +++ b/src/infra/retry.ts @@ -129,7 +129,9 @@ export async function retryAsync( err, label: options.label, }); - await sleep(delay); + if (delay > 0) { + await sleep(delay); + } } }