import { describe, expect, it, vi } from "vitest"; import { CommandHistory, createTransaction } from "../../src/commands/history"; describe("source transaction history", () => { it("undoes and redoes exact source without normalization", () => { const history = new CommandHistory(); const transaction = createTransaction({ label: "Set fill", baseRevision: 1, sourceBefore: "\r\n", sourceAfter: '\r\n', }); history.commit(transaction); expect(history.undo(transaction.sourceAfter)?.sourceBefore).toBe( transaction.sourceBefore, ); expect(history.redo(transaction.sourceBefore)?.sourceAfter).toBe( transaction.sourceAfter, ); }); it("coalesces rapid source-editor transactions with a shared merge key", () => { vi.spyOn(Date, "now").mockReturnValueOnce(100).mockReturnValueOnce(200); const history = new CommandHistory(); history.commit( createTransaction({ label: "Type", baseRevision: 0, sourceBefore: "a", sourceAfter: "ab", mergeKey: "typing", }), ); history.commit( createTransaction({ label: "Type", baseRevision: 1, sourceBefore: "ab", sourceAfter: "abc", mergeKey: "typing", }), ); expect(history.snapshot.past).toHaveLength(1); expect(history.snapshot.past[0]).toMatchObject({ sourceBefore: "a", sourceAfter: "abc", }); }); it("rejects stale undo and bounds history", () => { const history = new CommandHistory(2, 10_000); history.commit( createTransaction({ label: "one", baseRevision: 0, sourceBefore: "a", sourceAfter: "b", }), ); expect(() => history.undo("not-b")).toThrow(/stale/u); history.commit( createTransaction({ label: "two", baseRevision: 1, sourceBefore: "b", sourceAfter: "c", }), ); history.commit( createTransaction({ label: "three", baseRevision: 2, sourceBefore: "c", sourceAfter: "d", }), ); expect(history.snapshot.past).toHaveLength(2); }); });