1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | import * as R from 'ramda';
|
13 | import * as f from './functions';
|
14 | import {Just} from 'folktale/maybe';
|
15 | import * as Result from 'folktale/result';
|
16 |
|
17 | import {of} from 'folktale/concurrency/task';
|
18 | import {fromPairsDeep} from './functions';
|
19 | import {replaceValuesAtDepth} from './functions';
|
20 | import {replaceValuesAtDepthAndStringify} from './functions';
|
21 | import {replaceValuesWithCountAtDepth} from './functions';
|
22 | import {mapObjToValues} from './functions';
|
23 | import {chainObjToValues} from './functions';
|
24 | import {flattenObj} from './functions';
|
25 | import {unflattenObj} from './functions';
|
26 | import {filterObjToValues} from './functions';
|
27 | import {overDeep} from './functions';
|
28 | import {keyStringToLensPath} from './functions';
|
29 | import {mapKeysAndValues} from './functions';
|
30 | import {omitDeep} from './functions';
|
31 | import {mergeDeepWithRecurseArrayItems} from './functions';
|
32 | import {omitDeepPaths} from './functions';
|
33 | import {pickDeepPaths} from './functions';
|
34 | import {splitAtInclusive} from './functions';
|
35 | import {reqStrPathThrowing} from './throwingFunctions';
|
36 | import {omitDeepBy} from './functions';
|
37 | import {eqPropsAll} from './functions';
|
38 | import {eqStrPath} from './functions';
|
39 | import {eqStrPathsAll} from './functions';
|
40 | import {toArrayIfNot} from './functions';
|
41 | import {unflattenObjNoArrays} from './functions';
|
42 | import {flattenObjUntil} from './functions';
|
43 | import {findMapped} from './functions';
|
44 | import {duplicateKey} from './functions';
|
45 | import {renameKey} from './functions';
|
46 | import {isObject} from './functions';
|
47 |
|
48 | describe('helperFunctions', () => {
|
49 | test('Should be empty', () => {
|
50 | expect(f.orEmpty(null)).toEqual('');
|
51 | });
|
52 |
|
53 | test('Should filter out null and undef values', () => {
|
54 | expect(f.compact([1, null, 2])).toEqual([1, 2]);
|
55 | });
|
56 |
|
57 | test('Should filter out null and empty values', () => {
|
58 | expect(f.compactEmpty(['', null, []])).toEqual([]);
|
59 | });
|
60 |
|
61 | test('emptyToNull', () => {
|
62 | expect(f.emptyToNull('')).toEqual(null);
|
63 | });
|
64 |
|
65 | test('compactJoin should compact and join', () => {
|
66 | expect(f.compactJoin('-', ['', 'a', null, 'b'])).toEqual('a-b');
|
67 | expect(f.compactJoin('-', ['', null])).toEqual(null);
|
68 | });
|
69 |
|
70 | test('Should map bars', () => {
|
71 | expect(f.mapProp('bar')([{bar: 1}, {bar: 2}])).toEqual([1, 2]);
|
72 | });
|
73 |
|
74 | test('Should map prop as key', () => {
|
75 | expect(f.mapPropValueAsIndex('bar')([{bar: 1}, {bar: 2}])).toEqual(R.indexBy(R.prop('bar'), [{bar: 1}, {bar: 2}]));
|
76 | });
|
77 |
|
78 | test('Should remove duplicate objects with same prop key', () => {
|
79 | expect(f.removeDuplicateObjectsByProp('bar')([{bar: 1, foo: 2}, {bar: 1, foo: 2}, {bar: 2}])).toEqual([{
|
80 | bar: 1,
|
81 | foo: 2
|
82 | }, {bar: 2}]);
|
83 | });
|
84 |
|
85 | test('Should return an id from an object or the identify from a value', () => {
|
86 | expect(f.idOrIdFromObj('foo')).toEqual('foo');
|
87 | expect(f.idOrIdFromObj({id: 'foo'})).toEqual('foo');
|
88 | });
|
89 |
|
90 | test('Should deep merge objects', () => {
|
91 | expect(f.mergeDeep(
|
92 | {foo: 1, bar: {bizz: [2, 3], buzz: 7}},
|
93 | {foo: 4, bar: {bizz: [5, 6]}}
|
94 | )).toEqual({foo: 4, bar: {bizz: [5, 6], buzz: 7}});
|
95 | });
|
96 |
|
97 | test('Should deep merge objects with a function', () => {
|
98 | expect(f.mergeDeepWith(
|
99 | (l, r) => R.when(
|
100 | R.is(Number),
|
101 | R.add(l)
|
102 | )(r),
|
103 | {foo: 1, bar: {bizz: [2, 3], buzz: 7}},
|
104 | {foo: 4, bar: {bizz: [5, 6]}}
|
105 | )).toEqual({foo: 5, bar: {bizz: [5, 6], buzz: 7}});
|
106 | });
|
107 |
|
108 | test('Should deep merge objects and concat arrays of matching keys', () => {
|
109 | expect(f.mergeDeepWithConcatArrays(
|
110 | {foo: 1, bar: {bizz: [2, 3], buzz: 7}},
|
111 | {foo: 4, bar: {bizz: [5, 6]}}
|
112 | )).toEqual({foo: 4, bar: {bizz: [2, 3, 5, 6], buzz: 7}});
|
113 | });
|
114 |
|
115 | test('mergeDeepWithRecurseArrayItems', () => {
|
116 | expect(f.mergeDeepWithRecurseArrayItems(
|
117 | (l, r) => R.when(
|
118 | R.is(Number),
|
119 | R.add(l)
|
120 | )(r),
|
121 | {foo: 1, bar: {bizz: [2, {brewer: 9}], buzz: 7}},
|
122 | {foo: 4, bar: {bizz: [5, {brewer: 10}]}}
|
123 | )).toEqual({foo: 5, bar: {bizz: [7, {brewer: 19}], buzz: 7}});
|
124 | });
|
125 |
|
126 |
|
127 | test('mergeDeepWithRecurseArrayItemsByRight', () => {
|
128 | expect(f.mergeDeepWithRecurseArrayItemsByRight(
|
129 | (v, k) => R.when(isObject, R.propOr(v, 'id'))(v),
|
130 | {foo: 1, bar: {bizz: [{buddy: 2, id: 2, cow: 4}, {brewer: 9}], buzz: 7}},
|
131 | {foo: 4, bar: {bizz: [5, {buddy: 10, id: 2, snippy: 1}]}}
|
132 | )).toEqual({foo: 4, bar: {bizz: [5, {buddy: 10, id: 2, cow: 4, snippy: 1}], buzz: 7}});
|
133 | });
|
134 |
|
135 | test('mergeDeepWithRecurseArrayItemsByAndMergeObjectByRight', () => {
|
136 | const itemMatchBy = (v, k) => R.when(isObject, R.propOr(v, 'id'))(v);
|
137 | const renameSnippy = (left, right) => {
|
138 |
|
139 | const rename = renameKey(R.lensPath([]), 'snippy', 'snappy');
|
140 | return R.mergeWithKey(
|
141 | (kk, ll, rr) => {
|
142 | return f.mergeDeepWithRecurseArrayItemsByAndMergeObjectByRight(
|
143 | itemMatchBy,
|
144 | renameSnippy,
|
145 | ll,
|
146 | rr,
|
147 | kk
|
148 | );
|
149 | },
|
150 | rename(left),
|
151 | rename(right)
|
152 | );
|
153 | };
|
154 | expect(f.mergeDeepWithRecurseArrayItemsByAndMergeObjectByRight(
|
155 | itemMatchBy,
|
156 | renameSnippy,
|
157 | {foo: 1, bar: {bizz: [{buddy: 2, id: 2, cow: 4}, {brewer: 9}], buzz: 7}},
|
158 | {foo: 4, bar: {bizz: [5, {buddy: 10, id: 2, snippy: 1}]}}
|
159 | )).toEqual({foo: 4, bar: {bizz: [5, {buddy: 10, id: 2, cow: 4, snappy: 1}], buzz: 7}});
|
160 | });
|
161 |
|
162 | test('mergeDeepWithRecurseArrayItemsByRightHandlNull', () => {
|
163 | expect(f.mergeDeepWithRecurseArrayItemsByRight(
|
164 | () => {
|
165 | },
|
166 | {fever: 1},
|
167 | null
|
168 | )).toEqual({fever: 1});
|
169 |
|
170 | expect(f.mergeDeepWithRecurseArrayItemsByRight(
|
171 | () => {
|
172 | },
|
173 | [1],
|
174 | null
|
175 | )).toEqual([1]);
|
176 | });
|
177 |
|
178 | test('mergeDeepWithRecurseArrayItemsAndMapObjs', () => {
|
179 | expect(f.mergeDeepWithRecurseArrayItemsAndMapObjs(
|
180 | (l, r) => R.when(
|
181 | R.is(Number),
|
182 | R.add(l)
|
183 | )(r),
|
184 | (key, obj) => R.merge({key: R.toUpper(key.toString())}, obj),
|
185 | {foo: 1, bar: {bizz: [2, {brewer: 9}], buzz: 7}},
|
186 | {foo: 4, bar: {bizz: [5, {brewer: 10}]}}
|
187 | )).toEqual({foo: 5, bar: {key: 'BAR', bizz: [7, {brewer: 19, key: 'BIZZ'}], buzz: 7}});
|
188 | });
|
189 |
|
190 | test('Should merge deep all objects', () => {
|
191 | expect(f.mergeDeepAll([
|
192 | {foo: 1, bar: {bizz: [2, 3], buzz: 7}},
|
193 | {foo: 4, bar: {bizz: [5, 6]}},
|
194 | {foo: 4, bar: {cat: [5, 6], pterodactyl: 'time is running out!'}}
|
195 | ])).toEqual(
|
196 | {foo: 4, bar: {bizz: [5, 6], buzz: 7, cat: [5, 6], pterodactyl: 'time is running out!'}}
|
197 | );
|
198 | });
|
199 |
|
200 | test('Should capitalize first letter', () => {
|
201 | expect(f.capitalize('good grief')).toEqual('Good grief');
|
202 | });
|
203 |
|
204 | test('Required path', () => {
|
205 | expect(f.reqPath(['a'], {a: 1}).value).toBe(1);
|
206 | expect(f.reqPath(['a', 'b'], {a: {c: 1}}).value).toEqual({
|
207 | resolved: ['a'],
|
208 | path: ['a', 'b']
|
209 | });
|
210 | });
|
211 |
|
212 | test('reqStrPath', () => {
|
213 | expect(f.reqStrPath('foo.bar.goo', {
|
214 | foo: {
|
215 | bar: {
|
216 | goo: 1
|
217 | }
|
218 | }
|
219 | })).toEqual(Result.Ok(1));
|
220 |
|
221 | expect(f.reqStrPath('foo.bar.goo', {
|
222 | foo: {
|
223 | car: {
|
224 | goo: 1
|
225 | }
|
226 | }
|
227 | })).toEqual(Result.Error(
|
228 | {
|
229 | resolved: ['foo'],
|
230 | path: ['foo', 'bar', 'goo']
|
231 | })
|
232 | );
|
233 | });
|
234 |
|
235 | test('strPath', () => {
|
236 | expect(f.strPath('foo.bar.goo', {
|
237 | foo: {
|
238 | bar: {
|
239 | goo: 1
|
240 | }
|
241 | }
|
242 | })).toEqual(1);
|
243 |
|
244 | expect(typeof f.strPath('foo.bar.goo', {
|
245 | foo: {
|
246 | car: {
|
247 | goo: 1
|
248 | }
|
249 | }
|
250 | })).toEqual('undefined');
|
251 | });
|
252 |
|
253 | test('strPathOr', () => {
|
254 | expect(f.strPathOr(1, 'tan.khaki.pants', {tan: {khaki: {pants: false}}})).toEqual(false);
|
255 | expect(f.strPathOr(1, 'tan.khaki.blazer', {tan: {khaki: {pants: false}}})).toEqual(1);
|
256 | });
|
257 |
|
258 | test('strPathOrNullOk', () => {
|
259 | expect(f.strPathOrNullOk(1, 'tan.khaki.pants', {tan: {khaki: {pants: null}}})).toEqual(null);
|
260 | expect(f.strPathOrNullOk(1, 'tan.khaki.blazer', {tan: {khaki: {pants: false}}})).toEqual(1);
|
261 | expect(f.strPathOrNullOk(1, 'tan.khaki.blazer', {tan: {khaki: 'cabbage'}})).toEqual(1);
|
262 | });
|
263 |
|
264 | test('hasStrPath', () => {
|
265 | expect(f.hasStrPath('tan.khaki.pants', {tan: {khaki: {pants: false}}})).toEqual(true);
|
266 | expect(f.hasStrPath('tan.khaki.blazer', {tan: {khaki: {pants: false}}})).toEqual(false);
|
267 | });
|
268 |
|
269 | test('Required path prop equals', () => {
|
270 | expect(f.reqPathPropEq(['a'], 1, {a: 1}).value).toBe(true);
|
271 | expect(f.reqPathPropEq(['a', 'b'], 1, {a: {c: 1}}).value).toEqual({
|
272 | resolved: ['a'],
|
273 | path: ['a', 'b']
|
274 | });
|
275 | });
|
276 |
|
277 | test('Should merge all with key', () => {
|
278 | expect(
|
279 | f.mergeAllWithKey(
|
280 | (k, l, r) => k === 'a' ? R.concat(l, r) : r,
|
281 | [{a: [1], b: 2}, {a: [2], c: 3}, {a: [3]}]
|
282 | )).toEqual({a: [1, 2, 3], b: 2, c: 3});
|
283 | });
|
284 |
|
285 | test('Should reqPath of object', () => {
|
286 | expect(
|
287 | f.reqPath(['a', 'b', 1, 'c'], {a: {b: [null, {c: 2}]}})
|
288 | ).toEqual(Result.Ok(2));
|
289 | });
|
290 |
|
291 | test('mapKeys', () => {
|
292 | expect(f.mapKeys(
|
293 | key => `${f.capitalize(key)} Taco`,
|
294 | {fish: 'good', puppy: 'bad'})
|
295 | ).toEqual(
|
296 | {['Fish Taco']: 'good', ['Puppy Taco']: 'bad'}
|
297 | );
|
298 | });
|
299 |
|
300 | test('mapKeysForLens', () => {
|
301 | expect(f.mapKeysForLens(
|
302 | R.lensPath(['x', 1, 'y']),
|
303 | key => `${f.capitalize(key)} Taco`,
|
304 | {x: [null, {y: {fish: 'good', puppy: 'bad'}}]}
|
305 | )
|
306 | ).toEqual(
|
307 | {x: [null, {y: {['Fish Taco']: 'good', ['Puppy Taco']: 'bad'}}]}
|
308 | );
|
309 | });
|
310 |
|
311 | test('mapDefault should rename the default import', () => {
|
312 | expect(f.mapDefault('friend', {default: 'foo', other: 'boo'})).toEqual(
|
313 | {friend: 'foo', other: 'boo'}
|
314 | );
|
315 | });
|
316 |
|
317 | test('mapDefaultAndPrefixOthers should rename the default and prefix others', () => {
|
318 | expect(f.mapDefaultAndPrefixOthers('friend', 'prefix', {default: 'foo', other: 'boo'})).toEqual(
|
319 | {friend: 'foo', prefixOther: 'boo'}
|
320 | );
|
321 | });
|
322 |
|
323 | test('transformKeys', () => {
|
324 | expect(f.transformKeys(
|
325 | f.camelCase,
|
326 | {
|
327 | who_made_me_with_slugs: 'the snail',
|
328 | 'what-kind-of-camel-Races': 'a dromedary'
|
329 | }
|
330 | )).toEqual(
|
331 | {
|
332 | whoMadeMeWithSlugs: 'the snail',
|
333 | whatKindOfCamelRaces: 'a dromedary'
|
334 | }
|
335 | );
|
336 | });
|
337 |
|
338 | test('renameKey', () => {
|
339 | expect(
|
340 | f.renameKey(R.lensPath(['x', 'y']), 'z', 'and per se', {x: {y: {z: {cactus: 'blossoms'}}}})
|
341 | ).toEqual(
|
342 | {x: {y: {'and per se': {cactus: 'blossoms'}}}}
|
343 | );
|
344 | });
|
345 |
|
346 | test('duplicateKey', () => {
|
347 | expect(
|
348 | f.duplicateKey(R.lensPath(['x', 'y']), 'z', ['and per se', 'a per se', 'o per se'], {x: {y: {z: {cactus: 'blossoms'}}}})
|
349 | ).toEqual(
|
350 | {
|
351 | x: {
|
352 | y: {
|
353 | z: {cactus: 'blossoms'},
|
354 | 'and per se': {cactus: 'blossoms'},
|
355 | 'a per se': {cactus: 'blossoms'},
|
356 | 'o per se': {cactus: 'blossoms'}
|
357 | }
|
358 | }
|
359 | }
|
360 | );
|
361 | expect(
|
362 | f.duplicateKey(R.lensPath(['x', 'y']), 'z', 'and per se', {x: {y: {z: {cactus: 'blossoms'}}}})
|
363 | ).toEqual(
|
364 | {
|
365 | x: {
|
366 | y: {
|
367 | z: {cactus: 'blossoms'},
|
368 | 'and per se': {cactus: 'blossoms'}
|
369 | }
|
370 | }
|
371 | }
|
372 | );
|
373 | });
|
374 |
|
375 | test('moveToKeys', () => {
|
376 | expect(
|
377 | f.moveToKeys(R.lensPath(['x', 'y']), 'z', ['and per se', 'a per se', 'o per se'], {x: {y: {z: {cactus: 'blossoms'}}}})
|
378 | ).toEqual(
|
379 | {
|
380 | x: {
|
381 | y: {
|
382 | 'and per se': {cactus: 'blossoms'},
|
383 | 'a per se': {cactus: 'blossoms'},
|
384 | 'o per se': {cactus: 'blossoms'}
|
385 | }
|
386 | }
|
387 | }
|
388 | );
|
389 | });
|
390 |
|
391 | test('findOne', () => {
|
392 |
|
393 | expect(
|
394 | f.findOne(R.equals('Eli Whitney'), {a: 1, b: 'Eli Whitney'})
|
395 | ).toEqual(
|
396 | Result.Ok({b: 'Eli Whitney'})
|
397 | );
|
398 |
|
399 |
|
400 | expect(
|
401 | f.findOne(R.equals('Eli Whitney'), [1, 'Eli Whitney'])
|
402 | ).toEqual(
|
403 | Result.Ok(['Eli Whitney'])
|
404 | );
|
405 |
|
406 |
|
407 | expect(
|
408 | f.findOne(R.equals('Eli Whitney'), {a: 1, b: 2})
|
409 | ).toEqual(
|
410 | Result.Error({all: {a: 1, b: 2}, matching: {}})
|
411 | );
|
412 |
|
413 |
|
414 | expect(
|
415 | f.findOne(R.equals('Eli Whitney'), {a: 'Eli Whitney', b: 'Eli Whitney'})
|
416 | ).toEqual(
|
417 | Result.Error({all: {a: 'Eli Whitney', b: 'Eli Whitney'}, matching: {a: 'Eli Whitney', b: 'Eli Whitney'}})
|
418 | );
|
419 | });
|
420 |
|
421 | test('onlyOne', () => {
|
422 | expect(f.onlyOne({a: 'Eli Whitney'})).toEqual(Result.Ok({a: 'Eli Whitney'}));
|
423 |
|
424 |
|
425 | expect(
|
426 | f.onlyOne({})
|
427 | ).toEqual(
|
428 | Result.Error({all: {}, matching: {}})
|
429 | );
|
430 |
|
431 |
|
432 | expect(
|
433 | f.onlyOne({a: 'Eli Whitney', b: 'Eli Whitney'})
|
434 | ).toEqual(
|
435 | Result.Error({all: {a: 'Eli Whitney', b: 'Eli Whitney'}, matching: {a: 'Eli Whitney', b: 'Eli Whitney'}})
|
436 | );
|
437 | });
|
438 |
|
439 | test('onlyOneValue', () => {
|
440 | expect(f.onlyOneValue({a: 'Eli Whitney'})).toEqual(Result.Ok('Eli Whitney'));
|
441 |
|
442 |
|
443 | expect(
|
444 | f.onlyOneValue({})
|
445 | ).toEqual(
|
446 | Result.Error({all: {}, matching: {}})
|
447 | );
|
448 |
|
449 |
|
450 | expect(
|
451 | f.onlyOneValue({a: 'Eli Whitney', b: 'Eli Whitney'})
|
452 | ).toEqual(
|
453 | Result.Error({all: {a: 'Eli Whitney', b: 'Eli Whitney'}, matching: {a: 'Eli Whitney', b: 'Eli Whitney'}})
|
454 | );
|
455 | });
|
456 |
|
457 | test('mapToObjValue', () => {
|
458 | expect(f.mapToObjValue(R.compose(f.camelCase, R.toLower), ['MY', 'SHOES_FIT'])).toEqual({
|
459 | MY: 'my',
|
460 | SHOES_FIT: 'shoesFit'
|
461 | });
|
462 | });
|
463 |
|
464 | test('findOneValueByParams', () => {
|
465 | const items = [
|
466 | {brand: 'crush', flavor: 'grape'},
|
467 | {brand: 'fanta', flavor: 'strawberry'},
|
468 | {brand: 'crush', flavor: 'orange'}
|
469 | ];
|
470 | const params = {brand: 'crush', flavor: 'orange'};
|
471 | expect(f.findOneValueByParams(params, items)).toEqual(
|
472 | Result.Ok({brand: 'crush', flavor: 'orange'})
|
473 | );
|
474 | const badParams = {brand: 'crush', flavor: 'pretzel'};
|
475 | expect(f.findOneValueByParams(badParams, items)).toEqual(
|
476 | Result.Error(
|
477 | {
|
478 | all: [{brand: 'crush', flavor: 'grape'}, {
|
479 | brand: 'fanta',
|
480 | flavor: 'strawberry'
|
481 | }, {brand: 'crush', flavor: 'orange'}], matching: []
|
482 | }
|
483 | )
|
484 | );
|
485 | const tooGoodParams = {brand: 'crush'};
|
486 | expect(f.findOneValueByParams(tooGoodParams, items)).toEqual(
|
487 | Result.Error(
|
488 | {
|
489 | all: [{brand: 'crush', flavor: 'grape'}, {
|
490 | brand: 'fanta',
|
491 | flavor: 'strawberry'
|
492 | }, {brand: 'crush', flavor: 'orange'}],
|
493 | matching: [{brand: 'crush', flavor: 'grape'}, {brand: 'crush', flavor: 'orange'}]
|
494 | }
|
495 | )
|
496 | );
|
497 | });
|
498 |
|
499 | test('findByParams', () => {
|
500 | const items = [
|
501 | {brand: 'crush', flavor: 'grape'},
|
502 | {brand: 'fanta', flavor: 'strawberry'},
|
503 | {brand: 'crush', flavor: 'orange'}
|
504 | ];
|
505 | const params = {brand: 'crush', flavor: 'orange'};
|
506 | expect(f.findByParams(params, items)).toEqual(
|
507 | [{brand: 'crush', flavor: 'orange'}]
|
508 | );
|
509 | const badParams = {brand: 'crush', flavor: 'pretzel'};
|
510 | expect(f.findByParams(badParams, items)).toEqual(
|
511 | []
|
512 | );
|
513 | const tooGoodParams = {brand: 'crush'};
|
514 | expect(f.findByParams(tooGoodParams, items)).toEqual(
|
515 | [
|
516 | {brand: 'crush', flavor: 'grape'},
|
517 | {brand: 'crush', flavor: 'orange'}
|
518 | ]
|
519 | );
|
520 |
|
521 | const objs = {a: {foo: 1}, b: {foo: 2}};
|
522 | expect(f.findByParams({foo: 2}, objs)).toEqual({b: {foo: 2}});
|
523 | });
|
524 |
|
525 | test('findMapped', () => {
|
526 | expect(findMapped(R.prop('fri'), [{a: 1}, {b: 2}, {fri: 0}, {fi: 'willy'}, {fra: 4}])).toEqual(0);
|
527 | });
|
528 |
|
529 | test('alwaysFunc', () => {
|
530 | const alwaysIWannaFuncWithYou = R.identity;
|
531 | const str = 'and make believe with you';
|
532 | expect(f.alwaysFunc(alwaysIWannaFuncWithYou)('and live in harmony')).toEqual('and live in harmony');
|
533 | expect(f.alwaysFunc(str)(1, 1, 'was', 'a racehorse')).toEqual(str);
|
534 | });
|
535 |
|
536 | test('mapKeysAndValues', () => {
|
537 | const obj = {neun: 'und_neinzig', luft: 'balons'};
|
538 | expect(f.mapKeysAndValues((v, k) => [f.capitalize(k), f.camelCase(v)], obj)).toEqual(
|
539 | {Neun: 'undNeinzig', Luft: 'balons'}
|
540 | );
|
541 | });
|
542 |
|
543 | test('fromPairsDeep', () => {
|
544 |
|
545 | const deepPairs = [
|
546 | 'Here',
|
547 | 'come',
|
548 | 'some',
|
549 | 'pairs:',
|
550 |
|
551 | [
|
552 | ['I', [
|
553 | ['A', [
|
554 | ['i', [
|
555 |
|
556 | ['a', [1, 1, 'was', 'a', 'racehorse']],
|
557 | ['b', [2, 2, 'was', 1, 2]],
|
558 | ['c', {'I\'m': 'already an object!'}]
|
559 | ]],
|
560 | ['ii', [
|
561 | ['d', 4],
|
562 | ['e', 5],
|
563 | ['f', 6]
|
564 | ]]
|
565 | ]]
|
566 | ]]
|
567 | ]
|
568 | ];
|
569 | expect(fromPairsDeep(deepPairs)).toEqual(
|
570 | [
|
571 | 'Here',
|
572 | 'come',
|
573 | 'some',
|
574 | 'pairs:',
|
575 | {
|
576 | I: {
|
577 | A: {
|
578 | i: {
|
579 | a: [1, 1, 'was', 'a', 'racehorse'],
|
580 | b: [2, 2, 'was', 1, 2],
|
581 | c: {'I\'m': 'already an object!'}
|
582 | },
|
583 | ii: {
|
584 | d: 4,
|
585 | e: 5,
|
586 | f: 6
|
587 | }
|
588 | }
|
589 | }
|
590 | }
|
591 | ]
|
592 | );
|
593 | |
594 |
|
595 |
|
596 |
|
597 |
|
598 |
|
599 |
|
600 |
|
601 |
|
602 |
|
603 |
|
604 |
|
605 |
|
606 |
|
607 |
|
608 | });
|
609 |
|
610 | test('replaceValuesAtDepth', () => {
|
611 |
|
612 | expect(
|
613 | replaceValuesAtDepth(3, '...', {a: {A: {å: 1}, kitty: 2}})
|
614 | ).toEqual({a: {A: {å: '...'}, kitty: 2}});
|
615 | expect(
|
616 | replaceValuesAtDepth(2, '...', {a: {A: {å: 1}}, kitty: 2})
|
617 | ).toEqual({a: {A: '...'}, kitty: 2});
|
618 | expect(
|
619 | replaceValuesAtDepth(1, '...', {a: {A: {å: 1}}})
|
620 | ).toEqual({a: '...'});
|
621 | expect(
|
622 | replaceValuesAtDepth(0, '...', {a: {A: {å: 1}}})
|
623 | ).toEqual('...');
|
624 |
|
625 |
|
626 | expect(replaceValuesAtDepth(2, '...', [['A', ['a']], 'b'])).toEqual([['...', '...'], 'b']);
|
627 |
|
628 |
|
629 | expect(
|
630 | replaceValuesAtDepth(3, R.when(isObject, R.compose(R.length, R.keys)), {
|
631 | a: {
|
632 | A: {
|
633 | å: [1, 2, 3],
|
634 | moo: {cow: 'yes', sheep: 'no'},
|
635 | ø: 'æ'
|
636 | }, kitty: 2
|
637 | }
|
638 | })
|
639 | ).toEqual({a: {A: {å: 3, moo: 2, ø: 'æ'}, kitty: 2}});
|
640 | });
|
641 |
|
642 | test('replaceValuesWithCountAtDepth', () => {
|
643 | expect(
|
644 | replaceValuesWithCountAtDepth(3, {a: {A: {å: [1, 2, 3], moo: {cow: 'yes', sheep: 'no'}, ø: 'æ'}, kitty: 2}})
|
645 | ).toEqual({a: {A: {å: '[...3]', moo: '{...2}', ø: 'æ'}, kitty: 2}});
|
646 | });
|
647 |
|
648 | test('replaceValuesAtDepthAndStringify', () => {
|
649 | expect(
|
650 | replaceValuesAtDepthAndStringify(3, '...', {a: {A: {å: 1}}})
|
651 | ).toEqual('{"a":{"A":{"å":"..."}}}');
|
652 | });
|
653 |
|
654 | test('mapObjToValues', () => {
|
655 |
|
656 | expect(mapObjToValues(R.ap([R.add(1)]), {a: [1], b: [2, 3]})).toEqual([[2], [3, 4]]);
|
657 | });
|
658 |
|
659 | test('filterObjToValues', () => {
|
660 |
|
661 | expect(filterObjToValues((v, k) => k !== 'toto', {dorothy: 1, toto: 2})).toEqual([1]);
|
662 | });
|
663 |
|
664 | test('chainObjToValues', () => {
|
665 |
|
666 | expect(chainObjToValues(R.ap([R.concat([1])]), {
|
667 | a: [[1]],
|
668 | b: [[2, 3], [4, 5]]
|
669 | })).toEqual([[1, 1], [1, 2, 3], [1, 4, 5]]);
|
670 | });
|
671 |
|
672 | test('flattenObj', () => {
|
673 | expect(flattenObj({a: 1})).toEqual({a: 1});
|
674 | expect(flattenObj({a: 1, b: {johnny: 'b good'}})).toEqual({a: 1, 'b.johnny': 'b good'});
|
675 | expect(flattenObj(
|
676 | {a: 1, b: {johnny: 'b good', sam: [1, 2, 3]}}
|
677 | )).toEqual(
|
678 | {a: 1, 'b.johnny': 'b good', 'b.sam.0': 1, 'b.sam.1': 2, 'b.sam.2': 3}
|
679 | );
|
680 | expect(flattenObj([1, 2, 3])).toEqual({0: 1, 1: 2, 2: 3});
|
681 | });
|
682 |
|
683 | test('flattenObjUntil', () => {
|
684 | expect(flattenObjUntil(R.propOr(false, 'cow'),
|
685 | {a: 1, b: {johnny: 'b good', c: {cow: {pie: true}}, sam: [1, 2, 3]}}
|
686 | )).toEqual(
|
687 | {a: 1, 'b.johnny': 'b good', 'b.c': {cow: {pie: true}}, 'b.sam.0': 1, 'b.sam.1': 2, 'b.sam.2': 3}
|
688 | );
|
689 |
|
690 | expect(flattenObjUntil(Array.isArray,
|
691 | {a: 1, b: {johnny: 'b good', sam: [1, 2, 3]}}
|
692 | )).toEqual(
|
693 | {a: 1, 'b.johnny': 'b good', 'b.sam': [1, 2, 3]}
|
694 | );
|
695 | });
|
696 |
|
697 | test('unflattenObj', () => {
|
698 | const pancake = R.compose(unflattenObj, flattenObj);
|
699 | const x = [
|
700 | {
|
701 | id: '2226274',
|
702 | country: 'Norway'
|
703 | }
|
704 | ];
|
705 | expect(pancake(x)).toEqual(x);
|
706 |
|
707 | expect(pancake({a: 1})).toEqual({a: 1});
|
708 | expect(pancake({a: 1, b: {johnny: 'b good'}})).toEqual({a: 1, b: {johnny: 'b good'}});
|
709 | expect(pancake({a: 1, b: {johnny: 'b good', sam: [1, 2, 3]}})).toEqual(
|
710 | {a: 1, b: {johnny: 'b good', sam: [1, 2, 3]}}
|
711 | );
|
712 | });
|
713 |
|
714 | test('unflattenObjNoArrays', () => {
|
715 | const pancake = R.compose(unflattenObjNoArrays, flattenObj);
|
716 | const x = [
|
717 | {
|
718 | id: '2226274',
|
719 | country: 'Norway'
|
720 | }
|
721 | ];
|
722 | expect(pancake(x)).toEqual({0: x[0]});
|
723 |
|
724 | expect(pancake({a: 1})).toEqual({a: 1});
|
725 | expect(pancake({a: 1, b: {johnny: 'b good'}})).toEqual({a: 1, b: {johnny: 'b good'}});
|
726 | expect(pancake({a: 1, b: {johnny: 'b good', sam: [1, 2, 3]}})).toEqual(
|
727 | {a: 1, b: {johnny: 'b good', sam: {0: 1, 1: 2, 2: 3}}}
|
728 | );
|
729 | });
|
730 |
|
731 |
|
732 | test('overDeep', () => {
|
733 | const res = overDeep(
|
734 | (k, v) => R.merge({butter: `${R.toUpper(k.toString())} Butter`})(v),
|
735 | {
|
736 | peanut: {
|
737 | almond: {
|
738 | cashew: {
|
739 | brazilNut: {}
|
740 | },
|
741 | filbert: [
|
742 | {
|
743 | walnut: {},
|
744 | pecan: {}
|
745 | }
|
746 | ]
|
747 | }
|
748 | }
|
749 | }
|
750 | );
|
751 | expect(res.peanut.almond.cashew.brazilNut).toEqual({butter: 'BRAZILNUT Butter'});
|
752 | expect(res.peanut.almond.butter).toEqual('ALMOND Butter');
|
753 | });
|
754 |
|
755 | test('omitDeepBy', () => {
|
756 | const whatTheFunc = () => {
|
757 | return 'what the func';
|
758 | };
|
759 | const res = omitDeepBy(
|
760 | (k, v) => R.startsWith('_')(k),
|
761 | {
|
762 | peanut: {
|
763 | almond: {
|
764 | cashew: {
|
765 | _brazilNut: {},
|
766 | pecan: [
|
767 | {are: {the: {_best: true}}}
|
768 | ]
|
769 | },
|
770 | _filbert: [
|
771 | {
|
772 | walnut: {}
|
773 | }
|
774 | ]
|
775 | }
|
776 | },
|
777 | funkyNut: {
|
778 | wingnut: 'yes',
|
779 | cornnut: whatTheFunc
|
780 | }
|
781 | }
|
782 | );
|
783 | expect(res).toEqual({
|
784 | peanut: {
|
785 | almond: {
|
786 | cashew: {
|
787 | pecan: [
|
788 | {are: {the: {}}}
|
789 | ]
|
790 | }
|
791 | }
|
792 | },
|
793 | funkyNut: {
|
794 | wingnut: 'yes',
|
795 | cornnut: whatTheFunc
|
796 | }
|
797 | });
|
798 | const res2 = omitDeepBy(
|
799 | (k, v) => R.startsWith('_')(k),
|
800 | {
|
801 | _peanut: {
|
802 | almond: {
|
803 | cashew: {
|
804 | _brazilNut: {}
|
805 | },
|
806 | _filbert: [
|
807 | {
|
808 | walnut: {},
|
809 | pecan: {}
|
810 | }
|
811 | ]
|
812 | }
|
813 | }
|
814 | }
|
815 | );
|
816 | expect(res2).toEqual({});
|
817 | });
|
818 |
|
819 | test('omitDeepByNullsStayNull', () => {
|
820 | const obj = {
|
821 | viewport: {
|
822 | latitude: null,
|
823 | longitude: null,
|
824 | zoom: 1
|
825 | }
|
826 | };
|
827 | expect(omitDeepBy(R.startsWith('_'), obj)).toEqual(
|
828 | obj
|
829 | );
|
830 | });
|
831 |
|
832 | test('keyStringToLensPath', () => {
|
833 | expect(keyStringToLensPath('foo.bar.0.wopper')).toEqual(['foo', 'bar', 0, 'wopper']);
|
834 | });
|
835 |
|
836 | test('omitDeep', () => {
|
837 | |
838 |
|
839 |
|
840 |
|
841 |
|
842 |
|
843 |
|
844 |
|
845 |
|
846 |
|
847 |
|
848 | const tricky = {
|
849 | urlObjSpots: [],
|
850 | location: {},
|
851 | routeResponses: [
|
852 | {
|
853 | status: 200,
|
854 | headers: {
|
855 | 'content-type': 'application/json; charset=UTF-8',
|
856 | date: 'Tue, 28 May 2019 13:22:04 GMT',
|
857 | expires: 'Wed, 29 May 2019 13:22:04 GMT',
|
858 | 'cache-control': 'public, max-age=86400',
|
859 | server: 'mafe',
|
860 | 'x-xss-protection': '0',
|
861 | 'x-frame-options': 'SAMEORIGIN',
|
862 | 'server-timing': 'gfet4t7; dur=57',
|
863 | 'alt-svc': 'quic=":443"; ma=2592000; v="46,44,43,39"',
|
864 | 'accept-ranges': 'none',
|
865 | vary: 'Accept-Language,Accept-Encoding',
|
866 | connection: 'close'
|
867 | }
|
868 | },
|
869 | {
|
870 | status: 200,
|
871 | headers: {
|
872 | 'content-type': 'application/json; charset=UTF-8',
|
873 | date: 'Tue, 28 May 2019 13:22:04 GMT',
|
874 | expires: 'Wed, 29 May 2019 13:22:04 GMT',
|
875 | 'cache-control': 'public, max-age=86400',
|
876 | server: 'mafe',
|
877 | 'x-xss-protection': '0',
|
878 | 'x-frame-options': 'SAMEORIGIN',
|
879 | 'server-timing': 'gfet4t7; dur=74',
|
880 | 'alt-svc': 'quic=":443"; ma=2592000; v="46,44,43,39"',
|
881 | 'accept-ranges': 'none',
|
882 | vary: 'Accept-Language,Accept-Encoding',
|
883 | connection: 'close'
|
884 | }
|
885 | }
|
886 | ]
|
887 | };
|
888 | expect(omitDeep(
|
889 | ['date', 'expires'],
|
890 | tricky
|
891 | )).toEqual(
|
892 | {
|
893 | urlObjSpots: [],
|
894 | location: {},
|
895 | routeResponses: [
|
896 | {
|
897 | status: 200,
|
898 | headers: {
|
899 | 'content-type': 'application/json; charset=UTF-8',
|
900 | 'cache-control': 'public, max-age=86400',
|
901 | server: 'mafe',
|
902 | 'x-xss-protection': '0',
|
903 | 'x-frame-options': 'SAMEORIGIN',
|
904 | 'server-timing': 'gfet4t7; dur=57',
|
905 | 'alt-svc': 'quic=":443"; ma=2592000; v="46,44,43,39"',
|
906 | 'accept-ranges': 'none',
|
907 | vary: 'Accept-Language,Accept-Encoding',
|
908 | connection: 'close'
|
909 | }
|
910 | },
|
911 | {
|
912 | status: 200,
|
913 | headers: {
|
914 | 'content-type': 'application/json; charset=UTF-8',
|
915 | 'cache-control': 'public, max-age=86400',
|
916 | server: 'mafe',
|
917 | 'x-xss-protection': '0',
|
918 | 'x-frame-options': 'SAMEORIGIN',
|
919 | 'server-timing': 'gfet4t7; dur=74',
|
920 | 'alt-svc': 'quic=":443"; ma=2592000; v="46,44,43,39"',
|
921 | 'accept-ranges': 'none',
|
922 | vary: 'Accept-Language,Accept-Encoding',
|
923 | connection: 'close'
|
924 | }
|
925 | }
|
926 | ]
|
927 | }
|
928 | );
|
929 | });
|
930 |
|
931 | test('omitDeepPaths', () => {
|
932 | expect(omitDeepPaths(
|
933 | ['foo.bunny', 'boo.funny.foo.sunny.2', 'boo.funny.foo.sunny.1.4.go'],
|
934 | {
|
935 | foo: {
|
936 | bunny: {
|
937 | humorous: 'stuff'
|
938 | }
|
939 | },
|
940 | boo: {
|
941 | funny: {
|
942 | foo: {
|
943 | sunny: [
|
944 | 8,
|
945 | [10,
|
946 | 'more',
|
947 | 'miles',
|
948 | 'to',
|
949 | {
|
950 | go: 'teo',
|
951 | wo: 1
|
952 | }
|
953 | ], 9
|
954 | ]
|
955 | },
|
956 | soo: 3
|
957 | }
|
958 | }
|
959 | }
|
960 | )).toEqual(
|
961 | {
|
962 | foo: {},
|
963 | boo: {
|
964 | funny: {
|
965 | foo: {
|
966 | sunny: [
|
967 | 8, [
|
968 | 10,
|
969 | 'more',
|
970 | 'miles',
|
971 | 'to', {
|
972 | wo: 1
|
973 | }
|
974 | ]
|
975 | ]
|
976 | },
|
977 | soo: 3
|
978 | }
|
979 | }
|
980 | }
|
981 | );
|
982 | });
|
983 |
|
984 | test('omitDeepBug', () => {
|
985 | const buggy = {
|
986 | geojson: {
|
987 | type: 'FeatureCollection',
|
988 | features: [
|
989 | {
|
990 | type: 'Feature',
|
991 | id: 'node/248124950',
|
992 | geometry: {
|
993 | type: 'Point',
|
994 | coordinates: [
|
995 | -115.0646702,
|
996 | 49.5161346
|
997 | ]
|
998 | },
|
999 | properties: {
|
1000 | id: 248124950,
|
1001 | meta: {},
|
1002 | tags: {},
|
1003 | type: 'node',
|
1004 | relations: []
|
1005 | },
|
1006 | __typename: {}
|
1007 | }
|
1008 | ]
|
1009 | }
|
1010 | };
|
1011 | expect(R.propOr('great', '__typename', reqStrPathThrowing('geojson.features.0', omitDeep(['__typename'], buggy)))).toEqual('great');
|
1012 | });
|
1013 |
|
1014 | test('pickDeepPaths', () => {
|
1015 | expect(pickDeepPaths(
|
1016 | ['foo.bunny',
|
1017 | 'boo.funny.foo.sunny.2',
|
1018 | 'boo.funny.foo.sunny.1.4.go',
|
1019 | 'coo.moo.*.cow./[1|6]/.*.forever'
|
1020 | ],
|
1021 | {
|
1022 | foo: {bunny: {humorous: 'stuff'}},
|
1023 | boo: {funny: {foo: {sunny: [8, [10, 'more', 'miles', 'to', {go: 'teo', wo: 1}], 9]}, soo: 3}},
|
1024 | coo: {
|
1025 | moo: [
|
1026 | 1,
|
1027 | 2,
|
1028 | {
|
1029 | cow: [
|
1030 | 'come',
|
1031 | {me: {forever: 'hers'}, never: 'mine'},
|
1032 | 'baby',
|
1033 | 'say',
|
1034 | {me: {forever: 'his'}, never: 'mine'},
|
1035 | 'love',
|
1036 | {me: {forever: 'yours'}, never: 'mine'}
|
1037 | ]
|
1038 | },
|
1039 | 4
|
1040 | ]
|
1041 | }
|
1042 | }
|
1043 | )).toEqual(
|
1044 | {
|
1045 | foo:
|
1046 | {
|
1047 | bunny: {humorous: 'stuff'}
|
1048 | },
|
1049 | boo: {
|
1050 | funny: {
|
1051 | foo: {
|
1052 | sunny: [[{go: 'teo'}], 9]
|
1053 | }
|
1054 | }
|
1055 | },
|
1056 | coo: {
|
1057 | moo: [{cow: [{me: {forever: 'hers'}}, {me: {forever: 'yours'}}]}]
|
1058 | }
|
1059 | }
|
1060 | );
|
1061 | });
|
1062 |
|
1063 | test('camelCase', () => {
|
1064 | expect(f.camelCase('Tough_Mudder_Hubbard')).toEqual('toughMudderHubbard');
|
1065 | });
|
1066 |
|
1067 | test('splitAtInclusive', () => {
|
1068 | expect(splitAtInclusive(1, [1, 2, 3, 4, 5])).toEqual(
|
1069 | [[1, 2], [2, 3, 4, 5]]
|
1070 | );
|
1071 | expect(splitAtInclusive(0, [1, 2, 3, 4, 5])).toEqual(
|
1072 | [[1], [1, 2, 3, 4, 5]]
|
1073 | );
|
1074 | expect(splitAtInclusive(-1, [1, 2, 3, 4, 5])).toEqual(
|
1075 | [[1, 2, 3, 4, 5], [5]]
|
1076 | );
|
1077 | expect(splitAtInclusive(1, 'murderforajarofredrum')).toEqual(
|
1078 | ['mu', 'urderforajarofredrum']
|
1079 | );
|
1080 | });
|
1081 |
|
1082 | test('eqStrPath', () => {
|
1083 | expect(eqStrPath('bubble.gum.0.soup',
|
1084 | {bubble: {gum: [{soup: 'banana'}]}},
|
1085 | {bubble: {gum: [{soup: 'banana'}]}}
|
1086 | )).toEqual(true);
|
1087 | expect(eqStrPath('bubble.gum.soup',
|
1088 | {bubble: {gum: {soup: 'banana'}}},
|
1089 | {bubble: {gum: {soup: 'goat'}}}
|
1090 | )).toEqual(false);
|
1091 | });
|
1092 |
|
1093 | test('eqStrPathsAll', () => {
|
1094 | expect(eqStrPathsAll(['a', 'b'], {a: 1, b: 2, c: 3}, {a: 1, b: 2, c: 'hubabalu'})).toEqual(true);
|
1095 | expect(eqStrPathsAll(['a', 'b', 'c'], {a: 1, b: 2, c: 3}, {a: 1, b: 2, c: 'hubabalu'})).toEqual(false);
|
1096 | expect(eqStrPathsAll(['a.goat', 'b'], {a: {goat: 1}, b: 2, c: 3}, {
|
1097 | a: {goat: 1},
|
1098 | b: 2,
|
1099 | c: 'hubabalu'
|
1100 | })).toEqual(true);
|
1101 | expect(eqStrPathsAll(['a', 'b.pumpkin', 'c'], {a: 1, b: {pumpkin: null}, c: 3}, {
|
1102 | a: 1,
|
1103 | b: {pumpkin: null},
|
1104 | c: 'hubabalu'
|
1105 | })).toEqual(false);
|
1106 | });
|
1107 |
|
1108 | test('toArrayIfNot', () => {
|
1109 | const eh = ['eh'];
|
1110 | expect(toArrayIfNot(eh)).toBe(eh);
|
1111 | expect(toArrayIfNot('eh')).toEqual(eh);
|
1112 | });
|
1113 | });
|