UNPKG

53.5 kBJavaScriptView Raw
1/* eslint-env mocha */
2
3var httpism = require('../index')
4var express = require('express')
5var bodyParser = require('body-parser')
6var chai = require('chai')
7chai.use(require('chai-as-promised'))
8var assert = chai.assert
9var expect = chai.expect
10var http = require('http')
11var https = require('https')
12var fs = require('fs-promise')
13var qs = require('qs')
14var middleware = require('../middleware')
15var basicAuthConnect = require('basic-auth-connect')
16var basicAuth = require('basic-auth')
17var cookieParser = require('cookie-parser')
18var toughCookie = require('tough-cookie')
19var httpProxy = require('http-proxy')
20var net = require('net')
21var FormData = require('form-data')
22var multiparty = require('multiparty')
23var obfuscateUrlPassword = require('../obfuscateUrlPassword')
24var urlTemplate = require('url-template')
25var pathUtils = require('path')
26var cache = require('../middleware/cache')
27
28describe('httpism', function () {
29 var server
30 var app
31 var port = 12345
32 var baseurl = 'http://localhost:' + port
33
34 beforeEach(function () {
35 app = express()
36 server = app.listen(port)
37 })
38
39 afterEach(function () {
40 server.close()
41 })
42
43 describe('json', function () {
44 beforeEach(function () {
45 app.use(bodyParser.json())
46 })
47
48 function itCanMakeRequests (method) {
49 it('can make ' + method + ' requests', function () {
50 app[method.toLowerCase()]('/', function (req, res) {
51 res.send({
52 method: req.method,
53 path: req.path,
54 accept: req.headers.accept
55 })
56 })
57
58 return httpism[method.toLowerCase()](baseurl).then(function (body) {
59 expect(body).to.eql({
60 method: method,
61 path: '/',
62 accept: 'application/json'
63 })
64 })
65 })
66 }
67
68 it('can make HEAD requests', function () {
69 app.head('/', function (req, res) {
70 res.header('x-method', req.method)
71 res.header('x-path', req.path)
72 res.end()
73 })
74
75 return httpism.head(baseurl).then(function (response) {
76 expect(response.headers['x-method']).to.equal('HEAD')
77 expect(response.headers['x-path']).to.equal('/')
78 })
79 })
80
81 function itCanMakeRequestsWithBody (method) {
82 it('can make ' + method + ' requests with body', function () {
83 app[method.toLowerCase()]('/', function (req, res) {
84 res.send({
85 method: req.method,
86 path: req.path,
87 accept: req.headers.accept,
88 body: req.body
89 })
90 })
91
92 return httpism[method.toLowerCase()](baseurl, {
93 joke: 'a chicken...'
94 }).then(function (body) {
95 expect(body).to.eql({
96 method: method,
97 path: '/',
98 accept: 'application/json',
99 body: {
100 joke: 'a chicken...'
101 }
102 })
103 })
104 })
105 }
106
107 itCanMakeRequests('GET')
108 itCanMakeRequests('DELETE')
109 itCanMakeRequestsWithBody('POST')
110 itCanMakeRequestsWithBody('PUT')
111 itCanMakeRequestsWithBody('PATCH')
112 itCanMakeRequestsWithBody('OPTIONS')
113
114 describe('content type request header', function () {
115 beforeEach(function () {
116 app.post('/', function (req, res) {
117 res.header('received-content-type', req.headers['content-type'])
118 res.header('content-type', 'text/plain')
119 req.pipe(res)
120 })
121 })
122
123 it('can upload JSON as application/custom', function () {
124 return httpism.post(baseurl, { json: 'json' }, { response: true, headers: { 'content-type': 'application/custom' } }).then(function (response) {
125 expect(JSON.parse(response.body)).to.eql({
126 json: 'json'
127 })
128 expect(response.headers['received-content-type']).to.eql('application/custom')
129 })
130 })
131
132 it('can upload form as application/custom', function () {
133 return httpism.post(baseurl, { json: 'json' }, {
134 response: true,
135 form: true,
136 headers: {
137 'content-type': 'application/custom'
138 }
139 }).then(function (response) {
140 expect(qs.parse(response.body)).to.eql({
141 json: 'json'
142 })
143 expect(response.headers['received-content-type']).to.eql('application/custom')
144 })
145 })
146
147 it('can upload string as application/custom', function () {
148 return httpism.post(baseurl, 'a string', {
149 response: true,
150 headers: {
151 'content-type': 'application/custom'
152 }
153 }).then(function (response) {
154 expect(response.body).to.eql('a string')
155 expect(response.headers['received-content-type']).to.eql('application/custom')
156 })
157 })
158 })
159
160 describe('content-length header', function () {
161 var unicodeText = '♫♫♫♫♪ ☺'
162
163 beforeEach(function () {
164 return app.post('/', function (req, res) {
165 res.send({
166 'content-length': req.headers['content-length'],
167 'transfer-encoding': req.headers['transfer-encoding']
168 })
169 })
170 })
171
172 it('sends content-length, and not transfer-encoding: chunked, with JSON', function () {
173 return httpism.post(baseurl, { json: unicodeText }).then(function (body) {
174 expect(body).to.eql({
175 'content-length': Buffer.byteLength(JSON.stringify({
176 json: unicodeText
177 })).toString()
178 })
179 })
180 })
181
182 it('sends content-length, and not transfer-encoding: chunked, with plain text', function () {
183 return httpism.post(baseurl, unicodeText).then(function (body) {
184 expect(body).to.eql({
185 'content-length': Buffer.byteLength(unicodeText).toString()
186 })
187 })
188 })
189
190 it('sends content-length, and not transfer-encoding: chunked, with form data', function () {
191 return httpism.post(baseurl, { formData: unicodeText }, {
192 form: true
193 }).then(function (response) {
194 expect(response).to.eql({
195 'content-length': Buffer.byteLength(qs.stringify({
196 formData: unicodeText
197 })).toString()
198 })
199 })
200 })
201 })
202
203 describe('accept request header', function () {
204 beforeEach(function () {
205 app.get('/', function (req, res) {
206 res.header('content-type', 'text/plain')
207 res.send(req.headers.accept)
208 })
209 })
210
211 it('sends Accept: application/json by default', function () {
212 return httpism.get(baseurl).then(function (body) {
213 expect(body).to.eql('application/json')
214 })
215 })
216
217 it('can send a custom Accept header', function () {
218 return httpism.get(baseurl, {
219 headers: {
220 accept: 'application/custom'
221 }
222 }).then(function (body) {
223 expect(body).to.eql('application/custom')
224 })
225 })
226
227 it('can send a custom Accept header even mixed case', function () {
228 return httpism.get(baseurl, {
229 headers: {
230 Accept: 'application/custom'
231 }
232 }).then(function (body) {
233 expect(body).to.eql('application/custom')
234 })
235 })
236 })
237
238 describe('request headers', function () {
239 it('can specify headers for the request', function () {
240 app.get('/', function (req, res) {
241 res.send({
242 'x-header': req.headers['x-header']
243 })
244 })
245
246 return httpism.get(baseurl, {
247 headers: {
248 'x-header': 'haha'
249 }
250 }).then(function (body) {
251 expect(body['x-header']).to.equal('haha')
252 })
253 })
254 })
255
256 describe('text', function () {
257 function itReturnsAStringForContentType (mimeType) {
258 it('returns a string if the content-type is ' + mimeType, function () {
259 app.get('/', function (req, res) {
260 res.header('content-type', mimeType)
261 res.send('content as string')
262 })
263
264 return httpism.get(baseurl).then(function (body) {
265 expect(body).to.equal('content as string')
266 })
267 })
268 }
269
270 itReturnsAStringForContentType('text/plain')
271 itReturnsAStringForContentType('text/html')
272 itReturnsAStringForContentType('text/css')
273 itReturnsAStringForContentType('text/javascript')
274 itReturnsAStringForContentType('application/javascript')
275
276 it('will upload a string as text/plain', function () {
277 app.post('/text', function (req, res) {
278 res.header('received-content-type', req.headers['content-type'])
279 res.header('content-type', 'text/plain')
280 req.pipe(res)
281 })
282
283 return httpism.post(baseurl + '/text', 'content as string', {response: true}).then(function (response) {
284 expect(response.headers['received-content-type']).to.equal('text/plain')
285 expect(response.body).to.equal('content as string')
286 })
287 })
288 })
289
290 describe('params', function () {
291 beforeEach(function () {
292 app.get('/auth', function (req, res) {
293 res.send(basicAuth(req) || {})
294 })
295
296 app.get('*', function (req, res) {
297 res.send(req.url)
298 })
299 })
300
301 it('can set params', function () {
302 return httpism.get(baseurl + '/:a', {
303 params: {
304 a: 'aa',
305 b: 'bb'
306 }
307 }).then(function (body) {
308 expect(body).to.eql('/aa?b=bb')
309 })
310 })
311
312 it('can set path params', function () {
313 return httpism.get(baseurl + '/:a*/:b', {
314 params: {
315 a: 'a/long/path',
316 b: 'bb'
317 }
318 }).then(function (body) {
319 expect(body).to.eql('/a/long/path/bb')
320 })
321 })
322
323 it("doesn't replace credentials", function () {
324 return httpism.get('http://user:pass@localhost:' + port + '/auth', {
325 params: {
326 a: 'a/long/path',
327 b: 'bb'
328 }
329 }).then(function (body) {
330 expect(body).to.eql({name: 'user', pass: 'pass'})
331 })
332 })
333
334 it('uses escapes', function () {
335 return httpism.get(baseurl + '/:a/:b', {
336 params: {
337 a: 'a/a',
338 b: 'b/b',
339 c: 'c/c'
340 }
341 }).then(function (body) {
342 expect(body).to.eql('/a%2Fa/b%2Fb?c=c%2Fc')
343 })
344 })
345
346 it('can use other template engines', function () {
347 return httpism.get(baseurl + '/{a}{?b,c}', {
348 params: {
349 a: 'x',
350 b: 'y',
351 c: 'z'
352 },
353 expandUrl: function (url, params) {
354 var template = urlTemplate.parse(url)
355 return template.expand(params)
356 }
357 }).then(function (body) {
358 expect(body).to.eql('/x?b=y&c=z')
359 })
360 })
361 })
362
363 describe('.client()', function () {
364 it('can make a new client that adds headers', function () {
365 app.get('/', function (req, res) {
366 res.send({
367 joke: req.headers.joke
368 })
369 })
370
371 var client = httpism.client(function (request, next) {
372 request.headers.joke = 'a chicken...'
373 return next(request)
374 })
375
376 return client.get(baseurl).then(function (body) {
377 expect(body).to.eql({
378 joke: 'a chicken...'
379 })
380 })
381 })
382
383 it('can make a new client that adds headers by passing them to options', function () {
384 app.get('/', function (req, res) {
385 res.send({
386 x: req.headers.x,
387 y: req.headers.y
388 })
389 })
390
391 var client = httpism.client('/', { headers: { x: '123' } }).client('/', { headers: { y: '456' } })
392
393 return client.get(baseurl).then(function (body) {
394 expect(body).to.eql({
395 x: '123',
396 y: '456'
397 })
398 })
399 })
400
401 it('makes requests with additional headers', function () {
402 app.get('/', function (req, res) {
403 res.send({
404 x: req.headers.x,
405 y: req.headers.y
406 })
407 })
408
409 var client = httpism.client({ headers: { x: '123' } })
410
411 return client.get(baseurl, { headers: { y: '456' } }).then(function (body) {
412 expect(body).to.eql({
413 x: '123',
414 y: '456'
415 })
416 })
417 })
418
419 describe('cache example', function () {
420 var filename = pathUtils.join(__dirname, 'cachefile.txt')
421
422 beforeEach(function () {
423 return fs.writeFile(filename, '{"from": "cache"}')
424 })
425
426 afterEach(function () {
427 return fs.unlink(filename)
428 })
429
430 it('can insert a new middleware just before the http request, dealing with streams', function () {
431 app.get('/', function (req, res) {
432 res.send({from: 'server'})
433 })
434
435 var cache = function (req, next) {
436 return next().then(function (response) {
437 response.body = fs.createReadStream(filename)
438 return response
439 })
440 }
441
442 cache.httpismMiddleware = {
443 before: 'http'
444 }
445
446 var http = httpism.client(cache)
447
448 return http.get(baseurl).then(function (body) {
449 expect(body).to.eql({from: 'cache'})
450 })
451 })
452 })
453
454 describe('middleware', function () {
455 describe('defining middleware', function () {
456 var client
457
458 beforeEach(function () {
459 app.get('/', function (req, res) {
460 res.send(req.query)
461 })
462
463 client = httpism.client(baseurl)
464 })
465
466 it('can modify the request', function () {
467 client.use(function (req, next) {
468 req.url += '?param=hi'
469 return next()
470 })
471
472 return client.get('/').then(function (response) {
473 expect(response).to.eql({param: 'hi'})
474 })
475 })
476
477 it('can send an entirely new request', function () {
478 client.use(function (req, next) {
479 return next({
480 url: req.url + '?param=hi',
481 options: {},
482 headers: {}
483 })
484 })
485
486 return client.get('/').then(function (response) {
487 expect(response).to.eql({param: 'hi'})
488 })
489 })
490
491 it('can return an entirely new response', function () {
492 client.use(function (req, next) {
493 return next().then(function (response) {
494 return {
495 body: 'body'
496 }
497 })
498 })
499
500 return client.get('/').then(function (response) {
501 expect(response).to.eql('body')
502 })
503 })
504 })
505
506 describe('inserting middleware', function () {
507 var pipeline, a, b
508
509 function middlwareNamed (name) {
510 function middleware () {
511 }
512
513 middleware.httpismMiddleware = {
514 name: name
515 }
516
517 return middleware
518 }
519
520 beforeEach(function () {
521 pipeline = httpism.raw.client()
522 pipeline.middleware = [
523 a = middlwareNamed('a'),
524 b = middlwareNamed('b')
525 ]
526 })
527
528 describe('before', function () {
529 it('can insert middleware before another', function () {
530 var m = function () {}
531 m.httpismMiddleware = {
532 before: 'b'
533 }
534
535 var client = pipeline.client(m)
536
537 expect(client.middleware).to.eql([
538 a,
539 m,
540 b
541 ])
542 })
543
544 it('can insert middleware into same client before another', function () {
545 var m = function () {}
546 m.httpismMiddleware = {
547 before: 'b'
548 }
549
550 pipeline.use(m)
551
552 expect(pipeline.middleware).to.eql([
553 a,
554 m,
555 b
556 ])
557 })
558
559 it('inserts before the named middleware if at least one is found', function () {
560 var m = function () {}
561 m.httpismMiddleware = {
562 before: ['b', 'c']
563 }
564
565 var client = pipeline.client(m)
566 expect(client.middleware).to.eql([
567 a,
568 m,
569 b
570 ])
571 })
572
573 it('inserts before all the named middleware if all are found', function () {
574 var m = function () {}
575 m.httpismMiddleware = {
576 before: ['b', 'b']
577 }
578 var client = pipeline.client(m)
579 expect(client.middleware).to.eql([
580 a,
581 m,
582 b
583 ])
584 })
585 })
586
587 describe('after', function () {
588 it('can insert middleware after another', function () {
589 var m = function () {}
590 m.httpismMiddleware = {
591 after: 'a'
592 }
593 var client = pipeline.client(m)
594 expect(client.middleware).to.eql([
595 a,
596 m,
597 b
598 ])
599 })
600
601 it('inserts after the named middleware if at lesat one is found', function () {
602 var m = function () {}
603 m.httpismMiddleware = {
604 after: ['a', 'c']
605 }
606 var client = pipeline.client(m)
607 expect(client.middleware).to.eql([
608 a,
609 m,
610 b
611 ])
612 })
613
614 it('inserts after all the named middleware if all are found', function () {
615 var m = function () {}
616 m.httpismMiddleware = {
617 after: ['a', 'b']
618 }
619 var client = pipeline.client(m)
620 expect(client.middleware).to.eql([
621 a,
622 b,
623 m
624 ])
625 })
626 })
627
628 it('can remove middleware', function () {
629 pipeline.remove('b')
630
631 expect(pipeline.middleware).to.eql([
632 a
633 ])
634 })
635
636 it('throws if before middleware name cannot be found', function () {
637 var m = function () {}
638 m.httpismMiddleware = {
639 before: 'notfound'
640 }
641 expect(function () { httpism.client(m) }).to.throw('no such middleware: notfound')
642 })
643
644 it('throws if none of the before middleware names can be found', function () {
645 var m = function () {}
646 m.httpismMiddleware = {
647 before: ['notfound']
648 }
649 expect(function () { httpism.client(m) }).to.throw('no such middleware: notfound')
650 })
651
652 it('throws if after middleware name cannot be found', function () {
653 var m = function () {}
654 m.httpismMiddleware = {
655 after: 'notfound'
656 }
657 expect(function () { httpism.client(m) }).to.throw('no such middleware: notfound')
658 })
659
660 it('throws if none of the after middleware names can be found', function () {
661 var m = function () {}
662 m.httpismMiddleware = {
663 after: ['notfound']
664 }
665 expect(function () { httpism.client(m) }).to.throw('no such middleware: notfound')
666 })
667 })
668 })
669
670 describe('2.x compatibility', function () {
671 it('can be created using `.api()`', function () {
672 app.get('/', function (req, res) {
673 res.send({
674 joke: req.headers.joke
675 })
676 })
677
678 var client = httpism.api(function (request, next) {
679 request.headers.joke = 'a chicken...'
680 return next(request)
681 })
682
683 return client.get(baseurl).then(function (body) {
684 expect(body).to.eql({
685 joke: 'a chicken...'
686 })
687 })
688 })
689 })
690
691 describe('query strings (deprecated)', function () {
692 beforeEach(function () {
693 app.get('/', function (req, res) {
694 res.send(req.query)
695 })
696 })
697
698 it('can set query string', function () {
699 return httpism.get(baseurl, {
700 querystring: {
701 a: 'a',
702 b: 'b'
703 }
704 }).then(function (body) {
705 expect(body).to.eql({
706 a: 'a',
707 b: 'b'
708 })
709 })
710 })
711
712 it('can override query string in url', function () {
713 return httpism.get(baseurl + '/?a=a&c=c', {
714 querystring: {
715 a: 'newa',
716 b: 'b'
717 }
718 }).then(function (body) {
719 expect(body).to.eql({
720 a: 'newa',
721 b: 'b',
722 c: 'c'
723 })
724 })
725 })
726 })
727 })
728
729 describe('exceptions', function () {
730 beforeEach(function () {
731 app.get('/400', function (req, res) {
732 res.status(400).send({
733 message: 'oh dear'
734 })
735 })
736 })
737
738 it('throws exceptions on 400-500 status codes, by default', function () {
739 return httpism.client(baseurl).get('/400').then(function () {
740 assert.fail('expected an exception to be thrown')
741 }).catch(function (e) {
742 expect(e.message).to.equal('GET ' + baseurl + '/400 => 400 Bad Request')
743 expect(e.statusCode).to.equal(400)
744 expect(e.body.message).to.equal('oh dear')
745 })
746 })
747
748 it("doesn't include the password in the error message", function () {
749 return httpism.client('http://user:pass@localhost:' + port + '/').get('/400').then(function () {
750 assert.fail('expected an exception to be thrown')
751 }).catch(function (e) {
752 expect(e.message).to.equal('GET http://user:********@localhost:' + port + '/400 => 400 Bad Request')
753 expect(e.statusCode).to.equal(400)
754 expect(e.body.message).to.equal('oh dear')
755 })
756 })
757
758 it("doesn't throw exceptions on 400-500 status codes, when specified", function () {
759 return httpism.client(baseurl).get('/400', { exceptions: false }).then(function (body) {
760 expect(body.message).to.equal('oh dear')
761 })
762 })
763
764 describe('error predicate', function () {
765 it('throws exceptions when predicate returns true', function () {
766 function isError (response) {
767 return response.statusCode === 400
768 }
769
770 return httpism.client(baseurl).get('/400', { exceptions: isError }).then(function () {
771 assert.fail('expected an exception to be thrown')
772 }).catch(function (e) {
773 expect(e.message).to.equal('GET ' + baseurl + '/400 => 400 Bad Request')
774 expect(e.statusCode).to.equal(400)
775 expect(e.body.message).to.equal('oh dear')
776 })
777 })
778
779 it("doesn't throw exceptions when predicate returns false", function () {
780 function isError (response) {
781 return response.statusCode !== 400
782 }
783
784 return httpism.client(baseurl).get('/400', { exceptions: isError }).then(function (body) {
785 expect(body.message).to.equal('oh dear')
786 })
787 })
788 })
789
790 it('throws if it cannot connect', function () {
791 return expect(httpism.get('http://localhost:50000/')).to.eventually.be.rejectedWith('ECONNREFUSED')
792 })
793 })
794
795 describe('options', function () {
796 var client
797
798 beforeEach(function () {
799 client = httpism.client(function (request, next) {
800 request.body = request.options
801 return next(request)
802 }, { a: 'a' })
803
804 app.post('/', function (req, res) {
805 res.send(req.body)
806 })
807 })
808
809 it('clients have options, which can be overwritten on each request', function () {
810 var root = client.client(baseurl)
811 return root.post('', undefined, { b: 'b' }).then(function (body) {
812 expect(body).to.eql({
813 a: 'a',
814 b: 'b'
815 })
816
817 return root.client().post('', undefined, { c: 'c' }).then(function (body) {
818 expect(body).to.eql({
819 a: 'a',
820 c: 'c'
821 })
822
823 return root.post('', undefined).then(function (body) {
824 expect(body).eql({
825 a: 'a'
826 })
827 })
828 })
829 })
830 })
831 })
832
833 describe('responses', function () {
834 beforeEach(function () {
835 app.get('/', function (req, res) {
836 res.set({'x-custom-header': 'header value'})
837 res.status(234)
838 res.send({data: 'data'})
839 })
840 })
841
842 describe('response: true', function () {
843 var response
844
845 beforeEach(function () {
846 return httpism.get(baseurl, {response: true}).then(function (_response) {
847 response = _response
848 })
849 })
850
851 it('contains the url', function () {
852 expect(response.url).to.equal(baseurl)
853 })
854
855 it('contains the status code', function () {
856 expect(response.statusCode).to.equal(234)
857 })
858
859 it('contains the headers', function () {
860 expect(response.headers['x-custom-header']).to.equal('header value')
861 })
862
863 it('contains the body', function () {
864 expect(response.body).to.eql({data: 'data'})
865 })
866 })
867
868 describe('response: false (default)', function () {
869 var body
870
871 beforeEach(function () {
872 return httpism.get(baseurl).then(function (_body) {
873 body = _body
874 })
875 })
876
877 describe('2.x compatibility', function () {
878 it('contains the url', function () {
879 expect(body.url).to.equal(baseurl)
880 })
881
882 it('contains the status code', function () {
883 expect(body.statusCode).to.equal(234)
884 })
885
886 it('contains the headers', function () {
887 expect(body.headers['x-custom-header']).to.equal('header value')
888 })
889
890 it('contains the body', function () {
891 expect(body.body).to.eql({data: 'data'})
892 })
893 })
894
895 it('returns the body', function () {
896 expect(body).to.eql({data: 'data'})
897 })
898 })
899 })
900
901 describe('redirects', function () {
902 beforeEach(function () {
903 app.get('/redirecttoredirect', function (req, res) {
904 res.redirect('/redirect')
905 })
906
907 app.get('/redirect', function (req, res) {
908 res.location('/path/')
909 res.status(302).send({
910 path: req.path
911 })
912 })
913 app.get('/', function (req, res) {
914 res.send({
915 path: req.path
916 })
917 })
918 app.get('/path/', function (req, res) {
919 res.send({
920 path: req.path
921 })
922 })
923 app.get('/path/file', function (req, res) {
924 res.send({
925 path: req.path
926 })
927 })
928 })
929
930 it('follows redirects by default', function () {
931 return httpism.get(baseurl + '/redirect', {response: true}).then(function (response) {
932 expect(response.body).to.eql({
933 path: '/path/'
934 })
935 expect(response.url).to.eql(baseurl + '/path/')
936 })
937 })
938
939 function itFollowsRedirects (statusCode) {
940 it('follows ' + statusCode + ' redirects', function () {
941 app.get('/' + statusCode, function (req, res) {
942 res.location('/path/')
943 res.status(statusCode).send()
944 })
945
946 return httpism.get(baseurl + '/' + statusCode, {response: true}).then(function (response) {
947 expect(response.body).to.eql({
948 path: '/path/'
949 })
950 expect(response.url).to.eql(baseurl + '/path/')
951 })
952 })
953 }
954
955 describe('redirects', function () {
956 itFollowsRedirects(300)
957 itFollowsRedirects(301)
958 itFollowsRedirects(302)
959 itFollowsRedirects(303)
960 itFollowsRedirects(307)
961 })
962
963 it('follows a more than one redirect', function () {
964 return httpism.get(baseurl + '/redirecttoredirect', {response: true}).then(function (response) {
965 expect(response.body).to.eql({
966 path: '/path/'
967 })
968 expect(response.url).to.eql(baseurl + '/path/')
969 })
970 })
971
972 it("doesn't follow redirects when specified", function () {
973 return httpism.get(baseurl + '/redirect', {
974 redirect: false,
975 response: true
976 }).then(function (response) {
977 expect(response.body).to.eql({
978 path: '/redirect'
979 })
980 expect(response.url).to.eql(baseurl + '/redirect')
981 expect(response.headers.location).to.equal('/path/')
982 expect(response.statusCode).to.equal(302)
983 })
984 })
985 })
986
987 describe('cookies', function () {
988 beforeEach(function () {
989 app.use(cookieParser())
990 app.get('/setcookie', function (req, res) {
991 res.cookie('mycookie', 'value')
992 res.send({})
993 })
994 app.get('/getcookie', function (req, res) {
995 res.send(req.cookies)
996 })
997 })
998
999 it('can store cookies and send cookies', function () {
1000 var cookies = new toughCookie.CookieJar()
1001 return httpism.get(baseurl + '/setcookie', {
1002 cookies: cookies
1003 }).then(function () {
1004 return httpism.get(baseurl + '/getcookie', {
1005 cookies: cookies
1006 }).then(function (body) {
1007 expect(body).to.eql({
1008 mycookie: 'value'
1009 })
1010 })
1011 })
1012 })
1013
1014 it('can store cookies and send cookies', function () {
1015 var client = httpism.client(baseurl, {
1016 cookies: true
1017 })
1018 return client.get(baseurl + '/setcookie').then(function () {
1019 return client.get(baseurl + '/getcookie').then(function (body) {
1020 expect(body).to.eql({
1021 mycookie: 'value'
1022 })
1023 })
1024 })
1025 })
1026 })
1027
1028 describe('https', function () {
1029 var httpsServer
1030 var httpsPort = 23456
1031 var httpsBaseurl = 'https://localhost:' + httpsPort + '/'
1032
1033 beforeEach(function () {
1034 var credentials = {
1035 key: fs.readFileSync(pathUtils.join(__dirname, 'server.key'), 'utf-8'),
1036 cert: fs.readFileSync(pathUtils.join(__dirname, 'server.crt'), 'utf-8')
1037 }
1038 httpsServer = https.createServer(credentials, app)
1039 httpsServer.listen(httpsPort)
1040 })
1041
1042 afterEach(function () {
1043 httpsServer.close()
1044 })
1045
1046 it('can make HTTPS requests', function () {
1047 app.get('/', function (req, res) {
1048 res.send({
1049 protocol: req.protocol
1050 })
1051 })
1052
1053 return httpism.get(httpsBaseurl, { https: { rejectUnauthorized: false } }).then(function (body) {
1054 expect(body.protocol).to.equal('https')
1055 })
1056 })
1057 })
1058
1059 describe('forms', function () {
1060 it('can upload application/x-www-form-urlencoded', function () {
1061 app.post('/form', function (req, res) {
1062 res.header('content-type', 'text/plain')
1063 res.header('received-content-type', req.headers['content-type'])
1064 req.pipe(res)
1065 })
1066
1067 return httpism.post(baseurl + '/form', {
1068 name: 'Betty Boop',
1069 address: 'one & two'
1070 }, {
1071 form: true,
1072 response: true
1073 }).then(function (response) {
1074 expect(response.body).to.equal('name=Betty%20Boop&address=one%20%26%20two')
1075 expect(response.headers['received-content-type']).to.equal('application/x-www-form-urlencoded')
1076 })
1077 })
1078
1079 it('can download application/x-www-form-urlencoded', function () {
1080 app.get('/form', function (req, res) {
1081 res.header('content-type', 'application/x-www-form-urlencoded')
1082 res.send(qs.stringify({
1083 name: 'Betty Boop',
1084 address: 'one & two'
1085 }))
1086 })
1087
1088 return httpism.get(baseurl + '/form', {response: true}).then(function (response) {
1089 expect(response.body).to.eql({
1090 name: 'Betty Boop',
1091 address: 'one & two'
1092 })
1093 expect(response.headers['content-type']).to.equal('application/x-www-form-urlencoded; charset=utf-8')
1094 })
1095 })
1096
1097 describe('multipart forms', function () {
1098 var filename = pathUtils.join(__dirname, 'afile.jpg')
1099
1100 beforeEach(function () {
1101 return fs.writeFile(filename, 'an image')
1102 })
1103
1104 afterEach(function () {
1105 return fs.unlink(filename)
1106 })
1107
1108 it('can send multipart forms with `form-data`', function () {
1109 app.post('/form', function (req, res) {
1110 var form = new multiparty.Form()
1111
1112 form.parse(req, function (err, fields, files) {
1113 if (err) {
1114 console.log(err)
1115 res.status(500).send({message: err.message})
1116 }
1117 var response = {}
1118
1119 Object.keys(fields).forEach(function (field) {
1120 response[field] = fields[field][0]
1121 })
1122 Promise.all(Object.keys(files).map(function (field) {
1123 var file = files[field][0]
1124 return middleware.streamToString(fs.createReadStream(file.path)).then(function (contents) {
1125 response[field] = {
1126 contents: contents,
1127 headers: file.headers
1128 }
1129 })
1130 })).then(function () {
1131 res.send(response)
1132 })
1133 })
1134 })
1135
1136 var form = new FormData()
1137
1138 form.append('name', 'Betty Boop')
1139 form.append('address', 'one & two')
1140 form.append('photo', fs.createReadStream(filename))
1141
1142 return httpism.post(baseurl + '/form', form).then(function (body) {
1143 expect(body).to.eql({
1144 name: 'Betty Boop',
1145 address: 'one & two',
1146 photo: {
1147 contents: 'an image',
1148 headers: {
1149 'content-disposition': 'form-data; name="photo"; filename="afile.jpg"',
1150 'content-type': 'image/jpeg'
1151 }
1152 }
1153 })
1154 })
1155 })
1156 })
1157 })
1158
1159 describe('basic authentication', function () {
1160 beforeEach(function () {
1161 app.use(basicAuthConnect(function (user, pass) {
1162 return user === 'good user' && pass === 'good password!'
1163 }))
1164 return app.get('/secret', function (req, res) {
1165 res.send('this is secret')
1166 })
1167 })
1168
1169 it('can authenticate using username password', function () {
1170 return httpism.get(baseurl + '/secret', {
1171 basicAuth: {
1172 username: 'good user',
1173 password: 'good password!'
1174 }
1175 }).then(function (body) {
1176 expect(body).to.equal('this is secret')
1177 })
1178 })
1179
1180 it('can authenticate using username password encoded in URL', function () {
1181 var u = encodeURIComponent
1182 return httpism.get('http://' + u('good user') + ':' + u('good password!') + '@localhost:' + port + '/secret').then(function (body) {
1183 expect(body).to.equal('this is secret')
1184 })
1185 })
1186
1187 it('can authenticate using username with colons :', function () {
1188 return httpism.get(baseurl + '/secret', {
1189 basicAuth: {
1190 username: 'good: :user',
1191 password: 'good password!'
1192 }
1193 }).then(function (body) {
1194 expect(body).to.equal('this is secret')
1195 })
1196 })
1197
1198 it("doesn't crash if username or password are undefined", function () {
1199 return httpism.get(baseurl + '/secret', {
1200 basicAuth: {
1201 },
1202 exceptions: false,
1203 response: true
1204 }).then(function (response) {
1205 expect(response.statusCode).to.equal(401)
1206 })
1207 })
1208
1209 it('fails to authenticate when password is incorrect', function () {
1210 return httpism.get(baseurl + '/secret', {
1211 basicAuth: {
1212 username: 'good user',
1213 password: 'bad password!'
1214 },
1215 exceptions: false
1216 }).then(function (response) {
1217 expect(response.statusCode).to.equal(401)
1218 })
1219 })
1220 })
1221 })
1222
1223 describe('streams', function () {
1224 var filename = pathUtils.join(__dirname, 'afile.txt')
1225
1226 beforeEach(function () {
1227 return fs.writeFile(filename, 'some content').then(function () {
1228 app.post('/file', function (req, res) {
1229 res.header('content-type', 'text/plain')
1230 res.header('received-content-type', req.headers['content-type'])
1231 req.unshift('received: ')
1232 req.pipe(res)
1233 })
1234
1235 app.get('/file', function (req, res) {
1236 var stream
1237 stream = fs.createReadStream(filename)
1238 res.header('content-type', 'application/blah')
1239 stream.pipe(res)
1240 })
1241 })
1242 })
1243
1244 afterEach(function () {
1245 return fs.unlink(filename)
1246 })
1247
1248 function itCanUploadAStreamWithContentType (contentType) {
1249 it('can upload a stream with Content-Type: ' + contentType, function () {
1250 var stream = fs.createReadStream(filename)
1251
1252 return httpism.post(baseurl + '/file', stream, {
1253 headers: {
1254 'content-type': contentType
1255 },
1256 response: true
1257 }).then(function (response) {
1258 expect(response.headers['received-content-type']).to.equal(contentType)
1259 expect(response.body).to.equal('received: some content')
1260 })
1261 })
1262 }
1263
1264 itCanUploadAStreamWithContentType('application/blah')
1265 itCanUploadAStreamWithContentType('application/json')
1266 itCanUploadAStreamWithContentType('text/plain')
1267 itCanUploadAStreamWithContentType('application/x-www-form-urlencoded')
1268
1269 it('it guesses the Content-Type of the stream when created from a file', function () {
1270 var stream = fs.createReadStream(filename)
1271
1272 return httpism.post(baseurl + '/file', stream, {response: true}).then(function (response) {
1273 expect(response.headers['received-content-type']).to.equal('text/plain')
1274 expect(response.body).to.equal('received: some content')
1275 })
1276 })
1277
1278 it('can download a stream', function () {
1279 return httpism.get(baseurl + '/file', {response: true}).then(function (response) {
1280 expect(response.headers['content-type']).to.equal('application/blah')
1281 return middleware.streamToString(response.body).then(function (response) {
1282 expect(response).to.equal('some content')
1283 })
1284 })
1285 })
1286
1287 describe('forcing response parsing', function () {
1288 function describeForcingResponse (type, options) {
1289 var contentType = options !== undefined && Object.prototype.hasOwnProperty.call(options, 'contentType') && options.contentType !== undefined ? options.contentType : undefined
1290 var content = options !== undefined && Object.prototype.hasOwnProperty.call(options, 'content') && options.content !== undefined ? options.content : undefined
1291 var sendContent = options !== undefined && Object.prototype.hasOwnProperty.call(options, 'sendContent') && options.sendContent !== undefined ? options.sendContent : undefined
1292
1293 describe(type, function () {
1294 it('can download a stream of content-type ' + contentType, function () {
1295 app.get('/content', function (req, res) {
1296 var stream = fs.createReadStream(filename)
1297 res.header('content-type', contentType)
1298 stream.pipe(res)
1299 })
1300
1301 return httpism.get(baseurl + '/content', {
1302 responseBody: 'stream',
1303 response: true
1304 }).then(function (response) {
1305 expect(response.headers['content-type']).to.equal(contentType)
1306 return middleware.streamToString(response.body).then(function (response) {
1307 expect(response).to.equal('some content')
1308 })
1309 })
1310 })
1311
1312 it('can force parse ' + type + ' when content-type is application/blah', function () {
1313 app.get('/content', function (req, res) {
1314 res.header('content-type', 'application/blah')
1315 res.send(sendContent || content)
1316 })
1317
1318 return httpism.get(baseurl + '/content', {
1319 responseBody: type,
1320 response: true
1321 }).then(function (response) {
1322 expect(response.headers['content-type']).to.equal('application/blah; charset=utf-8')
1323 expect(response.body).to.eql(content)
1324 })
1325 })
1326 })
1327 }
1328
1329 describeForcingResponse('text', {
1330 contentType: 'text/plain; charset=utf-8',
1331 content: 'some text content'
1332 })
1333 describeForcingResponse('json', {
1334 contentType: 'application/json',
1335 content: {
1336 json: true
1337 }
1338 })
1339 describeForcingResponse('form', {
1340 contentType: 'application/x-www-form-urlencoded',
1341 content: {
1342 json: 'true'
1343 },
1344 sendContent: qs.stringify({
1345 json: 'true'
1346 })
1347 })
1348 })
1349 })
1350
1351 describe('proxy', function () {
1352 var proxyServer
1353 var proxyPort = 12346
1354 var proxy
1355 var urlProxied
1356 var proxied
1357 var proxyAuth = false
1358 var proxyUrl = 'http://localhost:' + proxyPort + '/'
1359 var secureProxyUrl = 'http://bob:secret@localhost:' + proxyPort + '/'
1360
1361 function proxyRequest (req, res) {
1362 urlProxied = req.url
1363 proxied = true
1364 proxy.web(req, res, { target: req.url })
1365 }
1366
1367 function checkProxyAuthentication (req, res, next) {
1368 var expectedAuthorisation = 'Basic ' + Buffer.from('bob:secret').toString('base64')
1369
1370 if (expectedAuthorisation === req.headers['proxy-authorization']) {
1371 next(req, res)
1372 } else {
1373 res.statusCode = 407
1374 res.end('bad proxy authentication')
1375 }
1376 }
1377
1378 beforeEach(function () {
1379 urlProxied = undefined
1380 proxied = false
1381 proxy = httpProxy.createProxyServer()
1382
1383 proxyServer = http.createServer(function (req, res) {
1384 if (proxyAuth) {
1385 return checkProxyAuthentication(req, res, proxyRequest)
1386 } else {
1387 return proxyRequest(req, res)
1388 }
1389 })
1390 proxyServer.listen(proxyPort)
1391
1392 proxyServer.on('connect', function (req, socket) {
1393 proxied = true
1394 var addr = req.url.split(':')
1395 // creating TCP connection to remote server
1396 var conn = net.connect(addr[1] || 443, addr[0], function () {
1397 // tell the client that the connection is established
1398 socket.write('HTTP/' + req.httpVersion + ' 200 OK\r\n\r\n', 'UTF-8', function () {
1399 // creating pipes in both ends
1400 conn.pipe(socket)
1401 socket.pipe(conn)
1402 })
1403 })
1404
1405 conn.on('error', function (e) {
1406 console.log('Server connection error: ' + e, addr)
1407 socket.end()
1408 })
1409 })
1410 })
1411
1412 afterEach(function () {
1413 proxyServer.close()
1414 })
1415
1416 var httpsServer
1417 var httpsPort = 23456
1418 var httpsBaseurl = 'https://localhost:' + httpsPort + '/'
1419
1420 beforeEach(function () {
1421 var credentials = {
1422 key: fs.readFileSync(pathUtils.join(__dirname, 'server.key'), 'utf-8'),
1423 cert: fs.readFileSync(pathUtils.join(__dirname, 'server.crt'), 'utf-8')
1424 }
1425 httpsServer = https.createServer(credentials, app)
1426 httpsServer.listen(httpsPort)
1427 })
1428
1429 afterEach(function () {
1430 httpsServer.close()
1431 })
1432
1433 context('unsecured proxy', function () {
1434 it('can use a proxy', function () {
1435 app.get('/', function (req, res) {
1436 res.send({
1437 blah: 'blah'
1438 })
1439 })
1440
1441 return httpism.get(baseurl, {proxy: proxyUrl}).then(function (body) {
1442 expect(body).to.eql({blah: 'blah'})
1443 expect(urlProxied).to.equal(baseurl)
1444 })
1445 })
1446
1447 it('can make HTTPS requests', function () {
1448 app.get('/', function (req, res) {
1449 res.send({
1450 protocol: req.protocol
1451 })
1452 })
1453
1454 return httpism.get(httpsBaseurl, { proxy: proxyUrl, https: { rejectUnauthorized: false } }).then(function (body) {
1455 expect(body.protocol).to.equal('https')
1456 })
1457 })
1458 })
1459
1460 context('proxy environment variables', function () {
1461 beforeEach(function () {
1462 app.get('/', function (req, res) {
1463 res.send({
1464 blah: 'blah'
1465 })
1466 })
1467 })
1468
1469 beforeEach(function () {
1470 delete process.env.NO_PROXY
1471 delete process.env.no_proxy
1472 delete process.env.HTTP_PROXY
1473 delete process.env.http_proxy
1474 delete process.env.HTTPS_PROXY
1475 delete process.env.https_proxy
1476 })
1477
1478 function assertProxied (url) {
1479 return httpism.get(url, { https: { rejectUnauthorized: false } }).then(function () {
1480 expect(proxied).to.equal(true)
1481 })
1482 }
1483
1484 function assertNotProxied (url) {
1485 return httpism.get(url, { https: { rejectUnauthorized: false } }).then(function () {
1486 expect(proxied).to.equal(false)
1487 })
1488 }
1489
1490 it('uses http_proxy for HTTP requests', function () {
1491 process.env.http_proxy = proxyUrl
1492
1493 return assertProxied(baseurl)
1494 })
1495
1496 it('uses HTTP_PROXY for HTTP requests', function () {
1497 process.env.HTTP_PROXY = proxyUrl
1498
1499 return assertProxied(baseurl)
1500 })
1501
1502 it('uses https_proxy for HTTPS requests', function () {
1503 process.env.https_proxy = proxyUrl
1504
1505 return assertProxied(httpsBaseurl)
1506 })
1507
1508 it('uses HTTPS_PROXY for HTTPS requests', function () {
1509 process.env.HTTPS_PROXY = proxyUrl
1510
1511 return assertProxied(httpsBaseurl)
1512 })
1513
1514 it('use skips hosts defined in no_proxy', function () {
1515 process.env.HTTP_PROXY = proxyUrl
1516 process.env.no_proxy = 'localhost'
1517
1518 return assertNotProxied(httpsBaseurl)
1519 })
1520
1521 it('use skips hosts defined in NO_PROXY', function () {
1522 process.env.HTTP_PROXY = proxyUrl
1523 process.env.NO_PROXY = 'localhost'
1524
1525 return assertNotProxied(baseurl)
1526 })
1527 })
1528
1529 context('secured proxy', function () {
1530 it('can use a proxy', function () {
1531 app.get('/', function (req, res) {
1532 res.send({
1533 blah: 'blah'
1534 })
1535 })
1536
1537 return httpism.get(baseurl, {proxy: secureProxyUrl}).then(function (body) {
1538 expect(body).to.eql({blah: 'blah'})
1539 expect(urlProxied).to.equal(baseurl)
1540 })
1541 })
1542
1543 it('can make HTTPS requests', function () {
1544 app.get('/', function (req, res) {
1545 res.send({
1546 protocol: req.protocol
1547 })
1548 })
1549
1550 return httpism.get(httpsBaseurl, { proxy: secureProxyUrl, https: { rejectUnauthorized: false } }).then(function (body) {
1551 expect(body.protocol).to.equal('https')
1552 })
1553 })
1554 })
1555 })
1556
1557 describe('raw', function () {
1558 it('can be used to create new middleware pipelines', function () {
1559 app.get('/', function (req, res) {
1560 res.status(400).send({
1561 blah: 'blah'
1562 })
1563 })
1564
1565 var client = httpism.raw.client(baseurl, function (request, next) {
1566 return next().then(function (res) {
1567 return middleware.streamToString(res.body).then(function (response) {
1568 res.body = response
1569 return res
1570 })
1571 })
1572 })
1573
1574 return client.get(baseurl, {response: true}).then(function (response) {
1575 expect(response.statusCode).to.equal(400)
1576 expect(JSON.parse(response.body)).to.eql({
1577 blah: 'blah'
1578 })
1579 })
1580 })
1581 })
1582
1583 describe('json reviver', function () {
1584 it('controls how the JSON response is deserialised', function () {
1585 app.get('/', function (req, res) {
1586 res.status(200).send({ blah: 1234 })
1587 })
1588
1589 var client = httpism.client(baseurl, {
1590 jsonReviver: function (key, value) {
1591 if (key === '') { return value }
1592 return key + value + '!'
1593 }
1594 })
1595
1596 return client.get(baseurl, {response: true}).then(function (response) {
1597 expect(response.statusCode).to.equal(200)
1598 expect(response.body).to.eql({
1599 blah: 'blah1234!'
1600 })
1601 })
1602 })
1603 })
1604
1605 describe('obfuscating passwords', function () {
1606 it('can obfuscate passwords from http URLs', function () {
1607 var obfuscated = obfuscateUrlPassword('https://user:password@example.com/a/:path/user:password/user:password.thing')
1608 expect(obfuscated).to.equal('https://user:********@example.com/a/:path/user:password/user:password.thing')
1609 })
1610
1611 it("doesn't do anything to relative paths", function () {
1612 var obfuscated = obfuscateUrlPassword('/a/:path/user:password/user:password.thing')
1613 expect(obfuscated).to.equal('/a/:path/user:password/user:password.thing')
1614 })
1615
1616 it("doesn't do anything to hosts with ports", function () {
1617 var obfuscated = obfuscateUrlPassword('http://localhost:4000/a/:path/user:password/user:password.thing')
1618 expect(obfuscated).to.equal('http://localhost:4000/a/:path/user:password/user:password.thing')
1619 })
1620 })
1621
1622 describe('output', function () {
1623 var filename = pathUtils.join(__dirname, 'streamfile.txt')
1624
1625 afterEach(function () {
1626 return fs.unlink(filename)
1627 })
1628
1629 it('can write to an output stream and wait for end', function () {
1630 app.get('/', function (req, res) {
1631 res.send('contents')
1632 })
1633
1634 return httpism.get(baseurl, {output: fs.createWriteStream(filename)}).then(function () {
1635 expect(fs.readFileSync(filename, 'utf-8')).to.equal('contents')
1636 })
1637 })
1638 })
1639
1640 describe('timeouts', function () {
1641 it('can set the timeout', function () {
1642 app.get('/', function (req, res) {
1643 // don't respond
1644 })
1645
1646 var startTime = Date.now()
1647 return expect(httpism.get(baseurl, {timeout: 20})).to.eventually.be.rejectedWith('timeout').then(function () {
1648 expect(Date.now() - startTime).to.be.within(20, 50)
1649 })
1650 })
1651 })
1652
1653 describe('cache', function () {
1654 var version
1655 var cachePath
1656
1657 beforeEach(function () {
1658 version = 1
1659 cachePath = pathUtils.join(__dirname, 'cache')
1660
1661 app.get('/', function (req, res) {
1662 res.set('x-version', version)
1663 res.send({version: version})
1664 })
1665
1666 app.get('/binary', function (req, res) {
1667 res.set('x-version', version)
1668 res.send(Buffer.from([1, 3, 3, 7, version]))
1669 })
1670
1671 return clearCache()
1672 })
1673
1674 function clearCache () {
1675 return fs.remove(cachePath)
1676 }
1677
1678 it('caches responses', function () {
1679 var http = httpism.client(cache({url: cachePath}), {response: true})
1680 return http.get(baseurl).then(function (response) {
1681 expect(response.headers['x-version']).to.eql('1')
1682 expect(response.body.version).to.equal(1)
1683 }).then(function () {
1684 version++
1685 return http.get(baseurl)
1686 }).then(function (response) {
1687 expect(response.headers['x-version']).to.eql('1')
1688 expect(response.body.version).to.equal(1)
1689 }).then(function () {
1690 return clearCache()
1691 }).then(function () {
1692 return http.get(baseurl)
1693 }).then(function (response) {
1694 expect(response.headers['x-version']).to.eql('2')
1695 expect(response.body.version).to.equal(2)
1696 })
1697 })
1698
1699 function streamToBuffer (stream) {
1700 return new Promise(function (resolve, reject) {
1701 var buffers = []
1702 stream.on('data', function (buffer) {
1703 buffers.push(buffer)
1704 })
1705 stream.on('error', reject)
1706 stream.on('end', function () {
1707 resolve(Buffer.concat(buffers))
1708 })
1709 })
1710 }
1711
1712 it('caches binary responses', function () {
1713 var http = httpism.client(cache({url: cachePath}), {response: true})
1714 return http.get(baseurl + '/binary').then(function (response) {
1715 expect(response.headers['x-version']).to.eql('1')
1716 return streamToBuffer(response.body)
1717 }).then(function (buffer) {
1718 expect(Array.from(buffer.values())).to.eql([1, 3, 3, 7, 1])
1719 }).then(function () {
1720 version++
1721 return http.get(baseurl + '/binary')
1722 }).then(function (response) {
1723 expect(response.headers['x-version']).to.eql('1')
1724 return streamToBuffer(response.body)
1725 }).then(function (buffer) {
1726 expect(Array.from(buffer.values())).to.eql([1, 3, 3, 7, 1])
1727 }).then(function () {
1728 return clearCache()
1729 }).then(function () {
1730 return http.get(baseurl + '/binary')
1731 }).then(function (response) {
1732 expect(response.headers['x-version']).to.eql('2')
1733 return streamToBuffer(response.body)
1734 }).then(function (buffer) {
1735 expect(Array.from(buffer.values())).to.eql([1, 3, 3, 7, 2])
1736 })
1737 })
1738 })
1739})