refactor(chat): remove frontend state saves
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import {
|
||||
createEmptyChatState,
|
||||
saveActiveChatState,
|
||||
deleteChatSession,
|
||||
listChatSessions,
|
||||
loadChatSessionById,
|
||||
updateChatSessionTitle,
|
||||
} from "./chatStorage";
|
||||
|
||||
const apiFetch = jest.fn();
|
||||
@@ -9,7 +12,7 @@ jest.mock("@/lib/apiFetch", () => ({
|
||||
apiFetch: (...args: unknown[]) => apiFetch(...args),
|
||||
}));
|
||||
|
||||
describe("chatStorage backend-only persistence", () => {
|
||||
describe("chatStorage backend session operations", () => {
|
||||
beforeEach(() => {
|
||||
apiFetch.mockReset();
|
||||
});
|
||||
@@ -25,46 +28,106 @@ describe("chatStorage backend-only persistence", () => {
|
||||
expect(apiFetch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("creates a backend conversation when saving the first non-empty state", async () => {
|
||||
apiFetch.mockImplementation(async (url: string, init?: RequestInit) => {
|
||||
if (url.endsWith("/api/v1/agent/chat/session")) {
|
||||
expect(init?.method).toBe("POST");
|
||||
return {
|
||||
ok: true,
|
||||
json: async () => ({ session_id: "chat-new-1" }),
|
||||
} as Response;
|
||||
}
|
||||
|
||||
if (url.endsWith("/api/v1/agent/chat/session/chat-new-1")) {
|
||||
expect(init?.method).toBe("PUT");
|
||||
expect(JSON.parse(String(init?.body))).toMatchObject({
|
||||
title: "新对话",
|
||||
is_title_manually_edited: false,
|
||||
});
|
||||
return {
|
||||
ok: true,
|
||||
json: async () => ({ id: "chat-new-1", session_id: "chat-new-1" }),
|
||||
} as Response;
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected request ${url}`);
|
||||
});
|
||||
|
||||
const savedSessionId = await saveActiveChatState(
|
||||
{
|
||||
title: "新对话",
|
||||
isTitleManuallyEdited: false,
|
||||
messages: [
|
||||
it("lists backend sessions sorted by created time", async () => {
|
||||
apiFetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
sessions: [
|
||||
{
|
||||
id: "message-2",
|
||||
role: "user",
|
||||
content: "第一条消息",
|
||||
id: "session-old",
|
||||
title: "旧会话",
|
||||
created_at: "2026-01-01T00:00:00.000Z",
|
||||
updated_at: "2026-01-02T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
id: "session-new",
|
||||
title: "新会话",
|
||||
created_at: "2026-01-03T00:00:00.000Z",
|
||||
updated_at: "2026-01-03T00:00:00.000Z",
|
||||
is_streaming: true,
|
||||
run_status: "running",
|
||||
},
|
||||
],
|
||||
sessionId: undefined,
|
||||
},
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
expect(savedSessionId).toBe("chat-new-1");
|
||||
await expect(listChatSessions()).resolves.toEqual([
|
||||
expect.objectContaining({
|
||||
id: "session-new",
|
||||
title: "新会话",
|
||||
isStreaming: true,
|
||||
runStatus: "running",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: "session-old",
|
||||
title: "旧会话",
|
||||
}),
|
||||
]);
|
||||
expect(apiFetch.mock.calls[0][1]).toMatchObject({ method: "GET" });
|
||||
});
|
||||
|
||||
it("loads a backend session state", async () => {
|
||||
apiFetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
id: "session-1",
|
||||
title: "管网分析",
|
||||
is_title_manually_edited: true,
|
||||
messages: [{ id: "message-1", role: "user", content: "查压力" }],
|
||||
is_streaming: false,
|
||||
}),
|
||||
});
|
||||
|
||||
await expect(loadChatSessionById("session-1")).resolves.toMatchObject({
|
||||
title: "管网分析",
|
||||
isTitleManuallyEdited: true,
|
||||
sessionId: "session-1",
|
||||
messages: [{ id: "message-1", role: "user", content: "查压力" }],
|
||||
});
|
||||
expect(String(apiFetch.mock.calls[0][0])).toContain("/session/session-1");
|
||||
expect(apiFetch.mock.calls[0][1]).toMatchObject({ method: "GET" });
|
||||
});
|
||||
|
||||
it("updates a backend session title through the title endpoint", async () => {
|
||||
apiFetch.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
text: async () => "",
|
||||
});
|
||||
|
||||
await updateChatSessionTitle("session-1", " 新标题 ", {
|
||||
isTitleManuallyEdited: true,
|
||||
});
|
||||
|
||||
expect(String(apiFetch.mock.calls[0][0])).toContain("/session/session-1/title");
|
||||
expect(apiFetch.mock.calls[0][1]).toMatchObject({ method: "PATCH" });
|
||||
expect(JSON.parse(String(apiFetch.mock.calls[0][1]?.body))).toEqual({
|
||||
title: "新标题",
|
||||
is_title_manually_edited: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("deletes a backend session and returns the next active session id", async () => {
|
||||
apiFetch
|
||||
.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
text: async () => "",
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
sessions: [
|
||||
{
|
||||
id: "session-next",
|
||||
title: "下一会话",
|
||||
created_at: "2026-01-01T00:00:00.000Z",
|
||||
updated_at: "2026-01-01T00:00:00.000Z",
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
await expect(deleteChatSession("session-1")).resolves.toBe("session-next");
|
||||
expect(apiFetch.mock.calls[0][1]).toMatchObject({ method: "DELETE" });
|
||||
expect(apiFetch.mock.calls[1][1]).toMatchObject({ method: "GET" });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user