@superhero/http-request 4.0.10 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -7
- package/index.js +101 -90
- package/index.test.js +51 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,11 +95,12 @@ console.log(response.body)
|
|
|
95
95
|
|
|
96
96
|
Errors are thrown with specific error codes for easier handling:
|
|
97
97
|
|
|
98
|
-
- `
|
|
99
|
-
- `
|
|
100
|
-
- `
|
|
101
|
-
- `
|
|
102
|
-
- `
|
|
98
|
+
- `E_HTTP_REQUEST_FAILED`
|
|
99
|
+
- `E_HTTP_REQUEST_CLIENT_ERROR`
|
|
100
|
+
- `E_HTTP_REQUEST_CLIENT_TIMEOUT`
|
|
101
|
+
- `E_HTTP_REQUEST_DOWNSTREAM_ERROR`
|
|
102
|
+
- `E_HTTP_REQUEST_INVALID_RESPONSE_BODY_FORMAT`
|
|
103
|
+
- `E_HTTP_REQUEST_INVALID_RESPONSE_STATUS`
|
|
103
104
|
|
|
104
105
|
Example:
|
|
105
106
|
|
|
@@ -334,10 +335,10 @@ pass 42
|
|
|
334
335
|
----------------------------------------------------------------------------------------
|
|
335
336
|
file | line % | branch % | funcs % | uncovered lines
|
|
336
337
|
----------------------------------------------------------------------------------------
|
|
337
|
-
index.js |
|
|
338
|
+
index.js | 89.56 | 87.39 | 86.67 | 100-104 137-139 150-153 353-357 361-365
|
|
338
339
|
index.test.js | 100.00 | 97.67 | 100.00 |
|
|
339
340
|
----------------------------------------------------------------------------------------
|
|
340
|
-
all files |
|
|
341
|
+
all files | 93.73 | 91.71 | 94.50 |
|
|
341
342
|
----------------------------------------------------------------------------------------
|
|
342
343
|
```
|
|
343
344
|
|
package/index.js
CHANGED
|
@@ -68,8 +68,8 @@ export default class Request
|
|
|
68
68
|
/**
|
|
69
69
|
* Connects to a HTTP/2 server.
|
|
70
70
|
*
|
|
71
|
-
* @param {String} authority the URL
|
|
72
|
-
* @param {Object} [options]
|
|
71
|
+
* @param {String|Object} [authority] the URL to connect to the server, or the options object
|
|
72
|
+
* @param {Object} [options] @see node:http2.connect options
|
|
73
73
|
*
|
|
74
74
|
* @throws {Error} E_HTTP_REQUEST_CONNECT_INVALID_ARGUMENT
|
|
75
75
|
*
|
|
@@ -77,31 +77,28 @@ export default class Request
|
|
|
77
77
|
*/
|
|
78
78
|
connect(authority, options)
|
|
79
79
|
{
|
|
80
|
-
return new Promise(async
|
|
80
|
+
return new Promise(async resolve =>
|
|
81
81
|
{
|
|
82
82
|
await this.close()
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
if('object' === typeof authority
|
|
85
|
+
&& null !== authority
|
|
86
|
+
&& false === !!options)
|
|
87
|
+
{
|
|
88
|
+
options = authority
|
|
89
|
+
authority = null
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
options = Object.assign(this.config, options)
|
|
93
|
+
const url = new URL(authority || options.authority || options.base || options.url)
|
|
87
94
|
|
|
88
|
-
this.config.
|
|
89
|
-
this.
|
|
90
|
-
this.http2Session = http2.connect(authority, options, () =>
|
|
95
|
+
this.config.authority = url.origin
|
|
96
|
+
this.http2Session = http2.connect(url.origin, options, () =>
|
|
91
97
|
{
|
|
92
98
|
this.http2Session.removeAllListeners('error')
|
|
93
99
|
this.http2Session.on('error', console.error)
|
|
94
100
|
|
|
95
|
-
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
// If there is a error on connection, reject the promise.
|
|
99
|
-
this.http2Session.once('error', (reason) =>
|
|
100
|
-
{
|
|
101
|
-
const error = new Error(`Failed to connect to server over HTTP2 using authority: ${authority}`)
|
|
102
|
-
error.code = 'E_HTTP_REQUEST_CONNECT_ERROR'
|
|
103
|
-
error.cause = reason
|
|
104
|
-
reject(error)
|
|
101
|
+
resolve()
|
|
105
102
|
})
|
|
106
103
|
})
|
|
107
104
|
}
|
|
@@ -113,7 +110,7 @@ export default class Request
|
|
|
113
110
|
*/
|
|
114
111
|
close()
|
|
115
112
|
{
|
|
116
|
-
return new Promise((
|
|
113
|
+
return new Promise((resolve, reject) =>
|
|
117
114
|
{
|
|
118
115
|
const http2Session = this.http2Session
|
|
119
116
|
|
|
@@ -129,7 +126,7 @@ export default class Request
|
|
|
129
126
|
|
|
130
127
|
error
|
|
131
128
|
? reject(error)
|
|
132
|
-
:
|
|
129
|
+
: resolve()
|
|
133
130
|
})
|
|
134
131
|
|
|
135
132
|
return // await the close event
|
|
@@ -138,8 +135,8 @@ export default class Request
|
|
|
138
135
|
delete this.http2Session
|
|
139
136
|
}
|
|
140
137
|
|
|
141
|
-
// fallback to
|
|
142
|
-
|
|
138
|
+
// fallback to resolve if nothing to close
|
|
139
|
+
resolve()
|
|
143
140
|
})
|
|
144
141
|
}
|
|
145
142
|
|
|
@@ -275,20 +272,13 @@ export default class Request
|
|
|
275
272
|
* @throws {Error} E_HTTP_REQUEST_RETRY_HTTP2_RECONNECT
|
|
276
273
|
* @throws {Error} E_HTTP_REQUEST_RETRY_ERROR
|
|
277
274
|
*/
|
|
278
|
-
#fetch(method, options)
|
|
275
|
+
async #fetch(method, options)
|
|
279
276
|
{
|
|
280
277
|
if(typeof options === 'string')
|
|
281
278
|
{
|
|
282
279
|
options = { url:options }
|
|
283
280
|
}
|
|
284
281
|
|
|
285
|
-
if(this.config.url && options.url)
|
|
286
|
-
{
|
|
287
|
-
options.url = options.url[0] === '/'
|
|
288
|
-
? options.url
|
|
289
|
-
: this.config.url + options.url
|
|
290
|
-
}
|
|
291
|
-
|
|
292
282
|
options = Object.assign(
|
|
293
283
|
{
|
|
294
284
|
method,
|
|
@@ -300,9 +290,19 @@ export default class Request
|
|
|
300
290
|
retryOnStatus : []
|
|
301
291
|
}, this.config, options)
|
|
302
292
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
293
|
+
try
|
|
294
|
+
{
|
|
295
|
+
return options.retry
|
|
296
|
+
? await this.#resolveRetryLoop(options)
|
|
297
|
+
: await this.#resolve(options)
|
|
298
|
+
}
|
|
299
|
+
catch(reason)
|
|
300
|
+
{
|
|
301
|
+
const error = new Error(`Failed request ${method} ${options.url}`)
|
|
302
|
+
error.code = 'E_HTTP_REQUEST_FAILED'
|
|
303
|
+
error.cause = reason
|
|
304
|
+
throw error
|
|
305
|
+
}
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
/**
|
|
@@ -315,20 +315,20 @@ export default class Request
|
|
|
315
315
|
*/
|
|
316
316
|
#resolve(options)
|
|
317
317
|
{
|
|
318
|
-
return new Promise((
|
|
318
|
+
return new Promise((resolve, reject) =>
|
|
319
319
|
{
|
|
320
320
|
const
|
|
321
321
|
method = options.method,
|
|
322
322
|
headers = this.#normalizeHeaders(options.headers),
|
|
323
323
|
body = this.#normalizeBody(options.body ?? options.data, headers['content-type']),
|
|
324
324
|
delimiter = this.#createBodyHeaderDelimiter(body, !!options.upstream || !!this.http2Session),
|
|
325
|
-
url = this.#normalizeUrl(options.
|
|
325
|
+
url = this.#normalizeUrl(options.authority, options.base, options.url)
|
|
326
326
|
|
|
327
327
|
Object.assign(headers, delimiter)
|
|
328
328
|
|
|
329
329
|
const upstream = this.http2Session
|
|
330
|
-
? this.#resolveHttp2Client(options, method, headers, url,
|
|
331
|
-
: this.#resolveHttp1Client(options, method, headers, url,
|
|
330
|
+
? this.#resolveHttp2Client(options, method, headers, url, resolve, reject)
|
|
331
|
+
: this.#resolveHttp1Client(options, method, headers, url, resolve, reject)
|
|
332
332
|
|
|
333
333
|
options.upstream
|
|
334
334
|
? options.upstream.pipe(upstream)
|
|
@@ -336,7 +336,7 @@ export default class Request
|
|
|
336
336
|
})
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
-
#resolveHttp2Client(options, method, headers, url,
|
|
339
|
+
#resolveHttp2Client(options, method, headers, url, resolve, reject)
|
|
340
340
|
{
|
|
341
341
|
if(true === this.http2Session.destroyed)
|
|
342
342
|
{
|
|
@@ -384,13 +384,13 @@ export default class Request
|
|
|
384
384
|
delete upstream.headers[HEADER_STATUS]
|
|
385
385
|
Object.defineProperty(upstream.headers, SENSITIVE_HEADERS, { enumerable:false, value:headers[SENSITIVE_HEADERS] })
|
|
386
386
|
|
|
387
|
-
this.#resolveOnResponse(options, method, url,
|
|
387
|
+
this.#resolveOnResponse(options, method, url, resolve, reject, upstream)
|
|
388
388
|
})
|
|
389
389
|
|
|
390
390
|
return upstream
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
-
#resolveHttp1Client(options, method, headers, url,
|
|
393
|
+
#resolveHttp1Client(options, method, headers, url, resolve, reject)
|
|
394
394
|
{
|
|
395
395
|
const
|
|
396
396
|
request = url.startsWith('https:') ? https.request : http.request,
|
|
@@ -400,7 +400,7 @@ export default class Request
|
|
|
400
400
|
upstream.on('close', this.#connectionClosed .bind(this, upstream, reject))
|
|
401
401
|
upstream.on('error', this.#resolveOnClientError .bind(this, method, url, reject))
|
|
402
402
|
upstream.on('timeout', this.#resolveOnClientTimeout.bind(this, upstream, options.timeout, method, url, reject))
|
|
403
|
-
upstream.on('response', this.#resolveOnResponse .bind(this, options, method, url,
|
|
403
|
+
upstream.on('response', this.#resolveOnResponse .bind(this, options, method, url, resolve, reject))
|
|
404
404
|
|
|
405
405
|
return upstream
|
|
406
406
|
}
|
|
@@ -419,13 +419,13 @@ export default class Request
|
|
|
419
419
|
* @param {RequestOptions} options
|
|
420
420
|
* @param {String} method
|
|
421
421
|
* @param {String} url
|
|
422
|
-
* @param {Function}
|
|
422
|
+
* @param {Function} resolve Promise resolve
|
|
423
423
|
* @param {Function} reject Promise reject
|
|
424
424
|
* @param {http.IncomingMessage} readable
|
|
425
425
|
*
|
|
426
426
|
* @returns {Void}
|
|
427
427
|
*/
|
|
428
|
-
#resolveOnResponse(options, method, url,
|
|
428
|
+
#resolveOnResponse(options, method, url, resolve, reject, readable)
|
|
429
429
|
{
|
|
430
430
|
const response =
|
|
431
431
|
{
|
|
@@ -448,11 +448,11 @@ export default class Request
|
|
|
448
448
|
{
|
|
449
449
|
readable.pipe(options.downstream)
|
|
450
450
|
readable.resume()
|
|
451
|
-
|
|
451
|
+
resolve(response)
|
|
452
452
|
}
|
|
453
453
|
else
|
|
454
454
|
{
|
|
455
|
-
this.#bufferResponseBody(readable, response, method, url,
|
|
455
|
+
this.#bufferResponseBody(readable, response, method, url, resolve, reject)
|
|
456
456
|
}
|
|
457
457
|
}
|
|
458
458
|
|
|
@@ -463,7 +463,7 @@ export default class Request
|
|
|
463
463
|
*/
|
|
464
464
|
async #resolveRetryLoop(options)
|
|
465
465
|
{
|
|
466
|
-
const
|
|
466
|
+
const reasons = []
|
|
467
467
|
|
|
468
468
|
let retry = Math.abs(Math.floor(options.retry))
|
|
469
469
|
|
|
@@ -485,49 +485,48 @@ export default class Request
|
|
|
485
485
|
return response
|
|
486
486
|
}
|
|
487
487
|
}
|
|
488
|
-
catch(
|
|
488
|
+
catch(reason)
|
|
489
489
|
{
|
|
490
|
-
if(retry
|
|
490
|
+
if(retry <= 0)
|
|
491
491
|
{
|
|
492
|
-
|
|
492
|
+
reasons.push(reason)
|
|
493
493
|
}
|
|
494
494
|
else
|
|
495
495
|
{
|
|
496
|
-
await this.#resolveRetryLoopError(options,
|
|
496
|
+
await this.#resolveRetryLoopError(options, reasons, reason)
|
|
497
497
|
await wait(options.retryDelay)
|
|
498
498
|
}
|
|
499
499
|
}
|
|
500
500
|
}
|
|
501
501
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
502
|
+
const
|
|
503
|
+
unique = reasons.filter((reason, i) => [i, -1].includes(reasons.map(e => e.code).lastIndexOf(code => code === reason.code))),
|
|
504
|
+
reason = unique.pop()
|
|
505
|
+
|
|
506
|
+
if(unique.length)
|
|
507
507
|
{
|
|
508
|
-
|
|
509
|
-
error.code = 'E_HTTP_REQUEST_RETRY_ERROR'
|
|
510
|
-
error.cause = errorTrace
|
|
511
|
-
throw error
|
|
508
|
+
reason.retried = unique
|
|
512
509
|
}
|
|
510
|
+
|
|
511
|
+
throw reason
|
|
513
512
|
}
|
|
514
513
|
|
|
515
514
|
/**
|
|
516
515
|
* Resolves the error in the retry loop.
|
|
517
516
|
*
|
|
518
517
|
* @param {RequestOptions} options
|
|
519
|
-
* @param {Error[]}
|
|
520
|
-
* @param {Error}
|
|
518
|
+
* @param {Error[]} reasons
|
|
519
|
+
* @param {Error} reason
|
|
521
520
|
*
|
|
522
521
|
* @returns {Void}
|
|
523
522
|
*/
|
|
524
|
-
async #resolveRetryLoopError(options,
|
|
523
|
+
async #resolveRetryLoopError(options, reasons, reason)
|
|
525
524
|
{
|
|
526
|
-
switch(
|
|
525
|
+
switch(reason.code)
|
|
527
526
|
{
|
|
528
527
|
case 'E_HTTP_REQUEST_CLIENT_ERROR':
|
|
529
528
|
{
|
|
530
|
-
return
|
|
529
|
+
return reasons.push(reason)
|
|
531
530
|
}
|
|
532
531
|
case 'E_HTTP_REQUEST_HTTP2_SESSION_DESTROYED':
|
|
533
532
|
case 'E_HTTP_REQUEST_HTTP2_SESSION_CLOSED':
|
|
@@ -535,67 +534,68 @@ export default class Request
|
|
|
535
534
|
try
|
|
536
535
|
{
|
|
537
536
|
await this.reconnect()
|
|
537
|
+
return reasons.push(reason)
|
|
538
538
|
}
|
|
539
539
|
catch(reason)
|
|
540
540
|
{
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
541
|
+
const error = new Error(`${reason.message}, retry to reconnect to the server failed`)
|
|
542
|
+
error.code = 'E_HTTP_REQUEST_RETRY_HTTP2_RECONNECT'
|
|
543
|
+
error.cause = reason
|
|
544
|
+
error.reasons = reasons
|
|
544
545
|
throw reason
|
|
545
546
|
}
|
|
546
|
-
return errorTrace.push(error)
|
|
547
547
|
}
|
|
548
548
|
case 'E_HTTP_REQUEST_CLIENT_TIMEOUT':
|
|
549
549
|
{
|
|
550
550
|
if(options.retryOnClientTimeout)
|
|
551
551
|
{
|
|
552
|
-
return
|
|
552
|
+
return reasons.push(reason)
|
|
553
553
|
}
|
|
554
554
|
else
|
|
555
555
|
{
|
|
556
|
-
throw
|
|
556
|
+
throw reason
|
|
557
557
|
}
|
|
558
558
|
}
|
|
559
559
|
case 'E_HTTP_REQUEST_DOWNSTREAM_ERROR':
|
|
560
560
|
{
|
|
561
561
|
if(options.retryOnDownstreamError)
|
|
562
562
|
{
|
|
563
|
-
return
|
|
563
|
+
return reasons.push(reason)
|
|
564
564
|
}
|
|
565
565
|
else
|
|
566
566
|
{
|
|
567
|
-
throw
|
|
567
|
+
throw reason
|
|
568
568
|
}
|
|
569
569
|
}
|
|
570
570
|
case 'E_HTTP_REQUEST_INVALID_RESPONSE_BODY_FORMAT':
|
|
571
571
|
{
|
|
572
572
|
if(options.retryOnInvalidResponseBodyFormat)
|
|
573
573
|
{
|
|
574
|
-
return
|
|
574
|
+
return reasons.push(reason)
|
|
575
575
|
}
|
|
576
576
|
else
|
|
577
577
|
{
|
|
578
|
-
throw
|
|
578
|
+
throw reason
|
|
579
579
|
}
|
|
580
580
|
}
|
|
581
581
|
case 'E_HTTP_REQUEST_INVALID_RESPONSE_STATUS':
|
|
582
582
|
{
|
|
583
583
|
if(options.retryOnErrorResponseStatus)
|
|
584
584
|
{
|
|
585
|
-
return
|
|
585
|
+
return reasons.push(reason)
|
|
586
586
|
}
|
|
587
|
-
else if(options.retryOnStatus.includes(
|
|
587
|
+
else if(options.retryOnStatus.includes(reason.response.status))
|
|
588
588
|
{
|
|
589
|
-
return
|
|
589
|
+
return reasons.push(reason)
|
|
590
590
|
}
|
|
591
591
|
else
|
|
592
592
|
{
|
|
593
|
-
throw
|
|
593
|
+
throw reason
|
|
594
594
|
}
|
|
595
595
|
}
|
|
596
596
|
default:
|
|
597
597
|
{
|
|
598
|
-
throw
|
|
598
|
+
throw reason
|
|
599
599
|
}
|
|
600
600
|
}
|
|
601
601
|
}
|
|
@@ -649,17 +649,28 @@ export default class Request
|
|
|
649
649
|
|
|
650
650
|
/**
|
|
651
651
|
* Normalizes the URL.
|
|
652
|
+
* One of authority or base must be provided,
|
|
652
653
|
*
|
|
653
|
-
* @param {String}
|
|
654
|
-
* @param {String}
|
|
654
|
+
* @param {String} [base]
|
|
655
|
+
* @param {String} [authority] the URL origin (e.g. https://example.com)
|
|
656
|
+
* @param {String} [url]
|
|
655
657
|
*
|
|
656
658
|
* @returns {String} Normalized URL
|
|
657
659
|
*/
|
|
658
|
-
#normalizeUrl(
|
|
660
|
+
#normalizeUrl(authority, base, url)
|
|
659
661
|
{
|
|
662
|
+
let baseURL = authority && base
|
|
663
|
+
? new URL(base, authority)
|
|
664
|
+
: new URL(base || authority)
|
|
665
|
+
|
|
666
|
+
if(url && false === baseURL.pathname.endsWith('/'))
|
|
667
|
+
{
|
|
668
|
+
baseURL = new URL(baseURL.pathname + '/', baseURL.href)
|
|
669
|
+
}
|
|
670
|
+
|
|
660
671
|
return url
|
|
661
|
-
? new URL(url,
|
|
662
|
-
:
|
|
672
|
+
? new URL(url, baseURL.href).href
|
|
673
|
+
: baseURL.href
|
|
663
674
|
}
|
|
664
675
|
|
|
665
676
|
/**
|
|
@@ -710,12 +721,12 @@ export default class Request
|
|
|
710
721
|
upstream.destroy(error)
|
|
711
722
|
}
|
|
712
723
|
|
|
713
|
-
#bufferResponseBody(readable, response, method, url,
|
|
724
|
+
#bufferResponseBody(readable, response, method, url, resolve, reject)
|
|
714
725
|
{
|
|
715
726
|
response.body = ''
|
|
716
727
|
readable.on('data', (chunk) => response.body += chunk)
|
|
717
728
|
readable.on('error', this.#onStreamError.bind(this, method, url, response))
|
|
718
|
-
readable.on('end', this.#onStreamEnd .bind(this, method, url, response,
|
|
729
|
+
readable.on('end', this.#onStreamEnd .bind(this, method, url, response, resolve, reject))
|
|
719
730
|
readable.resume()
|
|
720
731
|
}
|
|
721
732
|
|
|
@@ -746,14 +757,14 @@ export default class Request
|
|
|
746
757
|
* @param {String} method
|
|
747
758
|
* @param {String} url
|
|
748
759
|
* @param {http.IncomingMessage} response
|
|
749
|
-
* @param {Function}
|
|
760
|
+
* @param {Function} resolve promise resolve
|
|
750
761
|
* @param {Function} reject promise reject
|
|
751
762
|
*
|
|
752
763
|
* @returns {void}
|
|
753
764
|
*
|
|
754
765
|
* @throws {Error} E_HTTP_REQUEST_INVALID_RESPONSE_BODY_FORMAT
|
|
755
766
|
*/
|
|
756
|
-
#onStreamEnd(method, url, response,
|
|
767
|
+
#onStreamEnd(method, url, response, resolve, reject)
|
|
757
768
|
{
|
|
758
769
|
try
|
|
759
770
|
{
|
|
@@ -778,7 +789,7 @@ export default class Request
|
|
|
778
789
|
return
|
|
779
790
|
}
|
|
780
791
|
|
|
781
|
-
|
|
792
|
+
resolve(response)
|
|
782
793
|
}
|
|
783
794
|
|
|
784
795
|
#contentTypeApplicationJson(body)
|
package/index.test.js
CHANGED
|
@@ -53,6 +53,50 @@ suite('@superhero/http-request', () =>
|
|
|
53
53
|
assert.equal(response.body.url, '/', 'Should result to /')
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
+
test('Request using a relative path', async sub =>
|
|
57
|
+
{
|
|
58
|
+
// ...close the server that was started before the
|
|
59
|
+
// sub tests starts another server for each test...
|
|
60
|
+
await request.close()
|
|
61
|
+
await new Promise(resolve => server.close(resolve))
|
|
62
|
+
|
|
63
|
+
await sub.test('Request using an absolute path with a trailing base path slash', async () =>
|
|
64
|
+
{
|
|
65
|
+
const base = request.config.base || ''
|
|
66
|
+
request.config.base = base + '/path/'
|
|
67
|
+
const response = await request.get('/foobar')
|
|
68
|
+
assert.equal(response.status, 200, 'Should return a 200 status code')
|
|
69
|
+
assert.equal(response.body.url, '/foobar', 'Should result to the absolute path')
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
await sub.test('Request using a absolute path with out a trailing base path slash', async () =>
|
|
73
|
+
{
|
|
74
|
+
const base = request.config.base || ''
|
|
75
|
+
request.config.base = base + '/path'
|
|
76
|
+
const response = await request.get('/foobar')
|
|
77
|
+
assert.equal(response.status, 200, 'Should return a 200 status code')
|
|
78
|
+
assert.equal(response.body.url, '/foobar', 'Should result to the absolute path')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
await sub.test('Request using a relative path with a trailing base path slash', async () =>
|
|
82
|
+
{
|
|
83
|
+
const base = request.config.base || ''
|
|
84
|
+
request.config.base = base + '/path/'
|
|
85
|
+
const response = await request.get('foobar')
|
|
86
|
+
assert.equal(response.status, 200, 'Should return a 200 status code')
|
|
87
|
+
assert.equal(response.body.url, '/path/foobar', 'Should result to the absolute path')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
await sub.test('Request using a relative path with out a trailing base path slash', async () =>
|
|
91
|
+
{
|
|
92
|
+
const base = request.config.base || ''
|
|
93
|
+
request.config.base = base + '/path'
|
|
94
|
+
const response = await request.get('foobar')
|
|
95
|
+
assert.equal(response.status, 200, 'Should return a 200 status code')
|
|
96
|
+
assert.equal(response.body.url, '/path/foobar', 'Should result to the absolute path')
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
|
|
56
100
|
test('Request using a string body', async () =>
|
|
57
101
|
{
|
|
58
102
|
const response = await request.post({ body: 'test body' })
|
|
@@ -199,10 +243,10 @@ suite('@superhero/http-request', () =>
|
|
|
199
243
|
}
|
|
200
244
|
await assert.rejects(
|
|
201
245
|
request.get(options),
|
|
202
|
-
(error) => error.code === 'E_HTTP_REQUEST_CLIENT_TIMEOUT',
|
|
246
|
+
(error) => error.cause.code === 'E_HTTP_REQUEST_CLIENT_TIMEOUT',
|
|
203
247
|
'Should throw a timeout error')
|
|
204
248
|
})
|
|
205
|
-
|
|
249
|
+
|
|
206
250
|
test('Rejects invalid JSON response accurately', async () =>
|
|
207
251
|
{
|
|
208
252
|
// Alter the server to respond with invalid JSON
|
|
@@ -216,7 +260,7 @@ suite('@superhero/http-request', () =>
|
|
|
216
260
|
// Make the request
|
|
217
261
|
await assert.rejects(
|
|
218
262
|
request.get({ url: '/invalid-json' }),
|
|
219
|
-
(error) => error.code === 'E_HTTP_REQUEST_INVALID_RESPONSE_BODY_FORMAT',
|
|
263
|
+
(error) => error.cause.code === 'E_HTTP_REQUEST_INVALID_RESPONSE_BODY_FORMAT',
|
|
220
264
|
'Should throw a parse error')
|
|
221
265
|
})
|
|
222
266
|
|
|
@@ -383,7 +427,7 @@ suite('@superhero/http-request', () =>
|
|
|
383
427
|
|
|
384
428
|
await assert.rejects(
|
|
385
429
|
request.get(options),
|
|
386
|
-
|
|
430
|
+
(error) => error.cause.code === 'E_HTTP_REQUEST_INVALID_RESPONSE_STATUS',
|
|
387
431
|
'Should throw an error after the second attempt')
|
|
388
432
|
|
|
389
433
|
assert.equal(attempt, 2, 'Should make exactly 2 attempts')
|
|
@@ -401,7 +445,7 @@ suite('@superhero/http-request', () =>
|
|
|
401
445
|
|
|
402
446
|
await assert.rejects(
|
|
403
447
|
request.get(options),
|
|
404
|
-
(error) => error.code === 'E_HTTP_REQUEST_INVALID_RESPONSE_STATUS',
|
|
448
|
+
(error) => error.cause.code === 'E_HTTP_REQUEST_INVALID_RESPONSE_STATUS',
|
|
405
449
|
'Should throw an error right away')
|
|
406
450
|
|
|
407
451
|
assert.equal(attempt, 1, 'Should make exactly 1 attempt')
|
|
@@ -503,7 +547,7 @@ suite('@superhero/http-request', () =>
|
|
|
503
547
|
})
|
|
504
548
|
})
|
|
505
549
|
|
|
506
|
-
afterEach(
|
|
550
|
+
afterEach(done => request.close().then(() => server.close(done)))
|
|
507
551
|
|
|
508
552
|
executeTheSameTestSuitFor_http1_http2()
|
|
509
553
|
|
|
@@ -547,7 +591,7 @@ suite('@superhero/http-request', () =>
|
|
|
547
591
|
|
|
548
592
|
await assert.rejects(
|
|
549
593
|
request.get({ url: '/timeout-test', timeout: 100 }),
|
|
550
|
-
(error) => error.code === 'E_HTTP_REQUEST_CLIENT_TIMEOUT',
|
|
594
|
+
(error) => error.cause.code === 'E_HTTP_REQUEST_CLIENT_TIMEOUT',
|
|
551
595
|
'Should throw a timeout error')
|
|
552
596
|
})
|
|
553
597
|
})
|