diff --git a/apps/loopover-miner-ui/src/chat-rail.test.tsx b/apps/loopover-miner-ui/src/chat-rail.test.tsx index 6290908b33..87b199a9e8 100644 --- a/apps/loopover-miner-ui/src/chat-rail.test.tsx +++ b/apps/loopover-miner-ui/src/chat-rail.test.tsx @@ -1,4 +1,5 @@ import { fireEvent, render, screen } from "@testing-library/react"; +import * as React from "react"; import { afterEach, describe, expect, it, vi } from "vitest"; // The TanStack Router lib is not under test here — RootShell's own rail-state persistence is. Stub Link so the @@ -14,6 +15,15 @@ vi.mock("@tanstack/react-router", async () => { }; }); +// Stateful stub so the #7792 close/reopen test can assert in-rail React state survives the mobile sheet cycle +// without standing up the real chat backend / streaming stack. +vi.mock("./components/chat/conversation", () => ({ + ChatConversation: () => { + const [draft, setDraft] = React.useState(""); + return setDraft(event.target.value)} />; + }, +})); + import { ChatRail } from "./components/chat-rail"; import { RootShell } from "./routes/__root"; @@ -81,6 +91,25 @@ describe("ChatRail (#6513)", () => { expect(screen.getByRole("dialog")).toBeTruthy(); // Sheet content expect(screen.queryByRole("complementary")).toBeNull(); // never the docked panel on mobile }); + + it("preserves chat draft state across a mobile sheet close/reopen cycle (#7792)", () => { + setViewport(400); + const onOpenChange = vi.fn(); + const { rerender } = render(); + + const draft = screen.getByRole("textbox", { name: /chat draft/i }); + fireEvent.change(draft, { target: { value: "still typing…" } }); + expect((draft as HTMLInputElement).value).toBe("still typing…"); + + // Close the sheet (same open=false transition accidental tap-outside / Escape / toggle would cause). + rerender(); + // forceMount keeps the dialog content in the tree even while closed. + expect(screen.getByRole("dialog", { hidden: true })).toBeTruthy(); + + // Reopen — draft must still be there (RailBody never unmounted). + rerender(); + expect((screen.getByRole("textbox", { name: /chat draft/i }) as HTMLInputElement).value).toBe("still typing…"); + }); }); describe("RootShell chat-rail integration (#6513)", () => { diff --git a/apps/loopover-miner-ui/src/components/chat-rail.tsx b/apps/loopover-miner-ui/src/components/chat-rail.tsx index 53e3b9494e..b92478c617 100644 --- a/apps/loopover-miner-ui/src/components/chat-rail.tsx +++ b/apps/loopover-miner-ui/src/components/chat-rail.tsx @@ -47,7 +47,10 @@ export function ChatRail({ open, onOpenChange }: ChatRailProps) { Chat - + {/* forceMount: keep RailBody mounted when the sheet closes so chat state survives, matching the + desktop `