UNPKG

@nostr-dev-kit/ndk

Version:

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

176 lines (149 loc) 6.17 kB
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { EventGenerator, RelayPoolMock } from "../test"; import NDK, { NDKSubscriptionCacheUsage, type NDKEvent, type NDKFilter, NDKKind, type NDKRelay, NDKRelaySet, NDKSubscription, } from "./index"; describe("NDKSubscription", () => { let ndk: NDK; let pool: RelayPoolMock; beforeEach(() => { pool = new RelayPoolMock(); ndk = new NDK({ explicitRelayUrls: [] }); // Set up the EventGenerator with our NDK instance EventGenerator.setNDK(ndk); // Replace the relay pool with our mock // @ts-expect-error - We're intentionally replacing the pool for testing ndk.pool = pool; // Add some mock relays pool.addMockRelay("wss://relay1.example.com"); pool.addMockRelay("wss://relay2.example.com"); pool.addMockRelay("wss://relay3.example.com"); }); afterEach(() => { pool.disconnectAll(); pool.resetAll(); }); it("should receive events matching the filter", async () => { // Create test events const event1 = await EventGenerator.createSignedTextNote("Hello world #1"); const event2 = await EventGenerator.createSignedTextNote("Hello world #2"); const event3 = await EventGenerator.createSignedTextNote("Hello world #3"); // Define filter const filter: NDKFilter = { kinds: [NDKKind.Text] }; // Get the first relay const relaysArray = Array.from(pool.relays); const mockRelay = relaysArray[0]; const relaySet = new NDKRelaySet(new Set([mockRelay as unknown as NDKRelay]), ndk); // Create subscription with explicit subId const subId = "test-subscription-1"; const sub = new NDKSubscription(ndk, filter, { subId, skipVerification: true, // Skip verification to simplify test skipValidation: true, // Skip validation to simplify test relaySet, }); // Track received events const receivedEvents: NDKEvent[] = []; let eoseReceived = false; sub.on("event", (event: NDKEvent) => { receivedEvents.push(event); }); sub.on("eose", () => { eoseReceived = true; }); sub.start(); await mockRelay.simulateEvent(event1, sub.subId!); await mockRelay.simulateEvent(event2, sub.subId!); await mockRelay.simulateEvent(event3, sub.subId!); mockRelay.simulateEOSE(sub.subId!); expect(receivedEvents.length).toEqual(3); expect(eoseReceived).toBe(true); }); it("should close subscription on EOSE when requested", async () => { // Create test events const event = await EventGenerator.createSignedTextNote("Test event"); // Define filter const filter: NDKFilter = { kinds: [NDKKind.Text] }; // Get the first relay const relaysArray = Array.from(pool.relays); const mockRelay = relaysArray[0]; const relaySet = new NDKRelaySet(new Set([mockRelay as unknown as NDKRelay]), ndk); // Create subscription with closeOnEose=true and explicit subId const sub = new NDKSubscription(ndk, filter, { closeOnEose: true, subId: "test-subscription-2", skipVerification: true, // Skip verification to simplify test skipValidation: true, // Skip validation to simplify test relaySet, }); // Track events let eventReceived = false; let eoseReceived = false; let closedReceived = false; sub.on("event", () => { console.log("event received"); eventReceived = true; }); sub.on("eose", () => { eoseReceived = true; console.log("eose received"); }); sub.on("close", () => { closedReceived = true; }); sub.start(); await mockRelay.simulateEvent(event, sub.subId!); // Simulate EOSE mockRelay.simulateEOSE(sub.subId!); console.log("continue"); expect(eventReceived).toBe(true); expect(eoseReceived).toBe(true); expect(closedReceived).toBe(true); }); it("should not cache ephemeral events", async () => { // Mock cache adapter const mockCacheAdapter = { setEvent: vi.fn(), query: vi.fn().mockResolvedValue([]), }; // @ts-expect-error - We're intentionally replacing the cache for testing ndk.cacheAdapter = mockCacheAdapter; // Create replaceable and ephemeral events const replaceableEvent = EventGenerator.createEvent(10002, "replaceable"); await replaceableEvent.sign(); const ephemeralEvent = EventGenerator.createEvent(20000, "ephemeral"); await ephemeralEvent.sign(); // Get the first relay const relaysArray = Array.from(pool.relays); const mockRelay = relaysArray[0]; const relaySet = new NDKRelaySet(new Set([mockRelay as unknown as NDKRelay]), ndk); const filter: NDKFilter = { kinds: [replaceableEvent.kind as number, ephemeralEvent.kind as number], }; const sub = new NDKSubscription(ndk, filter, { subId: "test-subscription-cache", skipVerification: true, skipValidation: true, relaySet, cacheUsage: NDKSubscriptionCacheUsage.ONLY_RELAY, }); // Start subscription and simulate events sub.start(); await mockRelay.simulateEvent(replaceableEvent, sub.subId!); await mockRelay.simulateEvent(ephemeralEvent, sub.subId!); mockRelay.simulateEOSE(sub.subId!); // Verify cache adapter was only called for the replaceable event expect(mockCacheAdapter.setEvent).toHaveBeenCalledTimes(1); expect(mockCacheAdapter.setEvent).toHaveBeenCalledWith( expect.objectContaining({ id: replaceableEvent.id }), expect.any(Array), expect.any(Object) ); }); });