Skip to content

Commit 46e7ace

Browse files
committed
test(http-client): add JSON parsing error branch tests
Add comprehensive tests for JSON parsing error detection in getResponseJson. Tests cover Content-Type validation, HTML detection, empty responses, and server error messages (502/503). Coverage improvements: - http-client.ts statements: 76.39% → 78.26% (+1.87%) - http-client.ts branches: 67.34% → 70.4% (+3.06%) - http-client.ts lines: 77.56% → 79.48% (+1.92%) - Overall statements: 75.18% → 75.49% (+0.31%) - Overall branches: 60.69% → 61.39% (+0.7%) - Total tests: 466 → 471 (+5 tests)
1 parent e6ed9d9 commit 46e7ace

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/** @fileoverview Tests for HTTP client JSON parsing error branches. */
2+
3+
import { describe, expect, it } from 'vitest'
4+
5+
import { getResponseJson } from '../../src/http-client'
6+
import {
7+
createRouteHandler,
8+
setupLocalHttpServer,
9+
} from '../utils/local-server-helpers.mts'
10+
11+
import type { IncomingMessage } from 'node:http'
12+
13+
describe('HTTP Client - JSON Parsing Error Branches', () => {
14+
describe('getResponseJson Content-Type validation', () => {
15+
const getBaseUrl = setupLocalHttpServer(
16+
createRouteHandler({
17+
'/wrong-content-type': (_req: IncomingMessage, res) => {
18+
res.writeHead(200, { 'Content-Type': 'text/html' })
19+
res.end('<!DOCTYPE html><html></html>')
20+
},
21+
'/html-response': (_req: IncomingMessage, res) => {
22+
res.writeHead(200, { 'Content-Type': 'application/json' })
23+
res.end('<html><body>Error Page</body></html>')
24+
},
25+
'/empty-json-response': (_req: IncomingMessage, res) => {
26+
res.writeHead(200, { 'Content-Type': 'application/json' })
27+
res.end('')
28+
},
29+
'/502-gateway-error': (_req: IncomingMessage, res) => {
30+
res.writeHead(200, { 'Content-Type': 'application/json' })
31+
res.end('502 Bad Gateway - Upstream server error')
32+
},
33+
'/503-service-unavailable': (_req: IncomingMessage, res) => {
34+
res.writeHead(200, { 'Content-Type': 'application/json' })
35+
res.end('503 Service Unavailable - Please try again later')
36+
},
37+
}),
38+
)
39+
40+
it('should detect wrong Content-Type header', async () => {
41+
const http = await import('node:http')
42+
const req = http.request(`${getBaseUrl()}/wrong-content-type`, {
43+
method: 'GET',
44+
})
45+
46+
const responsePromise = new Promise<IncomingMessage>(
47+
(resolve, reject) => {
48+
req.on('response', resolve)
49+
req.on('error', reject)
50+
},
51+
)
52+
53+
req.end()
54+
55+
const response = await responsePromise
56+
response.setEncoding('utf8')
57+
58+
await expect(getResponseJson(response)).rejects.toThrow(
59+
'Unexpected Content-Type: text/html',
60+
)
61+
})
62+
63+
it('should detect HTML response', async () => {
64+
const http = await import('node:http')
65+
const req = http.request(`${getBaseUrl()}/html-response`, {
66+
method: 'GET',
67+
})
68+
69+
const responsePromise = new Promise<IncomingMessage>(
70+
(resolve, reject) => {
71+
req.on('response', resolve)
72+
req.on('error', reject)
73+
},
74+
)
75+
76+
req.end()
77+
78+
const response = await responsePromise
79+
response.setEncoding('utf8')
80+
81+
await expect(getResponseJson(response)).rejects.toThrow(
82+
'Response appears to be HTML',
83+
)
84+
})
85+
86+
it('should detect empty response body', async () => {
87+
const http = await import('node:http')
88+
const req = http.request(`${getBaseUrl()}/empty-json-response`, {
89+
method: 'GET',
90+
})
91+
92+
const responsePromise = new Promise<IncomingMessage>(
93+
(resolve, reject) => {
94+
req.on('response', resolve)
95+
req.on('error', reject)
96+
},
97+
)
98+
99+
req.end()
100+
101+
const response = await responsePromise
102+
response.setEncoding('utf8')
103+
104+
// Empty response should parse as {} successfully
105+
const result = await getResponseJson(response)
106+
expect(result).toEqual({})
107+
})
108+
109+
it('should detect 502 Bad Gateway in response', async () => {
110+
const http = await import('node:http')
111+
const req = http.request(`${getBaseUrl()}/502-gateway-error`, {
112+
method: 'GET',
113+
})
114+
115+
const responsePromise = new Promise<IncomingMessage>(
116+
(resolve, reject) => {
117+
req.on('response', resolve)
118+
req.on('error', reject)
119+
},
120+
)
121+
122+
req.end()
123+
124+
const response = await responsePromise
125+
response.setEncoding('utf8')
126+
127+
await expect(getResponseJson(response)).rejects.toThrow(
128+
'Response indicates a server error',
129+
)
130+
})
131+
132+
it('should detect 503 Service in response', async () => {
133+
const http = await import('node:http')
134+
const req = http.request(`${getBaseUrl()}/503-service-unavailable`, {
135+
method: 'GET',
136+
})
137+
138+
const responsePromise = new Promise<IncomingMessage>(
139+
(resolve, reject) => {
140+
req.on('response', resolve)
141+
req.on('error', reject)
142+
},
143+
)
144+
145+
req.end()
146+
147+
const response = await responsePromise
148+
response.setEncoding('utf8')
149+
150+
await expect(getResponseJson(response)).rejects.toThrow(
151+
'Response indicates a server error',
152+
)
153+
})
154+
})
155+
})

0 commit comments

Comments
 (0)