import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; import { NEW_CHAT_DRAFT_ID, chatDraftStorageKey, clearChatDraft, readChatDraft, writeChatDraft, } from "../web/static/js/chat_drafts.js"; class MemoryStorage { constructor() { this.values = new Map(); } getItem(key) { return this.values.get(key) ?? null; } setItem(key, value) { this.values.set(key, String(value)); } removeItem(key) { this.values.delete(key); } } test("chat drafts are isolated by user and conversation", () => { const storage = new MemoryStorage(); writeChatDraft(storage, "user-a", "task-1", "任务一草稿", 1); writeChatDraft(storage, "user-a", "task-2", "任务二草稿", 2); writeChatDraft(storage, "user-b", "task-1", "另一用户草稿", 3); assert.equal(readChatDraft(storage, "user-a", "task-1"), "任务一草稿"); assert.equal(readChatDraft(storage, "user-a", "task-2"), "任务二草稿"); assert.equal(readChatDraft(storage, "user-b", "task-1"), "另一用户草稿"); assert.notEqual(chatDraftStorageKey("user-a"), chatDraftStorageKey("user-b")); }); test("new conversation draft persists and blank content clears it", () => { const storage = new MemoryStorage(); writeChatDraft(storage, "user-a", NEW_CHAT_DRAFT_ID, "未创建对话", 1); assert.equal(readChatDraft(storage, "user-a", NEW_CHAT_DRAFT_ID), "未创建对话"); clearChatDraft(storage, "user-a", NEW_CHAT_DRAFT_ID); assert.equal(readChatDraft(storage, "user-a", NEW_CHAT_DRAFT_ID), ""); assert.equal(storage.getItem(chatDraftStorageKey("user-a")), null); }); test("chat integrates draft save, restore, migration, and sent cleanup", () => { const source = readFileSync(new URL("../web/static/js/chat.js", import.meta.url), "utf8"); assert.match(source, /export async function selectTask\(tid\) \{\s*persistComposerDraft\(\)/); assert.match(source, /state\.taskId = tid;\s*restoreComposerDraft\(tid\)/); assert.match(source, /persistComposerDraft\(t\.task_id\)/); assert.match(source, /clearChatDraft\(localStorage, state\.userId, taskId\)/); assert.match(source, /addEventListener\("input", \(\) => \{\s*scheduleComposerDraftSave\(\)/); assert.match(source, /addEventListener\("pagehide", \(\) => persistComposerDraft\(\)\)/); });