webhoster 0.1.1 → 0.3.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 (85) hide show
  1. package/.eslintrc.json +74 -58
  2. package/.github/copilot-instructions.md +100 -0
  3. package/.github/workflows/test-matrix.yml +37 -0
  4. package/.test/benchmark.js +28 -0
  5. package/.test/constants.js +4 -0
  6. package/{test → .test}/http2server.js +1 -1
  7. package/{test → .test}/httpserver.js +1 -1
  8. package/{test → .test}/index.js +178 -192
  9. package/.test/multipromise.js +32 -0
  10. package/{test → .test}/tls.js +3 -3
  11. package/{test → .test}/urlencoded.js +3 -0
  12. package/.vscode/launch.json +24 -3
  13. package/README.md +116 -90
  14. package/data/CookieObject.js +14 -14
  15. package/errata/socketio.js +6 -11
  16. package/examples/starter.js +11 -0
  17. package/helpers/HeadersParser.js +7 -8
  18. package/helpers/HttpListener.js +387 -42
  19. package/helpers/RequestHeaders.js +43 -36
  20. package/helpers/RequestReader.js +27 -26
  21. package/helpers/ResponseHeaders.js +47 -36
  22. package/jsconfig.json +1 -1
  23. package/lib/HttpHandler.js +447 -277
  24. package/lib/HttpRequest.js +383 -39
  25. package/lib/HttpResponse.js +316 -52
  26. package/lib/HttpTransaction.js +146 -0
  27. package/middleware/AutoHeadersMiddleware.js +73 -0
  28. package/middleware/CORSMiddleware.js +45 -47
  29. package/middleware/CaseInsensitiveHeadersMiddleware.js +5 -11
  30. package/middleware/ContentDecoderMiddleware.js +81 -35
  31. package/middleware/ContentEncoderMiddleware.js +179 -132
  32. package/middleware/ContentLengthMiddleware.js +66 -41
  33. package/middleware/ContentWriterMiddleware.js +5 -5
  34. package/middleware/HashMiddleware.js +68 -40
  35. package/middleware/HeadMethodMiddleware.js +24 -21
  36. package/middleware/MethodMiddleware.js +29 -36
  37. package/middleware/PathMiddleware.js +49 -66
  38. package/middleware/ReadFormData.js +99 -0
  39. package/middleware/SendJsonMiddleware.js +131 -0
  40. package/middleware/SendStringMiddleware.js +87 -0
  41. package/package.json +38 -29
  42. package/polyfill/FormData.js +164 -0
  43. package/rollup.config.js +0 -1
  44. package/scripts/test-all-sync.sh +6 -0
  45. package/scripts/test-all.sh +7 -0
  46. package/templates/starter.js +53 -0
  47. package/test/fixtures/stream.js +68 -0
  48. package/test/helpers/HttpListener/construct.js +18 -0
  49. package/test/helpers/HttpListener/customOptions.js +22 -0
  50. package/test/helpers/HttpListener/doubleCreate.js +40 -0
  51. package/test/helpers/HttpListener/events.js +77 -0
  52. package/test/helpers/HttpListener/http.js +31 -0
  53. package/test/helpers/HttpListener/http2.js +41 -0
  54. package/test/helpers/HttpListener/https.js +38 -0
  55. package/test/helpers/HttpListener/startAll.js +31 -0
  56. package/test/helpers/HttpListener/stopNotStarted.js +23 -0
  57. package/test/lib/HttpHandler/class.js +8 -0
  58. package/test/lib/HttpHandler/handleRequest.js +11 -0
  59. package/test/lib/HttpHandler/middleware.js +941 -0
  60. package/test/lib/HttpHandler/parse.js +41 -0
  61. package/test/lib/HttpRequest/class.js +8 -0
  62. package/test/lib/HttpRequest/downstream.js +171 -0
  63. package/test/lib/HttpRequest/properties.js +101 -0
  64. package/test/lib/HttpRequest/read.js +518 -0
  65. package/test/lib/HttpResponse/class.js +8 -0
  66. package/test/lib/HttpResponse/properties.js +59 -0
  67. package/test/lib/HttpResponse/send.js +275 -0
  68. package/test/lib/HttpTransaction/class.js +8 -0
  69. package/test/lib/HttpTransaction/ping.js +50 -0
  70. package/test/lib/HttpTransaction/push.js +89 -0
  71. package/test/middleware/SendJsonMiddleware.js +222 -0
  72. package/test/sanity.js +10 -0
  73. package/test/templates/starter.js +93 -0
  74. package/tsconfig.json +12 -0
  75. package/types/index.js +61 -34
  76. package/types/typings.d.ts +8 -9
  77. package/utils/AsyncObject.js +6 -3
  78. package/utils/CaseInsensitiveObject.js +2 -3
  79. package/utils/function.js +1 -7
  80. package/utils/headers.js +42 -0
  81. package/utils/qualityValues.js +1 -1
  82. package/utils/stream.js +4 -20
  83. package/index.cjs +0 -3190
  84. package/test/constants.js +0 -4
  85. /package/{test → .test}/cookietester.js +0 -0
