Skip to content

Commit 0c4da6e

Browse files
committed
test(integration): verify response content-types across HTTP routes
Signed-off-by: ABHAY PANDEY <pandeyabhay967@gmail.com>
1 parent aee8940 commit 0c4da6e

3 files changed

Lines changed: 154 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"nostream": patch
3+
---
4+
5+
test(integration): verify response content-type across core HTTP paths
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@response-types
2+
Feature: HTTP response types
3+
Scenario Outline: GET path returns expected response Content-Type
4+
When a client requests path "<path>" with Accept header "<acceptHeader>"
5+
Then the HTTP response status is <statusCode>
6+
And the HTTP response Content-Type includes "<contentType>"
7+
8+
Examples:
9+
| path | acceptHeader | statusCode | contentType |
10+
| / | application/nostr+json | 200 | application/nostr+json |
11+
| / | text/html | 200 | text/html |
12+
| /healthz | */* | 200 | text/plain |
13+
| /terms | */* | 200 | text/html |
14+
| /.well-known/nodeinfo | */* | 200 | application/json |
15+
| /nodeinfo/2.1 | */* | 200 | application/json |
16+
| /nodeinfo/2.0 | */* | 200 | application/json |
17+
18+
Scenario Outline: dynamic GET path returns expected response Content-Type
19+
When a client requests dynamic path "<path>"
20+
Then the HTTP response status is <statusCode>
21+
And the HTTP response Content-Type includes "<contentType>"
22+
23+
Examples:
24+
| path | statusCode | contentType |
25+
| /admissions/check/0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef | 200 | application/json |
26+
| /invoices/non-existent-invoice/status | 404 | application/json |
27+
28+
Scenario Outline: POST path returns expected response Content-Type
29+
Given payments are enabled with processor "<processor>"
30+
When a client posts "<body>" to path "<path>" with Content-Type "<contentTypeHeader>"
31+
Then the HTTP response status is <statusCode>
32+
And the HTTP response Content-Type includes "<contentType>"
33+
34+
Examples:
35+
| path | processor | contentTypeHeader | body | statusCode | contentType |
36+
| /invoices | lnurl | application/x-www-form-urlencoded | | 400 | text/plain |
37+
| /callbacks/lnbits | lnbits | application/json | {} | 403 | text/html |
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { After, Given, Then, When, World } from '@cucumber/cucumber'
2+
import { expect } from 'chai'
3+
import axios, { AxiosResponse } from 'axios'
4+
import { assocPath, pipe } from 'ramda'
5+
import { SettingsStatic } from '../../../../src/utils/settings'
6+
7+
const BASE_URL = 'http://localhost:18808'
8+
9+
Given(
10+
'payments are enabled with processor {string}',
11+
function (this: World<Record<string, any>>, processor: string) {
12+
const settings = SettingsStatic._settings as any
13+
if (!this.parameters.previousResponseTypesSettings) {
14+
this.parameters.previousResponseTypesSettings = structuredClone(settings)
15+
}
16+
17+
const baseSettings = pipe(
18+
assocPath(['payments', 'enabled'], true),
19+
assocPath(['payments', 'processor'], processor),
20+
)(settings) as any
21+
22+
if (processor === 'zebedee') {
23+
SettingsStatic._settings = assocPath(['paymentsProcessors', 'zebedee', 'ipWhitelist'], [], baseSettings) as any
24+
return
25+
}
26+
27+
if (processor === 'lnbits') {
28+
this.parameters.lnbitsApiKeyModified = true
29+
if (typeof this.parameters.previousLnbitsApiKey === 'undefined') {
30+
this.parameters.previousLnbitsApiKey = process.env.LNBITS_API_KEY
31+
}
32+
process.env.LNBITS_API_KEY = 'integration-lnbits-api-key'
33+
34+
SettingsStatic._settings = assocPath(
35+
['paymentsProcessors', 'lnbits', 'callbackBaseURL'],
36+
'http://localhost:18808/callbacks/lnbits',
37+
baseSettings,
38+
) as any
39+
return
40+
}
41+
42+
SettingsStatic._settings = baseSettings
43+
},
44+
)
45+
46+
When(
47+
'a client requests path {string} with Accept header {string}',
48+
async function (this: World<Record<string, any>>, requestPath: string, acceptHeader: string) {
49+
const response: AxiosResponse = await axios.get(`${BASE_URL}${requestPath}`, {
50+
headers: { Accept: acceptHeader },
51+
validateStatus: () => true,
52+
})
53+
54+
this.parameters.httpResponse = response
55+
},
56+
)
57+
58+
When('a client requests dynamic path {string}', async function (this: World<Record<string, any>>, requestPath: string) {
59+
const response: AxiosResponse = await axios.get(`${BASE_URL}${requestPath}`, {
60+
validateStatus: () => true,
61+
})
62+
63+
this.parameters.httpResponse = response
64+
})
65+
66+
When(
67+
'a client posts {string} to path {string} with Content-Type {string}',
68+
async function (
69+
this: World<Record<string, any>>,
70+
body: string,
71+
requestPath: string,
72+
contentTypeHeader: string,
73+
) {
74+
const response: AxiosResponse = await axios.post(`${BASE_URL}${requestPath}`, body, {
75+
headers: { 'content-type': contentTypeHeader },
76+
validateStatus: () => true,
77+
})
78+
79+
this.parameters.httpResponse = response
80+
},
81+
)
82+
83+
Then('the HTTP response status is {int}', function (this: World<Record<string, any>>, statusCode: number) {
84+
expect(this.parameters.httpResponse.status).to.equal(statusCode)
85+
})
86+
87+
Then(
88+
'the HTTP response Content-Type includes {string}',
89+
function (this: World<Record<string, any>>, contentType: string) {
90+
const contentTypeHeader = this.parameters.httpResponse.headers['content-type']
91+
const headerValue = Array.isArray(contentTypeHeader) ? contentTypeHeader.join(';') : contentTypeHeader
92+
const normalizedHeader = typeof headerValue === 'string' ? headerValue.toLowerCase() : ''
93+
expect(normalizedHeader).to.include(contentType.toLowerCase())
94+
},
95+
)
96+
97+
After({ tags: '@response-types' }, function (this: World<Record<string, any>>) {
98+
if (this.parameters.previousResponseTypesSettings) {
99+
SettingsStatic._settings = this.parameters.previousResponseTypesSettings
100+
this.parameters.previousResponseTypesSettings = undefined
101+
}
102+
103+
if (this.parameters.lnbitsApiKeyModified) {
104+
if (typeof this.parameters.previousLnbitsApiKey === 'undefined') {
105+
delete process.env.LNBITS_API_KEY
106+
} else {
107+
process.env.LNBITS_API_KEY = this.parameters.previousLnbitsApiKey
108+
}
109+
this.parameters.previousLnbitsApiKey = undefined
110+
this.parameters.lnbitsApiKeyModified = false
111+
}
112+
})

0 commit comments

Comments
 (0)