@arrai-innovations/reactive-helpers 1.0.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 (53) hide show
  1. package/.circleci/config.yml +91 -0
  2. package/.commitlintrc.json +3 -0
  3. package/.editorconfig +5 -0
  4. package/.eslintignore +2 -0
  5. package/.eslintrc.js +26 -0
  6. package/.husky/commit-msg +2 -0
  7. package/.husky/pre-commit +2 -0
  8. package/.idea/encodings.xml +6 -0
  9. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  10. package/.idea/modules.xml +8 -0
  11. package/.idea/prettier.xml +8 -0
  12. package/.idea/reactive-helpers.iml +15 -0
  13. package/.lintstagedrc +11 -0
  14. package/.prettierignore +4 -0
  15. package/.prettierrc.js +5 -0
  16. package/README.md +598 -0
  17. package/babel.config.js +15 -0
  18. package/index.js +2 -0
  19. package/jest.config.mjs +27 -0
  20. package/package.json +59 -0
  21. package/tests/unit/.eslintrc.js +10 -0
  22. package/tests/unit/expectHelpers.js +6 -0
  23. package/tests/unit/mockOnUnmounted.js +9 -0
  24. package/tests/unit/use/index.spec.js +18 -0
  25. package/tests/unit/use/listFilter.spec.js +332 -0
  26. package/tests/unit/use/listInstance.spec.js +424 -0
  27. package/tests/unit/use/listRelated.spec.js +73 -0
  28. package/tests/unit/use/listSort.spec.js +220 -0
  29. package/tests/unit/use/listSubscription.spec.js +540 -0
  30. package/tests/unit/use/objectInstance.spec.js +897 -0
  31. package/tests/unit/use/objectSubscription.spec.js +671 -0
  32. package/tests/unit/use/search.spec.js +67 -0
  33. package/tests/unit/use/watches.spec.js +252 -0
  34. package/tests/unit/utils/assignReactiveObject.spec.js +127 -0
  35. package/tests/unit/utils/index.spec.js +18 -0
  36. package/tests/unit/utils/keyDiff.spec.js +67 -0
  37. package/tests/unit/utils/set.spec.js +68 -0
  38. package/tests/unit/utils/unrefAndToRawDeep.spec.js +170 -0
  39. package/use/index.js +8 -0
  40. package/use/listFilter.js +157 -0
  41. package/use/listInstance.js +144 -0
  42. package/use/listRelated.js +135 -0
  43. package/use/listSort.js +190 -0
  44. package/use/listSubscription.js +143 -0
  45. package/use/objectInstance.js +222 -0
  46. package/use/objectSubscription.js +188 -0
  47. package/use/search.js +104 -0
  48. package/utils/assignReactiveObject.js +62 -0
  49. package/utils/index.js +5 -0
  50. package/utils/keyDiff.js +10 -0
  51. package/utils/set.js +48 -0
  52. package/utils/unrefAndToRawDeep.js +49 -0
  53. package/utils/watches.js +170 -0
