@mic-rexjs/usecases-react 1.3.36 → 1.4.1

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 (97) hide show
  1. package/README.md +2 -2
  2. package/dist/index.min.js +1 -1
  3. package/es/components/UpdateFragment/index.d.ts +2 -0
  4. package/es/components/UpdateFragment/index.js +8 -0
  5. package/es/components/UpdateFragment/types.d.ts +3 -0
  6. package/es/components/UseCaseFragment/index.d.ts +1 -1
  7. package/es/components/UseCaseFragment/types.d.ts +3 -3
  8. package/es/configs/defaultUseCaseContext/index.d.ts +3 -1
  9. package/es/configs/defaultUseCaseContext/index.js +1 -1
  10. package/es/configs/defaultUseCaseContext/types.d.ts +11 -0
  11. package/es/configs/defaultUseCaseContext/types.js +1 -0
  12. package/es/configs/usecaseContextMap/index.d.ts +1 -3
  13. package/es/configs/usecaseContextMap/types.d.ts +4 -17
  14. package/es/hooks/useCompareDeps/index.d.ts +1 -0
  15. package/es/hooks/useCompareDeps/index.js +24 -0
  16. package/es/hooks/useConstant/index.d.ts +2 -0
  17. package/es/hooks/useConstant/index.js +5 -0
  18. package/es/hooks/useConstant/types.d.ts +3 -0
  19. package/es/hooks/useConstant/types.js +1 -0
  20. package/es/hooks/useConstantFn/index.d.ts +1 -0
  21. package/es/hooks/useConstantFn/index.js +7 -0
  22. package/es/hooks/useOptionsRefCollection/index.d.ts +3 -0
  23. package/es/hooks/useOptionsRefCollection/index.js +22 -0
  24. package/es/hooks/useOptionsRefCollection/types.d.ts +2 -0
  25. package/es/hooks/useOptionsRefCollection/types.js +1 -0
  26. package/es/hooks/useProvider/index.d.ts +7 -0
  27. package/es/hooks/useProvider/index.js +17 -0
  28. package/es/hooks/useProvider/types.d.ts +3 -0
  29. package/es/hooks/useProvider/types.js +1 -0
  30. package/es/hooks/useScope/index.d.ts +2 -0
  31. package/es/hooks/useScope/index.js +3 -0
  32. package/es/hooks/useScope/types.d.ts +3 -0
  33. package/es/hooks/useScope/types.js +1 -0
  34. package/es/hooks/useUseCase/index.js +68 -89
  35. package/es/hooks/useUseCase/index.test.js +638 -156
  36. package/es/hooks/useUseCase/types.d.ts +27 -13
  37. package/es/hooks/useUseCaseContext/index.d.ts +3 -0
  38. package/es/hooks/useUseCaseContext/index.js +17 -0
  39. package/es/index.d.ts +3 -2
  40. package/es/methods/compareProperty/index.d.ts +2 -0
  41. package/es/methods/compareProperty/index.js +34 -0
  42. package/es/methods/compareProperty/types.d.ts +3 -0
  43. package/es/methods/compareProperty/types.js +1 -0
  44. package/es/methods/getRootEntity/index.d.ts +2 -0
  45. package/es/methods/getRootEntity/index.js +9 -0
  46. package/es/methods/hasField/index.d.ts +1 -0
  47. package/es/methods/hasField/index.js +6 -0
  48. package/es/methods/initEntityReducers/index.d.ts +5 -0
  49. package/es/methods/initEntityReducers/index.js +13 -0
  50. package/es/methods/initEntityReducers/types.d.ts +3 -0
  51. package/es/methods/initEntityReducers/types.js +1 -0
  52. package/es/methods/removeItem/index.d.ts +1 -0
  53. package/es/methods/removeItem/index.js +7 -0
  54. package/es/methods/triggerCallbacks/index.d.ts +3 -0
  55. package/es/methods/triggerCallbacks/index.js +14 -0
  56. package/es/methods/triggerWatchers/index.d.ts +2 -0
  57. package/es/methods/triggerWatchers/index.js +14 -0
  58. package/lib/components/UpdateFragment/index.js +16 -0
  59. package/lib/configs/defaultUseCaseContext/index.js +1 -1
  60. package/lib/configs/defaultUseCaseContext/types.js +5 -0
  61. package/lib/hooks/useCompareDeps/index.js +31 -0
  62. package/lib/hooks/useConstant/index.js +16 -0
  63. package/lib/hooks/useConstant/types.js +5 -0
  64. package/lib/hooks/useConstantFn/index.js +18 -0
  65. package/lib/hooks/useOptionsRefCollection/index.js +29 -0
  66. package/lib/hooks/useOptionsRefCollection/types.js +5 -0
  67. package/lib/hooks/useProvider/index.js +30 -0
  68. package/lib/hooks/useProvider/types.js +5 -0
  69. package/lib/hooks/useScope/index.js +10 -0
  70. package/lib/hooks/useScope/types.js +5 -0
  71. package/lib/hooks/useUseCase/index.js +73 -115
  72. package/lib/hooks/useUseCase/index.test.js +841 -240
  73. package/lib/hooks/useUseCaseContext/index.js +24 -0
  74. package/lib/methods/compareProperty/index.js +50 -0
  75. package/lib/methods/compareProperty/types.js +5 -0
  76. package/lib/methods/getRootEntity/index.js +16 -0
  77. package/lib/methods/hasField/index.js +15 -0
  78. package/lib/methods/initEntityReducers/index.js +29 -0
  79. package/lib/methods/initEntityReducers/types.js +5 -0
  80. package/lib/methods/removeItem/index.js +14 -0
  81. package/lib/methods/triggerCallbacks/index.js +22 -0
  82. package/lib/{hooks/useUseCase/methods → methods}/triggerWatchers/index.js +16 -9
  83. package/package.json +2 -2
  84. package/es/core/usecases/optionsGetterCellectionUseCase/index.d.ts +0 -2
  85. package/es/core/usecases/optionsGetterCellectionUseCase/index.js +0 -13
  86. package/es/core/usecases/optionsGetterCellectionUseCase/types.d.ts +0 -8
  87. package/es/hooks/useOptionsTransfer/index.d.ts +0 -3
  88. package/es/hooks/useOptionsTransfer/index.js +0 -15
  89. package/es/hooks/useUseCase/methods/triggerCallbacks/index.d.ts +0 -3
  90. package/es/hooks/useUseCase/methods/triggerCallbacks/index.js +0 -11
  91. package/es/hooks/useUseCase/methods/triggerWatchers/index.d.ts +0 -2
  92. package/es/hooks/useUseCase/methods/triggerWatchers/index.js +0 -10
  93. package/lib/core/usecases/optionsGetterCellectionUseCase/index.js +0 -23
  94. package/lib/hooks/useOptionsTransfer/index.js +0 -23
  95. package/lib/hooks/useUseCase/methods/triggerCallbacks/index.js +0 -32
  96. /package/es/{core/usecases/optionsGetterCellectionUseCase → components/UpdateFragment}/types.js +0 -0
  97. /package/lib/{core/usecases/optionsGetterCellectionUseCase → components/UpdateFragment}/types.js +0 -0
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { objectUseCase, } from '@mic-rexjs/usecases';
2
+ import { objectUseCase, entityUseCase, } from '@mic-rexjs/usecases';
3
3
  import { describe, expect, jest, test } from '@jest/globals';
