mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-28 16:32:28 +00:00
255 lines
7.0 KiB
JavaScript
255 lines
7.0 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
const originalCanonical = globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__;
|
|
const originalNostrTools = globalThis.NostrTools;
|
|
const originalNostrToolsReady = globalThis.nostrToolsReady;
|
|
|
|
class BootstrapSimplePool {
|
|
sub() {}
|
|
close() {}
|
|
}
|
|
|
|
const bootstrapToolkit = {
|
|
ok: true,
|
|
nip19: {
|
|
decode: (value) => value,
|
|
npubEncode: (value) => value,
|
|
},
|
|
SimplePool: BootstrapSimplePool,
|
|
};
|
|
|
|
globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__ = bootstrapToolkit;
|
|
globalThis.NostrTools = bootstrapToolkit;
|
|
globalThis.nostrToolsReady = Promise.resolve(bootstrapToolkit);
|
|
|
|
const toolkitModule = await import("../../js/nostr/toolkit.js");
|
|
const {
|
|
rememberNostrTools,
|
|
getCachedNostrTools,
|
|
ensureNostrTools,
|
|
resolveSimplePoolConstructor,
|
|
shimLegacySimplePoolMethods,
|
|
} = toolkitModule;
|
|
|
|
const baselineToolkit = getCachedNostrTools() || bootstrapToolkit;
|
|
|
|
test.after(() => {
|
|
if (originalCanonical === undefined) {
|
|
delete globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__;
|
|
} else {
|
|
globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__ = originalCanonical;
|
|
}
|
|
|
|
if (originalNostrTools === undefined) {
|
|
delete globalThis.NostrTools;
|
|
} else {
|
|
globalThis.NostrTools = originalNostrTools;
|
|
}
|
|
|
|
if (originalNostrToolsReady === undefined) {
|
|
delete globalThis.nostrToolsReady;
|
|
} else {
|
|
globalThis.nostrToolsReady = originalNostrToolsReady;
|
|
}
|
|
|
|
rememberNostrTools(baselineToolkit);
|
|
});
|
|
|
|
test("ensureNostrTools resolves the cached toolkit", async () => {
|
|
class CachedSimplePool {
|
|
sub() {}
|
|
close() {}
|
|
}
|
|
|
|
const cachedToolkit = {
|
|
ok: true,
|
|
nip19: {
|
|
decode: (value) => value,
|
|
npubEncode: (value) => value,
|
|
},
|
|
SimplePool: CachedSimplePool,
|
|
};
|
|
|
|
const previousCanonicalForTest = globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__;
|
|
const previousNostrToolsForTest = globalThis.NostrTools;
|
|
|
|
globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__ = cachedToolkit;
|
|
globalThis.NostrTools = cachedToolkit;
|
|
rememberNostrTools(cachedToolkit);
|
|
|
|
try {
|
|
const ensured = await ensureNostrTools();
|
|
assert.strictEqual(ensured, cachedToolkit);
|
|
} finally {
|
|
if (previousCanonicalForTest === undefined) {
|
|
delete globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__;
|
|
} else {
|
|
globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__ = previousCanonicalForTest;
|
|
}
|
|
|
|
if (previousNostrToolsForTest === undefined) {
|
|
delete globalThis.NostrTools;
|
|
} else {
|
|
globalThis.NostrTools = previousNostrToolsForTest;
|
|
}
|
|
|
|
rememberNostrTools(baselineToolkit);
|
|
}
|
|
});
|
|
|
|
test("resolveSimplePoolConstructor handles supported permutations", () => {
|
|
class MockSimplePool {
|
|
sub() {}
|
|
close() {}
|
|
}
|
|
|
|
const variations = [
|
|
{ label: "tools.SimplePool", tools: { SimplePool: MockSimplePool } },
|
|
{ label: "tools.pool.SimplePool", tools: { pool: { SimplePool: MockSimplePool } } },
|
|
{ label: "tools.pool constructor", tools: { pool: MockSimplePool } },
|
|
{
|
|
label: "tools.SimplePool.SimplePool",
|
|
tools: { SimplePool: { SimplePool: MockSimplePool } },
|
|
},
|
|
{
|
|
label: "tools.SimplePool.default",
|
|
tools: { SimplePool: { default: MockSimplePool } },
|
|
},
|
|
{ label: "tools.pool.default", tools: { pool: { default: MockSimplePool } } },
|
|
{
|
|
label: "tools.default.SimplePool",
|
|
tools: { default: { SimplePool: MockSimplePool } },
|
|
},
|
|
{
|
|
label: "tools.default.pool.SimplePool",
|
|
tools: { default: { pool: { SimplePool: MockSimplePool } } },
|
|
},
|
|
{
|
|
label: "tools.default.pool constructor",
|
|
tools: { default: { pool: MockSimplePool } },
|
|
},
|
|
];
|
|
|
|
for (const { label, tools } of variations) {
|
|
assert.strictEqual(
|
|
resolveSimplePoolConstructor(tools),
|
|
MockSimplePool,
|
|
`expected ${label}`
|
|
);
|
|
}
|
|
|
|
assert.strictEqual(
|
|
resolveSimplePoolConstructor({}, { SimplePool: MockSimplePool }),
|
|
MockSimplePool,
|
|
"scope.SimplePool fallback"
|
|
);
|
|
|
|
assert.strictEqual(
|
|
resolveSimplePoolConstructor({}, { pool: { SimplePool: MockSimplePool } }),
|
|
MockSimplePool,
|
|
"scope.pool.SimplePool fallback"
|
|
);
|
|
|
|
assert.strictEqual(
|
|
resolveSimplePoolConstructor(
|
|
{},
|
|
{ NostrTools: { pool: { SimplePool: MockSimplePool } } }
|
|
),
|
|
MockSimplePool,
|
|
"scope.NostrTools.pool.SimplePool fallback"
|
|
);
|
|
|
|
assert.strictEqual(
|
|
resolveSimplePoolConstructor({}, {}),
|
|
null,
|
|
"returns null when no candidates are available"
|
|
);
|
|
});
|
|
|
|
test("shimLegacySimplePoolMethods adds legacy sub/list wrappers", async () => {
|
|
let capturedRequests = null;
|
|
let capturedParams = null;
|
|
const closeReasons = [];
|
|
|
|
const mockPool = {
|
|
subscribeMap(requests, params) {
|
|
capturedRequests = requests;
|
|
capturedParams = params;
|
|
return {
|
|
close(reason) {
|
|
closeReasons.push(reason);
|
|
},
|
|
};
|
|
},
|
|
};
|
|
|
|
shimLegacySimplePoolMethods(mockPool);
|
|
|
|
assert.strictEqual(typeof mockPool.sub, "function");
|
|
assert.strictEqual(typeof mockPool.list, "function");
|
|
|
|
const relays = ["wss://relay.one", "wss://relay.two"];
|
|
const filters = [{ kinds: [1] }, { authors: ["abc"] }];
|
|
|
|
const sub = mockPool.sub(relays, filters, {
|
|
alreadyHaveEvent(id) {
|
|
return id === "skip";
|
|
},
|
|
});
|
|
|
|
assert.ok(Array.isArray(capturedRequests));
|
|
assert.strictEqual(capturedRequests.length, relays.length * filters.length);
|
|
assert.ok(capturedRequests.every((entry) => entry && entry.url && entry.filter));
|
|
assert.ok(capturedParams);
|
|
assert.strictEqual(typeof capturedParams.onevent, "function");
|
|
assert.strictEqual(typeof capturedParams.oneose, "function");
|
|
assert.strictEqual(typeof capturedParams.onclose, "function");
|
|
assert.strictEqual(typeof capturedParams.alreadyHaveEvent, "function");
|
|
|
|
const receivedEvents = [];
|
|
const eosePromise = new Promise((resolve) => sub.on("eose", resolve));
|
|
const closePromise = new Promise((resolve) => sub.on("close", resolve));
|
|
sub.on("event", (event) => {
|
|
receivedEvents.push(event.id);
|
|
});
|
|
|
|
assert.strictEqual(capturedParams.alreadyHaveEvent("skip"), true);
|
|
assert.strictEqual(capturedParams.alreadyHaveEvent("id-1"), false);
|
|
assert.strictEqual(capturedParams.alreadyHaveEvent("id-1"), true);
|
|
|
|
capturedParams.onevent({ id: "id-1" });
|
|
capturedParams.onevent({ id: "id-2" });
|
|
capturedParams.oneose();
|
|
capturedParams.onclose(["done"]);
|
|
|
|
await eosePromise;
|
|
const closePayload = await closePromise;
|
|
|
|
assert.deepStrictEqual(receivedEvents, ["id-1", "id-2"]);
|
|
assert.deepStrictEqual(closePayload, ["done"]);
|
|
|
|
sub.unsub();
|
|
|
|
closeReasons.length = 0;
|
|
const immediateUnsub = mockPool.sub(["wss://relay.extra"], [{ kinds: [2] }]);
|
|
immediateUnsub.unsub();
|
|
assert.ok(closeReasons.includes("closed by caller"));
|
|
|
|
capturedParams = null;
|
|
capturedRequests = null;
|
|
closeReasons.length = 0;
|
|
|
|
const listPromise = mockPool.list(["wss://relay.example"], [{ kinds: [1] }]);
|
|
assert.ok(capturedParams);
|
|
capturedParams.onevent({ id: "evt-1" });
|
|
capturedParams.onevent({ id: "evt-2" });
|
|
capturedParams.oneose();
|
|
|
|
const listed = await listPromise;
|
|
assert.deepStrictEqual(
|
|
listed.map((event) => event.id),
|
|
["evt-1", "evt-2"]
|
|
);
|
|
});
|