@mic-rexjs/usecases-react 1.4.0 → 1.5.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 (40) hide show
  1. package/README.md +2 -2
  2. package/dist/index.min.js +1 -1
  3. package/es/components/UseCaseFragment/types.d.ts +1 -1
  4. package/es/hooks/useCompareDeps/index.js +3 -16
  5. package/es/hooks/useReducer/index.d.ts +2 -0
  6. package/es/hooks/useReducer/index.js +20 -0
  7. package/es/hooks/useUseCase/index.js +2 -2
  8. package/es/hooks/useUseCase/index.test.js +493 -41
  9. package/es/hooks/useUseCase/types.d.ts +18 -6
  10. package/es/index.d.ts +1 -0
  11. package/es/index.js +1 -0
  12. package/es/methods/compareProperty/index.d.ts +2 -0
  13. package/es/methods/compareProperty/index.js +34 -0
  14. package/es/methods/compareProperty/types.d.ts +3 -0
  15. package/es/methods/hasField/index.d.ts +1 -0
  16. package/es/methods/hasField/index.js +6 -0
  17. package/es/methods/initEntityReducers/types.d.ts +1 -1
  18. package/es/methods/isSameArray/index.d.ts +1 -0
  19. package/es/methods/isSameArray/index.js +14 -0
  20. package/es/methods/triggerCallbacks/index.d.ts +1 -1
  21. package/es/methods/triggerCallbacks/index.js +3 -3
  22. package/es/methods/triggerWatchers/index.d.ts +1 -1
  23. package/es/methods/triggerWatchers/index.js +12 -8
  24. package/lib/hooks/useCompareDeps/index.js +3 -16
  25. package/lib/hooks/useReducer/index.js +30 -0
  26. package/lib/hooks/useUseCase/index.js +2 -2
  27. package/lib/hooks/useUseCase/index.test.js +643 -91
  28. package/lib/index.js +7 -0
  29. package/lib/methods/compareProperty/index.js +50 -0
  30. package/lib/methods/hasField/index.js +15 -0
  31. package/lib/methods/isSameArray/index.js +21 -0
  32. package/lib/methods/triggerCallbacks/index.js +3 -3
  33. package/lib/methods/triggerWatchers/index.js +16 -9
  34. package/package.json +1 -1
  35. package/es/hooks/useScope/index.d.ts +0 -2
  36. package/es/hooks/useScope/index.js +0 -3
  37. package/es/hooks/useScope/types.d.ts +0 -3
  38. package/lib/hooks/useScope/index.js +0 -10
  39. /package/es/{hooks/useScope → methods/compareProperty}/types.js +0 -0
  40. /package/lib/{hooks/useScope → methods/compareProperty}/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,9 +297,8 @@ describe('useUseCase', () => {
294
297
  const { result } = renderHook(() => {
295
298
  return useUseCase(defaultFile, fileUseCase, { onChange });
296
299
  });
297
- ``;
298
- const { current: context } = result;
299
- const [, reducers] = context;
300
+ const { current: cores } = result;
301
+ const [, reducers] = cores;
300
302
  const { setPath } = reducers;
301
303
  expect(onChange).toHaveBeenCalledTimes(0);
302
304
  act(() => {
@@ -312,8 +314,8 @@ describe('useUseCase', () => {
312
314
  options: { pathPrefix: '123/' },
313
315
  });
314
316
  });
315
- const { current: context } = result;
316
- const [{ path }, reducers] = context;
317
+ const { current: cores } = result;
318
+ const [{ path }, reducers] = cores;
317
319
  const { setPath } = reducers;
318
320
  expect(path).toBe('');
319
321
  act(() => {
@@ -344,6 +346,33 @@ describe('useUseCase', () => {
344
346
  expect(onDeepUpdate).toHaveBeenCalledTimes(0);
345
347
  });
346
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', () => {
347
376
  const onPathChange1 = jest.fn();
348
377
  const onPathChange2 = jest.fn();
349
378
  let onPathChange = onPathChange1;
@@ -354,8 +383,8 @@ describe('useUseCase', () => {
354
383
  },
355
384
  });
356
385
  });
357
- const { current: context } = result;
358
- const [, { setPath, setEntity }] = context;
386
+ const { current: cores } = result;
387
+ const [, { setPath, setEntity }] = cores;
359
388
  onPathChange = onPathChange2;
360
389
  expect(onPathChange1).toHaveBeenCalledTimes(0);
361
390
  act(() => {
@@ -363,12 +392,24 @@ describe('useUseCase', () => {
363
392
  setEntity({ size: 5000 });
364
393
  });
365
394
  expect(onPathChange1).toHaveBeenCalledTimes(1);
366
- 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
+ });
367
402
  act(() => {
368
403
  setPath('');
369
404
  });
370
405
  expect(onPathChange2).toHaveBeenCalledTimes(1);
371
- 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
+ });
372
413
  });
