Skip to content

Commit a9c84e3

Browse files
authored
fix(session): preserve live comments across daemon-driven reloads (#278)
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
1 parent 0bdb620 commit a9c84e3

3 files changed

Lines changed: 102 additions & 2 deletions

File tree

src/hunk-session/bridge.test.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,11 @@ describe("createHunkSessionBridge", () => {
116116
type: "command",
117117
requestId: "reload-1",
118118
command: "reload_session",
119-
input: { sessionId: "session-1", nextInput: { kind: "vcs", staged: false, options: {} } },
119+
input: {
120+
sessionId: "session-1",
121+
nextInput: { kind: "vcs", staged: false, options: {} },
122+
sourcePath: "/repo",
123+
},
120124
});
121125
await bridge.dispatchCommand({
122126
type: "command",
@@ -133,6 +137,10 @@ describe("createHunkSessionBridge", () => {
133137

134138
expect(handlers.navigateToLocation).toHaveBeenCalledTimes(1);
135139
expect(handlers.reloadSession).toHaveBeenCalledTimes(1);
140+
expect(handlers.reloadSession).toHaveBeenCalledWith(
141+
{ kind: "vcs", staged: false, options: {} },
142+
{ resetApp: false, sourcePath: "/repo" },
143+
);
136144
expect(handlers.removeLiveComment).toHaveBeenCalledTimes(1);
137145
expect(handlers.clearLiveComments).toHaveBeenCalledTimes(1);
138146
});

src/hunk-session/bridge.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export interface HunkSessionBridgeHandlers {
3030
HunkSessionServerMessage,
3131
{ command: "reload_session" }
3232
>["input"]["nextInput"],
33-
options?: { sourcePath?: string },
33+
options?: { resetApp?: boolean; sourcePath?: string },
3434
) => Promise<ReloadedSessionResult>;
3535
removeLiveComment: (commentId: string) => RemovedCommentResult;
3636
}
@@ -68,6 +68,7 @@ export function createHunkSessionBridge(handlers: HunkSessionBridgeHandlers) {
6868
return handlers.navigateToLocation(message.input);
6969
case "reload_session":
7070
return handlers.reloadSession(message.input.nextInput, {
71+
resetApp: false,
7172
sourcePath: message.input.sourcePath,
7273
});
7374
case "remove_comment":

src/ui/AppHost.interactions.test.tsx

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ function createMockHostClient() {
7575
latestSnapshot = snapshot.state;
7676
},
7777
} as unknown as HunkSessionBrokerClient,
78+
dispatchCommand: async (message: HunkSessionServerMessage) => {
79+
if (!bridge) {
80+
throw new Error("Expected App to register a bridge before running the test command.");
81+
}
82+
83+
return bridge.dispatchCommand(message);
84+
},
7885
getBridge: () => bridge,
7986
getLatestSnapshot: () => latestSnapshot,
8087
navigateToHunk: async (
@@ -1113,6 +1120,90 @@ describe("App interactions", () => {
11131120
}
11141121
});
11151122

1123+
test("session reload preserves live comments while refreshing the file diff", async () => {
1124+
const dir = mkdtempSync(join(tmpdir(), "hunk-session-reload-"));
1125+
const left = join(dir, "before.ts");
1126+
const right = join(dir, "after.ts");
1127+
const reviewNote = "Keep this daemon review note";
1128+
1129+
writeFileSync(left, "export const answer = 41;\n");
1130+
writeFileSync(right, "export const answer = 42;\n");
1131+
1132+
const bootstrap = await loadAppBootstrap({
1133+
kind: "diff",
1134+
left,
1135+
right,
1136+
options: {
1137+
mode: "split",
1138+
},
1139+
});
1140+
const { dispatchCommand, hostClient } = createMockHostClient();
1141+
1142+
const setup = await testRender(<AppHost bootstrap={bootstrap} hostClient={hostClient} />, {
1143+
width: 220,
1144+
height: 20,
1145+
});
1146+
1147+
try {
1148+
await flush(setup);
1149+
1150+
await act(async () => {
1151+
await dispatchCommand({
1152+
type: "command",
1153+
requestId: "comment-1",
1154+
command: "comment",
1155+
input: {
1156+
sessionId: "session-1",
1157+
filePath: "after.ts",
1158+
side: "new",
1159+
line: 1,
1160+
summary: reviewNote,
1161+
reveal: true,
1162+
},
1163+
});
1164+
});
1165+
1166+
let frame = await waitForFrame(setup, (currentFrame) => currentFrame.includes(reviewNote));
1167+
expect(frame).toContain(reviewNote);
1168+
1169+
writeFileSync(right, "export const answer = 42;\nexport const added = true;\n");
1170+
1171+
await act(async () => {
1172+
await dispatchCommand({
1173+
type: "command",
1174+
requestId: "reload-1",
1175+
command: "reload_session",
1176+
input: {
1177+
sessionId: "session-1",
1178+
nextInput: {
1179+
kind: "diff",
1180+
left,
1181+
right,
1182+
options: {
1183+
mode: "split",
1184+
},
1185+
},
1186+
sourcePath: dir,
1187+
},
1188+
});
1189+
});
1190+
1191+
frame = await waitForFrame(
1192+
setup,
1193+
(currentFrame) => currentFrame.includes("export const added = true;"),
1194+
20,
1195+
);
1196+
1197+
expect(frame).toContain("export const added = true;");
1198+
expect(frame).toContain(reviewNote);
1199+
} finally {
1200+
await act(async () => {
1201+
setup.renderer.destroy();
1202+
});
1203+
rmSync(dir, { force: true, recursive: true });
1204+
}
1205+
});
1206+
11161207
test("watch mode reloads the current file diff from disk", async () => {
11171208
const dir = mkdtempSync(join(tmpdir(), "hunk-watch-"));
11181209
const left = join(dir, "before.ts");

0 commit comments

Comments
 (0)