import { describe, it, expect } from "bun:test"; import { buildTransactionHistory } from "../src/events.js"; import type { WalletData, TokenData, HistoryEntry, TransactionRecord, } from "../src/types.js"; describe("buildTransactionHistory", () => { const emptyWallet: WalletData = { mints: [], privkey: "" }; it("should build records from history events", () => { const history: HistoryEntry[] = [ { direction: "in", amount: "100", unit: "sat", eventId: "evt1", createdAt: 1000, referencedEvents: [], }, { direction: "out", amount: "50", unit: "sat", eventId: "evt2", createdAt: 2000, referencedEvents: [], }, ]; const records = buildTransactionHistory(emptyWallet, [], history, [], []); expect(records).toHaveLength(2); expect(records[0].type).toBe("receive"); expect(records[0].amount).toBe(100); expect(records[1].type).toBe("send"); expect(records[1].amount).toBe(50); }); it("should deduplicate by event ID across sources", () => { const history: HistoryEntry[] = [ { direction: "in", amount: "100", unit: "sat", eventId: "same-id", createdAt: 1000, referencedEvents: [], }, ]; const nutzaps: TransactionRecord[] = [ { date: "2025-01-01T00:00:00Z", type: "zap", amount: 100, unit: "sat", mint: "", token_id: "same-id", memo: "", }, ]; const records = buildTransactionHistory( emptyWallet, [], history, nutzaps, [] ); expect(records).toHaveLength(1); }); it("should fall back to token events when no history events exist", () => { const tokens: TokenData[] = [ { mint: "https://mint.example", unit: "sat", proofs: [{ id: "p1", amount: 64, secret: "s", C: "c" }], eventId: "tok1", createdAt: 1000, }, ]; const records = buildTransactionHistory(emptyWallet, tokens, [], [], []); expect(records).toHaveLength(1); expect(records[0].amount).toBe(64); expect(records[0].type).toBe("receive"); }); it("should NOT use token events when history events exist", () => { const tokens: TokenData[] = [ { mint: "https://mint.example", unit: "sat", proofs: [{ id: "p1", amount: 64, secret: "s", C: "c" }], eventId: "tok1", createdAt: 1000, }, ]; const history: HistoryEntry[] = [ { direction: "in", amount: "100", unit: "sat", eventId: "evt1", createdAt: 2000, referencedEvents: [], }, ]; const records = buildTransactionHistory( emptyWallet, tokens, history, [], [] ); expect(records).toHaveLength(1); expect(records[0].token_id).toBe("evt1"); }); it("should sort records by date ascending", () => { const nutzaps: TransactionRecord[] = [ { date: new Date(3000 * 1000).toISOString(), type: "zap", amount: 10, unit: "sat", mint: "", token_id: "z1", memo: "", }, { date: new Date(1000 * 1000).toISOString(), type: "zap", amount: 20, unit: "sat", mint: "", token_id: "z2", memo: "", }, ]; const records = buildTransactionHistory( emptyWallet, [], [], nutzaps, [] ); expect(records[0].token_id).toBe("z2"); expect(records[1].token_id).toBe("z1"); }); it("should handle non-numeric amount gracefully (defaults to 0)", () => { const history: HistoryEntry[] = [ { direction: "in", amount: "not-a-number", unit: "sat", eventId: "evt1", createdAt: 1000, referencedEvents: [], }, ]; const records = buildTransactionHistory(emptyWallet, [], history, [], []); expect(records[0].amount).toBe(0); }); it("should merge nutzaps and redemptions with history", () => { const history: HistoryEntry[] = [ { direction: "in", amount: "100", unit: "sat", eventId: "h1", createdAt: 1000, referencedEvents: [], }, ]; const nutzaps: TransactionRecord[] = [ { date: new Date(2000 * 1000).toISOString(), type: "zap", amount: 50, unit: "sat", mint: "", token_id: "z1", memo: "", }, ]; const redemptions: TransactionRecord[] = [ { date: new Date(3000 * 1000).toISOString(), type: "receive", amount: 50, unit: "sat", mint: "", token_id: "r1", memo: "nutzap redemption", }, ]; const records = buildTransactionHistory( emptyWallet, [], history, nutzaps, redemptions ); expect(records).toHaveLength(3); expect(records[0].token_id).toBe("h1"); expect(records[1].token_id).toBe("z1"); expect(records[2].token_id).toBe("r1"); }); });