nostr-fetch
Version:
A utility library that allows JS/TS apps to effortlessly fetch past events from Nostr relays
179 lines (146 loc) • 5.58 kB
text/typescript
import type { NostrEvent } from "@nostr-fetch/kernel/nostr";
import { describe, expect, test } from "vitest";
import { EventBuckets, KeyRelayMatrix, compareNostrEvents, initSeenEvents } from "./fetcherHelper";
const dummyEventWithCreatedAtAndId = (created_at: number, id: string): NostrEvent => ({
id,
pubkey: "",
kind: 0,
content: "",
tags: [],
created_at,
sig: "",
});
describe("compareNostrEvents", () => {
test("compares Nostr events correctly", () => {
const older = dummyEventWithCreatedAtAndId(100, "0");
const newer1 = dummyEventWithCreatedAtAndId(200, "1");
const newer2 = dummyEventWithCreatedAtAndId(200, "2");
// newer event comes first
expect(compareNostrEvents(newer1, older)).toBeLessThan(0);
expect(compareNostrEvents(newer2, older)).toBeLessThan(0);
expect(compareNostrEvents(older, newer1)).toBeGreaterThan(0);
expect(compareNostrEvents(older, newer2)).toBeGreaterThan(0);
// event with lower id comes first if they have the same created_at
expect(compareNostrEvents(newer1, newer2)).toBeLessThan(0);
expect(compareNostrEvents(newer2, newer1)).toBeGreaterThan(0);
// returns 0 if the events are the same
expect(compareNostrEvents(older, older)).toBe(0);
expect(compareNostrEvents(newer1, newer1)).toBe(0);
expect(compareNostrEvents(newer2, newer2)).toBe(0);
});
});
const dummyEventWithId = (id: string) => {
return {
id,
pubkey: "",
kind: 0,
content: "",
tags: [],
created_at: 0,
sig: "",
};
};
describe("EventBuckets", () => {
test("has buckets for all keys specified on initialization", () => {
const buckets = new EventBuckets(["alice", "bob"], 10);
expect(buckets.getBucket("alice")).toBeDefined();
expect(buckets.getBucket("bob")).toBeDefined();
expect(buckets.getBucket("unknown")).toBeUndefined();
});
test("add() works correctly", () => {
const e1 = dummyEventWithId("1");
const e2 = dummyEventWithId("2");
const buckets = new EventBuckets(["alice", "bob"], 2);
expect(buckets.add("alice", e1).state).toBe("open");
expect(buckets.add("alice", e2)).toEqual({
state: "fulfilled",
events: expect.arrayContaining([e1, e2]),
});
expect(buckets.add("alice", e1).state).toBe("dropped");
buckets.add("bob", e1);
expect(buckets.add("bob", e2)).toEqual({
state: "fulfilled",
events: expect.arrayContaining([e1, e2]),
});
expect(buckets.add("unknown", e1).state).toBe("dropped");
});
test("calcKeyAndLimitForNextReq() works correctly", () => {
const e = dummyEventWithId("1");
const buckets = new EventBuckets(["alice", "bob"], 2);
expect(buckets.calcKeysAndLimitForNextReq()).toEqual({
keys: expect.arrayContaining(["alice", "bob"]),
limit: 4,
});
buckets.add("alice", e);
expect(buckets.calcKeysAndLimitForNextReq()).toEqual({
keys: expect.arrayContaining(["alice", "bob"]),
limit: 3,
});
buckets.add("bob", e);
expect(buckets.calcKeysAndLimitForNextReq()).toEqual({
keys: expect.arrayContaining(["alice", "bob"]),
limit: 2,
});
buckets.add("bob", e);
expect(buckets.calcKeysAndLimitForNextReq()).toEqual({
keys: ["alice"],
limit: 1,
});
buckets.add("alice", e);
expect(buckets.calcKeysAndLimitForNextReq()).toEqual({
keys: [],
limit: 0,
});
});
});
describe("KeyRelayMatrix", () => {
test("has expected entries", () => {
const matrix = new KeyRelayMatrix(
new Map([
["relay1", [1, 2, 3]],
["relay2", [2, 3]],
["relay3", [3]],
]),
() => 0,
);
expect(matrix.get(1, "relay1")).toBeDefined();
expect(matrix.get(2, "relay1")).toBeDefined();
expect(matrix.get(3, "relay1")).toBeDefined();
expect(matrix.get(2, "relay2")).toBeDefined();
expect(matrix.get(3, "relay2")).toBeDefined();
expect(matrix.get(3, "relay3")).toBeDefined();
expect(matrix.get(1, "relay2")).toBeUndefined();
expect(matrix.get(1, "relay3")).toBeUndefined();
expect(matrix.get(2, "relay3")).toBeUndefined();
expect(matrix.itemsByKey(1)?.length ?? -1).toBe(1);
expect(matrix.itemsByKey(2)?.length ?? -1).toBe(2);
expect(matrix.itemsByKey(3)?.length ?? -1).toBe(3);
});
});
describe("SeenEvents", () => {
test("SeenOnTable (withSeenOn = true) works", () => {
const seenEvents = initSeenEvents(true);
const res1 = seenEvents.report(dummyEventWithId("1"), "relay1");
expect(res1.hasSeen).toBe(false);
expect(res1.seenOn).toEqual(["relay1"]);
const res2 = seenEvents.report(dummyEventWithId("2"), "relay2");
expect(res2.hasSeen).toBe(false);
expect(res2.seenOn).toEqual(["relay2"]);
const res3 = seenEvents.report(dummyEventWithId("1"), "relay2");
expect(res3.hasSeen).toBe(true);
expect(res3.seenOn).toEqual(["relay1", "relay2"]);
expect(seenEvents.getSeenOn("1")).toEqual(["relay1", "relay2"]);
expect(seenEvents.getSeenOn("2")).toEqual(["relay2"]);
expect(seenEvents.getSeenOn("3")).toEqual([]);
});
test("SeenEventsSet (withSeenOn = false) works", () => {
const seenEvents = initSeenEvents(false);
const res1 = seenEvents.report(dummyEventWithId("1"), "relay1");
expect(res1.hasSeen).toBe(false);
expect(res1.seenOn).toBeUndefined();
const res2 = seenEvents.report(dummyEventWithId("2"), "relay2");
expect(res2.hasSeen).toBe(false);
const res3 = seenEvents.report(dummyEventWithId("1"), "relay2");
expect(res3.hasSeen).toBe(true);
});
});