initial release
[squeep-api-dingus] / test / lib / common.js
1 /* eslint-disable capitalized-comments */
2 /* eslint-env mocha */
3 'use strict';
4
5 const assert = require('assert');
6 const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
7 const common = require('../../lib/common');
8
9
10 describe('common', function () {
11
12 describe('fileScope', function () {
13 it('names a file path', function () {
14 const filename = 'lib/foo/bar.js';
15 const result = common.fileScope(filename)('baz');
16 assert.strictEqual(result, 'bar:baz');
17 });
18 it('names an index path', function () {
19 const filename = 'lib/foo/index.js';
20 const result = common.fileScope(filename)('baz');
21 assert.strictEqual(result, 'foo:baz');
22 });
23 }); // fileScope
24
25 describe('generateETag', function () {
26 it('generates a tag from data', function () {
27 const expected = '"RHUvNyculE/SyROjU0LqzN0arxibrlBnazAashP8UGE"';
28 const data = 'example data';
29 const result = common.generateETag(undefined, undefined, data);
30 assert.strictEqual(result, expected);
31 });
32 it('generates a tag from data and stats', function () {
33 const expected = '"mtI0qCyqXsZVfX0Pgi+G6mQM10y9yVyi1NZejXSYttk"';
34 const stat = {
35 mtimeMs: 1600113038270.2375,
36 };
37 const data = 'example data';
38 const result = common.generateETag(undefined, stat, data);
39 assert.strictEqual(result, expected);
40 });
41 }); // generateETag
42
43 describe('get', function () {
44 const def = 'default';
45 it('covers missing obj', function () {
46 const result = common.get(undefined, undefined, def);
47 assert.strictEqual(result, def);
48 });
49 it('covers missing prop', function () {
50 const result = common.get({}, undefined, def);
51 assert.strictEqual(result, def);
52 });
53 it('covers default', function () {
54 const result = common.get({ k: 'v' }, 'x', def);
55 assert.strictEqual(result, def);
56 });
57 it('covers prop', function () {
58 const result = common.get({ k: 'v' }, 'k', def);
59 assert.strictEqual(result, 'v');
60 });
61 }); // get
62
63 describe('isClientCached', function () {
64 let req, modifiedTimeMs, eTag;
65 const blueMoon = 'Sat, 31 Oct 2020 07:51:00 GMT';
66 const blueMoonMs = 1604130660000;
67 const oneDayMs = 86400000;
68 const anotherETag = '"RHUvNyculE/SyROjU0LqzN0arxibrlBnazAashP8UGE"';
69 beforeEach(function () {
70 req = {
71 getHeader: sinon.stub(),
72 };
73 modifiedTimeMs = 0;
74 eTag = '"mtI0qCyqXsZVfX0Pgi+G6mQM10y9yVyi1NZejXSYttk"';
75 });
76 it('no headers, not cached', function () {
77 const result = common.isClientCached(req, modifiedTimeMs, eTag);
78 assert.strictEqual(result, false);
79 });
80 it('modified header, not cached', function () {
81 req.getHeader.onCall(0).returns(blueMoon);
82 modifiedTimeMs = blueMoonMs + oneDayMs;
83 const result = common.isClientCached(req, modifiedTimeMs, eTag);
84 assert.strictEqual(result, false);
85 });
86 it('modified header, cached', function () {
87 req.getHeader.onCall(0).returns(blueMoon);
88 modifiedTimeMs = blueMoonMs - oneDayMs;
89 const result = common.isClientCached(req, modifiedTimeMs, eTag);
90 assert.strictEqual(result, true);
91 });
92 it('match header, not matched', function () {
93 req.getHeader.onCall(1).returns(anotherETag);
94 const result = common.isClientCached(req, modifiedTimeMs, eTag);
95 assert.strictEqual(result, false);
96 });
97 it('match header, matched', function () {
98 req.getHeader.onCall(1).returns(`${anotherETag}, ${eTag}, ${anotherETag}`);
99 const result = common.isClientCached(req, modifiedTimeMs, eTag);
100 assert.strictEqual(result, true);
101 });
102 it('match header any, matched', function () {
103 req.getHeader.onCall(1).returns('*');
104 const result = common.isClientCached(req, modifiedTimeMs, eTag);
105 assert.strictEqual(result, true);
106 });
107 it('modified header cached, match header not matched, not cached', function () {
108 req.getHeader.onCall(0).returns(blueMoon);
109 modifiedTimeMs = blueMoonMs - oneDayMs;
110 req.getHeader.onCall(1).returns(`${anotherETag}, ${anotherETag}`);
111 const result = common.isClientCached(req, modifiedTimeMs, eTag);
112 assert.strictEqual(result, false);
113 });
114 }); // iscClientCached
115
116 describe('pick', function () {
117 it('picks', function () {
118 const srcObj = {
119 a: 1,
120 b: 2,
121 c: 3,
122 };
123 const result = common.pick(srcObj, ['a', 'c', 'd']);
124 assert.deepStrictEqual(result, {
125 'a': 1,
126 'c': 3,
127 });
128 });
129 }); // pick
130
131 describe('requestLogData', function () {
132 it('gives data', function () {
133 const req = {
134 method: 'GET',
135 somethingElse: 'blah',
136 };
137 const result = common.requestLogData(req);
138 assert.deepStrictEqual(result, {
139 method: 'GET',
140 });
141 });
142 }); // requestLogData
143
144 describe('responseLogData', function () {
145 it('gives data', function () {
146 const res = {
147 getHeaders: () => ({}),
148 statusCode: 200,
149 blah: 'blah',
150 };
151 const result = common.responseLogData(res);
152 assert.deepStrictEqual(result, {
153 headers: {},
154 statusCode: 200,
155 });
156 });
157 }); // responseLogData
158
159 describe('setOptions', function () {
160 it('sets options', function () {
161 const expected = {
162 keyOne: 'default',
163 keyTwo: 'option',
164 keyThree: 'default',
165 };
166 const target = {};
167 const defaultOptions = {
168 keyOne: 'default',
169 keyTwo: 'default',
170 keyThree: 'default',
171 };
172 const options = {
173 keyTwo: 'option',
174 keyFour: 'option',
175 };
176 common.setOptions(target, defaultOptions, options);
177 assert.deepStrictEqual(target, expected);
178 });
179 }); // setOptions
180
181 describe('splitFirst', function () {
182 it('splits', function () {
183 const expected = ['foo', 'awoo'];
184 const src = 'foo?awoo';
185 const delim = '?';
186 const fill = 'fill';
187 const result = common.splitFirst(src, delim, fill);
188 assert.deepStrictEqual(result, expected);
189 });
190 it('fills', function () {
191 const expected = ['foo', 'fill'];
192 const src = 'foo';
193 const delim = '?';
194 const fill = 'fill';
195 const result = common.splitFirst(src, delim, fill);
196 assert.deepStrictEqual(result, expected);
197 });
198 }); // splitFirst
199
200 describe('mergeEnum', function () {
201 it('merges enums', function () {
202 const origEnum = {
203 ContentType: {
204 TextHTML: 'text/html',
205 },
206 ErrorResponse: {
207 BadRequest: {
208 statusCode: 400,
209 errorMessage: 'Bad Request',
210 },
211 },
212 };
213 const newEnum = {
214 ContentType: {
215 TextPlain: 'text/plain',
216 },
217 ErrorResponse: {
218 BadResponse: {
219 statusCode: 401,
220 errorMessage: 'Unauthorized',
221 },
222 },
223 Header: {
224 Accept: 'accept',
225 },
226 Value: 'value',
227 };
228 const mergedEnum = {
229 ContentType: {
230 TextHTML: 'text/html',
231 TextPlain: 'text/plain',
232 },
233 ErrorResponse: {
234 BadRequest: {
235 statusCode: 400,
236 errorMessage: 'Bad Request',
237 },
238 BadResponse: {
239 statusCode: 401,
240 errorMessage: 'Unauthorized',
241 },
242 },
243 Header: {
244 Accept: 'accept',
245 },
246 Value: 'value',
247 };
248 const result = common.mergeEnum(origEnum, newEnum);
249 assert.deepStrictEqual(result, mergedEnum);
250 });
251 }); // mergeEnum
252
253 describe('requestId', function () {
254 it('returns a string', function () {
255 const id = common.requestId();
256 assert.strictEqual(typeof id, 'string');
257 assert(id.length > 0);
258 });
259 }); // requestId
260
261
262 describe('ensureLoggerLevels', function () {
263 it('adds missing levels', function () {
264 const result = common.ensureLoggerLevels();
265 assert.deepStrictEqual(result, common.nullLogger);
266 });
267 }); // ensureLoggerLevels
268
269 describe('httpStatusCodeClass', function () {
270 it('works', function () {
271 for (const [statusCode, statusClassExpected] of Object.entries({
272 200: 2,
273 304: 3,
274 404: 4,
275 500: 5,
276 })) {
277 const statusClass = common.httpStatusCodeClass(statusCode);
278 assert.strictEqual(statusClass, statusClassExpected);
279 }
280 });
281 }); // ensureLoggerLevels
282
283 describe('mergeDeep', function () {
284 it('simple merge', function () {
285 const o1 = {
286 foo1: 'one',
287 };
288 const o2 = {
289 foo2: 'two',
290 };
291 const o3 = {
292 foo3: 'three',
293 };
294 const expected = {
295 foo1: 'one',
296 foo2: 'two',
297 foo3: 'three',
298 };
299 const result = common.mergeDeep(o1, o2, o3);
300 assert.deepStrictEqual(result, expected);
301 });
302 it('deep merge', function () {
303 const o1 = {
304 foo: {
305 quux: 1,
306 },
307 bar: 'baz',
308 };
309 const o2 = {
310 foo: {
311 myList: ['fancy'],
312 gleep: {
313 fraz: 2,
314 },
315 },
316 blah: 'frop',
317 };
318 const o3 = {
319 foo: {
320 myList: ['pants'],
321 gleep: {
322 troz: 'poit',
323 },
324 narf: 3,
325 },
326 bar: 'yup',
327 };
328 const expected = {
329 foo: {
330 myList: ['fancy', 'pants'],
331 gleep: {
332 fraz: 2,
333 troz: 'poit',
334 },
335 narf: 3,
336 quux: 1,
337 },
338 bar: 'yup',
339 blah: 'frop',
340 };
341 const result = common.mergeDeep(o1, o2, o3);
342 assert.deepStrictEqual(result, expected);
343 });
344 it('merged object is distinct', function () {
345 const o1 = {
346 foo: {
347 bar: 3,
348 },
349 };
350 const o2 = {
351 baz: {
352 quux: 4,
353 },
354 };
355 const expected = {
356 foo: {
357 bar: 3,
358 },
359 baz: {
360 quux: 4,
361 },
362 };
363 const result = common.mergeDeep(o1, o2);
364 assert.deepStrictEqual(result, expected);
365 const expected2 = {
366 foo: {
367 bar: 5,
368 },
369 baz: {
370 quux: 5,
371 },
372 };
373 result.foo.bar = 5;
374 result.baz.quux = 5;
375 assert.deepStrictEqual(result, expected2);
376 assert.strictEqual(o1.foo.bar, 3);
377 assert.strictEqual(o2.baz.quux, 4);
378 });
379 }); // mergeDeep
380
381 });