Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/nip-11-integration-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nostream": patch
---

Add NIP-11 integration tests and fix max_filters mapping in relay information document.
2 changes: 1 addition & 1 deletion src/handlers/request-handlers/root-request-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const rootRequestHandler = (request: Request, response: Response, next: N
limitation: {
max_message_length: settings.network.maxPayloadSize,
max_subscriptions: settings.limits?.client?.subscription?.maxSubscriptions,
max_filters: settings.limits?.client?.subscription?.maxFilterValues,
max_filters: settings.limits?.client?.subscription?.maxFilters,
max_limit: settings.limits?.client?.subscription?.maxLimit,
max_subid_length: settings.limits?.client?.subscription?.maxSubscriptionIdLength,
min_prefix: settings.limits?.client?.subscription?.minPrefixLength,
Expand Down
25 changes: 25 additions & 0 deletions test/integration/features/nip-11/nip-11.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Feature: NIP-11
Scenario: Relay returns information document for NIP-11 request
When a client requests the relay information document
Then the response status is 200
And the response Content-Type includes "application/nostr+json"
And the relay information document contains the required fields

Scenario: Relay information document lists supported NIPs from package.json
When a client requests the relay information document
Then the supported_nips field matches the NIPs declared in package.json

Scenario: Relay does not return information document for a non-NIP-11 Accept header
When a client requests the root path with Accept header "text/html"
Then the response Content-Type does not include "application/nostr+json"
And the response body is not a relay information document

Scenario: Relay information document reports max_filters from settings
When a client requests the relay information document
Then the limitation object contains a max_filters field

Scenario: WebSocket connections coexist with HTTP on the same port
Given someone called Alice
When Alice sends a text_note event with content "nostr is great"
And Alice subscribes to author Alice
Then Alice receives a text_note event from Alice with content "nostr is great"
72 changes: 72 additions & 0 deletions test/integration/features/nip-11/nip-11.feature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Then, When, World } from '@cucumber/cucumber'
import axios, { AxiosResponse } from 'axios'
import chai from 'chai'

import packageJson from '../../../../package.json'
import { createSettings } from '../../../../src/factories/settings-factory'

chai.use(require('sinon-chai'))
const { expect } = chai

const BASE_URL = 'http://localhost:18808'

When('a client requests the relay information document', async function(this: World<Record<string, any>>) {
const response: AxiosResponse = await axios.get(BASE_URL, {
headers: { Accept: 'application/nostr+json' },
validateStatus: () => true,
})
this.parameters.httpResponse = response
})

When('a client requests the root path with Accept header {string}', async function(
this: World<Record<string, any>>,
acceptHeader: string,
) {
const response: AxiosResponse = await axios.get(BASE_URL, {
headers: { Accept: acceptHeader },
validateStatus: () => true,
})
this.parameters.httpResponse = response
})

Then('the response status is {int}', function(this: World<Record<string, any>>, status: number) {
expect(this.parameters.httpResponse.status).to.equal(status)
})

Then('the response Content-Type includes {string}', function(
this: World<Record<string, any>>,
contentType: string,
) {
expect(this.parameters.httpResponse.headers['content-type']).to.include(contentType)
})

Then('the response Content-Type does not include {string}', function(
this: World<Record<string, any>>,
contentType: string,
) {
expect(this.parameters.httpResponse.headers['content-type']).to.not.include(contentType)
})

Then('the relay information document contains the required fields', function(this: World<Record<string, any>>) {
const doc = this.parameters.httpResponse.data
for (const field of ['name', 'description', 'pubkey', 'supported_nips', 'software', 'version']) {
expect(doc, `expected relay info doc to have field "${field}"`).to.have.property(field)
}
})

Then('the supported_nips field matches the NIPs declared in package.json', function(this: World<Record<string, any>>) {
const doc = this.parameters.httpResponse.data
expect(doc.supported_nips).to.deep.equal(packageJson.supportedNips)
})

Then('the response body is not a relay information document', function(this: World<Record<string, any>>) {
const body = this.parameters.httpResponse.data
const isRelayInfoDoc = typeof body === 'object' && body !== null && 'supported_nips' in body
expect(isRelayInfoDoc).to.equal(false)
})

Then('the limitation object contains a max_filters field', function(this: World<Record<string, any>>) {
const doc = this.parameters.httpResponse.data
const expectedMaxFilters = createSettings().limits?.client?.subscription?.maxFilters
expect(doc.limitation.max_filters).to.equal(expectedMaxFilters)
})
Loading