Removing integration tests from old repository

This commit is contained in:
Chris Troutner
2025-11-14 05:03:15 -08:00
parent 5ab5547bf3
commit f2e61fde35
7 changed files with 1 additions and 984 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ class TimerController {
}
// Constants
this.SHUTDOWN_INTERVAL_MS = 10 * 60 * 1000 // 10 minutes in milliseconds
this.SHUTDOWN_INTERVAL_MS = 10 * 60 * 60 * 1000 // 10 hours in milliseconds
this.LIVENESS_CHECK_INTERVAL_MS = 1 * 60 * 1000 // 1 minute in milliseconds
// Handlers
-250
View File
@@ -1,250 +0,0 @@
/*
Integration tests for POST /event endpoint.
These tests require a running Nostr relay.
*/
// npm libraries
import { assert } from 'chai'
// Unit under test
import Server from '../../../bin/server.js'
import { finalizeEvent, getPublicKey, generateSecretKey } from 'nostr-tools/pure'
import { hexToBytes } from '@noble/hashes/utils.js'
describe('#event-integration.js', () => {
let server
const baseUrl = 'http://localhost:3001' // Use different port for tests
before(async () => {
// Start test server
server = new Server()
server.config.port = 3001
await server.startServer()
// Wait for server to be ready
await new Promise(resolve => setTimeout(resolve, 1000))
})
after(async () => {
// Stop server
if (server && server.server) {
await new Promise((resolve) => {
server.server.close(() => {
resolve()
})
})
}
})
describe('POST /event', () => {
it('should publish kind 0 event (profile metadata) - covers example 01', async () => {
// Generate keys
const sk = generateSecretKey()
// Create profile metadata event (kind 0)
const profileMetadata = {
name: 'Test User',
about: 'Integration test user',
picture: 'https://example.com/test.jpg'
}
const eventTemplate = {
kind: 0,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: JSON.stringify(profileMetadata)
}
// Sign the event
const signedEvent = finalizeEvent(eventTemplate, sk)
// Publish to REST API
const response = await fetch(`${baseUrl}/event`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(signedEvent)
})
const result = await response.json()
// Assert response
assert.equal(response.status, 200)
assert.property(result, 'accepted')
assert.property(result, 'eventId')
assert.equal(result.eventId, signedEvent.id)
})
it('should publish kind 1 event (text post) - covers example 03', async () => {
// Alice's private key from examples
const alicePrivKeyHex = '3292a48aa331aeccce003d50d70fbd79617ba91860abbd2c78fa4a8301e36bc0'
const alicePrivKeyBin = hexToBytes(alicePrivKeyHex)
const alicePubKey = getPublicKey(alicePrivKeyBin)
// Generate a post
const eventTemplate = {
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'Integration test post'
}
// Sign the post
const signedEvent = finalizeEvent(eventTemplate, alicePrivKeyBin)
// Publish to REST API
const response = await fetch(`${baseUrl}/event`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(signedEvent)
})
const result = await response.json()
// Assert response
assert.equal(response.status, 200)
assert.property(result, 'accepted')
assert.property(result, 'eventId')
assert.equal(result.eventId, signedEvent.id)
assert.equal(signedEvent.pubkey, alicePubKey)
})
it('should publish kind 3 event (follow list) - covers example 06', async () => {
// Alice's private key
const alicePrivKeyHex = '3292a48aa331aeccce003d50d70fbd79617ba91860abbd2c78fa4a8301e36bc0'
const alicePrivKeyBin = hexToBytes(alicePrivKeyHex)
// Bob's public key
const bobPrivKeyHex = 'd2e71a977bc3900d6b0f787421e3d1a666cd12ca625482b0d9eeffd23489c99f'
const bobPrivKeyBin = hexToBytes(bobPrivKeyHex)
const bobPubKey = getPublicKey(bobPrivKeyBin)
const psf = 'wss://nostr-relay.psfoundation.info'
const followList = [
['p', bobPubKey, psf, 'bob']
]
// Generate a follow list event (kind 3)
const eventTemplate = {
kind: 3,
created_at: Math.floor(Date.now() / 1000),
tags: followList,
content: ''
}
// Sign the event
const signedEvent = finalizeEvent(eventTemplate, alicePrivKeyBin)
// Publish to REST API
const response = await fetch(`${baseUrl}/event`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(signedEvent)
})
const result = await response.json()
// Assert response
assert.equal(response.status, 200)
assert.property(result, 'accepted')
assert.property(result, 'eventId')
assert.equal(result.eventId, signedEvent.id)
})
it('should publish kind 7 event (reaction/like) - covers example 07', async () => {
// Bob's private key
const bobPrivKeyHex = 'd2e71a977bc3900d6b0f787421e3d1a666cd12ca625482b0d9eeffd23489c99f'
const bobPrivKeyBin = hexToBytes(bobPrivKeyHex)
const bobPubKey = getPublicKey(bobPrivKeyBin)
const psf = 'wss://nostr-relay.psfoundation.info'
// Use a test event ID
const evIdToLike = 'd09b4c5da59be3cd2768aa53fa78b77bf4859084c94f3bf26d401f004a9c8167'
const evIdAuthorPubKey = '2c7e76c0f8dc1dca9d0197c7d19be580a8d074ccada6a2f6ebe056ae41092e92'
// Generate like event (kind 7)
const likeEventTemplate = {
kind: 7,
created_at: Math.floor(Date.now() / 1000),
pubkey: bobPubKey,
tags: [
['e', evIdToLike, psf],
['p', evIdAuthorPubKey, psf]
],
content: '+'
}
// Sign the event
const signedEvent = finalizeEvent(likeEventTemplate, bobPrivKeyBin)
// Publish to REST API
const response = await fetch(`${baseUrl}/event`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(signedEvent)
})
const result = await response.json()
// Assert response
assert.equal(response.status, 200)
assert.property(result, 'accepted')
assert.property(result, 'eventId')
assert.equal(result.eventId, signedEvent.id)
})
it('should reject invalid event', async () => {
const invalidEvent = {
id: 'invalid',
pubkey: 'invalid',
created_at: Math.floor(Date.now() / 1000),
kind: 1,
tags: [],
content: 'Test',
sig: 'invalid'
}
const response = await fetch(`${baseUrl}/event`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(invalidEvent)
})
const result = await response.json()
// Should reject invalid event - error response format
assert.equal(response.status, 400)
assert.property(result, 'error')
assert.include(result.error, 'Invalid event structure')
})
it('should return 400 when event data is missing', async () => {
// Send empty body - Express will parse as undefined, controller should handle it
const response = await fetch(`${baseUrl}/event`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: ''
})
// Empty body should be parsed as undefined by Express
const result = await response.json()
assert.equal(response.status, 400)
assert.property(result, 'error')
assert.include(result.error, 'Event data is required')
})
})
})
-173
View File
@@ -1,173 +0,0 @@
/*
Integration tests for GET /req/:subId endpoint.
These tests require a running Nostr relay.
*/
// npm libraries
import { assert } from 'chai'
// Unit under test
import Server from '../../../bin/server.js'
import { getPublicKey } from 'nostr-tools/pure'
import { hexToBytes } from '@noble/hashes/utils.js'
describe('#req-integration.js', () => {
let server
const baseUrl = 'http://localhost:3002' // Use different port for tests
before(async () => {
// Start test server
server = new Server()
server.config.port = 3002
await server.startServer()
// Wait for server to be ready
await new Promise(resolve => setTimeout(resolve, 1000))
})
after(async () => {
// Stop server
if (server && server.server) {
await new Promise((resolve) => {
server.server.close(() => {
resolve()
})
})
}
})
describe('GET /req/:subId', () => {
it('should query kind 1 events (posts) - covers examples 02, 04', async () => {
// JB55's public key from example 02
const jb55 = '32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'
// Create subscription ID
const subId = 'read-posts-' + Date.now()
// Create filters - read posts from JB55
const filters = {
limit: 2,
kinds: [1],
authors: [jb55]
}
// Query events using GET /req/:subId
const filtersJson = encodeURIComponent(JSON.stringify([filters]))
const url = `${baseUrl}/req/${subId}?filters=${filtersJson}`
const response = await fetch(url)
const events = await response.json()
// Assert response
assert.equal(response.status, 200)
assert.isArray(events)
// May be empty if no events exist, but structure should be correct
if (events.length > 0) {
assert.property(events[0], 'id')
assert.property(events[0], 'pubkey')
assert.property(events[0], 'created_at')
assert.property(events[0], 'kind')
assert.property(events[0], 'content')
assert.equal(events[0].kind, 1)
}
})
it('should query Alice posts - covers example 04', async () => {
// Alice's public key
const alicePrivKeyHex = '3292a48aa331aeccce003d50d70fbd79617ba91860abbd2c78fa4a8301e36bc0'
const alicePrivKeyBin = hexToBytes(alicePrivKeyHex)
const alicePubKey = getPublicKey(alicePrivKeyBin)
// Create subscription ID
const subId = 'read-alice-posts-' + Date.now()
// Create filters - read posts from Alice
const filters = {
limit: 2,
kinds: [1],
authors: [alicePubKey]
}
// Query events using GET /req/:subId
const filtersJson = encodeURIComponent(JSON.stringify([filters]))
const url = `${baseUrl}/req/${subId}?filters=${filtersJson}`
const response = await fetch(url)
const events = await response.json()
// Assert response
assert.equal(response.status, 200)
assert.isArray(events)
if (events.length > 0) {
assert.equal(events[0].pubkey, alicePubKey)
assert.equal(events[0].kind, 1)
}
})
it('should query kind 3 events (follow list) - covers example 05', async () => {
// Alice's public key
const alicePrivKeyHex = '3292a48aa331aeccce003d50d70fbd79617ba91860abbd2c78fa4a8301e36bc0'
const alicePrivKeyBin = hexToBytes(alicePrivKeyHex)
const alicePubKey = getPublicKey(alicePrivKeyBin)
// Create subscription ID
const subId = 'get-follow-list-' + Date.now()
// Create filters - get follow list (kind 3) from Alice
const filters = {
limit: 5,
kinds: [3],
authors: [alicePubKey]
}
// Query events using GET /req/:subId
const filtersJson = encodeURIComponent(JSON.stringify([filters]))
const url = `${baseUrl}/req/${subId}?filters=${filtersJson}`
const response = await fetch(url)
const events = await response.json()
// Assert response
assert.equal(response.status, 200)
assert.isArray(events)
if (events.length > 0) {
assert.equal(events[0].kind, 3)
assert.equal(events[0].pubkey, alicePubKey)
assert.isArray(events[0].tags)
}
})
it('should handle filters as individual query params', async () => {
const subId = 'test-sub-' + Date.now()
const url = `${baseUrl}/req/${subId}?kinds=[1]&limit=10`
const response = await fetch(url)
const events = await response.json()
assert.equal(response.status, 200)
assert.isArray(events)
})
it('should return 400 when subscription ID is missing', async () => {
const url = `${baseUrl}/req/?filters=${encodeURIComponent(JSON.stringify([{ kinds: [1] }]))}`
const response = await fetch(url)
await response.json()
// Should return 404 or 400
assert.isAtLeast(response.status, 400)
})
it('should return 400 when filters JSON is invalid', async () => {
const subId = 'test-sub-' + Date.now()
const url = `${baseUrl}/req/${subId}?filters=invalid-json{`
const response = await fetch(url)
const result = await response.json()
assert.equal(response.status, 400)
assert.property(result, 'error')
assert.include(result.error, 'Invalid filters JSON')
})
})
})
@@ -1,198 +0,0 @@
/*
Integration tests for POST /req/:subId SSE subscription and DELETE /req/:subId.
These tests require a running Nostr relay.
*/
// npm libraries
import { assert } from 'chai'
// Unit under test
import Server from '../../../bin/server.js'
describe('#subscription-integration.js', () => {
let server
const baseUrl = 'http://localhost:3003' // Use different port for tests
before(async () => {
// Start test server
server = new Server()
server.config.port = 3003
await server.startServer()
// Wait for server to be ready
await new Promise(resolve => setTimeout(resolve, 1000))
})
after(async function () {
this.timeout(10000) // Increase timeout for cleanup
// Stop server
if (server && server.server) {
// Close all connections forcefully if available
if (server.server.closeAllConnections) {
server.server.closeAllConnections()
}
await new Promise((resolve) => {
const timeout = setTimeout(() => {
resolve() // Force resolve after 2 seconds
}, 2000)
server.server.close(() => {
clearTimeout(timeout)
resolve()
})
})
}
})
describe('POST /req/:subId', () => {
it('should create SSE subscription', async () => {
const subId = 'test-sub-' + Date.now()
const filters = { kinds: [1], limit: 10 }
const response = await fetch(`${baseUrl}/req/${subId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(filters)
})
// Assert SSE headers
assert.equal(response.headers.get('content-type'), 'text/event-stream')
assert.equal(response.headers.get('cache-control'), 'no-cache')
assert.equal(response.headers.get('connection'), 'keep-alive')
// Read initial connection message
const reader = response.body.getReader()
const decoder = new TextDecoder()
try {
const { value } = await reader.read()
const text = decoder.decode(value)
assert.include(text, 'connected')
assert.include(text, subId)
} finally {
reader.releaseLock()
}
})
it('should return 400 when subscription ID is missing', async () => {
const filters = { kinds: [1] }
const response = await fetch(`${baseUrl}/req/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(filters)
})
// Should return 404 or 400
assert.isAtLeast(response.status, 400)
})
it('should return 400 when filters are missing', async () => {
const subId = 'test-sub-' + Date.now()
const response = await fetch(`${baseUrl}/req/${subId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({})
})
const result = await response.json()
assert.equal(response.status, 400)
assert.property(result, 'error')
assert.include(result.error, 'Filters are required')
})
})
describe('DELETE /req/:subId', () => {
it('should close a subscription', async () => {
const subId = 'test-sub-' + Date.now()
const response = await fetch(`${baseUrl}/req/${subId}`, {
method: 'DELETE'
})
// May return 200 if subscription exists, or 500 if it doesn't
// The important thing is it doesn't crash
assert.isAtMost(response.status, 500)
})
it('should return 400 when subscription ID is missing', async () => {
const response = await fetch(`${baseUrl}/req/`, {
method: 'DELETE'
})
// Should return 404 or 400
assert.isAtLeast(response.status, 400)
})
})
describe('PUT /req/:subId', () => {
it('should create SSE subscription (alternative method)', async function () {
this.timeout(10000) // Increase timeout for this test
const subId = 'test-sub-' + Date.now()
const filters = { kinds: [1], limit: 10 }
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 8000)
let response
try {
response = await fetch(`${baseUrl}/req/${subId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(filters),
signal: controller.signal
})
// Assert SSE headers
assert.equal(response.headers.get('content-type'), 'text/event-stream')
clearTimeout(timeoutId)
// Consume the stream to prevent hanging
const reader = response.body.getReader()
const decoder = new TextDecoder()
try {
// Read initial connection message with timeout
const readPromise = reader.read()
const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve({ value: null, done: true }), 2000))
const { value, done } = await Promise.race([readPromise, timeoutPromise])
if (value && !done) {
const text = decoder.decode(value)
assert.include(text, 'connected')
}
} finally {
reader.releaseLock()
}
} catch (err) {
// AbortController aborted - this is expected
if (err.name !== 'AbortError') {
throw err
}
} finally {
clearTimeout(timeoutId)
// Always close the subscription
try {
await fetch(`${baseUrl}/req/${subId}`, {
method: 'DELETE'
})
} catch (err) {
// Ignore errors when closing
}
}
})
})
})
@@ -1,163 +0,0 @@
/*
Integration tests for ManageSubscriptionUseCase with real adapter.
These tests require a running Nostr relay.
*/
// npm libraries
import { assert } from 'chai'
// Unit under test
import Adapters from '../../../src/adapters/index.js'
import ManageSubscriptionUseCase from '../../../src/use-cases/manage-subscription.js'
describe('#manage-subscription-integration.js', () => {
let adapters
let uut
before(async () => {
// Initialize adapters (will connect to real relay)
adapters = new Adapters()
await adapters.start()
uut = new ManageSubscriptionUseCase({ adapters })
})
after(async () => {
// Clean up all subscriptions and disconnect from all relays
// Note: This is a simplified cleanup - in production you'd track all subscriptions
if (adapters && adapters.nostrRelays) {
await Promise.allSettled(
adapters.nostrRelays.map(relay => relay.disconnect())
)
}
})
describe('#createSubscription()', () => {
it('should successfully create a subscription', async () => {
const subscriptionId = 'test-sub-' + Date.now()
const filters = [{ kinds: [1], limit: 5 }]
let eventReceived = false
let eoseReceived = false
const onEvent = (event) => {
eventReceived = true
assert.property(event, 'id')
assert.property(event, 'kind')
}
const onEose = () => {
eoseReceived = true
}
const onClosed = () => {
// Handler for closed events
}
await uut.createSubscription(subscriptionId, filters, onEvent, onEose, onClosed)
// Assert subscription exists
assert.isTrue(uut.hasSubscription(subscriptionId))
// Wait a bit for events/EOSE
await new Promise(resolve => setTimeout(resolve, 2000))
// EOSE should be received (or events)
// Note: May not receive events if none exist, but EOSE should come
assert.isTrue(eoseReceived || eventReceived)
// Clean up
if (uut.hasSubscription(subscriptionId)) {
await uut.closeSubscription(subscriptionId)
}
})
it('should prevent duplicate subscriptions', async () => {
const subscriptionId = 'test-dup-' + Date.now()
const filters = [{ kinds: [1] }]
await uut.createSubscription(subscriptionId, filters)
try {
await uut.createSubscription(subscriptionId, filters)
assert.equal(true, false, 'unexpected result')
} catch (err) {
assert.include(err.message, 'already exists')
}
// Clean up
if (uut.hasSubscription(subscriptionId)) {
await uut.closeSubscription(subscriptionId)
}
})
it('should handle subscription with no events', async () => {
const subscriptionId = 'test-empty-' + Date.now()
const filters = [{ kinds: [99999], limit: 1 }] // Unlikely to have events
let eoseReceived = false
const onEose = () => {
eoseReceived = true
}
await uut.createSubscription(subscriptionId, filters, null, onEose, null)
// Wait for EOSE
await new Promise(resolve => setTimeout(resolve, 2000))
// Should receive EOSE even with no events
assert.isTrue(eoseReceived)
// Clean up
if (uut.hasSubscription(subscriptionId)) {
await uut.closeSubscription(subscriptionId)
}
})
})
describe('#closeSubscription()', () => {
it('should successfully close a subscription', async () => {
const subscriptionId = 'test-close-' + Date.now()
const filters = [{ kinds: [1] }]
await uut.createSubscription(subscriptionId, filters)
assert.isTrue(uut.hasSubscription(subscriptionId))
await uut.closeSubscription(subscriptionId)
// Assert subscription is removed
assert.isFalse(uut.hasSubscription(subscriptionId))
})
it('should return successfully when closing non-existent subscription (idempotent)', async () => {
const subscriptionId = 'non-existent-sub'
// Should not throw - idempotent operation
await uut.closeSubscription(subscriptionId)
// Should return successfully without error
assert.isTrue(true, 'closeSubscription should succeed for non-existent subscription')
})
})
describe('#hasSubscription()', () => {
it('should return false for non-existent subscription', () => {
assert.isFalse(uut.hasSubscription('non-existent'))
})
it('should return true for existing subscription', async () => {
const subscriptionId = 'test-has-' + Date.now()
const filters = [{ kinds: [1] }]
assert.isFalse(uut.hasSubscription(subscriptionId))
await uut.createSubscription(subscriptionId, filters)
assert.isTrue(uut.hasSubscription(subscriptionId))
// Clean up
if (uut.hasSubscription(subscriptionId)) {
await uut.closeSubscription(subscriptionId)
}
})
})
})
@@ -1,104 +0,0 @@
/*
Integration tests for PublishEventUseCase with real adapter.
These tests require a running Nostr relay.
*/
// npm libraries
import { assert } from 'chai'
// Unit under test
import Adapters from '../../../src/adapters/index.js'
import PublishEventUseCase from '../../../src/use-cases/publish-event.js'
import { finalizeEvent, generateSecretKey } from 'nostr-tools/pure'
describe('#publish-event-integration.js', () => {
let adapters
let uut
before(async () => {
// Initialize adapters (will connect to real relay)
adapters = new Adapters()
await adapters.start()
uut = new PublishEventUseCase({ adapters })
})
after(async () => {
// Clean up adapters - disconnect from all relays
if (adapters && adapters.nostrRelays) {
await Promise.allSettled(
adapters.nostrRelays.map(relay => relay.disconnect())
)
}
})
describe('#execute()', () => {
it('should successfully publish a valid event', async () => {
// Generate keys
const sk = generateSecretKey()
// Create event template
const eventTemplate = {
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'Integration test post from use case'
}
// Sign the event
const signedEvent = finalizeEvent(eventTemplate, sk)
// Execute use case
const result = await uut.execute(signedEvent)
// Assert result
assert.property(result, 'accepted')
assert.property(result, 'message')
assert.property(result, 'eventId')
assert.equal(result.eventId, signedEvent.id)
})
it('should reject invalid event structure', async () => {
const invalidEvent = {
id: 'invalid',
pubkey: 'invalid',
created_at: Math.floor(Date.now() / 1000),
kind: 1,
tags: [],
content: 'Test',
sig: 'invalid'
}
try {
await uut.execute(invalidEvent)
assert.equal(true, false, 'unexpected result')
} catch (err) {
assert.include(err.message, 'Invalid event structure')
}
})
it('should handle relay rejection', async () => {
// Generate keys
const sk = generateSecretKey()
// Create a duplicate event (if we send same event twice)
const eventTemplate = {
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'Duplicate test post'
}
const signedEvent = finalizeEvent(eventTemplate, sk)
// Publish first time
const result1 = await uut.execute(signedEvent)
assert.property(result1, 'accepted')
// Try to publish again (may be rejected as duplicate)
const result2 = await uut.execute(signedEvent)
assert.property(result2, 'accepted')
// Result may be accepted or rejected depending on relay
})
})
})
@@ -1,95 +0,0 @@
/*
Integration tests for QueryEventsUseCase with real adapter.
These tests require a running Nostr relay.
*/
// npm libraries
import { assert } from 'chai'
// Unit under test
import Adapters from '../../../src/adapters/index.js'
import QueryEventsUseCase from '../../../src/use-cases/query-events.js'
describe('#query-events-integration.js', () => {
let adapters
let uut
before(async () => {
// Initialize adapters (will connect to real relay)
adapters = new Adapters()
await adapters.start()
uut = new QueryEventsUseCase({ adapters })
})
after(async () => {
// Clean up adapters - disconnect from all relays
if (adapters && adapters.nostrRelays) {
await Promise.allSettled(
adapters.nostrRelays.map(relay => relay.disconnect())
)
}
})
describe('#execute()', () => {
it('should successfully query events', async () => {
const filters = [{ kinds: [1], limit: 5 }]
const subscriptionId = 'test-query-' + Date.now()
const events = await uut.execute(filters, subscriptionId)
// Assert result is an array
assert.isArray(events)
// If events are returned, verify structure
if (events.length > 0) {
assert.property(events[0], 'id')
assert.property(events[0], 'pubkey')
assert.property(events[0], 'created_at')
assert.property(events[0], 'kind')
assert.property(events[0], 'content')
assert.equal(events[0].kind, 1)
}
})
it('should handle empty results', async () => {
// Query for events that likely don't exist
const filters = [{ kinds: [99999], limit: 1 }]
const subscriptionId = 'test-empty-' + Date.now()
const events = await uut.execute(filters, subscriptionId)
// Should return empty array, not throw
assert.isArray(events)
assert.equal(events.length, 0)
})
it('should handle multiple filters', async function () {
// Increase timeout for this test - needs to be longer than use case timeout (30s)
this.timeout(35000)
const filters = [
{ kinds: [1], limit: 2 },
{ kinds: [3], limit: 2 }
]
const subscriptionId = 'test-multi-' + Date.now()
const events = await uut.execute(filters, subscriptionId)
// Should return array (may be empty)
assert.isArray(events)
})
it('should timeout if EOSE not received', async () => {
// This test may take up to 30 seconds
// Use a filter that might not return EOSE quickly
const filters = [{ kinds: [1] }] // No limit, might timeout
const subscriptionId = 'test-timeout-' + Date.now()
// Should eventually return (even if empty)
const events = await uut.execute(filters, subscriptionId)
assert.isArray(events)
})
})
})