From 95c6874dd66eae69b0bb051dabaddaf2fdd851b3 Mon Sep 17 00:00:00 2001 From: LHagfoss Date: Sun, 15 Nov 2026 13:10:25 +0100 Subject: [PATCH] test(desktop): drop a stray link book save and spell out merge notices resetForTests now drops the link book's pending save, which fired after the next test had no engine and printed a 'The server is not connected' stack trace in four files. The merge notice test names each expected line instead of rebuilding it with the code's own expression, and covers the state and empty fallbacks. --- apps/desktop/src/state/host.test.ts | 29 ++++++++++++++++++++--------- apps/desktop/src/state/host.ts | 11 +++++++++++ apps/desktop/src/state/store.ts | 2 ++ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/apps/desktop/src/state/host.test.ts b/apps/desktop/src/state/host.test.ts index 411d0a31a..c4fe1730b 100644 --- a/apps/desktop/src/state/host.test.ts +++ b/apps/desktop/src/state/host.test.ts @@ -1,20 +1,31 @@ import { expect, test } from "bun:test"; -import { type JsonObject, obj, str } from "../acp/jsonrpc"; +import type { JsonObject } from "../acp/jsonrpc"; import { mergeResultNotice, noProviderPullList } from "./host"; import { isContinueMessage, noticeLine } from "./thread"; test("background merge results are durable notices with the complete outcome for the agent", () => { - const results: JsonObject[] = [ - { state: "merged", merged: true, detail: "Squash-merged and the remote branch was deleted" }, - { state: "failing", merged: false, failing: ["Desktop"], detail: "Checks failed" }, - { error: { code: "failed", message: "The engine did not answer" } }, + // Each result and the line a person reads for it, written out: the detail, then the error's + // message, then the bare state, then a fallback for a result that says nothing. + const cases: [JsonObject, string][] = [ + [ + { state: "merged", merged: true, detail: "Squash-merged and the remote branch was deleted" }, + "Pull request #3792: Squash-merged and the remote branch was deleted", + ], + [ + { state: "failing", merged: false, failing: ["Desktop"], detail: "Checks failed" }, + "Pull request #3792: Checks failed", + ], + [ + { error: { code: "failed", message: "The engine did not answer" } }, + "Pull request #3792: The engine did not answer", + ], + [{ state: "timed_out", merged: false }, "Pull request #3792: timed_out"], + [{}, "Pull request #3792: Merge failed"], ]; - for (const result of results) { + for (const [result, line] of cases) { const text = mergeResultNotice(3792, result); expect(isContinueMessage(text)).toBe(true); - expect(noticeLine(text)).toBe( - `Pull request #3792: ${str(result.detail) || str(obj(result.error)?.message)}`, - ); + expect(noticeLine(text)).toBe(line); expect(text).toContain(JSON.stringify(result)); } }); diff --git a/apps/desktop/src/state/host.ts b/apps/desktop/src/state/host.ts index e08d15361..e923b224d 100644 --- a/apps/desktop/src/state/host.ts +++ b/apps/desktop/src/state/host.ts @@ -306,6 +306,17 @@ function scheduleSave() { saveTimer = setTimeout(() => void flushSave(), SAVE_DEBOUNCE_MS); } +/** + * Forgets the engine's copy of the book and drops a save still waiting to go: a test's debounced + * save otherwise fires after the next test has no engine and prints "the link book was not saved". + */ +export function resetLinkBook(): void { + clearTimeout(saveTimer); + saveTimer = undefined; + engineLinks = undefined; + savedText = undefined; +} + /** Sends the book now, if it differs from what the store already has. */ async function flushSave(): Promise { clearTimeout(saveTimer); diff --git a/apps/desktop/src/state/store.ts b/apps/desktop/src/state/store.ts index fb0508502..46b8399c4 100644 --- a/apps/desktop/src/state/store.ts +++ b/apps/desktop/src/state/store.ts @@ -182,6 +182,7 @@ import { reconcileLinks, releaseLimitWaitsFrom, requeueUnreadSteers, + resetLinkBook, resetWaits, restoreQueuedThreads, stateOf, @@ -8515,6 +8516,7 @@ export function resetForTests() { clearPageCache(); stopPlanPolling(); resetWaits(); + resetLinkBook(); keptUnlistedThreads.clear(); deletedThreads.clear(); deferredAnnouncements.length = 0;