Skip to content

Commit 6e55e17

Browse files
test: prettier-format multi-client skipIf wrap
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 17aa4e6 commit 6e55e17

1 file changed

Lines changed: 65 additions & 61 deletions

File tree

nodejs/test/e2e/multi-client.e2e.test.ts

Lines changed: 65 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -304,71 +304,75 @@ describe("Multi-client broadcast", async () => {
304304
}
305305
);
306306

307-
it.skipIf(isInProcessTransport)("disconnecting client removes its tools", { timeout: 90_000 }, async () => {
308-
const toolA = defineTool("stable_tool", {
309-
description: "A tool that persists across disconnects",
310-
parameters: z.object({ input: z.string() }),
311-
handler: ({ input }) => `STABLE_${input}`,
312-
});
313-
314-
const toolB = defineTool("ephemeral_tool", {
315-
description: "A tool that will disappear when its client disconnects",
316-
parameters: z.object({ input: z.string() }),
317-
handler: ({ input }) => `EPHEMERAL_${input}`,
318-
});
319-
320-
// Client 1 creates a session with stable_tool
321-
const session1 = await client1.createSession({
322-
onPermissionRequest: approveAll,
323-
tools: [toolA],
324-
});
307+
it.skipIf(isInProcessTransport)(
308+
"disconnecting client removes its tools",
309+
{ timeout: 90_000 },
310+
async () => {
311+
const toolA = defineTool("stable_tool", {
312+
description: "A tool that persists across disconnects",
313+
parameters: z.object({ input: z.string() }),
314+
handler: ({ input }) => `STABLE_${input}`,
315+
});
325316

326-
// Client 2 resumes with ephemeral_tool
327-
await client2.resumeSession(session1.sessionId, {
328-
onPermissionRequest: approveAll,
329-
tools: [toolB],
330-
});
317+
const toolB = defineTool("ephemeral_tool", {
318+
description: "A tool that will disappear when its client disconnects",
319+
parameters: z.object({ input: z.string() }),
320+
handler: ({ input }) => `EPHEMERAL_${input}`,
321+
});
331322

332-
// Verify both tools work before disconnect (sequential to avoid nondeterministic tool_call ordering)
333-
const stableResponse = await session1.sendAndWait({
334-
prompt: "Use the stable_tool with input 'test1' and tell me the result.",
335-
});
336-
expect(stableResponse?.data.content).toContain("STABLE_test1");
323+
// Client 1 creates a session with stable_tool
324+
const session1 = await client1.createSession({
325+
onPermissionRequest: approveAll,
326+
tools: [toolA],
327+
});
337328

338-
const ephemeralResponse = await session1.sendAndWait({
339-
prompt: "Use the ephemeral_tool with input 'test2' and tell me the result.",
340-
});
341-
expect(ephemeralResponse?.data.content).toContain("EPHEMERAL_test2");
342-
343-
// Disconnect client 2 without destroying the shared session.
344-
// Suppress "Connection is disposed" rejections that occur when the server
345-
// broadcasts events (e.g. tool_changed_notice) to the now-dead connection.
346-
const suppressDisposed = (reason: unknown) => {
347-
if (reason instanceof Error && reason.message.includes("Connection is disposed")) {
348-
return;
349-
}
350-
throw reason;
351-
};
352-
process.on("unhandledRejection", suppressDisposed);
353-
await client2.stop();
329+
// Client 2 resumes with ephemeral_tool
330+
await client2.resumeSession(session1.sessionId, {
331+
onPermissionRequest: approveAll,
332+
tools: [toolB],
333+
});
354334

355-
// Give the server time to process the connection close and remove tools
356-
await new Promise((resolve) => setTimeout(resolve, 500));
357-
process.removeListener("unhandledRejection", suppressDisposed);
335+
// Verify both tools work before disconnect (sequential to avoid nondeterministic tool_call ordering)
336+
const stableResponse = await session1.sendAndWait({
337+
prompt: "Use the stable_tool with input 'test1' and tell me the result.",
338+
});
339+
expect(stableResponse?.data.content).toContain("STABLE_test1");
358340

359-
// Recreate client2 for cleanup in afterAll (but don't rejoin the session)
360-
client2 = new CopilotClient({
361-
connection: RuntimeConnection.forUri(`localhost:${runtimePort}`, {
362-
connectionToken: tcpConnectionToken,
363-
}),
364-
});
341+
const ephemeralResponse = await session1.sendAndWait({
342+
prompt: "Use the ephemeral_tool with input 'test2' and tell me the result.",
343+
});
344+
expect(ephemeralResponse?.data.content).toContain("EPHEMERAL_test2");
345+
346+
// Disconnect client 2 without destroying the shared session.
347+
// Suppress "Connection is disposed" rejections that occur when the server
348+
// broadcasts events (e.g. tool_changed_notice) to the now-dead connection.
349+
const suppressDisposed = (reason: unknown) => {
350+
if (reason instanceof Error && reason.message.includes("Connection is disposed")) {
351+
return;
352+
}
353+
throw reason;
354+
};
355+
process.on("unhandledRejection", suppressDisposed);
356+
await client2.stop();
357+
358+
// Give the server time to process the connection close and remove tools
359+
await new Promise((resolve) => setTimeout(resolve, 500));
360+
process.removeListener("unhandledRejection", suppressDisposed);
361+
362+
// Recreate client2 for cleanup in afterAll (but don't rejoin the session)
363+
client2 = new CopilotClient({
364+
connection: RuntimeConnection.forUri(`localhost:${runtimePort}`, {
365+
connectionToken: tcpConnectionToken,
366+
}),
367+
});
365368

366-
// Now only stable_tool should be available
367-
const afterResponse = await session1.sendAndWait({
368-
prompt: "Use the stable_tool with input 'still_here'. Also try using ephemeral_tool if it is available.",
369-
});
370-
expect(afterResponse?.data.content).toContain("STABLE_still_here");
371-
// ephemeral_tool should NOT have produced a result
372-
expect(afterResponse?.data.content).not.toContain("EPHEMERAL_");
373-
});
369+
// Now only stable_tool should be available
370+
const afterResponse = await session1.sendAndWait({
371+
prompt: "Use the stable_tool with input 'still_here'. Also try using ephemeral_tool if it is available.",
372+
});
373+
expect(afterResponse?.data.content).toContain("STABLE_still_here");
374+
// ephemeral_tool should NOT have produced a result
375+
expect(afterResponse?.data.content).not.toContain("EPHEMERAL_");
376+
}
377+
);
374378
});

0 commit comments

Comments
 (0)