Skip to content

Commit da27992

Browse files
Test: Add e2e test for duplicate events after resume
Regression test for #567. Verifies that resuming a session multiple times does not cause duplicate event delivery. The test creates a session, resumes it twice (letting old handles go ungracefully), then sends a message and asserts that assistant.message arrives exactly once. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b9f746a commit da27992

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

nodejs/test/e2e/session.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,33 @@ describe("Sessions", async () => {
204204
expect(messages).toContainEqual(expect.objectContaining({ type: "session.resume" }));
205205
});
206206

207+
it("should not receive duplicate events after resume", async () => {
208+
// Regression test for https://github.com/github/copilot-sdk/issues/567
209+
// Each resumeSession call was adding an additional event listener without
210+
// removing the previous one, causing events to be delivered N+1 times after N resumes.
211+
212+
// Create session and do a turn, then let the session handle go away ungracefully
213+
const session1 = await client.createSession({ onPermissionRequest: approveAll });
214+
const sessionId = session1.sessionId;
215+
await session1.sendAndWait({ prompt: "What is 1+1?" });
216+
217+
// Resume twice (simulating two reconnects) without cleaning up previous handles.
218+
// The old session handles just go away as they would in a real disconnect.
219+
await client.resumeSession(sessionId, { onPermissionRequest: approveAll });
220+
const session3 = await client.resumeSession(sessionId, { onPermissionRequest: approveAll });
221+
222+
// Now send on the latest resumed session and collect events
223+
const receivedEvents: Array<{ type: string }> = [];
224+
session3.on((event) => {
225+
receivedEvents.push({ type: event.type });
226+
});
227+
await session3.sendAndWait({ prompt: "What is 3+3?" });
228+
229+
// Each assistant.message should arrive exactly once, not duplicated
230+
const assistantMessages = receivedEvents.filter((e) => e.type === "assistant.message");
231+
expect(assistantMessages).toHaveLength(1);
232+
});
233+
207234
it("should throw error when resuming non-existent session", async () => {
208235
await expect(
209236
client.resumeSession("non-existent-session-id", { onPermissionRequest: approveAll })
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
models:
2+
- claude-sonnet-4.5
3+
conversations:
4+
- messages:
5+
- role: system
6+
content: ${system}
7+
- role: user
8+
content: What is 1+1?
9+
- role: assistant
10+
content: 1+1 = 2
11+
- role: user
12+
content: What is 3+3?
13+
- role: assistant
14+
content: 3+3 = 6

0 commit comments

Comments
 (0)