@e22m4u/js-http-static-router 0.1.1 → 0.2.0

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.
Files changed (43) hide show
  1. package/.mocharc.json +2 -1
  2. package/README.md +265 -17
  3. package/build-cjs.js +1 -1
  4. package/dist/cjs/index.cjs +111 -73
  5. package/example/server.js +23 -13
  6. package/mocha.setup.js +4 -0
  7. package/package.json +5 -3
  8. package/src/http-static-router.d.ts +7 -2
  9. package/src/http-static-router.js +70 -58
  10. package/src/http-static-router.spec.js +899 -0
  11. package/src/static-route.js +18 -8
  12. package/src/types.d.ts +7 -0
  13. package/src/utils/create-cookie-string.d.ts +6 -0
  14. package/src/utils/create-cookie-string.js +28 -0
  15. package/src/utils/create-cookie-string.spec.js +32 -0
  16. package/src/utils/create-error.d.ts +14 -0
  17. package/src/utils/create-error.js +29 -0
  18. package/src/utils/create-error.spec.js +42 -0
  19. package/src/utils/create-request-mock.d.ts +35 -0
  20. package/src/utils/create-request-mock.js +483 -0
  21. package/src/utils/create-request-mock.spec.js +646 -0
  22. package/src/utils/create-response-mock.d.ts +18 -0
  23. package/src/utils/create-response-mock.js +131 -0
  24. package/src/utils/create-response-mock.spec.js +150 -0
  25. package/src/utils/fetch-request-body.d.ts +26 -0
  26. package/src/utils/fetch-request-body.js +148 -0
  27. package/src/utils/fetch-request-body.spec.js +209 -0
  28. package/src/utils/get-pathname-from-url.d.ts +1 -1
  29. package/src/utils/{get-request-pathname.spec.js → get-pathname-from-url.spec.js} +1 -1
  30. package/src/utils/index.d.ts +8 -0
  31. package/src/utils/index.js +8 -0
  32. package/src/utils/is-readable-stream.d.ts +9 -0
  33. package/src/utils/is-readable-stream.js +12 -0
  34. package/src/utils/is-readable-stream.spec.js +23 -0
  35. package/src/utils/parse-content-type.d.ts +15 -0
  36. package/src/utils/parse-content-type.js +34 -0
  37. package/src/utils/parse-content-type.spec.js +79 -0
  38. package/src/utils/parse-cookie-string.d.ts +19 -0
  39. package/src/utils/parse-cookie-string.js +36 -0
  40. package/src/utils/parse-cookie-string.spec.js +45 -0
  41. package/{example/static → static}/index.html +2 -2
  42. /package/{example/static/nested/file.txt → static/assets/nested/heart.txt} +0 -0
  43. /package/{example/static/file.txt → static/assets/rabbit.txt} +0 -0