373
414
  test('when `deps` has changed, it should trigger update', () => {
374
415
  const onUpdate = jest.fn();
@@ -640,22 +681,31 @@ describe('useUseCase', () => {
640
681
  expect(onFirstExtChange).toHaveBeenCalledTimes(0);
641
682
  fireEvent.click(screen.getByText(firstButtonText));
642
683
  expect(onFirstExtChange).toHaveBeenCalledTimes(1);
643
- 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
+ });
644
691
  expect(onParentExtChange).toHaveBeenCalledTimes(1);
645
692
  expect(onSecondExtChange).toHaveBeenCalledTimes(0);
646
693
  fireEvent.click(screen.getByText(secondButtonText));
647
694
  expect(onSecondExtChange).toHaveBeenCalledTimes(1);
648
- expect(onSecondExtChange).toHaveBeenLastCalledWith(defaultFile, {
649
- ...defaultFile,
650
- ext: EXT_1,
651
- 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,
652
701
  });
653
702
  expect(onFirstExtChange).toHaveBeenCalledTimes(1);
654
703
  expect(onParentExtChange).toHaveBeenCalledTimes(2);
655
704
  });
656
705
  test('`options.watch` should be trigger in orders', () => {
657
706
  let changeTimes = 0;
658
- const updateChangeTimes = () => {
707
+ const updateChangeTimes = (e) => {
708
+ void e;
659
709
  return ++changeTimes;
660
710
  };
661
711
  const onChangeA = jest.fn(updateChangeTimes);
@@ -696,5 +746,407 @@ describe('useUseCase', () => {
696
746
  expect(onChangeB).toHaveReturnedWith(1);
697
747
  expect(onChangeC).toHaveReturnedWith(3);
698
748
  });
749
+ test('`options.watch` should work with array field path of array', () => {
750
+ const onExtChange = jest.fn();
751
+ const onSizeChange = jest.fn();
752
+ const { result } = renderHook(() => {
753
+ return useUseCase({}, fieldPathUseCase, {
754
+ watch: {
755
+ 'list.ext': onExtChange,
756
+ 'list.size': onSizeChange,
757
+ },
758
+ });
759
+ });
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,
963
+ });
964
+ });
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
+ };
971
+ const { result } = renderHook(() => {
972
+ return useUseCase([], lengthUseCase, {
973
+ watch: {
974
+ length: onEntityLengthChange,
975
+ 'list.length': onListLengthChange,
976
+ },
977
+ });
978
+ });
979
+ const { current: cores } = result;
980
+ const [, { setEntity }] = cores;
981
+ expect(onEntityLengthChange).toHaveBeenCalledTimes(0);
982
+ expect(onListLengthChange).toHaveBeenCalledTimes(0);
983
+ act(() => {
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,
1001
+ });
1002
+ });
1003
+ test('`options.watch` should work with field path of nested array', () => {
1004
+ const onChange = jest.fn();
1005
+ const { result } = renderHook(() => {
1006
+ return useUseCase({}, fieldPathUseCase, {
1007
+ watch: {
1008
+ 'nestedList.size': onChange,
1009
+ },
1010
+ });
1011
+ });
1012
+ const { current: cores } = result;
1013
+ const [, { setEntity }] = cores;
1014
+ expect(onChange).toHaveBeenCalledTimes(0);
1015
+ act(() => {
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,
1090
+ });
1091
+ });
1092
+ test('`options.watch` should work with field path of object', () => {
1093
+ const onExtChange = jest.fn();
1094
+ const onSizeChange = jest.fn();
1095
+ const { result } = renderHook(() => {
1096
+ return useUseCase({}, fieldPathUseCase, {
1097
+ watch: {
1098
+ 'obj.file.ext': onExtChange,
1099
+ 'obj.file.size': onSizeChange,
1100
+ },
1101
+ });
1102
+ });
1103
+ const { current: cores } = result;
1104
+ const [, { setEntity }] = cores;
1105
+ expect(onExtChange).toHaveBeenCalledTimes(0);
1106
+ act(() => {
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,
1149
+ });
1150
+ });
699
1151
  });
700
1152
  });