4
4
  import { renderHook, act, render, fireEvent, screen } from '@testing-library/react';
5
5
  import { useUseCase } from '.';
@@ -34,9 +34,9 @@ const fileUseCase = (options = {}) => {
34
34
  const size = 2000;
35
35
  yield* setPath(entity, path);
36
36
  await Promise.resolve(null);
37
- yield (prevEntity) => {
37
+ yield (oldEntity) => {
38
38
  return {
39
- ...prevEntity,
39
+ ...oldEntity,
40
40
  size,
41
41
  };
42
42
  };
@@ -58,6 +58,9 @@ const mathUseCase = (options = {}) => {
58
58
  };
59
59
  return { add, subtraction };
60
60
  };
61
+ const fieldPathUseCase = () => {
62
+ return objectUseCase();
63
+ };
61
64
  const Child = ({ textPrefix = '', onUpdate, onPathChange, onUndefinedEntity }) => {
62
65
  const [file, { setPath }] = useUseCase(fileUseCase);
63
66
  const { path, ext } = file || {};
@@ -121,31 +124,31 @@ describe('useUseCase', () => {
121
124
  const { result } = renderHook(() => {
122
125
  return useUseCase(defaultFile, fileUseCase);
123
126
  });
124
- const { current: context } = result;
125
- expect(context).toHaveLength(3);
127
+ const { current: cores } = result;
128
+ expect(cores).toHaveLength(3);
126
129
  });
127
130
  test('`entity` should equal `defaultFile`', () => {
128
131
  const { result } = renderHook(() => {
129
132
  return useUseCase(defaultFile, fileUseCase);
130
133
  });
131
- const { current: context } = result;
132
- const [entity] = context;
134
+ const { current: cores } = result;
135
+ const [entity] = cores;
133
136
  expect(entity).toBe(defaultFile);
134
137
  });
135
138
  test('`reducers` should be returned as an object', () => {
136
139
  const { result } = renderHook(() => {
137
140
  return useUseCase(defaultFile, fileUseCase);
138
141
  });
139
- const { current: context } = result;
140
- const [, reducers] = context;
142
+ const { current: cores } = result;
143
+ const [, reducers] = cores;
141
144
  expect(typeof reducers).toBe('object');
142
145
  });
143
146
  test('`Provider` should be returned as a function', () => {
144
147
  const { result } = renderHook(() => {
145
148
  return useUseCase(defaultFile, fileUseCase);
146
149
  });
147
- const { current: context } = result;
148
- const [, , Provider] = context;
150
+ const { current: cores } = result;
151
+ const [, , Provider] = cores;
149
152
  expect(typeof Provider).toBe('function');
150
153
  });
151
154
  test('after call non-generator reducer, it should not trigger update', () => {
@@ -189,14 +192,14 @@ describe('useUseCase', () => {
189
192
  });
190
193
  return useUseCase(defaultFile, fileUseCase);
191
194
  });
192
- const { current: context } = result;
193
- const [entity, reducers] = context;
195
+ const { current: cores } = result;
196
+ const [entity, reducers] = cores;
194
197
  const { setPath, setEntity } = reducers;
195
198
  act(() => {
196
199
  setPath(PATH_1);
197
200
  setEntity({ size: 5000 });
198
201
  });
199
- expect(result.current).not.toBe(context);
202
+ expect(result.current).not.toBe(cores);
200
203
  expect(result.current[0]).not.toBe(entity);
201
204
  expect(result.current[1]).not.toBe(reducers);
202
205
  expect(result.current[1].setPath).not.toBe(setPath);
@@ -216,14 +219,14 @@ describe('useUseCase', () => {
216
219
  });
217
220
  return useUseCase(defaultFile, fileUseCase);
218
221
  });
219
- const { current: context } = result;
220
- const [entity, reducers] = context;
222
+ const { current: cores } = result;
223
+ const [entity, reducers] = cores;
221
224
  const { readFile } = reducers;
222
225
  const promise = act(() => {
223
226
  return readFile(PATH_1);
224
227
  });
225
- expect(result.current).toBe(context);
226
- expect(result.current).toEqual(context);
228
+ expect(result.current).toBe(cores);
229
+ expect(result.current).toEqual(cores);
227
230
  expect(onUpdate).toHaveBeenCalledTimes(0);
228
231
  await promise;
229
232
  expect(result.current[0]).not.toBe(entity);
@@ -242,8 +245,8 @@ describe('useUseCase', () => {
242
245
  });
243
246
  return useUseCase(defaultFile, fileUseCase);
244
247
  });
245
- const { current: context } = result;
246
- const [, reducers] = context;
248
+ const { current: cores } = result;
249
+ const [, reducers] = cores;
247
250
  const { init } = reducers;
248
251
  act(() => {
249
252
  init({ ...defaultFile, size: 5000 });
@@ -261,8 +264,8 @@ describe('useUseCase', () => {
261
264
  });
262
265
  return useUseCase(file, fileUseCase, { stateless: true });
263
266
  });
264
- const { current: context } = result;
265
- const [, { setPath }] = context;
267
+ const { current: cores } = result;
268
+ const [, { setPath }] = cores;
266
269
  setPath(PATH_1);
267
270
  expect(onUpdate).toHaveBeenCalledTimes(0);
268
271
  expect(result.current[0].path).toBe('');
@@ -279,14 +282,14 @@ describe('useUseCase', () => {
279
282
  });
280
283
  return useUseCase(defaultFile, fileUseCase, { stateless: true });
281
284
  });
