SkateSpots/src/hooks/useZapTotals.test.ts
SkateSpots bcd99994a9 test: cover zap helpers and newsletter data
- useZapTotals: zapTargetKey (regular id vs addressable coord) and
  zapReceiptSats (amount tag -> bolt11 -> description JSON -> 0, malformed safe)
- newsletterIssues: schema, newest-first ordering, publish hashtags
2026-09-26 19:45:48 +07:00

85 lines
2.4 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import type { NostrEvent } from '@nostrify/nostrify';
import { zapTargetKey, zapReceiptSats } from './useZapTotals';
/** Minimal event factory — only the fields these helpers read. */
function ev(partial: Partial<NostrEvent> & Pick<NostrEvent, 'kind' | 'pubkey' | 'id'>): NostrEvent {
return {
content: '',
created_at: 0,
sig: '',
tags: [],
...partial,
} as NostrEvent;
}
describe('zapTargetKey', () => {
it('uses the event id for regular (non-addressable) events', () => {
const e = ev({ kind: 1, pubkey: 'aa', id: 'abc123' });
expect(zapTargetKey(e)).toBe('abc123');
});
it('uses the addressable coordinate for kind 30000-39999', () => {
const e = ev({
kind: 30818,
pubkey: 'deadbeef',
id: 'ignored',
tags: [['d', 'tilcayo']],
});
expect(zapTargetKey(e)).toBe('30818:deadbeef:tilcayo');
});
it('handles an addressable event with a missing d tag', () => {
const e = ev({ kind: 30818, pubkey: 'deadbeef', id: 'ignored' });
expect(zapTargetKey(e)).toBe('30818:deadbeef:');
});
});
describe('zapReceiptSats', () => {
it('reads the amount tag (millisats -> sats)', () => {
const receipt = ev({
kind: 9735,
pubkey: 'lnurl-server',
id: 'r1',
tags: [['amount', '21000']],
});
expect(zapReceiptSats(receipt)).toBe(21);
});
it('falls back to the bolt11 invoice amount', () => {
const receipt = ev({
kind: 9735,
pubkey: 'lnurl-server',
id: 'r2',
tags: [['bolt11', 'lnbc210n1pvjluezpp5abcdef']],
});
expect(zapReceiptSats(receipt)).toBe(21);
});
it('falls back to the zap request in the description tag', () => {
const receipt = ev({
kind: 9735,
pubkey: 'lnurl-server',
id: 'r3',
tags: [
['description', JSON.stringify({ tags: [['amount', '1000000']] })],
],
});
expect(zapReceiptSats(receipt)).toBe(1000);
});
it('returns 0 when no amount can be determined', () => {
const receipt = ev({ kind: 9735, pubkey: 'lnurl-server', id: 'r4' });
expect(zapReceiptSats(receipt)).toBe(0);
});
it('returns 0 for a malformed description instead of throwing', () => {
const receipt = ev({
kind: 9735,
pubkey: 'lnurl-server',
id: 'r5',
tags: [['description', '{not json']],
});
expect(zapReceiptSats(receipt)).toBe(0);
});
});