3 const assert
= require('node:assert');
4 const sinon
= require('sinon');
5 const common
= require('../../lib/common');
8 describe('common', function () {
10 describe('generateETag', function () {
11 it('generates a tag from data', function () {
12 const expected
= '"RHUvNyculE/SyROjU0LqzN0arxibrlBnazAashP8UGE"';
13 const data
= 'example data';
14 const result
= common
.generateETag(undefined, undefined, data
);
15 assert
.strictEqual(result
, expected
);
17 it('generates a tag from data and stats', function () {
18 const expected
= '"mtI0qCyqXsZVfX0Pgi+G6mQM10y9yVyi1NZejXSYttk"';
20 mtimeMs: 1600113038270.2375,
22 const data
= 'example data';
23 const result
= common
.generateETag(undefined, stat
, data
);
24 assert
.strictEqual(result
, expected
);
28 describe('get', function () {
29 const def
= 'default';
30 it('covers missing obj', function () {
31 const result
= common
.get(undefined, undefined, def
);
32 assert
.strictEqual(result
, def
);
34 it('covers missing prop', function () {
35 const result
= common
.get({}, undefined, def
);
36 assert
.strictEqual(result
, def
);
38 it('covers default', function () {
39 const result
= common
.get({ k: 'v' }, 'x', def
);
40 assert
.strictEqual(result
, def
);
42 it('covers prop', function () {
43 const result
= common
.get({ k: 'v' }, 'k', def
);
44 assert
.strictEqual(result
, 'v');
48 describe('isClientCached', function () {
49 let req
, modifiedTimeMs
, eTag
;
50 const blueMoon
= 'Sat, 31 Oct 2020 07:51:00 GMT';
51 const blueMoonMs
= 1604130660000;
52 const oneDayMs
= 86400000;
53 const anotherETag
= '"RHUvNyculE/SyROjU0LqzN0arxibrlBnazAashP8UGE"';
54 beforeEach(function () {
56 getHeader: sinon
.stub(),
59 eTag
= '"mtI0qCyqXsZVfX0Pgi+G6mQM10y9yVyi1NZejXSYttk"';
61 it('no headers, not cached', function () {
62 const result
= common
.isClientCached(req
, modifiedTimeMs
, eTag
);
63 assert
.strictEqual(result
, false);
65 it('modified header, not cached', function () {
66 req
.getHeader
.onCall(0).returns(blueMoon
);
67 modifiedTimeMs
= blueMoonMs
+ oneDayMs
;
68 const result
= common
.isClientCached(req
, modifiedTimeMs
, eTag
);
69 assert
.strictEqual(result
, false);
71 it('modified header, cached', function () {
72 req
.getHeader
.onCall(0).returns(blueMoon
);
73 modifiedTimeMs
= blueMoonMs
- oneDayMs
;
74 const result
= common
.isClientCached(req
, modifiedTimeMs
, eTag
);
75 assert
.strictEqual(result
, true);
77 it('match header, not matched', function () {
78 req
.getHeader
.onCall(1).returns(anotherETag
);
79 const result
= common
.isClientCached(req
, modifiedTimeMs
, eTag
);
80 assert
.strictEqual(result
, false);
82 it('match header, matched', function () {
83 req
.getHeader
.onCall(1).returns(`${anotherETag}, ${eTag}, ${anotherETag}`);
84 const result
= common
.isClientCached(req
, modifiedTimeMs
, eTag
);
85 assert
.strictEqual(result
, true);
87 it('match header any, matched', function () {
88 req
.getHeader
.onCall(1).returns('*');
89 const result
= common
.isClientCached(req
, modifiedTimeMs
, eTag
);
90 assert
.strictEqual(result
, true);
92 it('modified header cached, match header not matched, not cached', function () {
93 req
.getHeader
.onCall(0).returns(blueMoon
);
94 modifiedTimeMs
= blueMoonMs
- oneDayMs
;
95 req
.getHeader
.onCall(1).returns(`${anotherETag}, ${anotherETag}`);
96 const result
= common
.isClientCached(req
, modifiedTimeMs
, eTag
);
97 assert
.strictEqual(result
, false);
99 }); // iscClientCached
101 describe('pick', function () {
102 it('picks', function () {
108 const result
= common
.pick(srcObj
, ['a', 'c', 'd']);
109 assert
.deepStrictEqual(result
, {
116 describe('setOptions', function () {
117 it('sets options', function () {
124 const defaultOptions
= {
133 common
.setOptions(target
, defaultOptions
, options
);
134 assert
.deepStrictEqual(target
, expected
);
138 describe('splitFirst', function () {
139 it('splits', function () {
140 const expected
= ['foo', 'awoo'];
141 const src
= 'foo?awoo';
144 const result
= common
.splitFirst(src
, delim
, fill
);
145 assert
.deepStrictEqual(result
, expected
);
147 it('fills', function () {
148 const expected
= ['foo', 'fill'];
152 const result
= common
.splitFirst(src
, delim
, fill
);
153 assert
.deepStrictEqual(result
, expected
);
157 describe('mergeEnum', function () {
158 it('merges enums', function () {
161 TextHTML: 'text/html',
166 errorMessage: 'Bad Request',
172 TextPlain: 'text/plain',
177 errorMessage: 'Unauthorized',
187 TextHTML: 'text/html',
188 TextPlain: 'text/plain',
193 errorMessage: 'Bad Request',
197 errorMessage: 'Unauthorized',
205 const result
= common
.mergeEnum(origEnum
, newEnum
);
206 assert
.deepStrictEqual(result
, mergedEnum
);
210 describe('requestId', function () {
211 it('returns a string', function () {
212 const id
= common
.requestId();
213 assert
.strictEqual(typeof id
, 'string');
214 assert(id
.length
> 0);
218 describe('httpStatusCodeClass', function () {
219 it('works', function () {
220 for (const [statusCode
, statusClassExpected
] of Object
.entries({
226 const statusClass
= common
.httpStatusCodeClass(statusCode
);
227 assert
.strictEqual(statusClass
, statusClassExpected
);
230 }); // ensureLoggerLevels
232 describe('mergeDeep', function () {
233 it('simple merge', function () {
248 const result
= common
.mergeDeep(o1
, o2
, o3
);
249 assert
.deepStrictEqual(result
, expected
);
251 it('deep merge', function () {
279 myList: ['fancy', 'pants'],
290 const result
= common
.mergeDeep(o1
, o2
, o3
);
291 assert
.deepStrictEqual(result
, expected
);
293 it('merged object is distinct', function () {
312 const result
= common
.mergeDeep(o1
, o2
);
313 assert
.deepStrictEqual(result
, expected
);
324 assert
.deepStrictEqual(result
, expected2
);
325 assert
.strictEqual(o1
.foo
.bar
, 3);
326 assert
.strictEqual(o2
.baz
.quux
, 4);
330 describe('unfoldHeaderLines', function () {
331 it('folds', function () {
333 'Normal-Header: some header data',
334 'Folded-Header: more data',
335 ' second line of data',
336 ' third line of data',
339 'Normal-Header: some header data',
340 'Folded-Header: more data second line of data third line of data',
342 const result
= common
.unfoldHeaderLines(lines
);
343 assert
.deepStrictEqual(result
, expected
);
345 it('covers no input', function () {
346 const lines
= undefined;
347 const result
= common
.unfoldHeaderLines();
348 assert
.deepStrictEqual(result
, lines
);
350 }); // unfoldHeaderLines
352 describe('addCookie', function () {
353 let res
, name
, value
;
354 beforeEach(function () {
356 appendHeader: sinon
.stub(),
358 name
= 'someCookieName';
359 value
= 'someCookieValue';
361 it('covers no options', function () {
362 common
.addCookie(res
, name
, value
, {});
363 assert(res
.appendHeader
.called
);
365 it('covers all options', function () {
366 common
.addCookie(res
, name
, value
, {
367 domain: 'example.com',
374 extension: ['Mischief'],
376 assert(res
.appendHeader
.called
);
378 it('covers invalid expires', function () {
379 assert
.throws(() => common
.addCookie(res
, name
, value
, { expires: 'never' }), TypeError
);
381 it('covers invalid sameSite', function () {
382 assert
.throws(() => common
.addCookie(res
, name
, value
, { sameSite: 'Whatever' }), RangeError
);
384 it('covers invalid sameSite/secure setting', function () {
385 assert
.throws(() => common
.addCookie(res
, name
, value
, { sameSite: 'None', secure: false }), RangeError
);
387 it('covers invalid path', function () {
388 assert
.throws(() => common
.addCookie(res
, name
, value
, { path: '/bad;path' }), RangeError
);
390 it('covers invalid domain', function () {
391 assert
.throws(() => common
.addCookie(res
, name
, value
, { domain: 'a-.com' }), RangeError
);
393 it('covers invalid extension type', function () {
394 assert
.throws(() => common
.addCookie(res
, name
, value
, { extension: 'extension' }), TypeError
);
396 it('covers invalid extension', function () {
397 assert
.throws(() => common
.addCookie(res
, name
, value
, { extension: ['bad;extension'] }), RangeError
);
399 it('covers invalid name', function () {
401 assert
.throws(() => common
.addCookie(res
, name
, value
), RangeError
);
403 it('covers invalid value', function () {
405 assert
.throws(() => common
.addCookie(res
, name
, value
), RangeError
);
407 it('covers quoted value', function () {
409 common
.addCookie(res
, name
, value
);
410 assert(res
.appendHeader
.called
);
412 it('covers invalid quoted value', function () {
413 value
= '"bad;value"';
414 assert
.throws(() => common
.addCookie(res
, name
, value
), RangeError
);
416 it('covers no options', function () {
417 common
.addCookie(res
, name
, value
);
418 assert(res
.appendHeader
.called
);