282
- const { current: context } = result;
283
- const [, reducers] = context;
285
+ const { current: cores } = result;
286
+ const [, reducers] = cores;
284
287
  const { setPath } = reducers;
285
288
  act(() => {
286
289
  setPath(PATH_1);
287
290
  });
288
- expect(result.current).toBe(context);
289
- expect(result.current).toEqual(context);
291
+ expect(result.current).toBe(cores);
292
+ expect(result.current).toEqual(cores);
290
293
  expect(onUpdate).toHaveBeenCalledTimes(0);
291
294
  });
292
295
  test('`options.onChange` should be trigger when entity has changed', () => {
@@ -294,8 +297,8 @@ describe('useUseCase', () => {
294
297
  const { result } = renderHook(() => {
295
298
  return useUseCase(defaultFile, fileUseCase, { onChange });
296
299
  });
297
- const { current: context } = result;
298
- const [, reducers] = context;
300
+ const { current: cores } = result;
301
+ const [, reducers] = cores;
299
302
  const { setPath } = reducers;
300
303
  expect(onChange).toHaveBeenCalledTimes(0);
301
304
  act(() => {
@@ -311,8 +314,8 @@ describe('useUseCase', () => {
311
314
  options: { pathPrefix: '123/' },
312
315
  });
313
316
  });
314
- const { current: context } = result;
315
- const [{ path }, reducers] = context;
317
+ const { current: cores } = result;
318
+ const [{ path }, reducers] = cores;
316
319
  const { setPath } = reducers;
317
320
  expect(path).toBe('');
318
321
  act(() => {
@@ -343,6 +346,33 @@ describe('useUseCase', () => {
343
346
  expect(onDeepUpdate).toHaveBeenCalledTimes(0);
344
347
  });
345
348
  test('when `entity` change, it should trigger watchers', () => {
349
+ const onPathChange = jest.fn();
350
+ const onSizeChange = jest.fn();
351
+ const { result } = renderHook(() => {
352
+ return useUseCase(defaultFile, fileUseCase, {
353
+ watch: {
354
+ path: onPathChange,
355
+ size: onSizeChange,
356
+ },
357
+ });
358
+ });
359
+ const { current: cores } = result;
360
+ const [, { setPath }] = cores;
361
+ expect(onPathChange).toHaveBeenCalledTimes(0);
362
+ act(() => {
363
+ setPath(PATH_1);
364
+ });
365
+ expect(onPathChange).toHaveBeenCalledTimes(1);
366
+ expect(onSizeChange).toHaveBeenCalledTimes(0);
367
+ expect(onPathChange).toHaveBeenLastCalledWith({
368
+ fieldPaths: ['path'],
369
+ newEntity: { ...defaultFile, path: PATH_1, ext: EXT_1 },
370
+ oldEntity: defaultFile,
371
+ newValue: PATH_1,
372
+ oldValue: '',
373
+ });
374
+ });
375
+ test('watcher should be updated after `entity` change', () => {
346
376
  const onPathChange1 = jest.fn();
347
377
  const onPathChange2 = jest.fn();
348
378
  let onPathChange = onPathChange1;
@@ -353,8 +383,8 @@ describe('useUseCase', () => {
353
383
  },
354
384
  });
355
385
  });
356
- const { current: context } = result;
357
- const [, { setPath, setEntity }] = context;
386
+ const { current: cores } = result;
387
+ const [, { setPath, setEntity }] = cores;
358
388
  onPathChange = onPathChange2;
359
389
  expect(onPathChange1).toHaveBeenCalledTimes(0);
360
390
  act(() => {
@@ -362,12 +392,24 @@ describe('useUseCase', () => {
362
392
  setEntity({ size: 5000 });
363
393
  });
364
394
  expect(onPathChange1).toHaveBeenCalledTimes(1);
365
- expect(onPathChange1).toHaveBeenLastCalledWith({ ...defaultFile, path: PATH_1, ext: EXT_1 }, defaultFile);
395
+ expect(onPathChange1).toHaveBeenLastCalledWith({
396
+ fieldPaths: ['path'],
397
+ newEntity: { ...defaultFile, path: PATH_1, ext: EXT_1 },
398
+ oldEntity: defaultFile,
399
+ newValue: PATH_1,
400
+ oldValue: '',
401
+ });
366
402
  act(() => {
367
403
  setPath('');
368
404
  });
369
405
  expect(onPathChange2).toHaveBeenCalledTimes(1);
370
- expect(onPathChange2).toHaveBeenLastCalledWith({ ...defaultFile, size: 5000 }, { ...defaultFile, path: PATH_1, size: 5000, ext: EXT_1 });
406
+ expect(onPathChange2).toHaveBeenLastCalledWith({
407
+ fieldPaths: ['path'],
408
+ newEntity: { ...defaultFile, size: 5000 },
409
+ oldEntity: { ...defaultFile, path: PATH_1, size: 5000, ext: EXT_1 },
410
+ newValue: '',
411
+ oldValue: PATH_1,
412
+ });
371
413
  });
372
414
  test('when `deps` has changed, it should trigger update', () => {
373
415
  const onUpdate = jest.fn();
@@ -414,72 +456,122 @@ describe('useUseCase', () => {
414
456
  expect(onDeepUpdate).toHaveBeenCalledTimes(0);
415
457
  });
416
458
  });
417
- describe('`useUseCase` should work with 1+ argument on accessor mode', () => {
418
- test('check `context.length`', () => {
459
+ describe('`useUseCase` should work with 1+ arguments on non-entity mode', () => {
460
+ test('`entity` should equal `defaultFile`', () => {
419
461
  const { result } = renderHook(() => {
420
- return useUseCase(fileUseCase);
462
+ return useUseCase(mathUseCase);
421
463
  });
422
- const { current: context } = result;
423
- expect(context).toHaveLength(2);
464
+ const { current: reducers } = result;
465
+ expect(Array.isArray(reducers)).toBe(false);
424
466
  });
425
- test('`entity` should be `undefined`', () => {
467
+ test('returned reducer should work', () => {
426
468
  const { result } = renderHook(() => {
427
- return useUseCase(fileUseCase);
469
+ return useUseCase(mathUseCase);
428
470
  });
429
- const { current: context } = result;
430
- const [entity] = context;
431
- expect(entity).toBe(void 0);
471
+ const { current: reducers } = result;
472
+ const { add } = reducers;
473
+ expect(add(1, 2)).toBe(3);
432
474
  });
433
- test('`reducers` should be returned as an object', () => {
475
+ test('`options.extraValue` should be added after call `add` method', () => {
434
476
  const { result } = renderHook(() => {
435
- return useUseCase(fileUseCase);
477
+ return useUseCase(mathUseCase, { extraValue: 5 });
436
478
  });
437
- const { current: context } = result;
438
- const [, reducers] = context;
439
- expect(typeof reducers).toBe('object');
479
+ const { current: reducers } = result;
480
+ const { add } = reducers;
481
+ expect(add(1, 2)).toBe(8);
440
482
  });
441
- test('`yield entity` should not trigger update', () => {
483
+ test('when `options` has changed, it should not trigger update', () => {
442
484
  const onUpdate = jest.fn();
485
+ const onDeepUpdate = jest.fn();
443
486
  const { result } = renderHook(() => {
487
+ const [extraValue, setExtraValue] = useState(0);
488
+ const reducers = useUseCase(mathUseCase, { extraValue });
444
489
  useUpdateEffect(() => {
445
490
  onUpdate();
446
- });
447
- return useUseCase(fileUseCase);
491
+ }, [reducers]);
492
+ useDeepCompareUpdate(() => {
493
+ onDeepUpdate();
494
+ }, [reducers]);
495
+ return setExtraValue;
448
496
  });
449
- const { current: context } = result;
450
- const [, reducers] = context;
451
- const { setPath } = reducers;
497
+ expect(onUpdate).toHaveBeenCalledTimes(0);
498
+ expect(onDeepUpdate).toHaveBeenCalledTimes(0);
452
499
  act(() => {
453
- setPath(PATH_1);
500
+ result.current(3);
454
501
  });
455
- expect(result.current).toBe(context);
456
- expect(result.current).toEqual(context);
457
502
  expect(onUpdate).toHaveBeenCalledTimes(0);
503
+ expect(onDeepUpdate).toHaveBeenCalledTimes(0);
458
504
  });
459
- test('should work within <Child />', () => {
505
+ test('when `deps` change, it should update reducers', () => {
506
+ const onUpdate = jest.fn();
507
+ const onDeepUpdate = jest.fn();
508
+ const { result } = renderHook(() => {
509
+ const [extraValue, setExtraValue] = useState(0);
510
+ const reducers = useUseCase(mathUseCase, { extraValue }, [extraValue]);
511
+ useUpdateEffect(() => {
512
+ onUpdate();
513
+ }, [reducers]);
514
+ useDeepCompareUpdate(() => {
515
+ onDeepUpdate();
516
+ }, [reducers]);
517
+ return setExtraValue;
518
+ });
519
+ expect(onUpdate).toHaveBeenCalledTimes(0);
520
+ expect(onDeepUpdate).toHaveBeenCalledTimes(0);
521
+ act(() => {
522
+ result.current(3);
523
+ });
524
+ expect(onUpdate).toHaveBeenCalledTimes(1);
525
+ expect(onDeepUpdate).toHaveBeenCalledTimes(1);
526
+ });
527
+ test('empty `deps` should not update reducers', () => {
528
+ const onUpdate = jest.fn();
529
+ const onDeepUpdate = jest.fn();
530
+ const { result } = renderHook(() => {
531
+ const [extraValue, setExtraValue] = useState(0);
532
+ const reducers = useUseCase(mathUseCase, { extraValue }, []);
533
+ useUpdateEffect(() => {
534
+ onUpdate();
535
+ }, [reducers]);
536
+ useDeepCompareUpdate(() => {
537
+ onDeepUpdate();
538
+ }, [reducers]);
539
+ return setExtraValue;
540
+ });
541
+ expect(onUpdate).toHaveBeenCalledTimes(0);
542
+ expect(onDeepUpdate).toHaveBeenCalledTimes(0);
543
+ act(() => {
544
+ result.current(3);
545
+ });
546
+ expect(onUpdate).toHaveBeenCalledTimes(0);
547
+ expect(onDeepUpdate).toHaveBeenCalledTimes(0);
548
+ });
549
+ test('should not trigger update', () => {
550
+ const onUpdate = jest.fn();
551
+ render(_jsx(MathParent, { onUpdate: onUpdate }));
552
+ fireEvent.click(screen.getByText(PARENT_BUTTON_TEXT));
553
+ expect(onUpdate).toHaveBeenCalledTimes(0);
554
+ });
555
+ });
556
+ describe('`useUseCase` should work with 1+ arguments on context mode', () => {
557
+ test('should work within <Child /> which it is under <Parent />', () => {
460
558
  const textPrefix = '>>';
461
- const onUpdate1 = jest.fn();
462
- const onPathChange1 = jest.fn();
463
- const onUndefinedEntity1 = jest.fn();
464
- const onUpdate2 = jest.fn();
465
- const onPathChange2 = jest.fn();
466
- const onUndefinedEntity2 = jest.fn();
559
+ const onUpdate = jest.fn();
560
+ const onPathChange = jest.fn();
561
+ const onUndefinedEntity = jest.fn();
467
562
  const onSetPath = jest.fn(() => {
468
563
  return PATH_1;
469
564
  });
470
- render(_jsxs("div", { children: [_jsx(Parent, { onSetPath: onSetPath, children: _jsx(Child, { textPrefix: textPrefix, onUpdate: onUpdate1, onPathChange: onPathChange1, onUndefinedEntity: onUndefinedEntity1 }) }), _jsx(Child, { onUpdate: onUpdate2, onPathChange: onPathChange2, onUndefinedEntity: onUndefinedEntity2 })] }));
565
+ render(_jsx("div", { children: _jsx(Parent, { onSetPath: onSetPath, children: _jsx(Child, { textPrefix: textPrefix, onUpdate: onUpdate, onPathChange: onPathChange, onUndefinedEntity: onUndefinedEntity }) }) }));
471
566
  fireEvent.click(screen.getByText(PARENT_BUTTON_TEXT));
472
567
  expect(onSetPath).toHaveBeenCalledTimes(1);
473
- expect(onUpdate1).toHaveBeenCalledTimes(1);
474
- expect(onPathChange1).toHaveBeenCalledWith(PATH_1);
568
+ expect(onUpdate).toHaveBeenCalledTimes(1);
569
+ expect(onPathChange).toHaveBeenCalledWith(PATH_1);
475
570
  fireEvent.click(screen.getByText(textPrefix + CHILD_BUTTON_TEXT));
476
571
  expect(onSetPath).toHaveBeenCalledTimes(1);
477
- expect(onUpdate1).toHaveBeenCalledTimes(2);
478
- expect(onPathChange1).toHaveBeenCalledWith('');
479
- expect(onUpdate2).toHaveBeenCalledTimes(0);
480
- expect(onPathChange2).toHaveBeenCalledTimes(0);
481
- expect(onUndefinedEntity1).toHaveBeenCalledTimes(0);
482
- expect(onUndefinedEntity2).toHaveBeenCalledTimes(1);
572
+ expect(onUpdate).toHaveBeenCalledTimes(2);
573
+ expect(onPathChange).toHaveBeenCalledWith('');
574
+ expect(onUndefinedEntity).toHaveBeenCalledTimes(0);
483
575
  });
484
576
  test('`options.onChange` event should be trigger at child elements', () => {
485
577
  const onFirstChange = jest.fn();
@@ -522,6 +614,39 @@ describe('useUseCase', () => {
522
614
  expect(onFirstChange).toHaveBeenCalledTimes(1);
523
615
  expect(onParentPathChange).toHaveBeenCalledTimes(2);
524
616
  });
617
+ test('`options.onChange` event should be trigger in orders', () => {
618
+ let changeTimes = 0;
619
+ const updateChangeTimes = () => {
620
+ return ++changeTimes;
621
+ };
622
+ const onChangeA = jest.fn(updateChangeTimes);
623
+ const onChangeB = jest.fn(updateChangeTimes);
624
+ const onChangeC = jest.fn(updateChangeTimes);
625
+ const buttonText = 'my button';
626
+ const A = ({ children }) => {
627
+ useUseCase(fileUseCase, { onChange: onChangeA });
628
+ return _jsx(Fragment, { children: children });
629
+ };
630
+ const B = () => {
631
+ useUseCase(fileUseCase, { onChange: onChangeB });
632
+ return _jsx(Fragment, {});
633
+ };
634
+ const C = () => {
635
+ const [, { setPath }, Provider] = useUseCase(defaultFile, fileUseCase, {
636
+ onChange: onChangeC,
637
+ });
638
+ const onFirstClick = () => {
639
+ setPath(PATH_1);
640
+ };
641
+ return (_jsxs(Provider, { children: [_jsx(A, { children: _jsx(B, {}) }), _jsx("button", { onClick: onFirstClick, children: buttonText })] }));
642
+ };
643
+ render(_jsx(C, {}));
644
+ expect(changeTimes).toBe(0);
645
+ fireEvent.click(screen.getByText(buttonText));
646
+ expect(onChangeA).toHaveReturnedWith(2);
647
+ expect(onChangeB).toHaveReturnedWith(1);
648
+ expect(onChangeC).toHaveReturnedWith(3);
649
+ });
525
650
  test('`options.watch` should be trigger at child elements', () => {
526
651
  const onFirstExtChange = jest.fn();
527
652
  const onSecondExtChange = jest.fn();
@@ -556,115 +681,472 @@ describe('useUseCase', () => {
556
681
  expect(onFirstExtChange).toHaveBeenCalledTimes(0);
557
682
  fireEvent.click(screen.getByText(firstButtonText));
558
683
  expect(onFirstExtChange).toHaveBeenCalledTimes(1);
559
- expect(onFirstExtChange).toHaveBeenLastCalledWith({ ...defaultFile, ext: EXT_1, path: PATH_1 }, defaultFile);
684
+ expect(onFirstExtChange).toHaveBeenLastCalledWith({
685
+ fieldPaths: ['ext'],
686
+ newEntity: { ...defaultFile, ext: EXT_1, path: PATH_1 },
687
+ oldEntity: defaultFile,
688
+ newValue: EXT_1,
689
+ oldValue: '',
690
+ });
560
691
  expect(onParentExtChange).toHaveBeenCalledTimes(1);
561
692
  expect(onSecondExtChange).toHaveBeenCalledTimes(0);
562
693
  fireEvent.click(screen.getByText(secondButtonText));
563
694
  expect(onSecondExtChange).toHaveBeenCalledTimes(1);
564
- expect(onSecondExtChange).toHaveBeenLastCalledWith(defaultFile, {
565
- ...defaultFile,
566
- ext: EXT_1,
567
- path: PATH_1,
695
+ expect(onSecondExtChange).toHaveBeenLastCalledWith({
696
+ fieldPaths: ['ext'],
697
+ newEntity: defaultFile,
698
+ oldEntity: { ...defaultFile, ext: EXT_1, path: PATH_1 },
699
+ newValue: '',
700
+ oldValue: EXT_1,
568
701
  });
569
702
  expect(onFirstExtChange).toHaveBeenCalledTimes(1);
570
703
  expect(onParentExtChange).toHaveBeenCalledTimes(2);
571
704
  });
572
- });
573
- describe('`useUseCase` should work with 1+ arguments on non-entity mode', () => {
574
- test('`entity` should equal `defaultFile`', () => {
575
- const { result } = renderHook(() => {
576
- return useUseCase(mathUseCase);
577
- });
578
- const { current: reducers } = result;
579
- expect(typeof reducers).toBe('object');
705
+ test('`options.watch` should be trigger in orders', () => {
706
+ let changeTimes = 0;
707
+ const updateChangeTimes = (e) => {
708
+ void e;
709
+ return ++changeTimes;
710
+ };
711
+ const onChangeA = jest.fn(updateChangeTimes);
712
+ const onChangeB = jest.fn(updateChangeTimes);
713
+ const onChangeC = jest.fn(updateChangeTimes);
714
+ const buttonText = 'my button';
715
+ const A = ({ children }) => {
716
+ useUseCase(fileUseCase, {
717
+ watch: {
718
+ ext: onChangeA,
719
+ },
720
+ });
721
+ return _jsx(Fragment, { children: children });
722
+ };
723
+ const B = () => {
724
+ useUseCase(fileUseCase, {
725
+ watch: {
726
+ ext: onChangeB,
727
+ },
728
+ });
729
+ return _jsx(Fragment, {});
730
+ };
731
+ const C = () => {
732
+ const [, { setPath }, Provider] = useUseCase(defaultFile, fileUseCase, {
733
+ watch: {
734
+ ext: onChangeC,
735
+ },
736
+ });
737
+ const onFirstClick = () => {
738
+ setPath(PATH_1);
739
+ };
740
+ return (_jsxs(Provider, { children: [_jsx(A, { children: _jsx(B, {}) }), _jsx("button", { onClick: onFirstClick, children: buttonText })] }));
741
+ };
742
+ render(_jsx(C, {}));
743
+ expect(changeTimes).toBe(0);
744
+ fireEvent.click(screen.getByText(buttonText));
745
+ expect(onChangeA).toHaveReturnedWith(2);
746
+ expect(onChangeB).toHaveReturnedWith(1);
747
+ expect(onChangeC).toHaveReturnedWith(3);
580
748
  });
581
- test('returned reducer should work', () => {
749
+ test('`options.watch` should work with array field path of array', () => {
750
+ const onExtChange = jest.fn();
751
+ const onSizeChange = jest.fn();
582
752
  const { result } = renderHook(() => {
583
- return useUseCase(mathUseCase);
753
+ return useUseCase({}, fieldPathUseCase, {
754
+ watch: {
755
+ 'list.ext': onExtChange,
756
+ 'list.size': onSizeChange,
757
+ },
758
+ });
584
759
  });
585
- const { current: reducers } = result;
586
- const { add } = reducers;
587
- expect(add(1, 2)).toBe(3);
588
- });
589
- test('`options.extraValue` should be added after call `add` method', () => {
590
- const { result } = renderHook(() => {
591
- return useUseCase(mathUseCase, { extraValue: 5 });
760
+ const { current: cores } = result;
761
+ const [, { setEntity }] = cores;
762
+ act(() => {
763
+ setEntity({ list: [defaultFile] });
764
+ });
765
+ expect(onExtChange).toHaveBeenCalledTimes(1);
766
+ expect(onSizeChange).toHaveBeenCalledTimes(1);
767
+ expect(onExtChange).toHaveBeenCalledWith({
768
+ fieldPaths: ['list', '0', 'ext'],
769
+ newEntity: { list: [defaultFile] },
770
+ oldEntity: {},
771
+ newValue: '',
772
+ oldValue: void 0,
773
+ });
774
+ expect(onSizeChange).toHaveBeenCalledWith({
775
+ fieldPaths: ['list', '0', 'size'],
776
+ newEntity: { list: [defaultFile] },
777
+ oldEntity: {},
778
+ newValue: 0,
779
+ oldValue: void 0,
780
+ });
781
+ act(() => {
782
+ setEntity({ list: [{ ...defaultFile, ext: EXT_1 }] });
783
+ });
784
+ expect(onExtChange).toHaveBeenCalledTimes(2);
785
+ expect(onSizeChange).toHaveBeenCalledTimes(1);
786
+ expect(onExtChange).toHaveBeenCalledWith({
787
+ fieldPaths: ['list', '0', 'ext'],
788
+ newEntity: { list: [{ ...defaultFile, ext: EXT_1 }] },
789
+ oldEntity: { list: [defaultFile] },
790
+ newValue: EXT_1,
791
+ oldValue: '',
792
+ });
793
+ act(() => {
794
+ setEntity({
795
+ list: [
796
+ { ...defaultFile, ext: EXT_1 },
797
+ { ...defaultFile, ext: EXT_2 },
798
+ ],
799
+ });
800
+ });
801
+ expect(onExtChange).toHaveBeenCalledTimes(3);
802
+ expect(onSizeChange).toHaveBeenCalledTimes(2);
803
+ expect(onExtChange).toHaveBeenCalledWith({
804
+ fieldPaths: ['list', '1', 'ext'],
805
+ newEntity: {
806
+ list: [
807
+ { ...defaultFile, ext: EXT_1 },
808
+ { ...defaultFile, ext: EXT_2 },
809
+ ],
810
+ },
811
+ oldEntity: { list: [{ ...defaultFile, ext: EXT_1 }] },
812
+ newValue: EXT_2,
813
+ oldValue: void 0,
814
+ });
815
+ expect(onSizeChange).toHaveBeenCalledWith({
816
+ fieldPaths: ['list', '1', 'size'],
817
+ newEntity: {
818
+ list: [
819
+ { ...defaultFile, ext: EXT_1 },
820
+ { ...defaultFile, ext: EXT_2 },
821
+ ],
822
+ },
823
+ oldEntity: { list: [{ ...defaultFile, ext: EXT_1 }] },
824
+ newValue: 0,
825
+ oldValue: void 0,
826
+ });
827
+ act(() => {
828
+ setEntity({
829
+ nestedList: [],
830
+ });
831
+ });
832
+ expect(onExtChange).toHaveBeenCalledTimes(3);
833
+ expect(onSizeChange).toHaveBeenCalledTimes(2);
834
+ act(() => {
835
+ setEntity(() => {
836
+ return {
837
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
838
+ };
839
+ });
840
+ });
841
+ expect(onExtChange).toHaveBeenCalledTimes(6);
842
+ expect(onSizeChange).toHaveBeenCalledTimes(3);
843
+ expect(onExtChange).toHaveBeenNthCalledWith(4, {
844
+ fieldPaths: ['list', '0', 'ext'],
845
+ newEntity: {
846
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
847
+ },
848
+ oldEntity: {
849
+ list: [
850
+ { ...defaultFile, ext: EXT_1 },
851
+ { ...defaultFile, ext: EXT_2 },
852
+ ],
853
+ nestedList: [],
854
+ },
855
+ newValue: EXT_2,
856
+ oldValue: EXT_1,
857
+ });
858
+ expect(onExtChange).toHaveBeenNthCalledWith(5, {
859
+ fieldPaths: ['list', '1', 'ext'],
860
+ newEntity: {
861
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
862
+ },
863
+ oldEntity: {
864
+ list: [
865
+ { ...defaultFile, ext: EXT_1 },
866
+ { ...defaultFile, ext: EXT_2 },
867
+ ],
868
+ nestedList: [],
869
+ },
870
+ newValue: EXT_1,
871
+ oldValue: EXT_2,
872
+ });
873
+ expect(onExtChange).toHaveBeenNthCalledWith(6, {
874
+ fieldPaths: ['list', '2', 'ext'],
875
+ newEntity: {
876
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
877
+ },
878
+ oldEntity: {
879
+ list: [
880
+ { ...defaultFile, ext: EXT_1 },
881
+ { ...defaultFile, ext: EXT_2 },
882
+ ],
883
+ nestedList: [],
884
+ },
885
+ newValue: '',
886
+ oldValue: void 0,
887
+ });
888
+ expect(onSizeChange).toHaveBeenCalledWith({
889
+ fieldPaths: ['list', '2', 'size'],
890
+ newEntity: {
891
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
892
+ },
893
+ oldEntity: {
894
+ list: [
895
+ { ...defaultFile, ext: EXT_1 },
896
+ { ...defaultFile, ext: EXT_2 },
897
+ ],
898
+ nestedList: [],
899
+ },
900
+ newValue: 0,
901
+ oldValue: void 0,
902
+ });
903
+ act(() => {
904
+ setEntity(() => {
905
+ return {};
906
+ });
907
+ });
908
+ expect(onExtChange).toHaveBeenCalledTimes(9);
909
+ expect(onSizeChange).toHaveBeenCalledTimes(6);
910
+ expect(onExtChange).toHaveBeenNthCalledWith(7, {
911
+ fieldPaths: ['list', '0', 'ext'],
912
+ newEntity: {},
913
+ oldEntity: {
914
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
915
+ },
916
+ newValue: void 0,
917
+ oldValue: EXT_2,
918
+ });
919
+ expect(onExtChange).toHaveBeenNthCalledWith(8, {
920
+ fieldPaths: ['list', '1', 'ext'],
921
+ newEntity: {},
922
+ oldEntity: {
923
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
924
+ },
925
+ newValue: void 0,
926
+ oldValue: EXT_1,
927
+ });
928
+ expect(onExtChange).toHaveBeenNthCalledWith(9, {
929
+ fieldPaths: ['list', '2', 'ext'],
930
+ newEntity: {},
931
+ oldEntity: {
932
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
933
+ },
934
+ newValue: void 0,
935
+ oldValue: '',
936
+ });
937
+ expect(onSizeChange).toHaveBeenNthCalledWith(4, {
938
+ fieldPaths: ['list', '0', 'size'],
939
+ newEntity: {},
940
+ oldEntity: {
941
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
942
+ },
943
+ newValue: void 0,
944
+ oldValue: 0,
945
+ });
946
+ expect(onSizeChange).toHaveBeenNthCalledWith(5, {
947
+ fieldPaths: ['list', '1', 'size'],
948
+ newEntity: {},
949
+ oldEntity: {
950
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
951
+ },
952
+ newValue: void 0,
953
+ oldValue: 0,
954
+ });
955
+ expect(onSizeChange).toHaveBeenNthCalledWith(6, {
956
+ fieldPaths: ['list', '2', 'size'],
957
+ newEntity: {},
958
+ oldEntity: {
959
+ list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
960
+ },
961
+ newValue: void 0,
962
+ oldValue: 0,
592
963
  });
593
- const { current: reducers } = result;
594
- const { add } = reducers;
595
- expect(add(1, 2)).toBe(8);
596
964
  });
597
- test('when `options` has changed, it should not trigger update', () => {
598
- const onUpdate = jest.fn();
599
- const onDeepUpdate = jest.fn();
965
+ test('`options.watch` should work with field path of array length', () => {
966
+ const onEntityLengthChange = jest.fn();
967
+ const onListLengthChange = jest.fn();
968
+ const lengthUseCase = () => {
969
+ return entityUseCase();
970
+ };
600
971
  const { result } = renderHook(() => {
601
- const [extraValue, setExtraValue] = useState(0);
602
- const reducers = useUseCase(mathUseCase, { extraValue });
603
- useUpdateEffect(() => {
604
- onUpdate();
605
- }, [reducers]);
606
- useDeepCompareUpdate(() => {
607
- onDeepUpdate();
608
- }, [reducers]);
609
- return setExtraValue;
972
+ return useUseCase([], lengthUseCase, {
973
+ watch: {
974
+ length: onEntityLengthChange,
975
+ 'list.length': onListLengthChange,
976
+ },
977
+ });
610
978
  });
611
- expect(onUpdate).toHaveBeenCalledTimes(0);
612
- expect(onDeepUpdate).toHaveBeenCalledTimes(0);
979
+ const { current: cores } = result;
980
+ const [, { setEntity }] = cores;
981
+ expect(onEntityLengthChange).toHaveBeenCalledTimes(0);
982
+ expect(onListLengthChange).toHaveBeenCalledTimes(0);
613
983
  act(() => {
614
- result.current(3);
984
+ setEntity([{ list: [defaultFile, defaultFile] }]);
985
+ });
986
+ expect(onEntityLengthChange).toHaveBeenCalledTimes(1);
987
+ expect(onListLengthChange).toHaveBeenCalledTimes(1);
988
+ expect(onEntityLengthChange).toHaveBeenCalledWith({
989
+ fieldPaths: ['length'],
990
+ newEntity: [{ list: [defaultFile, defaultFile] }],
991
+ oldEntity: [],
992
+ newValue: 1,
993
+ oldValue: 0,
994
+ });
995
+ expect(onListLengthChange).toHaveBeenCalledWith({
996
+ fieldPaths: ['0', 'list', 'length'],
997
+ newEntity: [{ list: [defaultFile, defaultFile] }],
998
+ oldEntity: [],
999
+ newValue: 2,
1000
+ oldValue: void 0,
615
1001
  });
616
- expect(onUpdate).toHaveBeenCalledTimes(0);
617
- expect(onDeepUpdate).toHaveBeenCalledTimes(0);
618
1002
  });
619
- test('when `deps` change, it should update reducers', () => {
620
- const onUpdate = jest.fn();
621
- const onDeepUpdate = jest.fn();
1003
+ test('`options.watch` should work with field path of nested array', () => {
1004
+ const onChange = jest.fn();
622
1005
  const { result } = renderHook(() => {
623
- const [extraValue, setExtraValue] = useState(0);
624
- const reducers = useUseCase(mathUseCase, { extraValue }, [extraValue]);
625
- useUpdateEffect(() => {
626
- onUpdate();
627
- }, [reducers]);
628
- useDeepCompareUpdate(() => {
629
- onDeepUpdate();
630
- }, [reducers]);
631
- return setExtraValue;
1006
+ return useUseCase({}, fieldPathUseCase, {
1007
+ watch: {
1008
+ 'nestedList.size': onChange,
1009
+ },
1010
+ });
632
1011
  });
633
- expect(onUpdate).toHaveBeenCalledTimes(0);
634
- expect(onDeepUpdate).toHaveBeenCalledTimes(0);
1012
+ const { current: cores } = result;
1013
+ const [, { setEntity }] = cores;
1014
+ expect(onChange).toHaveBeenCalledTimes(0);
635
1015
  act(() => {
636
- result.current(3);
1016
+ setEntity({ nestedList: [[[defaultFile]]] });
1017
+ });
1018
+ expect(onChange).toHaveBeenCalledTimes(1);
1019
+ expect(onChange).toHaveBeenCalledWith({
1020
+ fieldPaths: ['nestedList', '0', '0', '0', 'size'],
1021
+ newEntity: { nestedList: [[[defaultFile]]] },
1022
+ oldEntity: {},
1023
+ newValue: 0,
1024
+ oldValue: void 0,
1025
+ });
1026
+ act(() => {
1027
+ setEntity({
1028
+ nestedList: [
1029
+ [
1030
+ [
1031
+ { ...defaultFile, size: 100 },
1032
+ { ...defaultFile, size: 200 },
1033
+ ],
1034
+ ],
1035
+ [[{ ...defaultFile, size: 300 }]],
1036
+ ],
1037
+ });
1038
+ });
1039
+ expect(onChange).toHaveBeenCalledTimes(4);
1040
+ expect(onChange).toHaveBeenNthCalledWith(2, {
1041
+ fieldPaths: ['nestedList', '0', '0', '0', 'size'],
1042
+ newEntity: {
1043
+ nestedList: [
1044
+ [
1045
+ [
1046
+ { ...defaultFile, size: 100 },
1047
+ { ...defaultFile, size: 200 },
1048
+ ],
1049
+ ],
1050
+ [[{ ...defaultFile, size: 300 }]],
1051
+ ],
1052
+ },
1053
+ oldEntity: { nestedList: [[[defaultFile]]] },
1054
+ newValue: 100,
1055
+ oldValue: 0,
1056
+ });
1057
+ expect(onChange).toHaveBeenNthCalledWith(3, {
1058
+ fieldPaths: ['nestedList', '0', '0', '1', 'size'],
1059
+ newEntity: {
1060
+ nestedList: [
1061
+ [
1062
+ [
1063
+ { ...defaultFile, size: 100 },
1064
+ { ...defaultFile, size: 200 },
1065
+ ],
1066
+ ],
1067
+ [[{ ...defaultFile, size: 300 }]],
1068
+ ],
1069
+ },
1070
+ oldEntity: { nestedList: [[[defaultFile]]] },
1071
+ newValue: 200,
1072
+ oldValue: void 0,
1073
+ });
1074
+ expect(onChange).toHaveBeenNthCalledWith(4, {
1075
+ fieldPaths: ['nestedList', '1', '0', '0', 'size'],
1076
+ newEntity: {
1077
+ nestedList: [
1078
+ [
1079
+ [
1080
+ { ...defaultFile, size: 100 },
1081
+ { ...defaultFile, size: 200 },
1082
+ ],
1083
+ ],
1084
+ [[{ ...defaultFile, size: 300 }]],
1085
+ ],
1086
+ },
1087
+ oldEntity: { nestedList: [[[defaultFile]]] },
1088
+ newValue: 300,
1089
+ oldValue: void 0,
637
1090
  });
638
- expect(onUpdate).toHaveBeenCalledTimes(1);
639
- expect(onDeepUpdate).toHaveBeenCalledTimes(1);
640
1091
  });
641
- test('empty `deps` should not update reducers', () => {
642
- const onUpdate = jest.fn();
643
- const onDeepUpdate = jest.fn();
1092
+ test('`options.watch` should work with field path of object', () => {
1093
+ const onExtChange = jest.fn();
1094
+ const onSizeChange = jest.fn();
644
1095
  const { result } = renderHook(() => {
645
- const [extraValue, setExtraValue] = useState(0);
646
- const reducers = useUseCase(mathUseCase, { extraValue }, []);
647
- useUpdateEffect(() => {
648
- onUpdate();
649
- }, [reducers]);
650
- useDeepCompareUpdate(() => {
651
- onDeepUpdate();
652
- }, [reducers]);
653
- return setExtraValue;
1096
+ return useUseCase({}, fieldPathUseCase, {
1097
+ watch: {
1098
+ 'obj.file.ext': onExtChange,
1099
+ 'obj.file.size': onSizeChange,
1100
+ },
1101
+ });
654
1102
  });
655
- expect(onUpdate).toHaveBeenCalledTimes(0);
656
- expect(onDeepUpdate).toHaveBeenCalledTimes(0);
1103
+ const { current: cores } = result;
1104
+ const [, { setEntity }] = cores;
1105
+ expect(onExtChange).toHaveBeenCalledTimes(0);
657
1106
  act(() => {
658
- result.current(3);
1107
+ setEntity({
1108
+ obj: {
1109
+ file: {
1110
+ ext: EXT_1,
1111
+ },
1112
+ },
1113
+ });
1114
+ });
1115
+ expect(onExtChange).toHaveBeenCalledTimes(1);
1116
+ expect(onSizeChange).toHaveBeenCalledTimes(0);
1117
+ expect(onExtChange).toHaveBeenCalledWith({
1118
+ fieldPaths: ['obj', 'file', 'ext'],
1119
+ newEntity: {
1120
+ obj: {
1121
+ file: {
1122
+ ext: EXT_1,
1123
+ },
1124
+ },
1125
+ },
1126
+ oldEntity: {},
1127
+ newValue: EXT_1,
1128
+ oldValue: void 0,
1129
+ });
1130
+ act(() => {
1131
+ setEntity(() => {
1132
+ return {};
1133
+ });
1134
+ });
1135
+ expect(onExtChange).toHaveBeenCalledTimes(2);
1136
+ expect(onSizeChange).toHaveBeenCalledTimes(0);
1137
+ expect(onExtChange).toHaveBeenCalledWith({
1138
+ fieldPaths: ['obj', 'file', 'ext'],
1139
+ newEntity: {},
1140
+ oldEntity: {
1141
+ obj: {
1142
+ file: {
1143
+ ext: EXT_1,
1144
+ },
1145
+ },
1146
+ },
1147
+ newValue: void 0,
1148
+ oldValue: EXT_1,
659
1149
  });
660
- expect(onUpdate).toHaveBeenCalledTimes(0);
661
- expect(onDeepUpdate).toHaveBeenCalledTimes(0);
662
- });
663
- test('should not trigger update', () => {
664
- const onUpdate = jest.fn();
665
- render(_jsx(MathParent, { onUpdate: onUpdate }));
666
- fireEvent.click(screen.getByText(PARENT_BUTTON_TEXT));
667
- expect(onUpdate).toHaveBeenCalledTimes(0);
668
1150
  });
669
1151
  });
670
1152
  });