Skip to content

Commit cafd071

Browse files
committed
test(react-core): tighten use-threads phoenix mock and indexing
Drop the dead `MockChannel.channels` field — never read or populated. Stop auto-firing `onOpen` from `MockSocket.connect()`. Real Phoenix sockets fire `onOpen` once per upgrade, so tests should drive the transition explicitly via `triggerOpen()`. The auto-fire would either double-fire when a test also called `triggerOpen()` or hide cases where production code forgets to await the open before joining a channel. No tests in this file relied on the auto-fire. Convert the archive/delete fetch assertions to filter by URL+method, the same way the rename test was already written. Hardcoded `mock.calls[2]` and `[3]` indices broke the moment any startup fetch was added or reordered; the filter-based form survives that without losing specificity. Reset `mockUseCopilotKit` at the start of `beforeEach` before re-priming via `setupCopilotKit()`. `mockReturnValue` is stable across calls, but a future test using `mockReturnValueOnce` would otherwise leak un-consumed queued returns into the next test.
1 parent 9b7c051 commit cafd071

1 file changed

Lines changed: 34 additions & 18 deletions

File tree

packages/react-core/src/v2/hooks/__tests__/use-threads.test.tsx

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ vi.mock("phoenix", () => {
5353
topic: string;
5454
params: Record<string, unknown>;
5555
left = false;
56-
channels: MockChannel[] = [];
5756

5857
private handlers = new Map<
5958
string,
@@ -125,14 +124,13 @@ vi.mock("phoenix", () => {
125124
}
126125

127126
connect(): void {
127+
// Phoenix sockets fire `onOpen` exactly once per WebSocket upgrade,
128+
// and the upgrade is asynchronous. Tests must drive that transition
129+
// explicitly via `triggerOpen()` so we exercise one open per
130+
// connection — auto-firing here would either double-fire (when a
131+
// test also calls `triggerOpen()`) or hide cases where production
132+
// code forgets to await the open before joining a channel.
128133
this.connected = true;
129-
// Mirror real Phoenix sockets: fire open handlers synchronously
130-
// once the WebSocket upgrade completes. Production code that
131-
// awaits onOpen (e.g. to start a join sequence) must be exercised
132-
// by the same lifecycle here.
133-
for (const handler of this.openHandlers) {
134-
handler();
135-
}
136134
}
137135

138136
disconnect(): void {
@@ -231,6 +229,10 @@ describe("useThreads", () => {
231229
beforeEach(() => {
232230
phoenix.sockets.splice(0);
233231
fetchMock.mockReset();
232+
// Reset before re-priming. setupCopilotKit() uses mockReturnValue, so a
233+
// future test that uses mockReturnValueOnce would otherwise leak any
234+
// un-consumed queued returns into the next test.
235+
mockUseCopilotKit.mockReset();
234236
setupCopilotKit();
235237
});
236238

@@ -416,17 +418,31 @@ describe("useThreads", () => {
416418
await result.current.deleteThread("t-1");
417419
});
418420

419-
expect(fetchMock.mock.calls[2][0]).toContain("/threads/t-2/archive");
420-
expect(fetchMock.mock.calls[2][1].method).toBe("POST");
421-
expect(JSON.parse(fetchMock.mock.calls[2][1].body)).toMatchObject({
422-
agentId: "agent-1",
423-
});
421+
// Filter by URL+method rather than fixed indices (mirrors the rename
422+
// test above). A future change to the startup fetch order — adding an
423+
// /info call, splitting the join token, etc. — must not silently miss
424+
// the actual archive/delete requests.
425+
const archiveCall = fetchMock.mock.calls.find(
426+
(args: unknown[]) =>
427+
typeof args[0] === "string" &&
428+
(args[0] as string).includes("/threads/t-2/archive") &&
429+
(args[1] as { method?: string } | undefined)?.method === "POST",
430+
);
431+
expect(archiveCall).toBeDefined();
432+
expect(
433+
JSON.parse((archiveCall![1] as { body: string }).body),
434+
).toMatchObject({ agentId: "agent-1" });
424435

425-
expect(fetchMock.mock.calls[3][0]).toContain("/threads/t-1");
426-
expect(fetchMock.mock.calls[3][1].method).toBe("DELETE");
427-
expect(JSON.parse(fetchMock.mock.calls[3][1].body)).toMatchObject({
428-
agentId: "agent-1",
429-
});
436+
const deleteCall = fetchMock.mock.calls.find(
437+
(args: unknown[]) =>
438+
typeof args[0] === "string" &&
439+
(args[0] as string).includes("/threads/t-1") &&
440+
(args[1] as { method?: string } | undefined)?.method === "DELETE",
441+
);
442+
expect(deleteCall).toBeDefined();
443+
expect(JSON.parse((deleteCall![1] as { body: string }).body)).toMatchObject(
444+
{ agentId: "agent-1" },
445+
);
430446
});
431447

432448
it("exposes thread-scoped pagination properties", async () => {

0 commit comments

Comments
 (0)