fix(chat): preserve agent UI across close
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import React from "react";
|
||||
import { act, render, screen } from "@testing-library/react";
|
||||
|
||||
import { GlobalChatbox } from "./GlobalChatbox";
|
||||
|
||||
const createSession = jest.fn();
|
||||
let mockCurrentProjectId = "project-1";
|
||||
|
||||
jest.mock("@refinedev/core", () => ({
|
||||
useNotification: () => ({ open: jest.fn() }),
|
||||
}));
|
||||
|
||||
jest.mock("@/lib/chatModels", () => ({
|
||||
fetchAgentModels: jest.fn(() => new Promise(() => {})),
|
||||
}));
|
||||
|
||||
jest.mock("@/store/projectStore", () => ({
|
||||
useProjectStore: (selector: (state: { currentProjectId: string }) => unknown) =>
|
||||
selector({ currentProjectId: mockCurrentProjectId }),
|
||||
}));
|
||||
|
||||
jest.mock("./globalChatboxVoice", () => ({
|
||||
useSpeechSynthesis: () => ({
|
||||
speechState: "idle",
|
||||
speakingMessageId: null,
|
||||
speak: jest.fn(),
|
||||
pause: jest.fn(),
|
||||
resume: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
isSupported: true,
|
||||
}),
|
||||
useSpeechRecognition: () => ({
|
||||
isListening: false,
|
||||
start: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
isSupported: true,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock("./hooks/useAgentToolActions", () => ({
|
||||
useAgentToolActions: () => jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("./hooks/useAgentChatSession", () => ({
|
||||
useAgentChatSession: () => ({
|
||||
messages: [],
|
||||
chatSessions: [],
|
||||
activeSessionId: undefined,
|
||||
isHydrating: false,
|
||||
loadingSessionId: null,
|
||||
isStreaming: false,
|
||||
sessionTitle: "新会话",
|
||||
sendPrompt: jest.fn(),
|
||||
createBranch: jest.fn(),
|
||||
abort: jest.fn(),
|
||||
replyPermission: jest.fn(),
|
||||
replyQuestion: jest.fn(),
|
||||
rejectQuestion: jest.fn(),
|
||||
createSession,
|
||||
renameSession: jest.fn(),
|
||||
removeSession: jest.fn(),
|
||||
switchSession: jest.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock("./AgentHeader", () => ({
|
||||
AgentHeader: () => <div>Agent header</div>,
|
||||
}));
|
||||
|
||||
jest.mock("./AgentHistoryPanel", () => ({
|
||||
AgentHistoryPanel: () => <div>History</div>,
|
||||
}));
|
||||
|
||||
jest.mock("./AgentWorkspace", () => ({
|
||||
AgentWorkspace: () => <div data-testid="agent-workspace">Workspace</div>,
|
||||
}));
|
||||
|
||||
jest.mock("./AgentComposer", () => ({
|
||||
AgentComposer: React.forwardRef(function MockAgentComposer() {
|
||||
return <div>Composer</div>;
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock("./GlobalChatboxParts", () => ({
|
||||
Blob: () => null,
|
||||
}));
|
||||
|
||||
describe("GlobalChatbox lifecycle", () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
createSession.mockClear();
|
||||
mockCurrentProjectId = "project-1";
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.runOnlyPendingTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it("keeps content mounted and preserves the session across close and reopen", async () => {
|
||||
const { rerender } = render(<GlobalChatbox open onClose={jest.fn()} />);
|
||||
|
||||
act(() => jest.runOnlyPendingTimers());
|
||||
expect(createSession).toHaveBeenCalledTimes(1);
|
||||
expect(screen.getByTestId("agent-workspace")).toBeInTheDocument();
|
||||
|
||||
rerender(<GlobalChatbox open={false} onClose={jest.fn()} />);
|
||||
act(() => jest.advanceTimersByTime(300));
|
||||
|
||||
expect(screen.getByTestId("agent-workspace")).toBeInTheDocument();
|
||||
|
||||
rerender(<GlobalChatbox open onClose={jest.fn()} />);
|
||||
act(() => jest.runOnlyPendingTimers());
|
||||
|
||||
expect(createSession).toHaveBeenCalledTimes(1);
|
||||
|
||||
mockCurrentProjectId = "project-2";
|
||||
rerender(<GlobalChatbox open onClose={jest.fn()} />);
|
||||
act(() => jest.runOnlyPendingTimers());
|
||||
|
||||
expect(createSession).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user