Spaces:
Paused
Paused
| import { afterEach, describe, expect, it, vi } from "vitest"; | |
| import { | |
| applyOptimisticIssueCommentUpdate, | |
| createOptimisticIssueComment, | |
| isQueuedIssueComment, | |
| mergeIssueComments, | |
| upsertIssueComment, | |
| } from "./optimistic-issue-comments"; | |
| describe("optimistic issue comments", () => { | |
| afterEach(() => { | |
| vi.unstubAllGlobals(); | |
| vi.restoreAllMocks(); | |
| }); | |
| it("creates a pending optimistic comment for the current user", () => { | |
| const comment = createOptimisticIssueComment({ | |
| companyId: "company-1", | |
| issueId: "issue-1", | |
| body: "Working on it", | |
| authorUserId: "board-1", | |
| }); | |
| expect(comment.id).toMatch(/^optimistic-/); | |
| expect(comment.clientId).toBe(comment.id); | |
| expect(comment.clientStatus).toBe("pending"); | |
| expect(comment.authorUserId).toBe("board-1"); | |
| expect(comment.authorAgentId).toBeNull(); | |
| }); | |
| it("falls back when crypto.randomUUID is unavailable", () => { | |
| vi.stubGlobal("crypto", {}); | |
| const nowSpy = vi.spyOn(Date, "now").mockReturnValue(1_746_000_000_000); | |
| const mathSpy = vi.spyOn(Math, "random").mockReturnValue(0.123456789); | |
| const comment = createOptimisticIssueComment({ | |
| companyId: "company-1", | |
| issueId: "issue-1", | |
| body: "Working on it", | |
| authorUserId: "board-1", | |
| }); | |
| expect(comment.id).toBe("optimistic-1746000000000-4fzzzxjy"); | |
| expect(comment.clientId).toBe(comment.id); | |
| nowSpy.mockRestore(); | |
| mathSpy.mockRestore(); | |
| }); | |
| it("supports queued optimistic comments for active-run follow-ups", () => { | |
| const comment = createOptimisticIssueComment({ | |
| companyId: "company-1", | |
| issueId: "issue-1", | |
| body: "Queue this", | |
| authorUserId: "board-1", | |
| clientStatus: "queued", | |
| queueTargetRunId: "run-1", | |
| }); | |
| expect(comment.clientStatus).toBe("queued"); | |
| expect(comment.queueTargetRunId).toBe("run-1"); | |
| }); | |
| it("merges optimistic comments into the server thread in chronological order", () => { | |
| const merged = mergeIssueComments( | |
| [ | |
| { | |
| id: "comment-2", | |
| companyId: "company-1", | |
| issueId: "issue-1", | |
| authorAgentId: null, | |
| authorUserId: "board-1", | |
| body: "Second", | |
| createdAt: new Date("2026-03-28T14:00:02.000Z"), | |
| updatedAt: new Date("2026-03-28T14:00:02.000Z"), | |
| }, | |
| ], | |
| [ | |
| { | |
| id: "optimistic-1", | |
| clientId: "optimistic-1", | |
| clientStatus: "pending", | |
| companyId: "company-1", | |
| issueId: "issue-1", | |
| authorAgentId: null, | |
| authorUserId: "board-1", | |
| body: "First", | |
| createdAt: new Date("2026-03-28T14:00:01.000Z"), | |
| updatedAt: new Date("2026-03-28T14:00:01.000Z"), | |
| }, | |
| ], | |
| ); | |
| expect(merged.map((comment) => comment.id)).toEqual(["optimistic-1", "comment-2"]); | |
| }); | |
| it("upserts confirmed comments without creating duplicates", () => { | |
| const next = upsertIssueComment( | |
| [ | |
| { | |
| id: "comment-1", | |
| companyId: "company-1", | |
| issueId: "issue-1", | |
| authorAgentId: null, | |
| authorUserId: "board-1", | |
| body: "Original", | |
| createdAt: new Date("2026-03-28T14:00:00.000Z"), | |
| updatedAt: new Date("2026-03-28T14:00:00.000Z"), | |
| }, | |
| ], | |
| { | |
| id: "comment-1", | |
| companyId: "company-1", | |
| issueId: "issue-1", | |
| authorAgentId: null, | |
| authorUserId: "board-1", | |
| body: "Updated", | |
| createdAt: new Date("2026-03-28T14:00:00.000Z"), | |
| updatedAt: new Date("2026-03-28T14:00:05.000Z"), | |
| }, | |
| ); | |
| expect(next).toHaveLength(1); | |
| expect(next[0]?.body).toBe("Updated"); | |
| }); | |
| it("applies optimistic reopen and reassignment updates to the issue cache", () => { | |
| const next = applyOptimisticIssueCommentUpdate( | |
| { | |
| id: "issue-1", | |
| companyId: "company-1", | |
| projectId: null, | |
| projectWorkspaceId: null, | |
| goalId: null, | |
| parentId: null, | |
| title: "Fix comment flow", | |
| description: null, | |
| status: "done", | |
| priority: "medium", | |
| assigneeAgentId: "agent-1", | |
| assigneeUserId: null, | |
| checkoutRunId: null, | |
| executionRunId: null, | |
| executionAgentNameKey: null, | |
| executionLockedAt: null, | |
| createdByAgentId: null, | |
| createdByUserId: "board-1", | |
| issueNumber: 1, | |
| identifier: "PAP-1", | |
| originKind: "manual", | |
| originId: null, | |
| originRunId: null, | |
| requestDepth: 0, | |
| billingCode: null, | |
| assigneeAdapterOverrides: null, | |
| executionWorkspaceId: null, | |
| executionWorkspacePreference: null, | |
| executionWorkspaceSettings: null, | |
| startedAt: null, | |
| completedAt: null, | |
| cancelledAt: null, | |
| hiddenAt: null, | |
| createdAt: new Date("2026-03-28T14:00:00.000Z"), | |
| updatedAt: new Date("2026-03-28T14:00:00.000Z"), | |
| }, | |
| { | |
| reopen: true, | |
| reassignment: { | |
| assigneeAgentId: null, | |
| assigneeUserId: "board-2", | |
| }, | |
| }, | |
| ); | |
| expect(next?.status).toBe("todo"); | |
| expect(next?.assigneeAgentId).toBeNull(); | |
| expect(next?.assigneeUserId).toBe("board-2"); | |
| }); | |
| it("treats comments without a run id as queued when they arrive during an active run", () => { | |
| expect( | |
| isQueuedIssueComment({ | |
| comment: { | |
| createdAt: new Date("2026-03-28T16:20:05.000Z"), | |
| }, | |
| activeRunStartedAt: new Date("2026-03-28T16:20:00.000Z"), | |
| runId: null, | |
| }), | |
| ).toBe(true); | |
| }); | |
| it("does not mark comments with an associated run as queued", () => { | |
| expect( | |
| isQueuedIssueComment({ | |
| comment: { | |
| createdAt: new Date("2026-03-28T16:20:05.000Z"), | |
| }, | |
| activeRunStartedAt: new Date("2026-03-28T16:20:00.000Z"), | |
| runId: "run-1", | |
| }), | |
| ).toBe(false); | |
| }); | |
| it("does not mark interrupt comments as queued", () => { | |
| expect( | |
| isQueuedIssueComment({ | |
| comment: { | |
| createdAt: new Date("2026-03-28T16:20:05.000Z"), | |
| }, | |
| activeRunStartedAt: new Date("2026-03-28T16:20:00.000Z"), | |
| interruptedRunId: "run-1", | |
| }), | |
| ).toBe(false); | |
| }); | |
| }); | |