重构会话标题编辑和删除确认逻辑;重构历史会话时间记录
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
import type { ChatSessionRecord } from "./GlobalChatbox.types";
|
||||
import {
|
||||
createEmptyChatSession,
|
||||
loadChatSessionById,
|
||||
saveActiveChatState,
|
||||
updateChatSessionTitle,
|
||||
} from "./chatStorage";
|
||||
|
||||
type StoreName = "sessions" | "meta";
|
||||
|
||||
const stores: Record<StoreName, Map<string, any>> = {
|
||||
sessions: new Map(),
|
||||
meta: new Map(),
|
||||
};
|
||||
|
||||
const mockDb = {
|
||||
get: jest.fn(async (storeName: StoreName, key: string) => stores[storeName].get(key)),
|
||||
getAll: jest.fn(async (storeName: StoreName) => Array.from(stores[storeName].values())),
|
||||
put: jest.fn(async (storeName: StoreName, value: { id?: string; key?: string }) => {
|
||||
const key = storeName === "sessions" ? value.id : value.key;
|
||||
if (!key) {
|
||||
throw new Error(`Missing key for store ${storeName}`);
|
||||
}
|
||||
stores[storeName].set(key, value);
|
||||
return key;
|
||||
}),
|
||||
delete: jest.fn(async (storeName: StoreName, key: string) => {
|
||||
stores[storeName].delete(key);
|
||||
}),
|
||||
};
|
||||
|
||||
jest.mock("idb", () => ({
|
||||
openDB: jest.fn(async () => mockDb),
|
||||
}));
|
||||
|
||||
describe("chatStorage timestamp semantics", () => {
|
||||
let now = new Date("2026-05-19T09:00:00+08:00").getTime();
|
||||
let dateNowSpy: jest.SpyInstance<number, []>;
|
||||
|
||||
beforeEach(() => {
|
||||
stores.sessions.clear();
|
||||
stores.meta.clear();
|
||||
mockDb.get.mockClear();
|
||||
mockDb.getAll.mockClear();
|
||||
mockDb.put.mockClear();
|
||||
mockDb.delete.mockClear();
|
||||
window.localStorage.clear();
|
||||
now = new Date("2026-05-19T09:00:00+08:00").getTime();
|
||||
dateNowSpy = jest.spyOn(Date, "now").mockImplementation(() => now);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
dateNowSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("keeps anchor and content timestamps when reopening an old session", async () => {
|
||||
const record: ChatSessionRecord = {
|
||||
id: "old-session",
|
||||
title: "很久之前的会话",
|
||||
isTitleManuallyEdited: false,
|
||||
createdAt: new Date("2026-04-01T10:00:00+08:00").getTime(),
|
||||
updatedAt: new Date("2026-04-01T10:30:00+08:00").getTime(),
|
||||
sessionId: "remote-1",
|
||||
messages: [
|
||||
{
|
||||
id: "message-1",
|
||||
role: "user",
|
||||
content: "老问题",
|
||||
branchRootId: "message-1",
|
||||
},
|
||||
],
|
||||
branchGroups: [],
|
||||
};
|
||||
stores.sessions.set(record.id, record);
|
||||
|
||||
const loadedState = await loadChatSessionById(record.id);
|
||||
now = new Date("2026-05-19T09:30:00+08:00").getTime();
|
||||
await saveActiveChatState(loadedState);
|
||||
|
||||
expect(stores.sessions.get(record.id)).toMatchObject({
|
||||
createdAt: record.createdAt,
|
||||
updatedAt: record.updatedAt,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not change timestamps when renaming a session", async () => {
|
||||
const record: ChatSessionRecord = {
|
||||
id: "rename-session",
|
||||
title: "旧标题",
|
||||
isTitleManuallyEdited: false,
|
||||
createdAt: new Date("2026-04-10T08:00:00+08:00").getTime(),
|
||||
updatedAt: new Date("2026-04-10T08:05:00+08:00").getTime(),
|
||||
sessionId: "remote-2",
|
||||
messages: [
|
||||
{
|
||||
id: "message-2",
|
||||
role: "user",
|
||||
content: "保留时间",
|
||||
branchRootId: "message-2",
|
||||
},
|
||||
],
|
||||
branchGroups: [],
|
||||
};
|
||||
stores.sessions.set(record.id, record);
|
||||
|
||||
now = new Date("2026-05-19T11:00:00+08:00").getTime();
|
||||
await updateChatSessionTitle(record.id, "新标题", {
|
||||
isTitleManuallyEdited: true,
|
||||
});
|
||||
|
||||
expect(stores.sessions.get(record.id)).toMatchObject({
|
||||
title: "新标题",
|
||||
isTitleManuallyEdited: true,
|
||||
createdAt: record.createdAt,
|
||||
updatedAt: record.updatedAt,
|
||||
});
|
||||
});
|
||||
|
||||
it("anchors createdAt to the first real message time for a new empty session", async () => {
|
||||
const emptyState = await createEmptyChatSession();
|
||||
const storageSessionId = emptyState.storageSessionId;
|
||||
|
||||
now = new Date("2026-05-19T09:05:00+08:00").getTime();
|
||||
await saveActiveChatState({
|
||||
...emptyState,
|
||||
messages: [
|
||||
{
|
||||
id: "message-3",
|
||||
role: "user",
|
||||
content: "第一条消息",
|
||||
branchRootId: "message-3",
|
||||
},
|
||||
],
|
||||
sessionId: "remote-3",
|
||||
});
|
||||
|
||||
expect(stores.sessions.get(storageSessionId!)).toMatchObject({
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user