UNPKG

@nostr-dev-kit/ndk

Version:

NDK - Nostr Development Kit. Includes AI Guardrails to catch common mistakes during development.

258 lines (208 loc) 11.1 kB
import { describe, expect, it, vi } from "vitest"; import { fetchingEvents } from "./fetch-events.js"; describe("fetchingEvents guardrail", () => { // Helper to create default mock functions const createMocks = (shouldWarn = true) => ({ warn: vi.fn(), shouldWarnRatio: vi.fn(() => shouldWarn), incrementCount: vi.fn(), }); describe("single event lookups", () => { it("should suggest fetchEvent() for single ID filter", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(); const filters = { ids: ["abc123"] }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(warn).toHaveBeenCalled(); expect(warn.mock.calls[0][0]).toBe("fetch-events-usage"); const message = warn.mock.calls[0][1]; expect(message).toContain("For fetching a single event, use fetchEvent()"); expect(message).toContain("fetchEvent(eventId)"); expect(message).toContain("note1..."); expect(message).toContain("nevent1..."); }); it("should suggest fetchEvent() for single ID filter in array", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(); const filters = [{ ids: ["abc123"] }]; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(warn).toHaveBeenCalled(); expect(warn.mock.calls[0][0]).toBe("fetch-events-usage"); const message = warn.mock.calls[0][1]; expect(message).toContain("For fetching a single event, use fetchEvent()"); }); it("should suggest fetchEvent() for NIP-33 single event filter (decoded naddr)", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(); const filters = { kinds: [30023], authors: ["pubkey123"], "#d": ["identifier"], }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(warn).toHaveBeenCalled(); expect(warn.mock.calls[0][0]).toBe("fetch-events-usage"); const message = warn.mock.calls[0][1]; expect(message).toContain("For fetching a NIP-33 addressable event"); expect(message).toContain("naddr directly"); expect(message).toContain("nip19.decode(naddr)"); expect(message).toContain("fetchEvent(naddr)"); expect(message).toContain("fetchEvent() handles naddr decoding automatically"); }); }); describe("multiple event lookups", () => { it("should suggest subscribe() for multiple IDs when ratio threshold is exceeded", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(true); const filters = { ids: ["abc123", "def456"] }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(shouldWarnRatio).toHaveBeenCalled(); expect(warn).toHaveBeenCalledWith( "fetch-events-usage", expect.stringContaining("In most cases, you should use subscribe()"), expect.any(String), ); expect(warn.mock.calls[0][1]).toContain("subscribe(filter"); }); it("should NOT suggest subscribe() for multiple IDs when ratio threshold is not exceeded", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(false); const filters = { ids: ["abc123", "def456"] }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(shouldWarnRatio).toHaveBeenCalled(); expect(warn).not.toHaveBeenCalled(); }); it("should suggest subscribe() for author filter when ratio threshold is exceeded", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(true); const filters = { kinds: [1], authors: ["pubkey123"] }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(shouldWarnRatio).toHaveBeenCalled(); expect(warn).toHaveBeenCalledWith( "fetch-events-usage", expect.stringContaining("In most cases, you should use subscribe()"), expect.any(String), ); }); it("should suggest subscribe() for multiple filters when ratio threshold is exceeded", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(true); const filters = [{ ids: ["abc123"] }, { ids: ["def456"] }]; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(shouldWarnRatio).toHaveBeenCalled(); expect(warn).toHaveBeenCalledWith( "fetch-events-usage", expect.stringContaining("In most cases, you should use subscribe()"), expect.any(String), ); }); it("should suggest subscribe() for kind filter only when ratio threshold is exceeded", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(true); const filters = { kinds: [1] }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(shouldWarnRatio).toHaveBeenCalled(); expect(warn).toHaveBeenCalledWith( "fetch-events-usage", expect.stringContaining("In most cases, you should use subscribe()"), expect.any(String), ); }); }); describe("replaceable events", () => { it("should NOT warn for ONLY_CACHE usage", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(); const filters = { kinds: [1], authors: ["pubkey123"] }; const opts = { cacheUsage: "ONLY_CACHE" as any }; fetchingEvents(filters, opts, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(warn).not.toHaveBeenCalled(); }); it("should NOT warn for kind 0 (profile) with authors", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(); const filters = { kinds: [0], authors: ["fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52"], }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(warn).not.toHaveBeenCalled(); }); it("should NOT warn for kind 3 (contacts) with authors", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(); const filters = { kinds: [3], authors: ["fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52"], }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(warn).not.toHaveBeenCalled(); }); it("should NOT warn for kind 10002 (relay metadata) with authors", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(); const filters = { kinds: [10002], authors: ["fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52"], }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(warn).not.toHaveBeenCalled(); }); it("should warn for kind 10002 WITHOUT authors when ratio threshold is exceeded", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(true); const filters = { kinds: [10002], }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(shouldWarnRatio).toHaveBeenCalled(); expect(warn).toHaveBeenCalledWith( "fetch-events-usage", expect.stringContaining("In most cases, you should use subscribe()"), expect.any(String), ); }); }); describe("edge cases", () => { it("should handle empty filters array when ratio threshold is exceeded", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(true); const filters: any[] = []; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(shouldWarnRatio).toHaveBeenCalled(); expect(warn).toHaveBeenCalledWith( "fetch-events-usage", expect.stringContaining("In most cases, you should use subscribe()"), expect.any(String), ); }); it("should handle filter without ids or NIP-33 structure when ratio threshold is exceeded", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(true); const filters = { limit: 10 }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(shouldWarnRatio).toHaveBeenCalled(); expect(warn).toHaveBeenCalledWith( "fetch-events-usage", expect.stringContaining("In most cases, you should use subscribe()"), expect.any(String), ); }); it("should not treat incomplete NIP-33 filter as single event when ratio threshold is exceeded", () => { const { warn, shouldWarnRatio, incrementCount } = createMocks(true); // Missing #d identifier const filters = { kinds: [30023], authors: ["pubkey123"], }; fetchingEvents(filters, undefined, warn, shouldWarnRatio, incrementCount); expect(incrementCount).toHaveBeenCalled(); expect(shouldWarnRatio).toHaveBeenCalled(); expect(warn).toHaveBeenCalledWith( "fetch-events-usage", expect.stringContaining("In most cases, you should use subscribe()"), expect.any(String), ); }); }); });