@expo/entity-testing-utils 0.41.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 (48) hide show
  1. package/README.md +3 -0
  2. package/build/PrivacyPolicyRuleTestUtils.d.ts +24 -0
  3. package/build/PrivacyPolicyRuleTestUtils.js +52 -0
  4. package/build/PrivacyPolicyRuleTestUtils.js.map +1 -0
  5. package/build/StubCacheAdapter.d.ts +25 -0
  6. package/build/StubCacheAdapter.js +103 -0
  7. package/build/StubCacheAdapter.js.map +1 -0
  8. package/build/StubDatabaseAdapter.d.ts +23 -0
  9. package/build/StubDatabaseAdapter.js +158 -0
  10. package/build/StubDatabaseAdapter.js.map +1 -0
  11. package/build/StubDatabaseAdapterProvider.d.ts +5 -0
  12. package/build/StubDatabaseAdapterProvider.js +14 -0
  13. package/build/StubDatabaseAdapterProvider.js.map +1 -0
  14. package/build/StubQueryContextProvider.d.ts +6 -0
  15. package/build/StubQueryContextProvider.js +16 -0
  16. package/build/StubQueryContextProvider.js.map +1 -0
  17. package/build/TSMockitoExtensions.d.ts +9 -0
  18. package/build/TSMockitoExtensions.js +63 -0
  19. package/build/TSMockitoExtensions.js.map +1 -0
  20. package/build/createUnitTestEntityCompanionProvider.d.ts +6 -0
  21. package/build/createUnitTestEntityCompanionProvider.js +35 -0
  22. package/build/createUnitTestEntityCompanionProvider.js.map +1 -0
  23. package/build/describeFieldTestCase.d.ts +2 -0
  24. package/build/describeFieldTestCase.js +18 -0
  25. package/build/describeFieldTestCase.js.map +1 -0
  26. package/build/index.d.ts +12 -0
  27. package/build/index.js +38 -0
  28. package/build/index.js.map +1 -0
  29. package/build/tsconfig.build.tsbuildinfo +1 -0
  30. package/package.json +48 -0
  31. package/src/PrivacyPolicyRuleTestUtils.ts +138 -0
  32. package/src/StubCacheAdapter.ts +167 -0
  33. package/src/StubDatabaseAdapter.ts +249 -0
  34. package/src/StubDatabaseAdapterProvider.ts +17 -0
  35. package/src/StubQueryContextProvider.ts +19 -0
  36. package/src/TSMockitoExtensions.ts +69 -0
  37. package/src/__testfixtures__/DateIDTestEntity.ts +62 -0
  38. package/src/__testfixtures__/SimpleTestEntity.ts +95 -0
  39. package/src/__testfixtures__/TestEntity.ts +130 -0
  40. package/src/__testfixtures__/TestEntityNumberKey.ts +62 -0
  41. package/src/__tests__/FileConsistentcyWithEntity-test.ts +32 -0
  42. package/src/__tests__/PrivacyPolicyRuleTestUtils-test.ts +44 -0
  43. package/src/__tests__/StubCacheAdapter-test.ts +134 -0
  44. package/src/__tests__/StubDatabaseAdapter-test.ts +607 -0
  45. package/src/__tests__/TSMockitoExtensions-test.ts +65 -0
  46. package/src/createUnitTestEntityCompanionProvider.ts +40 -0
  47. package/src/describeFieldTestCase.ts +21 -0
  48. package/src/index.ts +14 -0
