11import { describe , expect , it , onTestFinished } from "vitest" ;
22import { ParsedHttpExchange } from "../../../test/harness/replayingCapiProxy.js" ;
3- import { CopilotClient } from "../../src/index.js" ;
3+ import { CopilotClient , SessionEvent } from "../../src/index.js" ;
44import { CLI_PATH , createSdkTestContext } from "./harness/sdkTestContext.js" ;
5- import { getFinalAssistantMessage , getNextEventOfType } from "./harness/sdkTestHelper.js" ;
5+ import { getNextEventOfType } from "./harness/sdkTestHelper.js" ;
66
77describe ( "Sessions" , async ( ) => {
88 const { copilotClient : client , openAiEndpoint, homeDir, env } = await createSdkTestContext ( ) ;
@@ -167,7 +167,7 @@ describe("Sessions", async () => {
167167 expect ( session2 . sessionId ) . toBe ( sessionId ) ;
168168
169169 // TODO: There's an inconsistency here. When resuming with a new client, we don't see
170- // the session.idle message in the history, which means we can't use getFinalAssistantMessage .
170+ // the session.idle message in the history, so we can't easily identify when a turn completed .
171171
172172 const messages = await session2 . getMessages ( ) ;
173173 expect ( messages ) . toContainEqual ( expect . objectContaining ( { type : "user.message" } ) ) ;
@@ -328,9 +328,8 @@ describe("Sessions", async () => {
328328 expect ( session . sessionId ) . toMatch ( / ^ [ a - f 0 - 9 - ] + $ / ) ;
329329
330330 // Session should work normally with custom config dir
331- await session . send ( { prompt : "What is 1+1?" } ) ;
332- const assistantMessage = await getFinalAssistantMessage ( session ) ;
333- expect ( assistantMessage . data . content ) . toContain ( "2" ) ;
331+ const assistantMessage = await session . sendAndWait ( { prompt : "What is 1+1?" } ) ;
332+ expect ( assistantMessage ?. data . content ) . toContain ( "2" ) ;
334333 } ) ;
335334} ) ;
336335
@@ -348,23 +347,28 @@ describe("Send Blocking Behavior", async () => {
348347 it ( "send returns immediately while events stream in background" , async ( ) => {
349348 const session = await client . createSession ( ) ;
350349
351- const events : string [ ] = [ ] ;
352- session . on ( ( event ) => {
353- events . push ( event . type ) ;
354- } ) ;
350+ const events : Array < SessionEvent > = [ ] ;
351+ session . on ( ( event ) => events . push ( event ) ) ;
352+
353+ // Set up promise to wait for idle BEFORE sending
354+ const idlePromise = getNextEventOfType ( session , "session.idle" ) ;
355355
356356 // Use a slow command so we can verify send() returns before completion
357357 await session . send ( { prompt : "Run 'sleep 2 && echo done'" } ) ;
358358
359359 // send() should return before turn completes (no session.idle yet)
360- expect ( events ) . not . toContain ( "session.idle" ) ;
360+ expect ( events . some ( ( e ) => e . type === "session.idle" ) ) . toBe ( false ) ;
361361
362362 // Wait for turn to complete
363- const message = await getFinalAssistantMessage ( session ) ;
363+ await idlePromise ;
364364
365- expect ( message . data . content ) . toContain ( "done" ) ;
366- expect ( events ) . toContain ( "session.idle" ) ;
367- expect ( events ) . toContain ( "assistant.message" ) ;
365+ // Find the last assistant message from collected events
366+ const assistantMessages = events . filter ( ( e ) => e . type === "assistant.message" ) ;
367+ const message = assistantMessages [ assistantMessages . length - 1 ] ;
368+
369+ expect ( message . data ?. content ) . toContain ( "done" ) ;
370+ expect ( events . some ( ( e ) => e . type === "session.idle" ) ) . toBe ( true ) ;
371+ expect ( events . some ( ( e ) => e . type === "assistant.message" ) ) . toBe ( true ) ;
368372 } ) ;
369373
370374 it ( "sendAndWait blocks until session.idle and returns final assistant message" , async ( ) => {
0 commit comments