@@ -0,0 +1,646 @@
1
+ import {Socket} from 'net';
2
+ import {expect} from 'chai';
3
+ import {TLSSocket} from 'tls';
4
+ import {Readable, Stream} from 'stream';
5
+ import {format} from '@e22m4u/js-format';
6
+ import {createRequestMock} from './create-request-mock.js';
7
+ import {CHARACTER_ENCODING_LIST} from './fetch-request-body.js';
8
+
9
+ describe('createRequestMock', function () {
10
+ it('should require the parameter "options" to be an Object', function () {
11
+ const throwable = v => () => createRequestMock(v);
12
+ const error = v =>
13
+ format('Parameter "options" must be an Object, but %s was given.', v);
14
+ expect(throwable('str')).to.throw(error('"str"'));
15
+ expect(throwable('')).to.throw(error('""'));
16
+ expect(throwable(10)).to.throw(error('10'));
17
+ expect(throwable(0)).to.throw(error('0'));
18
+ expect(throwable(true)).to.throw(error('true'));
19
+ expect(throwable(false)).to.throw(error('false'));
20
+ expect(throwable([])).to.throw(error('Array'));
21
+ expect(throwable(null)).to.throw(error('null'));
22
+ throwable({})();
23
+ throwable(undefined)();
24
+ });
25
+
26
+ it('should require the option "host" to be a String', function () {
27
+ const throwable = v => () => createRequestMock({host: v});
28
+ const error = v =>
29
+ format('Option "host" must be a String, but %s was given.', v);
30
+ expect(throwable(10)).to.throw(error('10'));
31
+ expect(throwable(0)).to.throw(error('0'));
32
+ expect(throwable(true)).to.throw(error('true'));
33
+ expect(throwable(false)).to.throw(error('false'));
34
+ expect(throwable([])).to.throw(error('Array'));
35
+ expect(throwable({})).to.throw(error('Object'));
36
+ expect(throwable(null)).to.throw(error('null'));
37
+ throwable('str')();
38
+ throwable('')();
39
+ throwable(undefined)();
40
+ });
41
+
42
+ it('should require the option "method" to be a String', function () {
43
+ const throwable = v => () => createRequestMock({method: v});
44
+ const error = v =>
45
+ format('Option "method" must be a String, but %s was given.', v);
46
+ expect(throwable(10)).to.throw(error('10'));
47
+ expect(throwable(0)).to.throw(error('0'));
48
+ expect(throwable(true)).to.throw(error('true'));
49
+ expect(throwable(false)).to.throw(error('false'));
50
+ expect(throwable([])).to.throw(error('Array'));
51
+ expect(throwable({})).to.throw(error('Object'));
52
+ expect(throwable(null)).to.throw(error('null'));
53
+ throwable('str')();
54
+ throwable('')();
55
+ throwable(undefined)();
56
+ });
57
+
58
+ it('should require the option "secure" to be a Boolean', function () {
59
+ const throwable = v => () => createRequestMock({secure: v});
60
+ const error = v =>
61
+ format('Option "secure" must be a Boolean, but %s was given.', v);
62
+ expect(throwable('str')).to.throw(error('"str"'));
63
+ expect(throwable('')).to.throw(error('""'));
64
+ expect(throwable(10)).to.throw(error('10'));
65
+ expect(throwable(0)).to.throw(error('0'));
66
+ expect(throwable([])).to.throw(error('Array'));
67
+ expect(throwable({})).to.throw(error('Object'));
68
+ expect(throwable(null)).to.throw(error('null'));
69
+ throwable(true)();
70
+ throwable(false)();
71
+ throwable(undefined)();
72
+ });
73
+
74
+ it('should require the option "url" to be a String', function () {
75
+ const throwable = v => () => createRequestMock({url: v});
76
+ const error = v =>
77
+ format('Option "url" must be a String, but %s was given.', v);
78
+ expect(throwable(10)).to.throw(error('10'));
79
+ expect(throwable(0)).to.throw(error('0'));
80
+ expect(throwable(true)).to.throw(error('true'));
81
+ expect(throwable(false)).to.throw(error('false'));
82
+ expect(throwable([])).to.throw(error('Array'));
83
+ expect(throwable({})).to.throw(error('Object'));
84
+ expect(throwable(null)).to.throw(error('null'));
85
+ throwable('/path')();
86
+ throwable('/')();
87
+ throwable('')();
88
+ throwable(undefined)();
89
+ });
90
+
91
+ it('should require the option "url" to not contain "#"', function () {
92
+ const throwable = v => () => createRequestMock({url: v});
93
+ const mustThrowWith = v => {
94
+ expect(throwable(v)).to.throw(
95
+ format('Option "url" must not contain "#", but %v was given.', v),
96
+ );
97
+ };
98
+ mustThrowWith('#');
99
+ mustThrowWith('pathname#');
100
+ mustThrowWith('/pathname#');
101
+ mustThrowWith('http://example.com/#');
102
+ mustThrowWith('http://example.com/pathname#');
103
+ mustThrowWith('http://example.com/pathname?foo=bar#');
104
+ });
105
+
106
+ it('should require the option "path" to be a String', function () {
107
+ const throwable = v => () => createRequestMock({path: v});
108
+ const error = v =>
109
+ format('Option "path" must be a String, but %s was given.', v);
110
+ expect(throwable(10)).to.throw(error('10'));
111
+ expect(throwable(0)).to.throw(error('0'));
112
+ expect(throwable(true)).to.throw(error('true'));
113
+ expect(throwable(false)).to.throw(error('false'));
114
+ expect(throwable([])).to.throw(error('Array'));
115
+ expect(throwable({})).to.throw(error('Object'));
116
+ expect(throwable(null)).to.throw(error('null'));
117
+ throwable('/path')();
118
+ throwable('/')();
119
+ throwable(undefined)();
120
+ });
121
+
122
+ it('should require the option "path" to not contain "#"', function () {
123
+ const throwable = v => () => createRequestMock({path: v});
124
+ const mustThrowWith = v => {
125
+ expect(throwable(v)).to.throw(
126
+ format('Option "path" must not contain "#", but %v was given.', v),
127
+ );
128
+ };
129
+ mustThrowWith('/#');
130
+ mustThrowWith('/path#');
131
+ });
132
+
133
+ it('should require the option "path" to not contain "?"', function () {
134
+ const throwable = v => () => createRequestMock({path: v});
135
+ const mustThrowWith = v => {
136
+ expect(throwable(v)).to.throw(
137
+ format('Option "path" must not contain "?", but %v was given.', v),
138
+ );
139
+ };
140
+ mustThrowWith('/?');
141
+ mustThrowWith('/path?');
142
+ });
143
+
144
+ it('should require the option "path" to start with "/"', function () {
145
+ const throwable = v => () => createRequestMock({path: v});
146
+ const mustThrowWith = v => {
147
+ expect(throwable(v)).to.throw(
148
+ format('Option "path" must start with "/", but %v was given.', v),
149
+ );
150
+ };
151
+ mustThrowWith('path');
152
+ mustThrowWith('');
153
+ });
154
+
155
+ it('should require the option "query" to be a String or an Object', function () {
156
+ const throwable = v => () => createRequestMock({query: v});
157
+ const error = v =>
158
+ format(
159
+ 'Option "query" must be a String or an Object, but %s was given.',
160
+ v,
161
+ );
162
+ expect(throwable(10)).to.throw(error('10'));
163
+ expect(throwable(0)).to.throw(error('0'));
164
+ expect(throwable(true)).to.throw(error('true'));
165
+ expect(throwable(false)).to.throw(error('false'));
166
+ expect(throwable([])).to.throw(error('Array'));
167
+ expect(throwable(null)).to.throw(error('null'));
168
+ throwable({foo: 'bar'})();
169
+ throwable({})();
170
+ throwable('foo=bar')();
171
+ throwable('')();
172
+ throwable(undefined)();
173
+ });
174
+
175
+ it('should require the option "cookies" to be an Object', function () {
176
+ const throwable = v => () => createRequestMock({cookies: v});
177
+ const error = v =>
178
+ format('Option "cookies" must be an Object, but %s was given.', v);
179
+ expect(throwable('str')).to.throw(error('"str"'));
180
+ expect(throwable('')).to.throw(error('""'));
181
+ expect(throwable(10)).to.throw(error('10'));
182
+ expect(throwable(0)).to.throw(error('0'));
183
+ expect(throwable(true)).to.throw(error('true'));
184
+ expect(throwable(false)).to.throw(error('false'));
185
+ expect(throwable([])).to.throw(error('Array'));
186
+ expect(throwable(null)).to.throw(error('null'));
187
+ throwable({foo: 'bar'})();
188
+ throwable({})();
189
+ throwable(undefined)();
190
+ });
191
+
192
+ it('should require values in the option "cookies" to be a String', function () {
193
+ const throwable = v => () => createRequestMock({cookies: {test: v}});
194
+ const error = v =>
195
+ format('Cookie "test" must be a String, but %s was given.', v);
196
+ expect(throwable(10)).to.throw(error('10'));
197
+ expect(throwable(0)).to.throw(error('0'));
198
+ expect(throwable(true)).to.throw(error('true'));
199
+ expect(throwable(false)).to.throw(error('false'));
200
+ expect(throwable([])).to.throw(error('Array'));
201
+ expect(throwable({})).to.throw(error('Object'));
202
+ expect(throwable(null)).to.throw(error('null'));
203
+ throwable('str')();
204
+ throwable('')();
205
+ throwable(undefined)();
206
+ });
207
+
208
+ it('should require the option "headers" to be an Object', function () {
209
+ const throwable = v => () => createRequestMock({headers: v});
210
+ const error = v =>
211
+ format('Option "headers" must be an Object, but %s was given.', v);
212
+ expect(throwable('str')).to.throw(error('"str"'));
213
+ expect(throwable('')).to.throw(error('""'));
214
+ expect(throwable(10)).to.throw(error('10'));
215
+ expect(throwable(0)).to.throw(error('0'));
216
+ expect(throwable(true)).to.throw(error('true'));
217
+ expect(throwable(false)).to.throw(error('false'));
218
+ expect(throwable([])).to.throw(error('Array'));
219
+ expect(throwable(null)).to.throw(error('null'));
220
+ throwable({foo: 'bar'})();
221
+ throwable({})();
222
+ throwable(undefined)();
223
+ });
224
+
225
+ it('should require values in the option "headers" to be a String or an Array', function () {
226
+ const throwable = v => () => createRequestMock({headers: {Test: v}});
227
+ const error = v =>
228
+ format(
229
+ 'Header "Test" must be a String or an Array, but %s was given.',
230
+ v,
231
+ );
232
+ expect(throwable(10)).to.throw(error('10'));
233
+ expect(throwable(0)).to.throw(error('0'));
234
+ expect(throwable(true)).to.throw(error('true'));
235
+ expect(throwable(false)).to.throw(error('false'));
236
+ expect(throwable({})).to.throw(error('Object'));
237
+ expect(throwable(null)).to.throw(error('null'));
238
+ throwable('str')();
239
+ throwable('')();
240
+ throwable([])();
241
+ throwable(undefined)();
242
+ });
243
+
244
+ it('should require elements in the option "headers" to be a String', function () {
245
+ const throwable = v => () => createRequestMock({headers: {Test: [v]}});
246
+ const error = v =>
247
+ format(
248
+ 'Element 0 of the header "Test" must be a String, ' +
249
+ 'but %s was given.',
250
+ v,
251
+ );
252
+ expect(throwable(10)).to.throw(error('10'));
253
+ expect(throwable(0)).to.throw(error('0'));
254
+ expect(throwable(true)).to.throw(error('true'));
255
+ expect(throwable(false)).to.throw(error('false'));
256
+ expect(throwable([])).to.throw(error('Array'));
257
+ expect(throwable({})).to.throw(error('Object'));
258
+ expect(throwable(undefined)).to.throw(error('undefined'));
259
+ expect(throwable(null)).to.throw(error('null'));
260
+ throwable('str')();
261
+ throwable('')();
262
+ });
263
+
264
+ it('should require the option "stream" to be a Stream', function () {
265
+ const throwable = v => () => createRequestMock({stream: v});
266
+ const error = v =>
267
+ format('Option "stream" must be a Stream, but %s was given.', v);
268
+ expect(throwable('str')).to.throw(error('"str"'));
269
+ expect(throwable('')).to.throw(error('""'));
270
+ expect(throwable(10)).to.throw(error('10'));
271
+ expect(throwable(0)).to.throw(error('0'));
272
+ expect(throwable(true)).to.throw(error('true'));
273
+ expect(throwable(false)).to.throw(error('false'));
274
+ expect(throwable([])).to.throw(error('Array'));
275
+ expect(throwable({})).to.throw(error('Object'));
276
+ expect(throwable(null)).to.throw(error('null'));
277
+ throwable(new Stream())();
278
+ throwable(undefined)();
279
+ });
280
+
281
+ it('should require the option "encoding" to be a String', function () {
282
+ const throwable = v => () => createRequestMock({encoding: v});
283
+ const error = v =>
284
+ format('Option "encoding" must be a String, but %s was given.', v);
285
+ expect(throwable(10)).to.throw(error('10'));
286
+ expect(throwable(0)).to.throw(error('0'));
287
+ expect(throwable(true)).to.throw(error('true'));
288
+ expect(throwable(false)).to.throw(error('false'));
289
+ expect(throwable([])).to.throw(error('Array'));
290
+ expect(throwable({})).to.throw(error('Object'));
291
+ expect(throwable(null)).to.throw(error('null'));
292
+ throwable('utf-8')();
293
+ throwable(undefined)();
294
+ });
295
+
296
+ it('should not allow unsupported options', function () {
297
+ const throwable = () => createRequestMock({unknownOption: 'value'});
298
+ expect(throwable).to.throw('Option "unknownOption" is not supported.');
299
+ });
300
+
301
+ it('should not allow using the "url" and "path" options together', function () {
302
+ const throwable = () => createRequestMock({url: 'url', path: '/path'});
303
+ const error = 'The "url" and "path" options cannot be used together.';
304
+ expect(throwable).to.throw(error);
305
+ });
306
+
307
+ it('should not allow using the "url" and "query" options together', function () {
308
+ const throwable = () => createRequestMock({url: 'url', query: {p: 1}});
309
+ const error = 'The "url" and "query" options cannot be used together.';
310
+ expect(throwable).to.throw(error);
311
+ });
312
+
313
+ it('should require the option "encoding" to be a correct value', function () {
314
+ const throwable = v => () => createRequestMock({encoding: v});
315
+ const error = v => format('Character encoding %s is not supported.', v);
316
+ expect(throwable('str')).to.throw(error('"str"'));
317
+ expect(throwable('')).to.throw(error('""'));
318
+ CHARACTER_ENCODING_LIST.forEach(v => throwable(v)());
319
+ });
320
+
321
+ it('should not allow using the "stream" and "secure" options together', function () {
322
+ const throwable = v => () =>
323
+ createRequestMock({stream: new Stream(), secure: v});
324
+ const error = 'The "stream" and "secure" options cannot be used together.';
325
+ expect(throwable(true)).to.throw(error);
326
+ expect(throwable(false)).to.throw(error);
327
+ throwable(undefined)();
328
+ });
329
+
330
+ it('should not allow using the "stream" and "body" options together', function () {
331
+ const throwable = v => () =>
332
+ createRequestMock({stream: new Stream(), body: v});
333
+ const error = 'The "stream" and "body" options cannot be used together.';
334
+ expect(throwable('str')).to.throw(error);
335
+ expect(throwable({foo: 'bar'})).to.throw(error);
336
+ expect(throwable(Buffer.from('str'))).to.throw(error);
337
+ throwable(undefined)();
338
+ });
339
+
340
+ it('should not allow using the "stream" and "encoding" options together', function () {
341
+ const throwable = v => () =>
342
+ createRequestMock({stream: new Stream(), encoding: v});
343
+ const error =
344
+ 'The "stream" and "encoding" options cannot be used together.';
345
+ expect(throwable('utf-8')).to.throw(error);
346
+ throwable(undefined)();
347
+ });
348
+
349
+ it('should use "GET" as the default method', function () {
350
+ const req = createRequestMock();
351
+ expect(req.method).to.be.eq('GET');
352
+ });
353
+
354
+ it('should use an instance of Socket as the default socket', function () {
355
+ const req = createRequestMock();
356
+ expect(req.socket).to.be.instanceof(Socket);
357
+ });
358
+
359
+ it('should use "/" as the default value of the request url', function () {
360
+ const req = createRequestMock();
361
+ expect(req.url).to.be.eq('/');
362
+ });
363
+
364
+ it('should use "localhost" as the default value of the "host" header', function () {
365
+ const req = createRequestMock();
366
+ expect(req.headers).to.be.eql({host: 'localhost'});
367
+ });
368
+
369
+ it('should use "utf-8" as the default value of the data encoding', async function () {
370
+ const body = 'test';
371
+ const req = createRequestMock({body: Buffer.from(body)});
372
+ const chunks = [];
373
+ const data = await new Promise((resolve, reject) => {
374
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
375
+ req.on('error', err => reject(err));
376
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
377
+ });
378
+ expect(data).to.be.eql(body);
379
+ });
380
+
381
+ it('should use an instance of Socket when the option "secure" is false', function () {
382
+ const req = createRequestMock({secure: false});
383
+ expect(req.socket).to.be.instanceof(Socket);
384
+ });
385
+
386
+ it('should use an instance of TLSSocket when the option "secure" is true', function () {
387
+ const req = createRequestMock({secure: true});
388
+ expect(req.socket).to.be.instanceof(TLSSocket);
389
+ });
390
+
391
+ it('should handle an undefined body without writing it to the stream', async function () {
392
+ const req = createRequestMock({body: undefined});
393
+ expect(req.headers['content-length']).to.be.undefined;
394
+ const chunks = [];
395
+ const data = await new Promise((resolve, reject) => {
396
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
397
+ req.on('error', err => reject(err));
398
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
399
+ });
400
+ expect(data).to.be.eq('');
401
+ });
402
+
403
+ it('should handle a null body without writing it to the stream', async function () {
404
+ const req = createRequestMock({body: null});
405
+ expect(req.headers['content-length']).to.be.undefined;
406
+ const chunks = [];
407
+ const data = await new Promise((resolve, reject) => {
408
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
409
+ req.on('error', err => reject(err));
410
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
411
+ });
412
+ expect(data).to.be.eq('');
413
+ });
414
+
415
+ it('should pass a string body to the stream with "utf-8" encoding by default', async function () {
416
+ const body = 'requestBody';
417
+ const req = createRequestMock({body});
418
+ const chunks = [];
419
+ const data = await new Promise((resolve, reject) => {
420
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
421
+ req.on('error', err => reject(err));
422
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
423
+ });
424
+ expect(data).to.be.eq(body);
425
+ });
426
+
427
+ it('should pass a string body to the stream with "ascii" encoding', async function () {
428
+ const body = 'requestBody';
429
+ const req = createRequestMock({body, encoding: 'ascii'});
430
+ const chunks = [];
431
+ const data = await new Promise((resolve, reject) => {
432
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
433
+ req.on('error', err => reject(err));
434
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('ascii')));
435
+ });
436
+ expect(data).to.be.eq(body);
437
+ });
438
+
439
+ it('should pass a number from the "body" option to the stream as a string', async function () {
440
+ const body = 10;
441
+ const req = createRequestMock({body});
442
+ const chunks = [];
443
+ const data = await new Promise((resolve, reject) => {
444
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
445
+ req.on('error', err => reject(err));
446
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
447
+ });
448
+ expect(data).to.be.eq('10');
449
+ });
450
+
451
+ it('should pass a boolean from the "body" option to the stream as a string', async function () {
452
+ const body = true;
453
+ const req = createRequestMock({body});
454
+ const chunks = [];
455
+ const data = await new Promise((resolve, reject) => {
456
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
457
+ req.on('error', err => reject(err));
458
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
459
+ });
460
+ expect(data).to.be.eq('true');
461
+ });
462
+
463
+ it('should pass an array from the "body" option to the stream as JSON', async function () {
464
+ const body = [1, 2];
465
+ const req = createRequestMock({body});
466
+ const chunks = [];
467
+ const data = await new Promise((resolve, reject) => {
468
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
469
+ req.on('error', err => reject(err));
470
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
471
+ });
472
+ expect(data).to.be.eq(JSON.stringify(body));
473
+ });
474
+
475
+ it('should pass an object from the "body" option to the stream as JSON', async function () {
476
+ const body = {foo: 'bar'};
477
+ const req = createRequestMock({body});
478
+ const chunks = [];
479
+ const data = await new Promise((resolve, reject) => {
480
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
481
+ req.on('error', err => reject(err));
482
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
483
+ });
484
+ expect(data).to.be.eq(JSON.stringify(body));
485
+ });
486
+
487
+ it('should pass a Buffer from the "body" option to the stream', async function () {
488
+ const body = Buffer.from('test');
489
+ const req = createRequestMock({body});
490
+ const chunks = [];
491
+ const data = await new Promise((resolve, reject) => {
492
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
493
+ req.on('error', err => reject(err));
494
+ req.on('end', () => resolve(Buffer.concat(chunks)));
495
+ });
496
+ expect(data).to.be.eql(body);
497
+ });
498
+
499
+ it('should pass a value from the "url" option to the request url', function () {
500
+ const req = createRequestMock({url: '/test'});
501
+ expect(req.url).to.be.eq('/test');
502
+ });
503
+
504
+ it('should pass a value from the "path" option to the request url', function () {
505
+ const req = createRequestMock({path: '/test'});
506
+ expect(req.url).to.be.eq('/test');
507
+ });
508
+
509
+ it('should pass a string from the "query" option to the request url', async function () {
510
+ const req1 = createRequestMock({query: 'p1=foo&p2=bar'});
511
+ const req2 = createRequestMock({query: '?p1=foo&p2=bar'});
512
+ expect(req1.url).to.be.eq('/?p1=foo&p2=bar');
513
+ expect(req2.url).to.be.eq('/?p1=foo&p2=bar');
514
+ });
515
+
516
+ it('should pass an object from the "query" option to the request url', async function () {
517
+ const req = createRequestMock({query: {foo: 'bar', baz: 'qux'}});
518
+ expect(req.url).to.be.eq('/?foo=bar&baz=qux');
519
+ });
520
+
521
+ it('should combine the "path" and "query" options in the request url', function () {
522
+ const req1 = createRequestMock({path: '/test', query: 'foo=bar'});
523
+ const req2 = createRequestMock({path: '/test', query: '?foo=bar'});
524
+ const req3 = createRequestMock({path: '/test', query: {foo: 'bar'}});
525
+ expect(req1.url).to.be.eq('/test?foo=bar');
526
+ expect(req2.url).to.be.eq('/test?foo=bar');
527
+ expect(req3.url).to.be.eq('/test?foo=bar');
528
+ });
529
+
530
+ it('should set a value from the "method" option to the request method in upper case', async function () {
531
+ const req1 = createRequestMock({method: 'get'});
532
+ const req2 = createRequestMock({method: 'post'});
533
+ expect(req1.method).to.be.eq('GET');
534
+ expect(req2.method).to.be.eq('POST');
535
+ });
536
+
537
+ it('should not affect the property "url" when the option "host" is specified', async function () {
538
+ const req = createRequestMock({host: 'myHost'});
539
+ expect(req.url).to.be.eq('/');
540
+ expect(req.headers['host']).to.be.eq('myHost');
541
+ });
542
+
543
+ it('should set the header "x-forwarded-proto" when the option "secure" is true', async function () {
544
+ const req = createRequestMock({secure: true});
545
+ expect(req.headers['x-forwarded-proto']).to.be.eq('https');
546
+ });
547
+
548
+ it('should serialize and set a value from the "cookies" option to the "cookie" header', function () {
549
+ const req = createRequestMock({cookies: {p1: 'foo', p2: 'bar'}});
550
+ expect(req.headers['cookie']).to.be.eq('p1=foo; p2=bar');
551
+ });
552
+
553
+ it('should merge the "cookie" header with the "cookies" option', function () {
554
+ const req = createRequestMock({
555
+ headers: {cookie: 'p1=foo; p2=bar'},
556
+ cookies: {p2: 'baz', p3: 'qux'},
557
+ });
558
+ expect(req.headers['cookie']).to.be.eq('p1=foo; p2=baz; p3=qux');
559
+ });
560
+
561
+ it('should set the "content-type" header for a String body', function () {
562
+ const req = createRequestMock({body: 'test'});
563
+ expect(req.headers['content-type']).to.be.eq('text/plain');
564
+ });
565
+
566
+ it('should set the "content-type" header for a Buffer body', function () {
567
+ const req = createRequestMock({body: Buffer.from('test')});
568
+ expect(req.headers['content-type']).to.be.eq('application/octet-stream');
569
+ });
570
+
571
+ it('should set the "content-type" header for an Object body', function () {
572
+ const req = createRequestMock({body: {foo: 'bar'}});
573
+ expect(req.headers['content-type']).to.be.eq('application/json');
574
+ });
575
+
576
+ it('should set the "content-type" header for an Array body', function () {
577
+ const req = createRequestMock({body: [1, 2]});
578
+ expect(req.headers['content-type']).to.be.eq('application/json');
579
+ });
580
+
581
+ it('should set the "content-type" header for a Boolean body', function () {
582
+ const req1 = createRequestMock({body: true});
583
+ const req2 = createRequestMock({body: true});
584
+ expect(req1.headers['content-type']).to.be.eq('application/json');
585
+ expect(req2.headers['content-type']).to.be.eq('application/json');
586
+ });
587
+
588
+ it('should set the "content-type" header for a Number body', function () {
589
+ const req = createRequestMock({body: 10});
590
+ expect(req.headers['content-type']).to.be.eq('application/json');
591
+ });
592
+
593
+ it('should not override the "content-type" header from the provided options', function () {
594
+ const req = createRequestMock({
595
+ body: Buffer.from('test'),
596
+ headers: {'content-type': 'media/type'},
597
+ });
598
+ expect(req.headers['content-type']).to.be.eq('media/type');
599
+ });
600
+
601
+ it('should calculate the "content-length" header automatically', function () {
602
+ const body = 'test';
603
+ const length = Buffer.byteLength(body);
604
+ const req = createRequestMock({body});
605
+ expect(req.headers['content-length']).to.be.eq(String(length));
606
+ });
607
+
608
+ it('should not override the "content-length" header from the provided options', function () {
609
+ const req = createRequestMock({
610
+ body: 'test',
611
+ headers: {'content-length': '100'},
612
+ });
613
+ expect(req.headers['content-length']).to.be.eq('100');
614
+ });
615
+
616
+ it('should not calculate "content-length" automatically if "transfer-encoding" is provided', function () {
617
+ const req = createRequestMock({
618
+ body: 'test',
619
+ headers: {'transfer-encoding': 'chunked'},
620
+ });
621
+ expect(req.headers['content-length']).to.be.undefined;
622
+ expect(req.headers['transfer-encoding']).to.be.eq('chunked');
623
+ });
624
+
625
+ it('should convert header keys from the "headers" option to lower case', function () {
626
+ const req = createRequestMock({headers: {Auth: 'secret'}});
627
+ expect(req.headers['auth']).to.be.eq('secret');
628
+ });
629
+
630
+ it('should set default IP to socket properties', function () {
631
+ const req = createRequestMock();
632
+ expect(req.socket.remoteAddress).to.be.eq('127.0.0.1');
633
+ expect(req.socket.localAddress).to.be.eq('127.0.0.1');
634
+ });
635
+
636
+ it('should set default IP to socket properties when a custom stream is provided', function () {
637
+ const customStream = new Readable({
638
+ read() {
639
+ this.push(null);
640
+ },
641
+ });
642
+ const request = createRequestMock({stream: customStream});
643
+ expect(request.socket.remoteAddress).to.equal('127.0.0.1');
644
+ expect(request.socket.localAddress).to.equal('127.0.0.1');
645
+ });
646
+ });
@@ -0,0 +1,18 @@
1
+ import {ServerResponse} from 'http';
2
+
3
+ /**
4
+ * Server response mock.
5
+ */
6
+ export type ServerResponseMock = ServerResponse & {
7
+ statusCode: number;
8
+ _headersSent: boolean;
9
+ _headers: {[name: string]: string | undefined};
10
+ setEncoding(encoding: string): ServerResponseMock;
11
+ getEncoding(): string | undefined;
12
+ getBody(): Promise<string>;
13
+ };
14
+
15
+ /**
16
+ * Create response mock.
17
+ */
18
+ export declare function createResponseMock(): ServerResponseMock;