@@ -0,0 +1,540 @@
1
+ import { reactive } from "vue";
2
+ import { inspect } from "util";
3
+
4
+ describe("use/listSubscription.spec.js", function () {
5
+ let useListSubscription,
6
+ ListSubscriptionError,
7
+ useListSubscriptions,
8
+ useListInstance,
9
+ useListInstances,
10
+ globalList,
11
+ globalSubscribe,
12
+ globalUnsubscribe,
13
+ passedSubscriptionEventCallback;
14
+ beforeEach(async () => {
15
+ const listInstanceModule = await import("../../../use/listInstance");
16
+ globalList = jest.fn();
17
+ listInstanceModule.setListInstanceCrud({
18
+ list: globalList,
19
+ args: { stream: "test_stream" },
20
+ });
21
+ useListInstance = listInstanceModule.useListInstance;
22
+ useListInstances = listInstanceModule.useListInstances;
23
+ const imported = await import("../../../use/listSubscription");
24
+ globalUnsubscribe = jest.fn();
25
+ globalSubscribe = jest.fn();
26
+ globalSubscribe.mockImplementation(({ subscriptionEventCallback } = {}) => {
27
+ passedSubscriptionEventCallback = subscriptionEventCallback;
28
+ return Promise.resolve(globalUnsubscribe);
29
+ });
30
+ imported.setListSubscriptionCrud({
31
+ subscribe: globalSubscribe,
32
+ });
33
+ useListSubscription = imported.useListSubscription;
34
+ ListSubscriptionError = imported.ListSubscriptionError;
35
+ useListSubscriptions = imported.useListSubscriptions;
36
+ });
37
+ afterEach(function () {
38
+ jest.resetAllMocks();
39
+ });
40
+ const fields = ["id", "__str__", "name"];
41
+ describe("lifecycle", function () {
42
+ it("success", async function () {
43
+ globalUnsubscribe.mockImplementation(() => Promise.resolve(true));
44
+ const defaultListArgs = reactive({
45
+ user: 1,
46
+ });
47
+ const defaultRetrieveArgs = reactive({
48
+ fields: fields,
49
+ });
50
+ const listSubscription = useListSubscription({
51
+ defaultListArgs,
52
+ defaultRetrieveArgs,
53
+ });
54
+ await listSubscription.subscribe();
55
+ expect(globalSubscribe).toHaveBeenCalledWith({
56
+ crudArgs: { stream: "test_stream" },
57
+ listArgs: { user: 1 },
58
+ retrieveArgs: { fields: fields },
59
+ subscriptionEventCallback: expect.any(Function),
60
+ });
61
+ expect(globalSubscribe).toHaveBeenCalledTimes(1);
62
+
63
+ passedSubscriptionEventCallback(
64
+ {
65
+ id: 1,
66
+ __str__: "qwer",
67
+ name: "qwer",
68
+ },
69
+ "create"
70
+ );
71
+
72
+ expect(listSubscription.listInstance.state.objects).toEqual({
73
+ 1: {
74
+ id: 1,
75
+ __str__: "qwer",
76
+ name: "qwer",
77
+ },
78
+ });
79
+
80
+ passedSubscriptionEventCallback(
81
+ {
82
+ id: 1,
83
+ __str__: "qwert",
84
+ fame: "qwert",
85
+ },
86
+ "update"
87
+ );
88
+
89
+ expect(listSubscription.listInstance.state.objects).toEqual({
90
+ 1: {
91
+ id: 1,
92
+ __str__: "qwert",
93
+ fame: "qwert",
94
+ },
95
+ });
96
+
97
+ passedSubscriptionEventCallback(1, "delete");
98
+
99
+ expect(listSubscription.listInstance.state.objects).toEqual({});
100
+
101
+ const returnValue = await listSubscription.unsubscribe();
102
+ expect(globalUnsubscribe).toHaveBeenCalledWith();
103
+ expect(globalUnsubscribe).toHaveBeenCalledTimes(1);
104
+ expect(returnValue).toBe(true);
105
+ expect(listSubscription.state.subscribed).toBe(false);
106
+ });
107
+ it("missing data", async function () {
108
+ globalUnsubscribe.mockImplementation(() => Promise.resolve(true));
109
+ const defaultListArgs = reactive({
110
+ user: 1,
111
+ });
112
+ const defaultRetrieveArgs = reactive({
113
+ fields: fields,
114
+ });
115
+ const listSubscription = useListSubscription({
116
+ defaultListArgs,
117
+ defaultRetrieveArgs,
118
+ });
119
+ await listSubscription.subscribe({});
120
+ expect(globalSubscribe).toHaveBeenCalledWith({
121
+ crudArgs: { stream: "test_stream" },
122
+ listArgs: { user: 1 },
123
+ retrieveArgs: { fields: fields },
124
+ subscriptionEventCallback: expect.any(Function),
125
+ });
126
+ expect(globalSubscribe).toHaveBeenCalledTimes(1);
127
+
128
+ expect(() => passedSubscriptionEventCallback({}, "create")).toThrow(ListSubscriptionError);
129
+ expect(() => passedSubscriptionEventCallback({}, "create")).toThrow(
130
+ "got update with no data ({}), action: create"
131
+ );
132
+
133
+ expect(() =>
134
+ passedSubscriptionEventCallback(
135
+ {
136
+ id: 1,
137
+ __str__: "qwer",
138
+ name: "qwer",
139
+ },
140
+ "freate"
141
+ )
142
+ ).toThrow(ListSubscriptionError);
143
+ expect(() =>
144
+ passedSubscriptionEventCallback(
145
+ {
146
+ id: 1,
147
+ __str__: "qwer",
148
+ name: "qwer",
149
+ },
150
+ "freate"
151
+ )
152
+ ).toThrow("got update for unknown action: freate\n{ id: 1, __str__: 'qwer', name: 'qwer' }");
153
+
154
+ expect(() =>
155
+ passedSubscriptionEventCallback(
156
+ {
157
+ __str__: "qwer",
158
+ name: "qwer",
159
+ },
160
+ "create"
161
+ )
162
+ ).toThrow(ListSubscriptionError);
163
+ expect(() =>
164
+ passedSubscriptionEventCallback(
165
+ {
166
+ __str__: "qwer",
167
+ name: "qwer",
168
+ },
169
+ "create"
170
+ )
171
+ ).toThrow("addFromSubscription: data missing id.\n{ __str__: 'qwer', name: 'qwer' }");
172
+
173
+ passedSubscriptionEventCallback(
174
+ {
175
+ id: 1,
176
+ __str__: "qwer",
177
+ name: "qwer",
178
+ },
179
+ "create"
180
+ );
181
+
182
+ expect(() =>
183
+ passedSubscriptionEventCallback(
184
+ {
185
+ id: 1,
186
+ __str__: "qwer",
187
+ name: "qwer",
188
+ },
189
+ "create"
190
+ )
191
+ ).toThrow(ListSubscriptionError);
192
+ expect(() =>
193
+ passedSubscriptionEventCallback(
194
+ {
195
+ id: 1,
196
+ __str__: "qwer",
197
+ name: "qwer",
198
+ },
199
+ "create"
200
+ )
201
+ ).toThrow("addFromSubscription: add for existing id in objects (1).");
202
+
203
+ expect(listSubscription.listInstance.state.objects).toEqual({
204
+ 1: {
205
+ id: 1,
206
+ __str__: "qwer",
207
+ name: "qwer",
208
+ },
209
+ });
210
+
211
+ expect(() =>
212
+ passedSubscriptionEventCallback(
213
+ {
214
+ id: 2,
215
+ __str__: "qwer",
216
+ name: "qwer",
217
+ },
218
+ "update"
219
+ )
220
+ ).toThrow(ListSubscriptionError);
221
+ expect(() =>
222
+ passedSubscriptionEventCallback(
223
+ {
224
+ id: 2,
225
+ __str__: "qwer",
226
+ name: "qwer",
227
+ },
228
+ "update"
229
+ )
230
+ ).toThrow("updateFromSubscription: update for id not in objects (2).");
231
+
232
+ expect(() =>
233
+ passedSubscriptionEventCallback(
234
+ {
235
+ __str__: "qwer",
236
+ name: "qwer",
237
+ },
238
+ "update"
239
+ )
240
+ ).toThrow(ListSubscriptionError);
241
+ expect(() =>
242
+ passedSubscriptionEventCallback(
243
+ {
244
+ __str__: "qwer",
245
+ name: "qwer",
246
+ },
247
+ "update"
248
+ )
249
+ ).toThrow("updateFromSubscription: data missing id.\n{ __str__: 'qwer', name: 'qwer' }");
250
+
251
+ expect(() =>
252
+ passedSubscriptionEventCallback(
253
+ {
254
+ __str__: "qwer",
255
+ name: "qwer",
256
+ },
257
+ "delete"
258
+ )
259
+ ).toThrow(ListSubscriptionError);
260
+ expect(() =>
261
+ passedSubscriptionEventCallback(
262
+ {
263
+ __str__: "qwer",
264
+ name: "qwer",
265
+ },
266
+ "delete"
267
+ )
268
+ ).toThrow("deleteFromSubscription: delete for id not in objects ({ __str__: 'qwer', name: 'qwer' }).");
269
+
270
+ expect(() => passedSubscriptionEventCallback(2, "delete")).toThrow(ListSubscriptionError);
271
+ expect(() => passedSubscriptionEventCallback(2, "delete")).toThrow(
272
+ "deleteFromSubscription: delete for id not in objects (2)."
273
+ );
274
+
275
+ const returnValue = await listSubscription.unsubscribe();
276
+ expect(globalUnsubscribe).toHaveBeenCalledWith();
277
+ expect(globalUnsubscribe).toHaveBeenCalledTimes(1);
278
+ expect(returnValue).toBe(true);
279
+ expect(listSubscription.state.subscribed).toBe(false);
280
+ });
281
+ it("unsubscribe false", async function () {
282
+ globalUnsubscribe.mockImplementation(() => Promise.resolve(false));
283
+ const defaultListArgs = reactive({
284
+ user: 1,
285
+ });
286
+ const defaultRetrieveArgs = reactive({
287
+ fields: fields,
288
+ });
289
+ const listSubscription = useListSubscription({
290
+ defaultListArgs,
291
+ defaultRetrieveArgs,
292
+ });
293
+ await listSubscription.subscribe({});
294
+ expect(globalSubscribe).toHaveBeenCalledWith({
295
+ crudArgs: { stream: "test_stream" },
296
+ listArgs: { user: 1 },
297
+ retrieveArgs: { fields: fields },
298
+ subscriptionEventCallback: expect.any(Function),
299
+ });
300
+ expect(globalSubscribe).toHaveBeenCalledTimes(1);
301
+
302
+ const returnValue = await listSubscription.unsubscribe();
303
+ expect(globalUnsubscribe).toHaveBeenCalledWith();
304
+ expect(globalUnsubscribe).toHaveBeenCalledTimes(1);
305
+ expect(returnValue).toBe(false);
306
+ expect(listSubscription.state.subscribed).toBe(false);
307
+ });
308
+ it("just unsubscribe", async function () {
309
+ globalUnsubscribe.mockImplementation(() => Promise.resolve(false));
310
+ const defaultListArgs = reactive({
311
+ user: 1,
312
+ });
313
+ const defaultRetrieveArgs = reactive({
314
+ fields: fields,
315
+ });
316
+ const listSubscription = useListSubscription({
317
+ defaultListArgs,
318
+ defaultRetrieveArgs,
319
+ });
320
+
321
+ const returnValue = await listSubscription.unsubscribe();
322
+ expect(globalUnsubscribe).toHaveBeenCalledTimes(0);
323
+ expect(returnValue).toBe(false);
324
+ expect(listSubscription.state.subscribed).toBe(undefined);
325
+ });
326
+ it("passed subscribe args", async function () {
327
+ globalUnsubscribe.mockImplementation(() => Promise.resolve(true));
328
+ const listArgs = reactive({
329
+ user: 1,
330
+ });
331
+ const retrieveArgs = reactive({
332
+ fields: fields,
333
+ });
334
+ const listSubscription = useListSubscription({});
335
+ await listSubscription.subscribe({
336
+ listArgs,
337
+ retrieveArgs,
338
+ });
339
+ expect(globalSubscribe).toHaveBeenCalledWith({
340
+ crudArgs: { stream: "test_stream" },
341
+ listArgs: { user: 1 },
342
+ retrieveArgs: { fields: fields },
343
+ subscriptionEventCallback: expect.any(Function),
344
+ });
345
+ expect(globalSubscribe).toHaveBeenCalledTimes(1);
346
+
347
+ const returnValue = await listSubscription.unsubscribe();
348
+ expect(globalUnsubscribe).toHaveBeenCalledWith();
349
+ expect(globalUnsubscribe).toHaveBeenCalledTimes(1);
350
+ expect(returnValue).toBe(true);
351
+ expect(listSubscription.state.subscribed).toBe(false);
352
+ });
353
+ it("double subscribe", async function () {
354
+ globalUnsubscribe.mockImplementation(() => Promise.resolve(true));
355
+ const listArgs = reactive({
356
+ user: 1,
357
+ });
358
+ const retrieveArgs = reactive({
359
+ fields: fields,
360
+ });
361
+ const listSubscription = useListSubscription({});
362
+ const firstReturnValue = await listSubscription.subscribe({
363
+ listArgs,
364
+ retrieveArgs,
365
+ });
366
+ const secondReturnValue = await listSubscription.subscribe({
367
+ listArgs,
368
+ retrieveArgs,
369
+ });
370
+ expect(globalSubscribe).toHaveBeenCalledWith({
371
+ crudArgs: { stream: "test_stream" },
372
+ listArgs: { user: 1 },
373
+ retrieveArgs: { fields: fields },
374
+ subscriptionEventCallback: expect.any(Function),
375
+ });
376
+ expect(globalSubscribe).toHaveBeenCalledTimes(1);
377
+
378
+ expect(firstReturnValue).toBe(true);
379
+ expect(secondReturnValue).toBe(false);
380
+
381
+ const returnValue = await listSubscription.unsubscribe();
382
+ expect(globalUnsubscribe).toHaveBeenCalledWith();
383
+ expect(globalUnsubscribe).toHaveBeenCalledTimes(1);
384
+ expect(returnValue).toBe(true);
385
+ expect(listSubscription.state.subscribed).toBe(false);
386
+ });
387
+ it("manual list instance", async function () {
388
+ globalUnsubscribe.mockImplementation(() => Promise.resolve(true));
389
+ const defaultListArgs = reactive({
390
+ user: 1,
391
+ });
392
+ const defaultRetrieveArgs = reactive({
393
+ fields: fields,
394
+ });
395
+ const listInstance = useListInstance({
396
+ defaultListArgs,
397
+ defaultRetrieveArgs,
398
+ });
399
+ const listSubscription = useListSubscription({
400
+ listInstance,
401
+ });
402
+ expect(listSubscription.listInstance).toBe(listInstance);
403
+ await listSubscription.subscribe();
404
+ expect(globalSubscribe).toHaveBeenCalledWith({
405
+ crudArgs: { stream: "test_stream" },
406
+ listArgs: { user: 1 },
407
+ retrieveArgs: { fields: fields },
408
+ subscriptionEventCallback: expect.any(Function),
409
+ });
410
+ expect(globalSubscribe).toHaveBeenCalledTimes(1);
411
+
412
+ passedSubscriptionEventCallback(
413
+ {
414
+ id: 1,
415
+ __str__: "qwer",
416
+ name: "qwer",
417
+ },
418
+ "create"
419
+ );
420
+
421
+ expect(listInstance.state.objects).toEqual({
422
+ 1: {
423
+ id: 1,
424
+ __str__: "qwer",
425
+ name: "qwer",
426
+ },
427
+ });
428
+
429
+ passedSubscriptionEventCallback(
430
+ {
431
+ id: 1,
432
+ __str__: "qwert",
433
+ fame: "qwert",
434
+ },
435
+ "update"
436
+ );
437
+
438
+ expect(listInstance.state.objects).toEqual({
439
+ 1: {
440
+ id: 1,
441
+ __str__: "qwert",
442
+ fame: "qwert",
443
+ },
444
+ });
445
+
446
+ passedSubscriptionEventCallback(1, "delete");
447
+
448
+ expect(listInstance.state.objects).toEqual({});
449
+
450
+ const returnValue = await listSubscription.unsubscribe();
451
+ expect(globalUnsubscribe).toHaveBeenCalledWith();
452
+ expect(globalUnsubscribe).toHaveBeenCalledTimes(1);
453
+ expect(returnValue).toBe(true);
454
+ expect(listSubscription.state.subscribed).toBe(false);
455
+ });
456
+ });
457
+ it("useListSubscriptions", async function () {
458
+ const listSubscriptionA = useListSubscription({
459
+ crudArgs: { stream: "test_streamA" },
460
+ listArgs: { user: 1 },
461
+ retrieveArgs: {
462
+ fields,
463
+ },
464
+ });
465
+ const listSubscriptionB = useListSubscription({
466
+ crudArgs: { stream: "test_streamB" },
467
+ listArgs: { user: 2 },
468
+ retrieveArgs: {
469
+ fields,
470
+ },
471
+ });
472
+ const listSubscription = useListSubscriptions({
473
+ A: {
474
+ crudArgs: { stream: "test_streamA" },
475
+ listArgs: { user: 1 },
476
+ retrieveArgs: {
477
+ fields,
478
+ },
479
+ },
480
+ B: {
481
+ crudArgs: { stream: "test_streamB" },
482
+ listArgs: { user: 2 },
483
+ retrieveArgs: {
484
+ fields,
485
+ },
486
+ },
487
+ });
488
+ expect(inspect(listSubscription.A)).toEqual(inspect(listSubscriptionA));
489
+ expect(inspect(listSubscription.B)).toEqual(inspect(listSubscriptionB));
490
+ });
491
+ it("useListSubscriptions & useListInstances", async function () {
492
+ const listInstanceA = useListInstance({
493
+ crudArgs: { stream: "test_streamA" },
494
+ listArgs: { user: 1 },
495
+ retrieveArgs: {
496
+ fields,
497
+ },
498
+ });
499
+ const listInstanceB = useListInstance({
500
+ crudArgs: { stream: "test_streamB" },
501
+ listArgs: { user: 2 },
502
+ retrieveArgs: {
503
+ fields,
504
+ },
505
+ });
506
+ const listSubscriptionA = useListSubscription({
507
+ listInstance: listInstanceA,
508
+ });
509
+ const listSubscriptionB = useListSubscription({
510
+ listInstance: listInstanceB,
511
+ });
512
+ const listInstances = useListInstances({
513
+ A: {
514
+ crudArgs: { stream: "test_streamA" },
515
+ listArgs: { user: 1 },
516
+ retrieveArgs: {
517
+ fields,
518
+ },
519
+ },
520
+ B: {
521
+ crudArgs: { stream: "test_streamB" },
522
+ listArgs: { user: 2 },
523
+ retrieveArgs: {
524
+ fields,
525
+ },
526
+ },
527
+ });
528
+ const listSubscription = useListSubscriptions(
529
+ {
530
+ A: {},
531
+ B: {},
532
+ },
533
+ listInstances
534
+ );
535
+ expect(inspect(listSubscription.A.listInstance)).toEqual(inspect(listInstanceA));
536
+ expect(inspect(listSubscription.B.listInstance)).toEqual(inspect(listInstanceB));
537
+ expect(inspect(listSubscription.A)).toEqual(inspect(listSubscriptionA));
538
+ expect(inspect(listSubscription.B)).toEqual(inspect(listSubscriptionB));
539
+ });
540
+ });