@@ -0,0 +1,518 @@
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { PassThrough, Readable } from 'node:stream';
3
+
4
+ import test from 'ava';
5
+
6
+ import HttpHandler from '../../../lib/HttpHandler.js';
7
+ import HttpRequest from '../../../lib/HttpRequest.js';
8
+ import {
9
+ getTestBinaryStream, getTestHash, getTestString, getTestTextStream,
10
+ } from '../../fixtures/stream.js';
11
+
12
+ test('HttpRequest.body()', async (t) => {
13
+ const request = new HttpRequest({ stream: getTestBinaryStream() });
14
+
15
+ t.false(request.bodyUsed);
16
+
17
+ /** @type {typeof import('node:stream/web').ReadableStream} */
18
+ let ReadableStream;
19
+ try {
20
+ ({ ReadableStream } = (await import('node:stream/web')));
21
+ } catch {}
22
+
23
+ if (!ReadableStream || 'toWeb' in Readable === false) {
24
+ t.log('Not supported.');
25
+ const error = t.throws(() => request.body, { instanceOf: Error });
26
+ t.is(error.message, 'NOT_SUPPORTED');
27
+ t.false(request.bodyUsed);
28
+ return;
29
+ }
30
+
31
+ const stream = request.body;
32
+ t.true(request.bodyUsed);
33
+ t.true(request.stream.readable);
34
+ t.false(request.stream.readableEnded);
35
+
36
+ t.assert(stream instanceof ReadableStream);
37
+
38
+ const hash = createHash('sha256');
39
+ for await (const chunk of stream) {
40
+ hash.write(Buffer.from(chunk));
41
+ }
42
+ const computedHash = hash.digest().toString('hex');
43
+ const actualHash = await getTestHash();
44
+ t.is(actualHash, computedHash);
45
+ t.false(request.stream.readable);
46
+ t.true(request.stream.readableEnded);
47
+ });
48
+
49
+ test('HttpRequest.body() - GET', (t) => {
50
+ const request = new HttpRequest({ method: 'GET' });
51
+
52
+ t.false(request.bodyUsed);
53
+ const { body } = request;
54
+ t.is(body, null);
55
+ t.false(request.bodyUsed);
56
+ });
57
+
58
+ test('HttpRequest.buffer()', async (t) => {
59
+ const request = new HttpRequest({ stream: getTestBinaryStream() });
60
+
61
+ t.false(request.bodyUsed);
62
+ const data = await request.buffer();
63
+ t.true(request.bodyUsed);
64
+ t.false(request.stream.readable);
65
+ t.true(request.stream.readableEnded);
66
+
67
+ t.assert(Buffer.isBuffer(data));
68
+ // t.is(data.length, BUFFER_SIZE);
69
+
70
+ const hash = createHash('sha256');
71
+ hash.write(data);
72
+ const computedHash = hash.digest().toString('hex');
73
+ const actualHash = await getTestHash();
74
+ t.is(actualHash, computedHash);
75
+ });
76
+
77
+ test('HttpRequest.buffer() - MAX_BUFFER_SIZE_REACHED', async (t) => {
78
+ let streamConsumers;
79
+ try {
80
+ streamConsumers = await import(new URL('node:stream/consumers').toString());
81
+ } catch {}
82
+
83
+ if (streamConsumers) {
84
+ t.log('Not supported.');
85
+ t.pass();
86
+ return;
87
+ }
88
+ const request = new HttpRequest({ stream: getTestBinaryStream() });
89
+
90
+ t.false(request.bodyUsed);
91
+ request.MIN_INITIAL_BUFFER_SIZE = 64;
92
+ request.MAX_INITIAL_BUFFER_SIZE = 128;
93
+ request.MAX_BUFFER_SIZE = 1024;
94
+ const error = await t.throwsAsync(() => request.buffer());
95
+ t.is(error.message, 'MAX_BUFFER_SIZE_REACHED');
96
+ });
97
+
98
+ test('HttpRequest.buffer() - content-length invalid', async (t) => {
99
+ let streamConsumers;
100
+ try {
101
+ streamConsumers = await import(new URL('node:stream/consumers').toString());
102
+ } catch {}
103
+
104
+ if (streamConsumers) {
105
+ t.log('Not supported.');
106
+ t.pass();
107
+ return;
108
+ }
109
+
110
+ const request = new HttpRequest({
111
+ stream: getTestBinaryStream(),
112
+ headers: {
113
+ 'content-length': '100',
114
+ },
115
+ });
116
+
117
+ t.false(request.bodyUsed);
118
+ const data = await request.buffer();
119
+ t.true(request.bodyUsed);
120
+ t.false(request.stream.readable);
121
+ t.true(request.stream.readableEnded);
122
+
123
+ t.assert(Buffer.isBuffer(data));
124
+ // t.is(data.length, BUFFER_SIZE);
125
+
126
+ const hash = createHash('sha256');
127
+ hash.write(data);
128
+ const computedHash = hash.digest().toString('hex');
129
+ const actualHash = await getTestHash();
130
+ t.is(actualHash, computedHash);
131
+ });
132
+
133
+ test('HttpRequest.buffer() - encode string back', async (t) => {
134
+ const text = 'foo';
135
+ const source = Readable.from([Buffer.from(text)]);
136
+ const downstream = new PassThrough();
137
+ downstream.setEncoding('utf8');
138
+ const request = new HttpRequest({ stream: source, headers: {} });
139
+ request.addDownstream(downstream);
140
+ const data = await request.buffer();
141
+ t.true(Buffer.isBuffer(data));
142
+ t.is(data.toString(), text);
143
+ });
144
+
145
+ test('HttpRequest.arrayBuffer()', async (t) => {
146
+ const request = new HttpRequest({ stream: getTestBinaryStream() });
147
+
148
+ t.false(request.bodyUsed);
149
+ const data = await request.arrayBuffer();
150
+ t.true(request.bodyUsed);
151
+ t.false(request.stream.readable);
152
+ t.true(request.stream.readableEnded);
153
+
154
+ t.assert(data instanceof ArrayBuffer);
155
+ // t.is(data.byteLength, BUFFER_SIZE);
156
+
157
+ const hash = createHash('sha256');
158
+ hash.write(Buffer.from(data));
159
+ const computedHash = hash.digest().toString('hex');
160
+ const actualHash = await getTestHash();
161
+ t.is(actualHash, computedHash);
162
+ });
163
+
164
+ test('HttpRequest.blob()', async (t) => {
165
+ const contentType = 'application/octet-stream';
166
+ const request = new HttpRequest({
167
+ stream: getTestBinaryStream(),
168
+ headers: {
169
+ 'content-type': contentType,
170
+ },
171
+ });
172
+
173
+ t.false(request.bodyUsed);
174
+
175
+ let BlobClass = (typeof Blob === 'undefined' ? undefined : Blob);
176
+ try {
177
+ if (!BlobClass) {
178
+ BlobClass = (await import('node:buffer')).Blob;
179
+ }
180
+ } catch {}
181
+
182
+ /** @type {import('stream/consumers')} */
183
+ let streamConsumers;
184
+ try {
185
+ streamConsumers = await import(new URL('node:stream/consumers').toString());
186
+ } catch {}
187
+
188
+ if (!BlobClass && (!streamConsumers || !streamConsumers.blob)) {
189
+ t.log('Not supported.');
190
+ const error = await t.throwsAsync(() => request.blob(), { instanceOf: Error });
191
+ t.is(error.message, 'NOT_SUPPORTED');
192
+ t.false(request.bodyUsed);
193
+ return;
194
+ }
195
+
196
+ const data = await request.blob();
197
+ t.true(request.bodyUsed);
198
+ t.false(request.stream.readable);
199
+ t.true(request.stream.readableEnded);
200
+
201
+ if (BlobClass) {
202
+ t.assert(data instanceof BlobClass);
203
+ } else {
204
+ t.is(data.toString(), '[object Blob]');
205
+ }
206
+ t.is(data.type, contentType);
207
+ // t.is(data.size, BUFFER_SIZE);
208
+
209
+ const hash = createHash('sha256');
210
+ hash.write(Buffer.from(await data.arrayBuffer()));
211
+ const computedHash = hash.digest().toString('hex');
212
+ const actualHash = await getTestHash();
213
+ t.is(actualHash, computedHash);
214
+ });
215
+
216
+ test('HttpRequest.blob() - no content-type', async (t) => {
217
+ const request = new HttpRequest({
218
+ stream: getTestBinaryStream(),
219
+ headers: {},
220
+ });
221
+
222
+ t.false(request.bodyUsed);
223
+
224
+ let BlobClass = (typeof Blob === 'undefined' ? undefined : Blob);
225
+ try {
226
+ if (!BlobClass) {
227
+ BlobClass = (await import('node:buffer')).Blob;
228
+ }
229
+ } catch {}
230
+
231
+ /** @type {import('stream/consumers')} */
232
+ let streamConsumers;
233
+ try {
234
+ streamConsumers = await import(new URL('node:stream/consumers').toString());
235
+ } catch {}
236
+
237
+ if (!BlobClass && (!streamConsumers || !streamConsumers.blob)) {
238
+ t.log('Not supported.');
239
+ const error = await t.throwsAsync(() => request.blob(), { instanceOf: Error });
240
+ t.is(error.message, 'NOT_SUPPORTED');
241
+ t.false(request.bodyUsed);
242
+ return;
243
+ }
244
+
245
+ const data = await request.blob();
246
+
247
+ t.falsy(data.type);
248
+ });
249
+
250
+ test('HttpRequest.text()', async (t) => {
251
+ const request = new HttpRequest({
252
+ stream: getTestTextStream(),
253
+ headers: {},
254
+ });
255
+
256
+ t.false(request.bodyUsed);
257
+ const data = await request.text();
258
+ t.true(request.bodyUsed);
259
+ t.false(request.stream.readable);
260
+ t.true(request.stream.readableEnded);
261
+
262
+ t.assert(typeof data === 'string');
263
+ t.is(data, getTestString());
264
+ });
265
+
266
+ test('HttpRequest.text() - utf16', async (t) => {
267
+ const text = '\u{FF11}\u{FF12}\u{FF13}\u{FF14}';
268
+ const buffer = Buffer.from('\u{FF11}\u{FF12}\u{FF13}\u{FF14}', 'utf16le');
269
+ const request = new HttpRequest({
270
+ stream: Readable.from([buffer]),
271
+ headers: {
272
+ 'content-type': 'text/plain;charset=ucs-2',
273
+ },
274
+ });
275
+
276
+ t.false(request.bodyUsed);
277
+ const data = await request.text();
278
+ t.true(request.bodyUsed);
279
+ t.false(request.stream.readable);
280
+ t.true(request.stream.readableEnded);
281
+
282
+ t.assert(typeof data === 'string');
283
+ t.is(data, text);
284
+ t.is(text.length, 4);
285
+ });
286
+
287
+ test('HttpRequest.json() - Object', async (t) => {
288
+ const jsonContent = {
289
+ number: Math.floor(Math.random() * 10),
290
+ date: new Date(Math.random() * Date.now()),
291
+ string: randomBytes(48).toString('hex'),
292
+ boolean: true,
293
+ null: null,
294
+ array: [
295
+ 1,
296
+ 2,
297
+ ],
298
+ object: {
299
+ key: 'value',
300
+ },
301
+ };
302
+
303
+ const request = new HttpRequest({
304
+ stream: Readable.from([Buffer.from(JSON.stringify(jsonContent))]),
305
+ headers: {},
306
+ });
307
+
308
+ t.false(request.bodyUsed);
309
+ const data = await request.json();
310
+ t.true(request.bodyUsed);
311
+ t.false(request.stream.readable);
312
+ t.true(request.stream.readableEnded);
313
+
314
+ t.assert(typeof data === 'object');
315
+
316
+ t.deepEqual(data, {
317
+ ...jsonContent,
318
+ date: jsonContent.date.toISOString(),
319
+ });
320
+ });
321
+
322
+ test('HttpRequest.json() - Array', async (t) => {
323
+ const jsonContent = [
324
+ 1,
325
+ 2,
326
+ ];
327
+
328
+ const request = new HttpRequest({
329
+ stream: Readable.from([Buffer.from(JSON.stringify(jsonContent))]),
330
+ headers: {},
331
+ });
332
+
333
+ t.false(request.bodyUsed);
334
+ const data = await request.json();
335
+ t.true(request.bodyUsed);
336
+ t.false(request.stream.readable);
337
+ t.true(request.stream.readableEnded);
338
+
339
+ t.assert(typeof data === 'object');
340
+
341
+ t.deepEqual(data, jsonContent);
342
+ });
343
+
344
+ test('HttpRequest.formData - error', async (t) => {
345
+ const request = new HttpRequest({});
346
+ const error = await t.throwsAsync(async () => await request.formData());
347
+ t.is(error.message, 'UNSUPPORTED_MEDIA_TYPE');
348
+ });
349
+
350
+ test('HttpRequest.read() - GET', async (t) => {
351
+ const parsedUrl = HttpHandler.parseURL('http', 'my.domain.name', 'pathname?foo=bar&baz=qux&q1=a&q1=b#hash');
352
+ const request = new HttpRequest({ method: 'GET', ...parsedUrl });
353
+
354
+ /** @type {URLSearchParams} */
355
+ const data = await request.read();
356
+ t.true(data instanceof URLSearchParams);
357
+ t.is(data.get('foo'), 'bar');
358
+ t.is(data.get('baz'), 'qux');
359
+ // eslint-disable-next-line unicorn/prefer-set-has
360
+ const keys = [...data.keys()];
361
+ t.true(keys.includes('foo'));
362
+ t.true(keys.includes('baz'));
363
+ t.true(keys.includes('q1'));
364
+ t.is(data.get('q1'), 'a');
365
+ t.deepEqual(data.getAll('q1'), ['a', 'b']);
366
+ });
367
+
368
+ test('HttpRequest.read() - No content-type (buffer)', async (t) => {
369
+ const request = new HttpRequest({ stream: getTestBinaryStream(), headers: {} });
370
+
371
+ t.false(request.bodyUsed);
372
+ const data = await request.read();
373
+ t.true(request.bodyUsed);
374
+ t.false(request.stream.readable);
375
+ t.true(request.stream.readableEnded);
376
+
377
+ t.assert(Buffer.isBuffer(data));
378
+ // t.is(data.length, BUFFER_SIZE);
379
+
380
+ const hash = createHash('sha256');
381
+ hash.write(data);
382
+ const computedHash = hash.digest().toString('hex');
383
+ const actualHash = await getTestHash();
384
+ t.is(actualHash, computedHash);
385
+ });
386
+
387
+ test('HttpRequest.read() - No content-type (string)', async (t) => {
388
+ const request = new HttpRequest({ stream: Readable.from(['foo', 'bar']), headers: {} });
389
+
390
+ t.false(request.bodyUsed);
391
+ const data = await request.read();
392
+ t.true(request.bodyUsed);
393
+ t.false(request.stream.readable);
394
+ t.true(request.stream.readableEnded);
395
+
396
+ t.assert(typeof data === 'string');
397
+ // t.is(data.length, BUFFER_SIZE);
398
+
399
+ t.is(data, 'foobar');
400
+ });
401
+
402
+ test('HttpRequest.read() - No content-type (object-stream)', async (t) => {
403
+ const jsonContent = { foo: 'bar' };
404
+ const request = new HttpRequest({ stream: Readable.from([jsonContent]), headers: {} });
405
+
406
+ t.false(request.bodyUsed);
407
+ const data = await request.read();
408
+ t.true(request.bodyUsed);
409
+ t.false(request.stream.readable);
410
+ t.true(request.stream.readableEnded);
411
+
412
+ t.assert(typeof data === 'object');
413
+ // t.is(data.length, BUFFER_SIZE);
414
+
415
+ t.deepEqual(data, jsonContent);
416
+ });
417
+
418
+ test('HttpRequest.read() - No content-type (null)', async (t) => {
419
+ const request = new HttpRequest({ stream: Readable.from([]), headers: {} });
420
+
421
+ t.false(request.bodyUsed);
422
+ const data = await request.read();
423
+ t.true(request.bodyUsed);
424
+ t.false(request.stream.readable);
425
+ t.true(request.stream.readableEnded);
426
+ t.is(data, null);
427
+ });
428
+
429
+ test('HttpRequest.read() - application/json', async (t) => {
430
+ const jsonContent = { hello: 'world' };
431
+ const testString = JSON.stringify(jsonContent);
432
+ const request = new HttpRequest({
433
+ stream: Readable.from([Buffer.from(testString)]),
434
+ headers: {
435
+ 'content-type': 'application/json;charset=utf-8',
436
+ },
437
+ });
438
+
439
+ t.false(request.bodyUsed);
440
+ const data = await request.read();
441
+ t.true(request.bodyUsed);
442
+ t.false(request.stream.readable);
443
+ t.true(request.stream.readableEnded);
444
+
445
+ t.assert(typeof data === 'object');
446
+ t.deepEqual(data, jsonContent);
447
+ });
448
+
449
+ test('HttpRequest.read() - text/plain', async (t) => {
450
+ const jsonContent = { hello: 'world' };
451
+ const testString = JSON.stringify(jsonContent);
452
+ const request = new HttpRequest({
453
+ stream: Readable.from([Buffer.from(testString)]),
454
+ headers: {
455
+ 'content-type': 'text/plain;charset=utf-8',
456
+ },
457
+ });
458
+
459
+ t.false(request.bodyUsed);
460
+ const data = await request.read();
461
+ t.true(request.bodyUsed);
462
+ t.false(request.stream.readable);
463
+ t.true(request.stream.readableEnded);
464
+
465
+ t.assert(typeof data === 'string');
466
+ t.is(data, testString);
467
+ });
468
+
469
+ test('HttpRequest.read() - application/vnd.api+json', async (t) => {
470
+ const jsonContent = { hello: 'world' };
471
+ const testString = JSON.stringify(jsonContent);
472
+ const request = new HttpRequest({
473
+ stream: Readable.from([Buffer.from(testString)]),
474
+ headers: {
475
+ 'content-type': 'application/vnd.api+json;charset=utf-8',
476
+ },
477
+ });
478
+
479
+ t.false(request.bodyUsed);
480
+ const data = await request.read();
481
+ t.true(request.bodyUsed);
482
+ t.false(request.stream.readable);
483
+ t.true(request.stream.readableEnded);
484
+
485
+ t.assert(typeof data === 'object');
486
+ t.deepEqual(data, jsonContent);
487
+ });
488
+
489
+ test('HttpRequest.read() - contentReaders filtering', async (t) => {
490
+ const jsonContent = { hello: 'world' };
491
+ const testString = JSON.stringify(jsonContent);
492
+ const request = new HttpRequest({
493
+ stream: Readable.from([Buffer.from(testString)]),
494
+ headers: {
495
+ 'content-type': 'application/vnd.api;charset=utf-8',
496
+ },
497
+ });
498
+ request.contentReaders.push(
499
+ {
500
+ type: 'application', subtype: 'api', tree: 'vnd2', parse: request.text,
501
+ },
502
+ {
503
+ type: 'application', subtype: 'api', tree: 'vnd', test: () => false, parse: request.text,
504
+ },
505
+ {
506
+ type: 'application', subtype: 'api', tree: 'vnd', parse: request.json,
507
+ },
508
+ );
509
+
510
+ t.false(request.bodyUsed);
511
+ const data = await request.read();
512
+ t.true(request.bodyUsed);
513
+ t.false(request.stream.readable);
514
+ t.true(request.stream.readableEnded);
515
+
516
+ t.assert(typeof data === 'object');
517
+ t.deepEqual(data, jsonContent);
518
+ });
@@ -0,0 +1,8 @@
1
+ import test from 'ava';
2
+
3
+ import HttpResponse from '../../../lib/HttpResponse.js';
4
+
5
+ test('new HttpResponse()', (t) => {
6
+ const request = new HttpResponse({});
7
+ t.assert(request instanceof HttpResponse);
8
+ });
@@ -0,0 +1,59 @@
1
+ import test from 'ava';
2
+
3
+ import HttpResponse from '../../../lib/HttpResponse.js';
4
+
5
+ test('HttpResponse.status - constructor', (t) => {
6
+ const res = new HttpResponse({ status: 500 });
7
+ t.is(res.status, 500);
8
+ });
9
+
10
+ test('HttpResponse.status - .status', (t) => {
11
+ const res = new HttpResponse({});
12
+ res.status = 500;
13
+ t.is(res.status, 500);
14
+ });
15
+
16
+ test('HttpResponse.status - .statusCode', (t) => {
17
+ const res = new HttpResponse({});
18
+ res.statusCode = 500;
19
+ t.is(res.statusCode, 500);
20
+ t.is(res.status, 500);
21
+ });
22
+
23
+ test('HttpResponse.status - code()', (t) => {
24
+ const res = new HttpResponse({});
25
+ const result = res.code(500);
26
+ t.is(res.status, 500);
27
+ t.is(res, result);
28
+ });
29
+
30
+ test('HttpResponse.status - setStatus()', (t) => {
31
+ const res = new HttpResponse({});
32
+ const result = res.setStatus(500);
33
+ t.is(res.status, 500);
34
+ t.is(res, result);
35
+ });
36
+
37
+ test('HttpResponse.status - setStatus() error', (t) => {
38
+ const res = new HttpResponse({
39
+ onHeadersSent: () => true,
40
+ });
41
+ const error = t.throws(() => res.setStatus(500));
42
+ t.is(error.message, 'ERR_HEADER_SENT');
43
+ });
44
+
45
+ test('HttpResponse.ok', (t) => {
46
+ t.false(new HttpResponse({}).ok);
47
+ t.false(new HttpResponse({ status: 500 }).ok);
48
+ t.true(new HttpResponse({ status: 204 }).ok);
49
+ t.true(new HttpResponse({ status: 200 }).ok);
50
+ t.true(new HttpResponse({ status: 299 }).ok);
51
+ t.false(new HttpResponse({ status: 300 }).ok);
52
+ });
53
+
54
+ test('HttpResponse.ok - writable', (t) => {
55
+ const res = new HttpResponse({});
56
+ t.false(res.ok);
57
+ t.true(res.code(200).ok);
58
+ t.false(res.code(500).ok);
59
+ });