diff --git a/tests/ipcMain/helpers.ts b/tests/ipcMain/helpers.ts index b47469cf6d..da97ff652d 100644 --- a/tests/ipcMain/helpers.ts +++ b/tests/ipcMain/helpers.ts @@ -142,6 +142,15 @@ export class EventCollector { `waitForEvent timeout: Expected "${eventType}" but got events: [${eventTypes.join(", ")}]` ); + // If there was a stream-error, log the error details + const errorEvent = this.events.find((e) => "type" in e && e.type === "stream-error"); + if (errorEvent && "error" in errorEvent) { + console.error("Stream error details:", errorEvent.error); + if ("errorType" in errorEvent) { + console.error("Stream error type:", errorEvent.errorType); + } + } + return null; } @@ -186,12 +195,43 @@ export function createEventCollector( /** * Assert that a stream completed successfully + * Provides helpful error messages when assertions fail */ export function assertStreamSuccess(collector: EventCollector): void { - expect(collector.hasStreamEnd()).toBe(true); - expect(collector.hasError()).toBe(false); + const allEvents = collector.getEvents(); + const eventTypes = allEvents.filter((e) => "type" in e).map((e) => (e as { type: string }).type); + + // Check for stream-end + if (!collector.hasStreamEnd()) { + const errorEvent = allEvents.find((e) => "type" in e && e.type === "stream-error"); + if (errorEvent && "error" in errorEvent) { + throw new Error( + `Stream did not complete successfully. Got stream-error: ${errorEvent.error}\n` + + `All events: [${eventTypes.join(", ")}]` + ); + } + throw new Error( + `Stream did not emit stream-end event.\n` + `All events: [${eventTypes.join(", ")}]` + ); + } + + // Check for errors + if (collector.hasError()) { + const errorEvent = allEvents.find((e) => "type" in e && e.type === "stream-error"); + const errorMsg = errorEvent && "error" in errorEvent ? errorEvent.error : "unknown"; + throw new Error( + `Stream completed but also has error event: ${errorMsg}\n` + + `All events: [${eventTypes.join(", ")}]` + ); + } + + // Check for final message const finalMessage = collector.getFinalMessage(); - expect(finalMessage).toBeDefined(); + if (!finalMessage) { + throw new Error( + `Stream completed but final message is missing.\n` + `All events: [${eventTypes.join(", ")}]` + ); + } } /** diff --git a/tests/ipcMain/sendMessage.test.ts b/tests/ipcMain/sendMessage.test.ts index 4a4495e6b7..7f5d4de92a 100644 --- a/tests/ipcMain/sendMessage.test.ts +++ b/tests/ipcMain/sendMessage.test.ts @@ -833,7 +833,15 @@ describeIntegration("IpcMain sendMessage integration tests", () => { // Wait for stream to complete (longer timeout for tool policy tests) const collector = createEventCollector(env.sentEvents, workspaceId); - await collector.waitForEvent("stream-end", 30000); + + // Wait for either stream-end or stream-error + // (helpers will log diagnostic info on failure) + await Promise.race([ + collector.waitForEvent("stream-end", 30000), + collector.waitForEvent("stream-error", 30000), + ]); + + // This will throw with detailed error info if stream didn't complete successfully assertStreamSuccess(collector); // Verify file still exists (bash tool was disabled, so deletion shouldn't have happened) @@ -884,7 +892,15 @@ describeIntegration("IpcMain sendMessage integration tests", () => { // Wait for stream to complete (longer timeout for tool policy tests) const collector = createEventCollector(env.sentEvents, workspaceId); - await collector.waitForEvent("stream-end", 30000); + + // Wait for either stream-end or stream-error + // (helpers will log diagnostic info on failure) + await Promise.race([ + collector.waitForEvent("stream-end", 30000), + collector.waitForEvent("stream-error", 30000), + ]); + + // This will throw with detailed error info if stream didn't complete successfully assertStreamSuccess(collector); // Verify file content unchanged (file_edit tools and bash were disabled)