feat(FN-3062): add /clear command to Chat and Quick Chat, fix session banne
The merge adds a `/clear` command to both the Chat view and Quick Chat that clears transient chat state on session resets, with tests for all new hooks and components. It also persists session banner dismissals via a new `useSessionBannerPref` hook, adds a hide-banner setting, and preserves planning Fusion-Task-Id: FN-3062
This commit is contained in:
@@ -674,6 +674,54 @@ describe("useChat", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("selectSession clears pending queued message state", async () => {
|
||||
const sessionA = makeSession({ id: "session-001", agentId: "agent-001" });
|
||||
const sessionB = makeSession({ id: "session-002", agentId: "agent-002" });
|
||||
mockFetchChatSessions.mockResolvedValueOnce({ sessions: [sessionA, sessionB] });
|
||||
mockFetchChatMessages.mockResolvedValue({ messages: [] });
|
||||
|
||||
mockStreamChatResponse.mockReturnValue({ close: vi.fn(), isConnected: () => true });
|
||||
|
||||
const { result } = renderHook(() => useChat("proj-123"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.sessions).toHaveLength(2);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.selectSession("session-001");
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.activeSession?.id).toBe("session-001");
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.sendMessage("First");
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.isStreaming).toBe(true);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.sendMessage("Queued follow-up");
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.pendingMessage).toBe("Queued follow-up");
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.selectSession("session-002");
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.pendingMessage).toBe("");
|
||||
expect(result.current.isStreaming).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it("clearPendingMessage clears pending message", async () => {
|
||||
const session = makeSession({ id: "session-001", agentId: "agent-001" });
|
||||
mockFetchChatSessions.mockResolvedValueOnce({ sessions: [session] });
|
||||
|
||||
@@ -357,6 +357,47 @@ describe("useQuickChat", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("startFreshSession clears queued pending message state", async () => {
|
||||
const existingSession = makeSession({ id: "session-existing", agentId: "agent-001" });
|
||||
const freshSession = makeSession({ id: "session-fresh", agentId: "agent-001" });
|
||||
|
||||
mockFetchResumeChatSession.mockResolvedValueOnce({ session: existingSession });
|
||||
mockCreateChatSession.mockResolvedValueOnce({ session: freshSession });
|
||||
mockFetchChatMessages.mockResolvedValue({ messages: [] });
|
||||
|
||||
const { result } = renderHook(() => useQuickChat("proj-123"));
|
||||
|
||||
await act(async () => {
|
||||
await result.current.switchSession("agent-001");
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.sendMessage("Hello");
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.isStreaming).toBe(true);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.sendMessage("Queued follow-up");
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.pendingMessage).toBe("Queued follow-up");
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await result.current.startFreshSession();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.pendingMessage).toBe("");
|
||||
expect(result.current.isStreaming).toBe(false);
|
||||
expect(result.current.activeSession?.id).toBe("session-fresh");
|
||||
});
|
||||
});
|
||||
|
||||
it("stopStreaming aborts stream and resets streaming state", async () => {
|
||||
const existingSession = makeSession({ id: "session-existing", agentId: "agent-001" });
|
||||
const closeFn = vi.fn();
|
||||
|
||||
Reference in New Issue
Block a user