test: cover runtime regression scenarios

This commit is contained in:
2026-08-03 15:08:01 +08:00
parent 7082881624
commit 776d56320a
4 changed files with 633 additions and 2 deletions
@@ -0,0 +1,73 @@
import { describe, expect, it } from "vitest";
import { ConversationStore } from "./conversation-store";
class MemoryStorage implements Storage {
private readonly values = new Map<string, string>();
public get length(): number { return this.values.size; }
public clear(): void { this.values.clear(); }
public getItem(key: string): string | null { return this.values.get(key) ?? null; }
public key(index: number): string | null { return [...this.values.keys()][index] ?? null; }
public removeItem(key: string): void { this.values.delete(key); }
public setItem(key: string, value: string): void { this.values.set(key, value); }
}
const conversationID = "user_test:2:agent_channel";
const createdAt = "2026-08-03T00:00:00.000Z";
describe("ConversationStore", () => {
it("keeps the inclusive sync cursor at zero after a send acknowledgement", () => {
const store = new ConversationStore(new MemoryStorage());
store.open(conversationID);
store.appendLocalText("local_001", "hello", createdAt);
store.markSubmitted("local_001", 41, createdAt);
expect(store.snapshot()).toMatchObject({ cursor: 0, outbox: [] });
expect(store.snapshot().items).toEqual([expect.objectContaining({
local_id: "local_001",
message_seq: 41,
item: expect.objectContaining({ kind: "user-message", delivery: expect.objectContaining({ status: "submitted" }) }),
})]);
});
it("deduplicates the inclusive sync echo of a locally submitted user message", () => {
const store = new ConversationStore(new MemoryStorage());
store.open(conversationID);
store.appendLocalText("local_001", "hello", createdAt);
store.markSubmitted("local_001", 41, createdAt);
const restored = store.recordSyncedUserText(41, "hello", createdAt);
expect(restored).toBeUndefined();
expect(store.snapshot()).toMatchObject({ cursor: 41 });
expect(store.snapshot().items).toHaveLength(1);
});
it("persists a local echo and restores it for the same conversation", () => {
const storage = new MemoryStorage();
const first = new ConversationStore(storage);
first.open(conversationID);
first.appendLocalText("local_002", "persist me", createdAt);
const reopened = new ConversationStore(storage);
const snapshot = reopened.open(conversationID);
expect(snapshot.cursor).toBe(0);
expect(snapshot.outbox).toEqual([expect.objectContaining({ local_id: "local_002", payload: "persist me" })]);
expect(snapshot.items).toEqual([expect.objectContaining({
local_id: "local_002",
item: expect.objectContaining({ kind: "user-message", text: "persist me" }),
})]);
});
it("accepts one remote message per IM sequence and advances the cursor only from sync data", () => {
const store = new ConversationStore(new MemoryStorage());
store.open(conversationID);
const item = { kind: "markdown" as const, id: "evt_remote_001", markdown: "remote" };
expect(store.recordIncoming(item, 42, createdAt)).toBe(true);
expect(store.recordIncoming(item, 42, createdAt)).toBe(false);
expect(store.snapshot()).toMatchObject({ cursor: 42 });
expect(store.snapshot().items).toHaveLength(1);
});
});