Skip to content

Commit 5d7c9ec

Browse files
Test cleanup
1 parent 503dc80 commit 5d7c9ec

2 files changed

Lines changed: 37 additions & 64 deletions

File tree

nodejs/test/e2e/harness/sdkTestContext.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { basename, dirname, join, resolve } from "path";
99
import { rimraf } from "rimraf";
1010
import { fileURLToPath } from "url";
1111
import { afterAll, afterEach, beforeEach, onTestFailed, TestContext } from "vitest";
12-
import { CopilotClient } from "../../../src";
12+
import { CopilotClient, CopilotClientOptions } from "../../../src";
1313
import { CapiProxy } from "./CapiProxy";
1414
import { retry } from "./sdkTestHelper";
1515

@@ -22,10 +22,12 @@ const SNAPSHOTS_DIR = resolve(__dirname, "../../../../test/snapshots");
2222
export async function createSdkTestContext({
2323
logLevel,
2424
useStdio,
25+
copilotClientOptions,
2526
}: {
2627
logLevel?: "error" | "none" | "warning" | "info" | "debug" | "all";
2728
cliPath?: string;
2829
useStdio?: boolean;
30+
copilotClientOptions?: CopilotClientOptions;
2931
} = {}) {
3032
const homeDir = realpathSync(fs.mkdtempSync(join(os.tmpdir(), "copilot-test-config-")));
3133
const workDir = realpathSync(fs.mkdtempSync(join(os.tmpdir(), "copilot-test-work-")));
@@ -51,6 +53,7 @@ export async function createSdkTestContext({
5153
// Use fake token in CI to allow cached responses without real auth
5254
githubToken: isCI ? "fake-token-for-e2e-tests" : undefined,
5355
useStdio: useStdio,
56+
...copilotClientOptions,
5457
});
5558

5659
const harness = { homeDir, workDir, openAiEndpoint, copilotClient, env };

nodejs/test/e2e/session_fs.test.ts

Lines changed: 33 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
*--------------------------------------------------------------------------------------------*/
44

5-
import { describe, expect, it, onTestFinished, vi } from "vitest";
5+
import { beforeEach, describe, expect, it, onTestFinished } from "vitest";
66
import { CopilotClient } from "../../src/client.js";
77
import { approveAll, type SessionFsConfig } from "../../src/index.js";
88
import { createSdkTestContext } from "./harness/sdkTestContext.js";
@@ -30,6 +30,14 @@ class InMemorySessionFs {
3030
rename: 0,
3131
};
3232

33+
public reset() {
34+
this.files.clear();
35+
this.dirs.clear();
36+
for (const key in this.calls) {
37+
this.calls[key as keyof typeof this.calls] = 0;
38+
}
39+
}
40+
3341
private getSessionFiles(sessionId: string): Map<string, string> {
3442
let m = this.files.get(sessionId);
3543
if (!m) {
@@ -203,109 +211,71 @@ class InMemorySessionFs {
203211
}
204212
}
205213

206-
// These tests require a runtime built with SessionFs support.
207-
// Skip when COPILOT_CLI_PATH is not set (CI uses the published CLI which
208-
// doesn't include this feature yet).
209-
const runTests = process.env.COPILOT_CLI_PATH ? describe : describe.skip;
210-
211-
runTests("Session Fs", async () => {
212-
const { env } = await createSdkTestContext();
214+
describe("Session Fs", async () => {
215+
const fs = new InMemorySessionFs();
216+
beforeEach(() => fs.reset());
213217

214-
it("should route file operations through the session fs provider", async () => {
215-
const fs = new InMemorySessionFs();
216-
const client1 = new CopilotClient({
217-
env,
218-
logLevel: "error",
219-
cliPath: process.env.COPILOT_CLI_PATH,
218+
const { copilotClient: client, env } = await createSdkTestContext({
219+
copilotClientOptions: {
220220
sessionFs: fs.toConfig("/projects/test", "/session-state"),
221-
});
222-
onTestFinished(() => client1.forceStop());
221+
},
222+
});
223223

224-
const session = await client1.createSession({
225-
onPermissionRequest: approveAll,
226-
});
224+
it("should route file operations through the session fs provider", async () => {
225+
const session = await client.createSession({ onPermissionRequest: approveAll });
227226

228227
// Send a message and wait for the response
229228
const msg = await session.sendAndWait({ prompt: "What is 100 + 200?" });
230229
expect(msg?.data.content).toContain("300");
231230

232231
// Verify file operations were routed through our fs provider.
233232
// The runtime writes events as JSONL through appendFile/writeFile.
234-
await vi.waitFor(
235-
() => {
236-
const paths = fs.getFilePaths(session.sessionId);
237-
const hasEvents = paths.some((p) => p.includes("events"));
238-
expect(hasEvents).toBe(true);
239-
},
240-
{ timeout: 10_000, interval: 200 },
241-
);
242-
expect(fs.calls.writeFile + fs.calls.appendFile).toBeGreaterThan(0);
243-
expect(fs.calls.mkdir).toBeGreaterThan(0);
233+
// TODO: Replace these assertions with reading the events.jsonl file
234+
await expect.poll(() => fs.calls.writeFile + fs.calls.appendFile).toBeGreaterThan(0);
244235
});
245236

246237
it("should load session data from fs provider on resume", async () => {
247-
const sessionFs = new InMemorySessionFs();
248-
249-
const client2 = new CopilotClient({
250-
env,
251-
logLevel: "error",
252-
cliPath: process.env.COPILOT_CLI_PATH,
253-
sessionFs: sessionFs.toConfig("/projects/test", "/session-state"),
254-
});
255-
onTestFinished(() => client2.forceStop());
256-
257-
// Create a session and send a message
258-
const session1 = await client2.createSession({
259-
onPermissionRequest: approveAll,
260-
});
238+
const session1 = await client.createSession({ onPermissionRequest: approveAll });
261239
const sessionId = session1.sessionId;
262240

263-
const msg1 = await session1.sendAndWait({ prompt: "What is 50 + 50?" });
264-
expect(msg1?.data.content).toContain("100");
241+
const msg = await session1.sendAndWait({ prompt: "What is 50 + 50?" });
242+
expect(msg?.data.content).toContain("100");
265243
await session1.disconnect();
266244

267245
// Verify readFile is called when resuming (to load events)
268-
const readCountBefore = sessionFs.calls.readFile;
269-
const session2 = await client2.resumeSession(sessionId, {
246+
const readCountBefore = fs.calls.readFile;
247+
const session2 = await client.resumeSession(sessionId, {
270248
onPermissionRequest: approveAll,
271249
});
272250

273-
expect(sessionFs.calls.readFile).toBeGreaterThan(readCountBefore);
251+
expect(fs.calls.readFile).toBeGreaterThan(readCountBefore);
274252

275253
// Send another message to verify the session is functional
276254
const msg2 = await session2.sendAndWait({ prompt: "What is that times 3?" });
277255
expect(msg2?.data.content).toContain("300");
278256
});
279257

280258
it("should reject setProvider when sessions already exist", async () => {
281-
// First client uses TCP so a second client can connect to the same runtime
282-
const client5 = new CopilotClient({
259+
const client = new CopilotClient({
260+
useStdio: false, // Use TCP so we can connect from a second client
283261
env,
284-
logLevel: "error",
285-
cliPath: process.env.COPILOT_CLI_PATH,
286-
useStdio: false,
287262
});
288-
onTestFinished(() => client5.forceStop());
289-
290-
const session = await client5.createSession({
291-
onPermissionRequest: approveAll,
292-
});
293-
await session.sendAndWait({ prompt: "Hello" });
263+
await client.createSession({ onPermissionRequest: approveAll });
294264

295265
// Get the port the first client's runtime is listening on
296-
const port = (client5 as unknown as { actualPort: number }).actualPort;
266+
const port = (client as unknown as { actualPort: number }).actualPort;
297267

298268
// Second client tries to connect with a session fs — should fail
299269
// because sessions already exist on the runtime.
300270
const sessionFs = new InMemorySessionFs();
301-
const client6 = new CopilotClient({
271+
const client2 = new CopilotClient({
302272
env,
303273
logLevel: "error",
304274
cliUrl: `localhost:${port}`,
305275
sessionFs: sessionFs.toConfig("/projects/test", "/session-state"),
306276
});
307-
onTestFinished(() => client6.forceStop());
277+
onTestFinished(() => client2.forceStop());
308278

309-
await expect(client6.start()).rejects.toThrow();
279+
await expect(client2.start()).rejects.toThrow();
310280
});
311281
});

0 commit comments

Comments
 (0)