From f2e61fde35688969dd9b02b29ba7efef33d344be Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Fri, 14 Nov 2025 05:03:15 -0800 Subject: [PATCH] Removing integration tests from old repository --- src/controllers/timer-controller.js | 2 +- test/integration/api/event-integration.js | 250 ------------------ test/integration/api/req-integration.js | 173 ------------ .../api/subscription-integration.js | 198 -------------- .../manage-subscription-integration.js | 163 ------------ .../use-cases/publish-event-integration.js | 104 -------- .../use-cases/query-events-integration.js | 95 ------- 7 files changed, 1 insertion(+), 984 deletions(-) delete mode 100644 test/integration/api/event-integration.js delete mode 100644 test/integration/api/req-integration.js delete mode 100644 test/integration/api/subscription-integration.js delete mode 100644 test/integration/use-cases/manage-subscription-integration.js delete mode 100644 test/integration/use-cases/publish-event-integration.js delete mode 100644 test/integration/use-cases/query-events-integration.js diff --git a/src/controllers/timer-controller.js b/src/controllers/timer-controller.js index 1c524eb..fa13c79 100644 --- a/src/controllers/timer-controller.js +++ b/src/controllers/timer-controller.js @@ -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 diff --git a/test/integration/api/event-integration.js b/test/integration/api/event-integration.js deleted file mode 100644 index 5d35a73..0000000 --- a/test/integration/api/event-integration.js +++ /dev/null @@ -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') - }) - }) -}) diff --git a/test/integration/api/req-integration.js b/test/integration/api/req-integration.js deleted file mode 100644 index 5b53bbc..0000000 --- a/test/integration/api/req-integration.js +++ /dev/null @@ -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') - }) - }) -}) diff --git a/test/integration/api/subscription-integration.js b/test/integration/api/subscription-integration.js deleted file mode 100644 index 3c1e743..0000000 --- a/test/integration/api/subscription-integration.js +++ /dev/null @@ -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 - } - } - }) - }) -}) diff --git a/test/integration/use-cases/manage-subscription-integration.js b/test/integration/use-cases/manage-subscription-integration.js deleted file mode 100644 index b2a883e..0000000 --- a/test/integration/use-cases/manage-subscription-integration.js +++ /dev/null @@ -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) - } - }) - }) -}) diff --git a/test/integration/use-cases/publish-event-integration.js b/test/integration/use-cases/publish-event-integration.js deleted file mode 100644 index 228ad68..0000000 --- a/test/integration/use-cases/publish-event-integration.js +++ /dev/null @@ -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 - }) - }) -}) diff --git a/test/integration/use-cases/query-events-integration.js b/test/integration/use-cases/query-events-integration.js deleted file mode 100644 index 07702ca..0000000 --- a/test/integration/use-cases/query-events-integration.js +++ /dev/null @@ -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) - }) - }) -})