From 2e918570d66d4d7c8d495637953df80c842cdf9f Mon Sep 17 00:00:00 2001 From: Ammar Date: Mon, 24 Nov 2025 19:09:22 -0600 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A4=96=20fix:=20throw=20on=20sendMess?= =?UTF-8?q?ageAndWait=20timeout=20instead=20of=20silently=20returning=20pa?= =?UTF-8?q?rtial=20events?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The helper was ignoring the return value of waitForEvent, so when a timeout occurred tests would get partial events without stream-end, causing confusing assertion failures like 'expected undefined to be defined'. Now throws a clear error with diagnostics: 'Timeout waiting for stream-end after Xms' --- tests/ipcMain/helpers.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/ipcMain/helpers.ts b/tests/ipcMain/helpers.ts index 4eaea823dd..de27d7fae8 100644 --- a/tests/ipcMain/helpers.ts +++ b/tests/ipcMain/helpers.ts @@ -232,7 +232,16 @@ export async function sendMessageAndWait( // Wait for stream completion const collector = createEventCollector(env.sentEvents, workspaceId); - await collector.waitForEvent("stream-end", timeoutMs); + const streamEnd = await collector.waitForEvent("stream-end", timeoutMs); + + if (!streamEnd) { + collector.logEventDiagnostics(`sendMessageAndWait timeout after ${timeoutMs}ms`); + throw new Error( + `sendMessageAndWait: Timeout waiting for stream-end after ${timeoutMs}ms.\n` + + `See detailed event diagnostics above.` + ); + } + return collector.getEvents(); } From 5c7dff9e7f0bfe67e49cd2c5096dfbc6136ae56c Mon Sep 17 00:00:00 2001 From: Ammar Date: Mon, 24 Nov 2025 19:32:59 -0600 Subject: [PATCH 2/2] fix: use getFinalMessage() instead of getDeltas() in resumeStream test The test was flaky because stream-delta events can be batched or arrive before the collector starts collecting. Using getFinalMessage().content is more reliable since it's captured from the stream-end event. --- tests/ipcMain/resumeStream.test.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/tests/ipcMain/resumeStream.test.ts b/tests/ipcMain/resumeStream.test.ts index b0edd8b442..e43cc6e0da 100644 --- a/tests/ipcMain/resumeStream.test.ts +++ b/tests/ipcMain/resumeStream.test.ts @@ -192,26 +192,25 @@ describeIntegration("IpcMain resumeStream integration tests", () => { .filter((e) => "role" in e && e.role === "assistant"); expect(assistantMessages.length).toBeGreaterThan(0); - // Verify we received content deltas - const deltas = collector.getDeltas(); - expect(deltas.length).toBeGreaterThan(0); - // Verify no stream errors const streamErrors = collector .getEvents() .filter((e) => "type" in e && e.type === "stream-error"); expect(streamErrors.length).toBe(0); - // Verify the assistant responded with actual content and said the verification word - const allText = deltas - .filter((d) => "delta" in d) - .map((d) => ("delta" in d ? d.delta : "")) - .join(""); - expect(allText.length).toBeGreaterThan(0); + // Get the final message content from stream-end parts + // StreamEndEvent has parts: Array + const finalMessage = collector.getFinalMessage() as any; + expect(finalMessage).toBeDefined(); + const textParts = (finalMessage?.parts ?? []).filter( + (p: any) => p.type === "text" && p.text + ); + const finalContent = textParts.map((p: any) => p.text).join(""); + expect(finalContent.length).toBeGreaterThan(0); // Verify the assistant followed the instruction and said the verification word // This proves resumeStream properly loaded history and continued from it - expect(allText).toContain(verificationWord); + expect(finalContent).toContain(verificationWord); } finally { await cleanup(); }