@@ -0,0 +1,607 @@
1
+ import {
2
+ OrderByOrdering,
3
+ EntityQueryContext,
4
+ CompositeFieldHolder,
5
+ CompositeFieldValueHolder,
6
+ SingleFieldHolder,
7
+ SingleFieldValueHolder,
8
+ } from '@expo/entity';
9
+ import { instance, mock } from 'ts-mockito';
10
+
11
+ import StubDatabaseAdapter from '../StubDatabaseAdapter';
12
+ import {
13
+ DateIDTestFields,
14
+ dateIDTestEntityConfiguration,
15
+ } from '../__testfixtures__/DateIDTestEntity';
16
+ import {
17
+ SimpleTestFields,
18
+ simpleTestEntityConfiguration,
19
+ } from '../__testfixtures__/SimpleTestEntity';
20
+ import { TestFields, testEntityConfiguration } from '../__testfixtures__/TestEntity';
21
+ import {
22
+ NumberKeyFields,
23
+ numberKeyEntityConfiguration,
24
+ } from '../__testfixtures__/TestEntityNumberKey';
25
+
26
+ describe(StubDatabaseAdapter, () => {
27
+ describe('fetchManyWhereAsync', () => {
28
+ it('fetches many where single', async () => {
29
+ const queryContext = instance(mock(EntityQueryContext));
30
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
31
+ testEntityConfiguration,
32
+ StubDatabaseAdapter.convertFieldObjectsToDataStore(
33
+ testEntityConfiguration,
34
+ new Map([
35
+ [
36
+ testEntityConfiguration.tableName,
37
+ [
38
+ {
39
+ customIdField: 'hello',
40
+ testIndexedField: 'h1',
41
+ intField: 5,
42
+ stringField: 'huh',
43
+ dateField: new Date(),
44
+ nullableField: null,
45
+ },
46
+ {
47
+ customIdField: 'world',
48
+ testIndexedField: 'h2',
49
+ intField: 3,
50
+ stringField: 'wat',
51
+ dateField: new Date(),
52
+ nullableField: null,
53
+ },
54
+ ],
55
+ ],
56
+ ]),
57
+ ),
58
+ );
59
+
60
+ const results = await databaseAdapter.fetchManyWhereAsync(
61
+ queryContext,
62
+ new SingleFieldHolder('stringField'),
63
+ [new SingleFieldValueHolder('huh')],
64
+ );
65
+ expect(results.get(new SingleFieldValueHolder('huh'))).toHaveLength(1);
66
+ });
67
+
68
+ it('fetches many where composite', async () => {
69
+ const queryContext = instance(mock(EntityQueryContext));
70
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
71
+ testEntityConfiguration,
72
+ StubDatabaseAdapter.convertFieldObjectsToDataStore(
73
+ testEntityConfiguration,
74
+ new Map([
75
+ [
76
+ testEntityConfiguration.tableName,
77
+ [
78
+ {
79
+ customIdField: 'hello',
80
+ testIndexedField: 'h1',
81
+ intField: 5,
82
+ stringField: 'huh',
83
+ dateField: new Date(),
84
+ nullableField: null,
85
+ },
86
+ {
87
+ customIdField: 'world',
88
+ testIndexedField: 'h2',
89
+ intField: 3,
90
+ stringField: 'wat',
91
+ dateField: new Date(),
92
+ nullableField: null,
93
+ },
94
+ ],
95
+ ],
96
+ ]),
97
+ ),
98
+ );
99
+
100
+ const results = await databaseAdapter.fetchManyWhereAsync(
101
+ queryContext,
102
+ new CompositeFieldHolder<TestFields, 'customIdField'>(['stringField', 'intField']),
103
+ [new CompositeFieldValueHolder({ stringField: 'huh', intField: 5 })],
104
+ );
105
+ expect(
106
+ results.get(new CompositeFieldValueHolder({ stringField: 'huh', intField: 5 })),
107
+ ).toHaveLength(1);
108
+
109
+ const results2 = await databaseAdapter.fetchManyWhereAsync(
110
+ queryContext,
111
+ new CompositeFieldHolder<TestFields, 'customIdField'>(['stringField', 'intField']),
112
+ [new CompositeFieldValueHolder({ stringField: 'not-in-db', intField: 5 })],
113
+ );
114
+ expect(
115
+ results2.get(new CompositeFieldValueHolder({ stringField: 'not-in-db', intField: 5 })),
116
+ ).toHaveLength(0);
117
+ });
118
+ });
119
+
120
+ describe('fetchManyByFieldEqualityConjunctionAsync', () => {
121
+ it('supports conjuntions and query modifiers', async () => {
122
+ const queryContext = instance(mock(EntityQueryContext));
123
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
124
+ testEntityConfiguration,
125
+ StubDatabaseAdapter.convertFieldObjectsToDataStore(
126
+ testEntityConfiguration,
127
+ new Map([
128
+ [
129
+ testEntityConfiguration.tableName,
130
+ [
131
+ {
132
+ customIdField: 'hello',
133
+ testIndexedField: 'h1',
134
+ intField: 3,
135
+ stringField: 'a',
136
+ dateField: new Date(),
137
+ nullableField: null,
138
+ },
139
+ {
140
+ customIdField: 'world',
141
+ testIndexedField: 'h2',
142
+ intField: 3,
143
+ stringField: 'b',
144
+ dateField: new Date(),
145
+ nullableField: null,
146
+ },
147
+ {
148
+ customIdField: 'world',
149
+ testIndexedField: 'h2',
150
+ intField: 3,
151
+ stringField: 'c',
152
+ dateField: new Date(),
153
+ nullableField: null,
154
+ },
155
+ ],
156
+ ],
157
+ ]),
158
+ ),
159
+ );
160
+
161
+ const results = await databaseAdapter.fetchManyByFieldEqualityConjunctionAsync(
162
+ queryContext,
163
+ [
164
+ {
165
+ fieldName: 'customIdField',
166
+ fieldValues: ['hello', 'world'],
167
+ },
168
+ {
169
+ fieldName: 'intField',
170
+ fieldValue: 3,
171
+ },
172
+ ],
173
+ {
174
+ limit: 2,
175
+ offset: 1,
176
+ orderBy: [
177
+ {
178
+ fieldName: 'stringField',
179
+ order: OrderByOrdering.DESCENDING,
180
+ },
181
+ ],
182
+ },
183
+ );
184
+
185
+ expect(results).toHaveLength(2);
186
+ expect(results.map((e) => e.stringField)).toEqual(['b', 'a']);
187
+ });
188
+
189
+ it('supports multiple order bys', async () => {
190
+ const queryContext = instance(mock(EntityQueryContext));
191
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
192
+ testEntityConfiguration,
193
+ StubDatabaseAdapter.convertFieldObjectsToDataStore(
194
+ testEntityConfiguration,
195
+ new Map([
196
+ [
197
+ testEntityConfiguration.tableName,
198
+ [
199
+ {
200
+ customIdField: 'hello',
201
+ testIndexedField: 'h1',
202
+ intField: 3,
203
+ stringField: 'a',
204
+ dateField: new Date(),
205
+ nullableField: null,
206
+ },
207
+ {
208
+ customIdField: 'world',
209
+ testIndexedField: 'h2',
210
+ intField: 3,
211
+ stringField: 'b',
212
+ dateField: new Date(),
213
+ nullableField: null,
214
+ },
215
+ {
216
+ customIdField: 'world',
217
+ testIndexedField: 'h2',
218
+ intField: 3,
219
+ stringField: 'c',
220
+ dateField: new Date(),
221
+ nullableField: null,
222
+ },
223
+ ],
224
+ ],
225
+ ]),
226
+ ),
227
+ );
228
+
229
+ const results = await databaseAdapter.fetchManyByFieldEqualityConjunctionAsync(
230
+ queryContext,
231
+ [
232
+ {
233
+ fieldName: 'intField',
234
+ fieldValue: 3,
235
+ },
236
+ ],
237
+ {
238
+ orderBy: [
239
+ {
240
+ fieldName: 'intField',
241
+ order: OrderByOrdering.DESCENDING,
242
+ },
243
+ {
244
+ fieldName: 'stringField',
245
+ order: OrderByOrdering.DESCENDING,
246
+ },
247
+ ],
248
+ },
249
+ );
250
+
251
+ expect(results).toHaveLength(3);
252
+ expect(results.map((e) => e.stringField)).toEqual(['c', 'b', 'a']);
253
+ });
254
+
255
+ it('supports null field values', async () => {
256
+ const queryContext = instance(mock(EntityQueryContext));
257
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
258
+ testEntityConfiguration,
259
+ StubDatabaseAdapter.convertFieldObjectsToDataStore(
260
+ testEntityConfiguration,
261
+ new Map([
262
+ [
263
+ testEntityConfiguration.tableName,
264
+ [
265
+ {
266
+ customIdField: '1',
267
+ testIndexedField: 'h1',
268
+ intField: 1,
269
+ stringField: 'a',
270
+ dateField: new Date(),
271
+ nullableField: 'a',
272
+ },
273
+ {
274
+ customIdField: '2',
275
+ testIndexedField: 'h2',
276
+ intField: 2,
277
+ stringField: 'a',
278
+ dateField: new Date(),
279
+ nullableField: 'b',
280
+ },
281
+ {
282
+ customIdField: '3',
283
+ testIndexedField: 'h3',
284
+ intField: 3,
285
+ stringField: 'a',
286
+ dateField: new Date(),
287
+ nullableField: null,
288
+ },
289
+ {
290
+ customIdField: '4',
291
+ testIndexedField: 'h4',
292
+ intField: 4,
293
+ stringField: 'b',
294
+ dateField: new Date(),
295
+ nullableField: null,
296
+ },
297
+ ],
298
+ ],
299
+ ]),
300
+ ),
301
+ );
302
+
303
+ const results = await databaseAdapter.fetchManyByFieldEqualityConjunctionAsync(
304
+ queryContext,
305
+ [{ fieldName: 'nullableField', fieldValue: null }],
306
+ {},
307
+ );
308
+ expect(results).toHaveLength(2);
309
+ expect(results[0]!.nullableField).toBeNull();
310
+
311
+ const results2 = await databaseAdapter.fetchManyByFieldEqualityConjunctionAsync(
312
+ queryContext,
313
+ [
314
+ { fieldName: 'nullableField', fieldValues: ['a', null] },
315
+ { fieldName: 'stringField', fieldValue: 'a' },
316
+ ],
317
+ {
318
+ orderBy: [
319
+ {
320
+ fieldName: 'nullableField',
321
+ order: OrderByOrdering.DESCENDING,
322
+ },
323
+ ],
324
+ },
325
+ );
326
+ expect(results2).toHaveLength(2);
327
+ expect(results2.map((e) => e.nullableField)).toEqual([null, 'a']);
328
+ });
329
+ });
330
+
331
+ describe('fetchManyByRawWhereClauseAsync', () => {
332
+ it('throws because it is unsupported', async () => {
333
+ const queryContext = instance(mock(EntityQueryContext));
334
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
335
+ testEntityConfiguration,
336
+ new Map(),
337
+ );
338
+ await expect(
339
+ databaseAdapter.fetchManyByRawWhereClauseAsync(queryContext, '', [], {}),
340
+ ).rejects.toThrow();
341
+ });
342
+ });
343
+
344
+ describe('insertAsync', () => {
345
+ it('inserts a record', async () => {
346
+ const queryContext = instance(mock(EntityQueryContext));
347
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
348
+ testEntityConfiguration,
349
+ new Map(),
350
+ );
351
+ const result = await databaseAdapter.insertAsync(queryContext, {
352
+ stringField: 'hello',
353
+ });
354
+ expect(result).toMatchObject({
355
+ stringField: 'hello',
356
+ });
357
+
358
+ expect(
359
+ databaseAdapter.getObjectCollectionForTable(testEntityConfiguration.tableName),
360
+ ).toHaveLength(1);
361
+ });
362
+
363
+ it('inserts a record with valid v7 id', async () => {
364
+ const expectedTime = new Date('2024-06-03T20:16:33.761Z');
365
+
366
+ jest.useFakeTimers({
367
+ now: expectedTime,
368
+ });
369
+
370
+ const queryContext = instance(mock(EntityQueryContext));
371
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
372
+ testEntityConfiguration,
373
+ new Map(),
374
+ );
375
+ const result = await databaseAdapter.insertAsync(queryContext, {
376
+ stringField: 'hello',
377
+ });
378
+
379
+ const ts = getTimeFromUUIDv7(result.customIdField);
380
+ expect(ts).toEqual(expectedTime);
381
+ });
382
+ });
383
+
384
+ describe('updateAsync', () => {
385
+ it('updates a record', async () => {
386
+ const queryContext = instance(mock(EntityQueryContext));
387
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
388
+ testEntityConfiguration,
389
+ StubDatabaseAdapter.convertFieldObjectsToDataStore(
390
+ testEntityConfiguration,
391
+ new Map([
392
+ [
393
+ testEntityConfiguration.tableName,
394
+ [
395
+ {
396
+ customIdField: 'hello',
397
+ testIndexedField: 'h1',
398
+ intField: 3,
399
+ stringField: 'a',
400
+ dateField: new Date(),
401
+ nullableField: null,
402
+ },
403
+ ],
404
+ ],
405
+ ]),
406
+ ),
407
+ );
408
+ const result = await databaseAdapter.updateAsync(queryContext, 'customIdField', 'hello', {
409
+ stringField: 'b',
410
+ });
411
+ expect(result).toMatchObject({
412
+ stringField: 'b',
413
+ testIndexedField: 'h1',
414
+ });
415
+ });
416
+
417
+ it('throws error when empty update to match common DBMS behavior', async () => {
418
+ const queryContext = instance(mock(EntityQueryContext));
419
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
420
+ testEntityConfiguration,
421
+ StubDatabaseAdapter.convertFieldObjectsToDataStore(
422
+ testEntityConfiguration,
423
+ new Map([
424
+ [
425
+ testEntityConfiguration.tableName,
426
+ [
427
+ {
428
+ customIdField: 'hello',
429
+ testIndexedField: 'h1',
430
+ intField: 3,
431
+ stringField: 'a',
432
+ dateField: new Date(),
433
+ nullableField: null,
434
+ },
435
+ ],
436
+ ],
437
+ ]),
438
+ ),
439
+ );
440
+ await expect(
441
+ databaseAdapter.updateAsync(queryContext, 'customIdField', 'hello', {}),
442
+ ).rejects.toThrowError(`Empty update (custom_id = hello)`);
443
+ });
444
+ });
445
+
446
+ describe('deleteAsync', () => {
447
+ it('deletes an object', async () => {
448
+ const queryContext = instance(mock(EntityQueryContext));
449
+ const databaseAdapter = new StubDatabaseAdapter<TestFields, 'customIdField'>(
450
+ testEntityConfiguration,
451
+ StubDatabaseAdapter.convertFieldObjectsToDataStore(
452
+ testEntityConfiguration,
453
+ new Map([
454
+ [
455
+ testEntityConfiguration.tableName,
456
+ [
457
+ {
458
+ customIdField: 'hello',
459
+ testIndexedField: 'h1',
460
+ intField: 3,
461
+ stringField: 'a',
462
+ dateField: new Date(),
463
+ nullableField: null,
464
+ },
465
+ ],
466
+ ],
467
+ ]),
468
+ ),
469
+ );
470
+
471
+ await databaseAdapter.deleteAsync(queryContext, 'customIdField', 'hello');
472
+
473
+ expect(
474
+ databaseAdapter.getObjectCollectionForTable(testEntityConfiguration.tableName),
475
+ ).toHaveLength(0);
476
+ });
477
+ });
478
+
479
+ it('supports string and number IDs', async () => {
480
+ const queryContext = instance(mock(EntityQueryContext));
481
+ const databaseAdapter1 = new StubDatabaseAdapter<SimpleTestFields, 'id'>(
482
+ simpleTestEntityConfiguration,
483
+ new Map(),
484
+ );
485
+ const insertedObject1 = await databaseAdapter1.insertAsync(queryContext, {});
486
+ expect(typeof insertedObject1.id).toBe('string');
487
+
488
+ const databaseAdapter2 = new StubDatabaseAdapter<NumberKeyFields, 'id'>(
489
+ numberKeyEntityConfiguration,
490
+ new Map(),
491
+ );
492
+ const insertedObject2 = await databaseAdapter2.insertAsync(queryContext, {});
493
+ expect(typeof insertedObject2.id).toBe('number');
494
+
495
+ const databaseAdapter3 = new StubDatabaseAdapter<DateIDTestFields, 'id'>(
496
+ dateIDTestEntityConfiguration,
497
+ new Map(),
498
+ );
499
+ await expect(databaseAdapter3.insertAsync(queryContext, {})).rejects.toThrowError(
500
+ 'Unsupported ID type for StubDatabaseAdapter: DateField',
501
+ );
502
+ });
503
+
504
+ describe('compareByOrderBys', () => {
505
+ describe('comparison', () => {
506
+ it.each([
507
+ // nulls compare with 0
508
+ [OrderByOrdering.DESCENDING, null, 0, -1],
509
+ [OrderByOrdering.ASCENDING, null, 0, 1],
510
+ [OrderByOrdering.DESCENDING, 0, null, 1],
511
+ [OrderByOrdering.ASCENDING, 0, null, -1],
512
+
513
+ // nulls compare with nulls
514
+ [OrderByOrdering.DESCENDING, null, null, 0],
515
+ [OrderByOrdering.ASCENDING, null, null, 0],
516
+
517
+ // nulls compare with -1
518
+ [OrderByOrdering.DESCENDING, null, -1, -1],
519
+ [OrderByOrdering.ASCENDING, null, -1, 1],
520
+ [OrderByOrdering.DESCENDING, -1, null, 1],
521
+ [OrderByOrdering.ASCENDING, -1, null, -1],
522
+
523
+ // basic compares
524
+ [OrderByOrdering.ASCENDING, 'a', 'b', -1],
525
+ [OrderByOrdering.ASCENDING, 'b', 'a', 1],
526
+ [OrderByOrdering.DESCENDING, 'a', 'b', 1],
527
+ [OrderByOrdering.DESCENDING, 'b', 'a', -1],
528
+ ])('case (%p; %p; %p)', (order, v1, v2, expectedResult) => {
529
+ expect(
530
+ StubDatabaseAdapter['compareByOrderBys'](
531
+ [
532
+ {
533
+ columnName: 'hello',
534
+ order,
535
+ },
536
+ ],
537
+ {
538
+ hello: v1,
539
+ },
540
+ {
541
+ hello: v2,
542
+ },
543
+ ),
544
+ ).toEqual(expectedResult);
545
+ });
546
+
547
+ it('works for empty', () => {
548
+ expect(
549
+ StubDatabaseAdapter['compareByOrderBys'](
550
+ [],
551
+ {
552
+ hello: 'test',
553
+ },
554
+ {
555
+ hello: 'blah',
556
+ },
557
+ ),
558
+ ).toEqual(0);
559
+ });
560
+ });
561
+
562
+ describe('recursing', () => {
563
+ expect(
564
+ StubDatabaseAdapter['compareByOrderBys'](
565
+ [
566
+ {
567
+ columnName: 'hello',
568
+ order: OrderByOrdering.ASCENDING,
569
+ },
570
+ {
571
+ columnName: 'world',
572
+ order: OrderByOrdering.ASCENDING,
573
+ },
574
+ ],
575
+ {
576
+ hello: 'a',
577
+ world: 1,
578
+ },
579
+ {
580
+ hello: 'a',
581
+ world: 2,
582
+ },
583
+ ),
584
+ ).toEqual(-1);
585
+ });
586
+ });
587
+ });
588
+
589
+ const UUIDV7_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
590
+
591
+ /**
592
+ * Returns the Date object encoded in the first 48 bits of the given UUIDv7.
593
+ * @throws TypeError if the UUID is not version 7
594
+ */
595
+ function getTimeFromUUIDv7(uuid: string): Date {
596
+ if (!UUIDV7_REGEX.test(uuid)) {
597
+ throw new TypeError(`UUID must be version 7 to get its timestamp`);
598
+ }
599
+
600
+ // The first 48 bits = 12 hex characters of the UUID encode the timestamp in big endian
601
+ const hexCharacters = uuid.replaceAll('-', '').split('', 12);
602
+ const milliseconds = hexCharacters.reduce(
603
+ (milliseconds, character) => milliseconds * 16 + parseInt(character, 16),
604
+ 0,
605
+ );
606
+ return new Date(milliseconds);
607
+ }
@@ -0,0 +1,65 @@
1
+ import { SingleFieldHolder, SingleFieldValueHolder, SingleFieldValueHolderMap } from '@expo/entity';
2
+
3
+ import {
4
+ deepEqualEntityAware,
5
+ DeepEqualEntityAwareMatcher,
6
+ isEqualWithEntityAware,
7
+ } from '../TSMockitoExtensions';
8
+
9
+ describe(deepEqualEntityAware, () => {
10
+ it('should return a DeepEqualEntityAwareMatcher', () => {
11
+ const actual = deepEqualEntityAware('foo');
12
+ expect(actual).toBeInstanceOf(DeepEqualEntityAwareMatcher);
13
+ expect(actual.toString()).toBe('deepEqualEntityAware(foo)');
14
+
15
+ const actual2 = deepEqualEntityAware(['bar']);
16
+ expect(actual2.toString()).toBe('deepEqualEntityAware([bar])');
17
+ });
18
+ });
19
+
20
+ describe(isEqualWithEntityAware, () => {
21
+ it('works for basic cases', () => {
22
+ expect(isEqualWithEntityAware('foo', 'foo')).toBe(true);
23
+ expect(isEqualWithEntityAware('foo', 'bar')).toBe(false);
24
+
25
+ const obj1 = { foo: 'bar' };
26
+ const obj2 = { foo: 'bar' };
27
+ expect(isEqualWithEntityAware(obj1, obj2)).toBe(true);
28
+ });
29
+
30
+ it('works for nested matchers', () => {
31
+ const obj1 = { foo: deepEqualEntityAware('bar') };
32
+ const obj2 = { foo: 'bar' };
33
+ expect(isEqualWithEntityAware(obj1, obj2)).toBe(true);
34
+ });
35
+
36
+ it('works for SingleFieldHolder', () => {
37
+ const singleFieldHolder1 = new SingleFieldHolder('foo');
38
+ const singleFieldHolder2 = new SingleFieldHolder('foo');
39
+ const singleFieldHolder3 = new SingleFieldHolder('bar');
40
+ expect(isEqualWithEntityAware(singleFieldHolder1, singleFieldHolder2)).toBe(true);
41
+ expect(isEqualWithEntityAware(singleFieldHolder1, singleFieldHolder3)).toBe(false);
42
+ });
43
+
44
+ it('works for SingleFieldValueHolder', () => {
45
+ const singleFieldValueHolder1 = new SingleFieldValueHolder('foo');
46
+ const singleFieldValueHolder2 = new SingleFieldValueHolder('foo');
47
+ const singleFieldValueHolder3 = new SingleFieldValueHolder('bar');
48
+ expect(isEqualWithEntityAware(singleFieldValueHolder1, singleFieldValueHolder2)).toBe(true);
49
+ expect(isEqualWithEntityAware(singleFieldValueHolder1, singleFieldValueHolder3)).toBe(false);
50
+ });
51
+
52
+ it('works for SerializableKeyMap', () => {
53
+ const map1 = new SingleFieldValueHolderMap(
54
+ new Map([[new SingleFieldValueHolder('foo'), 'bar']]),
55
+ );
56
+ const map2 = new SingleFieldValueHolderMap(
57
+ new Map([[new SingleFieldValueHolder('foo'), 'bar']]),
58
+ );
59
+ const map3 = new SingleFieldValueHolderMap(
60
+ new Map([[new SingleFieldValueHolder('foo2'), 'bar']]),
61
+ );
62
+ expect(isEqualWithEntityAware(map1, map2)).toBe(true);
63
+ expect(isEqualWithEntityAware(map1, map3)).toBe(false);
64
+ });
65
+ });
@@ -0,0 +1,40 @@
1
+ import {
2
+ EntityCompanionProvider,
3
+ IEntityMetricsAdapter,
4
+ NoOpEntityMetricsAdapter,
5
+ } from '@expo/entity';
6
+
7
+ import { InMemoryFullCacheStubCacheAdapterProvider } from './StubCacheAdapter';
8
+ import StubDatabaseAdapterProvider from './StubDatabaseAdapterProvider';
9
+ import StubQueryContextProvider from './StubQueryContextProvider';
10
+
11
+ const queryContextProvider = new StubQueryContextProvider();
12
+
13
+ /**
14
+ * Entity companion provider for use in unit tests. All database and cache implementations
15
+ * are replaced with in-memory simulations.
16
+ */
17
+ export const createUnitTestEntityCompanionProvider = (
18
+ metricsAdapter: IEntityMetricsAdapter = new NoOpEntityMetricsAdapter(),
19
+ ): EntityCompanionProvider => {
20
+ return new EntityCompanionProvider(
21
+ metricsAdapter,
22
+ new Map([
23
+ [
24
+ 'postgres',
25
+ {
26
+ adapterProvider: new StubDatabaseAdapterProvider(),
27
+ queryContextProvider,
28
+ },
29
+ ],
30
+ ]),
31
+ new Map([
32
+ [
33
+ 'redis',
34
+ {
35
+ cacheAdapterProvider: new InMemoryFullCacheStubCacheAdapterProvider(),
36
+ },
37
+ ],
38
+ ]),
39
+ );
40
+ };