Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions apps/desktop/src/state/host.test.ts
Original file line number Diff line number Diff line change
@@ -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));
}
});
Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/state/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
clearTimeout(saveTimer);
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/state/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ import {
reconcileLinks,
releaseLimitWaitsFrom,
requeueUnreadSteers,
resetLinkBook,
resetWaits,
restoreQueuedThreads,
stateOf,
Expand Down Expand Up @@ -8515,6 +8516,7 @@ export function resetForTests() {
clearPageCache();
stopPlanPolling();
resetWaits();
resetLinkBook();
keptUnlistedThreads.clear();
deletedThreads.clear();
deferredAnnouncements.length = 0;
Expand Down
Loading