diff --git a/frontend/src/components/Chat.test.tsx b/frontend/src/components/Chat.test.tsx
index 4cb53be..e98f590 100644
--- a/frontend/src/components/Chat.test.tsx
+++ b/frontend/src/components/Chat.test.tsx
@@ -529,6 +529,57 @@ describe("Chat localStorage persistence (Story 145)", () => {
confirmSpy.mockRestore();
});
+ it("Bug 245: messages survive unmount/remount cycle (page refresh)", async () => {
+ // Step 1: Render Chat and populate messages via WebSocket onUpdate
+ const { unmount } = render(
+ ,
+ );
+
+ await waitFor(() => expect(capturedWsHandlers).not.toBeNull());
+
+ const history: Message[] = [
+ { role: "user", content: "Persist me across refresh" },
+ { role: "assistant", content: "I should survive a reload" },
+ ];
+
+ act(() => {
+ capturedWsHandlers?.onUpdate(history);
+ });
+
+ // Verify messages are persisted to localStorage
+ expect(localStorage.getItem(STORAGE_KEY)).not.toBeNull();
+ const storedBefore = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? "[]");
+ expect(storedBefore).toEqual(history);
+
+ // Step 2: Unmount the Chat component (simulates page unload)
+ unmount();
+
+ // Verify localStorage was NOT cleared by unmount
+ expect(localStorage.getItem(STORAGE_KEY)).not.toBeNull();
+ const storedAfterUnmount = JSON.parse(
+ localStorage.getItem(STORAGE_KEY) ?? "[]",
+ );
+ expect(storedAfterUnmount).toEqual(history);
+
+ // Step 3: Remount the Chat component (simulates page reload)
+ capturedWsHandlers = null;
+ render();
+
+ // Verify messages are restored from localStorage
+ expect(
+ await screen.findByText("Persist me across refresh"),
+ ).toBeInTheDocument();
+ expect(
+ await screen.findByText("I should survive a reload"),
+ ).toBeInTheDocument();
+
+ // Verify localStorage still has the messages
+ const storedAfterRemount = JSON.parse(
+ localStorage.getItem(STORAGE_KEY) ?? "[]",
+ );
+ expect(storedAfterRemount).toEqual(history);
+ });
+
it("AC5: uses project-scoped storage key", async () => {
const otherKey = "storykit-chat-history:/other/project";
localStorage.setItem(