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;