Skip to content

Commit 14d0a9f

Browse files
Add E2E tests for createSession/resumeSession without onPermissionRequest
Ports dotnet's Should_Allow_CreateSession_Called_Without_PermissionHandler (Theory: stdio + tcp) and Should_Allow_ResumeSession_Called_Without_PermissionHandler from dotnet/test/E2E/ClientE2ETests.cs into nodejs/test/e2e/session.e2e.test.ts. These exercise the contract that {onPermissionRequest} is optional on both SessionConfig and ResumeSessionConfig: when not provided, the runtime leaves permission prompts pending for the consumer to resolve via the low-level RPC. Without these tests, that contract was unprotected against regression. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3ac7ae8 commit 14d0a9f

2 files changed

Lines changed: 73 additions & 4 deletions

File tree

nodejs/test/e2e/client.e2e.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe("Client", () => {
2020
const client = new CopilotClient({ connection: connection() });
2121
onTestFinishedForceStop(client);
2222

23-
await using const session = await client.createSession({});
23+
await using session = await client.createSession({});
2424
expect(session.sessionId).toMatch(/^[a-f0-9-]+$/);
2525
});
2626

@@ -32,7 +32,7 @@ describe("Client", () => {
3232
});
3333
onTestFinishedForceStop(client);
3434

35-
await using const originalSession = await client.createSession({});
35+
await using originalSession = await client.createSession({});
3636

3737
const port = (client as unknown as { runtimePort: number | null }).runtimePort;
3838
if (port == null) {
@@ -44,7 +44,7 @@ describe("Client", () => {
4444
});
4545
onTestFinishedForceStop(resumeClient);
4646

47-
await using const resumedSession = await resumeClient.resumeSession(
47+
await using resumedSession = await resumeClient.resumeSession(
4848
originalSession.sessionId,
4949
{}
5050
);

nodejs/test/e2e/session.e2e.test.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { rm } from "fs/promises";
22
import { describe, expect, it, onTestFinished, vi } from "vitest";
33
import { ParsedHttpExchange } from "../../../test/harness/replayingCapiProxy.js";
4-
import { CopilotClient, approveAll, defineTool } from "../../src/index.js";
4+
import { CopilotClient, approveAll, defineTool, RuntimeConnection } from "../../src/index.js";
55
import { createSdkTestContext, isCI } from "./harness/sdkTestContext.js";
66
import { getFinalAssistantMessage, getNextEventOfType } from "./harness/sdkTestHelper.js";
77

@@ -14,6 +14,75 @@ describe("Sessions", async () => {
1414
env,
1515
} = await createSdkTestContext();
1616

17+
it.each([
18+
["stdio", () => RuntimeConnection.forStdio({ path: process.env.COPILOT_CLI_PATH })],
19+
["tcp", () => RuntimeConnection.forTcp({ path: process.env.COPILOT_CLI_PATH })],
20+
] as const)(
21+
"createSession works without onPermissionRequest (%s)",
22+
async (_name, makeConnection) => {
23+
const standaloneClient = new CopilotClient({
24+
cwd: workDir,
25+
env,
26+
connection: makeConnection(),
27+
});
28+
onTestFinished(async () => {
29+
try {
30+
await standaloneClient.forceStop();
31+
} catch {
32+
// ignore
33+
}
34+
});
35+
36+
const session = await standaloneClient.createSession({});
37+
expect(session.sessionId).toMatch(/^[a-f0-9-]+$/);
38+
await session.disconnect();
39+
}
40+
);
41+
42+
it("resumeSession works without onPermissionRequest", async () => {
43+
const connectionToken = "client-e2e-resume-token";
44+
45+
const tcpClient = new CopilotClient({
46+
cwd: workDir,
47+
env,
48+
connection: RuntimeConnection.forTcp({
49+
path: process.env.COPILOT_CLI_PATH,
50+
connectionToken,
51+
}),
52+
});
53+
onTestFinished(async () => {
54+
try {
55+
await tcpClient.forceStop();
56+
} catch {
57+
// ignore
58+
}
59+
});
60+
61+
const originalSession = await tcpClient.createSession({});
62+
63+
const port = (tcpClient as unknown as { runtimePort: number | null }).runtimePort;
64+
if (!port) {
65+
throw new Error("Client must be using TCP transport to support multi-client resume.");
66+
}
67+
68+
const resumeClient = new CopilotClient({
69+
cwd: workDir,
70+
env,
71+
connection: RuntimeConnection.forUri(`localhost:${port}`, { connectionToken }),
72+
});
73+
onTestFinished(async () => {
74+
try {
75+
await resumeClient.forceStop();
76+
} catch {
77+
// ignore
78+
}
79+
});
80+
81+
const resumedSession = await resumeClient.resumeSession(originalSession.sessionId, {});
82+
expect(resumedSession.sessionId).toBe(originalSession.sessionId);
83+
await resumedSession.disconnect();
84+
await originalSession.disconnect();
85+
});
1786
it("should create and disconnect sessions", async () => {
1887
const session = await client.createSession({
1988
onPermissionRequest: approveAll,

0 commit comments

Comments
 (0)