@mic-rexjs/usecases-react 2.3.2 → 2.3.4

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.
@@ -19,18 +19,21 @@ const defaultFile = {
19
19
  };
20
20
  const fileUseCase = (options = {}) => {
21
21
  const entityReducers = objectUseCase();
22
- const { pathPrefix = '' } = options;
22
+ const { pathPrefix = '', onPathChange } = options;
23
23
  const init = function* (entity, newEntity = defaultFile) {
24
24
  yield () => {
25
25
  return newEntity;
26
26
  };
27
27
  };
28
28
  const setPath = function* (entity, path) {
29
+ const { path: oldPath } = entity;
30
+ const newPath = pathPrefix + path;
29
31
  yield {
30
32
  ...entity,
31
- path: pathPrefix + path,
33
+ path: newPath,
32
34
  ext: path.match(/\.[^.]+$/)?.[0] || '',
33
35
  };
36
+ onPathChange?.(newPath, oldPath);
34
37
  };
35
38
  const readFile = async function* (entity, path) {
36
39
  const size = 2000;
@@ -60,9 +63,6 @@ const mathUseCase = (options = {}) => {
60
63
  };
61
64
  return { add, subtraction: subtractionReducer };
62
65
  };
63
- const fieldPathUseCase = () => {
64
- return objectUseCase();
65
- };
66
66
  const Child = ({ textPrefix = '', onUpdate, onPathChange, onUndefinedEntity }) => {
67
67
  const [file, { setPath }] = useUseCase(fileUseCase);
68
68
  const { path, ext } = file || {};
@@ -428,13 +428,12 @@ describe('useUseCase', () => {
428
428
  expect(onChange).toHaveBeenCalledTimes(1);
429
429
  expect(onChange).toHaveBeenLastCalledWith({ ...defaultFile, path: PATH_1, ext: EXT_1 }, defaultFile);
430
430
  });
431
- test('`options.onChange` should be updated after `deps` changed', () => {
431
+ test('`options.onChange` should always trigger the latest one', () => {
432
432
  const onChange1 = jest.fn();
433
433
  const onChange2 = jest.fn();
434
434
  let onChange = onChange1;
435
- let deps = [1];
436
435
  const { result } = renderHook(() => {
437
- return useUseCase(defaultFile, fileUseCase, { onChange }, deps);
436
+ return useUseCase(defaultFile, fileUseCase, { onChange }, []);
438
437
  });
439
438
  const { current: cores } = result;
440
439
  const [, reducers] = cores;
@@ -442,7 +441,6 @@ describe('useUseCase', () => {
442
441
  expect(onChange1).toHaveBeenCalledTimes(0);
443
442
  act(() => {
444
443
  setPath(PATH_1);
445
- deps = [2];
446
444
  onChange = onChange2;
447
445
  });
448
446
  expect(onChange2).toHaveBeenCalledTimes(0);
@@ -455,31 +453,6 @@ describe('useUseCase', () => {
455
453
  expect(onChange2).toHaveBeenCalledTimes(1);
456
454
  expect(onChange2).toHaveBeenLastCalledWith({ ...defaultFile, path: PATH_2, ext: EXT_2 }, { ...defaultFile, path: PATH_1, ext: EXT_1 });
457
455
  });
458
- test('`options.onChange` should not be updated if `deps` has not changed', () => {
459
- const onChange1 = jest.fn();
460
- const onChange2 = jest.fn();
461
- let onChange = onChange1;
462
- const { result } = renderHook(() => {
463
- return useUseCase(defaultFile, fileUseCase, { onChange }, []);
464
- });
465
- const { current: cores } = result;
466
- const [, reducers] = cores;
467
- const { setPath } = reducers;
468
- expect(onChange1).toHaveBeenCalledTimes(0);
469
- act(() => {
470
- setPath(PATH_1);
471
- onChange = onChange2;
472
- });
473
- expect(onChange2).toHaveBeenCalledTimes(0);
474
- expect(onChange1).toHaveBeenCalledTimes(1);
475
- expect(onChange1).toHaveBeenLastCalledWith({ ...defaultFile, path: PATH_1, ext: EXT_1 }, defaultFile);
476
- act(() => {
477
- setPath(PATH_2);
478
- });
479
- expect(onChange2).toHaveBeenCalledTimes(0);
480
- expect(onChange1).toHaveBeenCalledTimes(2);
481
- expect(onChange1).toHaveBeenLastCalledWith({ ...defaultFile, path: PATH_2, ext: EXT_2 }, { ...defaultFile, path: PATH_1, ext: EXT_1 });
482
- });
483
456
  test('`options.options` should override rest options', () => {
484
457
  const { result } = renderHook(() => {
485
458
  return useUseCase(defaultFile, fileUseCase, {
@@ -518,33 +491,6 @@ describe('useUseCase', () => {
518
491
  expect(onUpdate).toHaveBeenCalledTimes(0);
519
492
  expect(onDeepUpdate).toHaveBeenCalledTimes(0);
520
493
  });
521
- test('when `entity` change, it should trigger watchers', () => {
522
- const onPathChange = jest.fn();
523
- const onSizeChange = jest.fn();
524
- const { result } = renderHook(() => {
525
- return useUseCase(defaultFile, fileUseCase, {
526
- watch: {
527
- path: onPathChange,
528
- size: onSizeChange,
529
- },
530
- });
531
- });
532
- const { current: cores } = result;
533
- const [, { setPath }] = cores;
534
- expect(onPathChange).toHaveBeenCalledTimes(0);
535
- act(() => {
536
- setPath(PATH_1);
537
- });
538
- expect(onPathChange).toHaveBeenCalledTimes(1);
539
- expect(onSizeChange).toHaveBeenCalledTimes(0);
540
- expect(onPathChange).toHaveBeenLastCalledWith({
541
- fieldPaths: ['path'],
542
- newEntity: { ...defaultFile, path: PATH_1, ext: EXT_1 },
543
- oldEntity: defaultFile,
544
- newValue: PATH_1,
545
- oldValue: '',
546
- });
547
- });
548
494
  test('when `deps` has changed, it should trigger update', () => {
549
495
  const onUpdate = jest.fn();
550
496
  const onDeepUpdate = jest.fn();
@@ -589,489 +535,28 @@ describe('useUseCase', () => {
589
535
  expect(onUpdate).toHaveBeenCalledTimes(0);
590
536
  expect(onDeepUpdate).toHaveBeenCalledTimes(0);
591
537
  });
592
- test('`options.watch` should be updated after `deps` changed', () => {
538
+ test(`should call latest functions of usecase options even deps has not change`, () => {
593
539
  const onPathChange1 = jest.fn();
594
540
  const onPathChange2 = jest.fn();
595
541
  let onPathChange = onPathChange1;
596
- let deps = [1];
597
542
  const { result } = renderHook(() => {
598
- return useUseCase(defaultFile, fileUseCase, {
599
- watch: {
600
- path: onPathChange,
601
- },
602
- }, deps);
543
+ return useUseCase(defaultFile, fileUseCase, { onPathChange });
603
544
  });
604
- const { current: cores } = result;
605
- const [, { setPath, setEntity }] = cores;
606
- expect(onPathChange1).toHaveBeenCalledTimes(0);
545
+ const { current: context } = result;
546
+ const [, { setPath }] = context;
607
547
  act(() => {
608
548
  setPath(PATH_1);
609
- setEntity({ size: 5000 });
610
- deps = [2];
611
549
  onPathChange = onPathChange2;
612
550
  });
613
551
  expect(onPathChange1).toHaveBeenCalledTimes(1);
614
- expect(onPathChange1).toHaveBeenLastCalledWith({
615
- fieldPaths: ['path'],
616
- newEntity: { ...defaultFile, path: PATH_1, ext: EXT_1 },
617
- oldEntity: defaultFile,
618
- newValue: PATH_1,
619
- oldValue: '',
620
- });
552
+ expect(onPathChange2).toHaveBeenCalledTimes(0);
553
+ expect(onPathChange1).toHaveBeenLastCalledWith(PATH_1, '');
621
554
  act(() => {
622
- setPath('');
555
+ setPath(PATH_2);
623
556
  });
624
557
  expect(onPathChange1).toHaveBeenCalledTimes(1);
625
558
  expect(onPathChange2).toHaveBeenCalledTimes(1);
626
- expect(onPathChange2).toHaveBeenLastCalledWith({
627
- fieldPaths: ['path'],
628
- newEntity: { ...defaultFile, size: 5000 },
629
- oldEntity: { ...defaultFile, path: PATH_1, ext: EXT_1, size: 5000 },
630
- newValue: '',
631
- oldValue: PATH_1,
632
- });
633
- });
634
- test('`options.watch` should not be updated if `deps` has not changed', () => {
635
- const onPathChange1 = jest.fn();
636
- const onPathChange2 = jest.fn();
637
- let onPathChange = onPathChange1;
638
- const { result } = renderHook(() => {
639
- return useUseCase(defaultFile, fileUseCase, {
640
- watch: {
641
- path: onPathChange,
642
- },
643
- }, []);
644
- });
645
- const { current: cores } = result;
646
- const [, { setPath, setEntity }] = cores;
647
- expect(onPathChange1).toHaveBeenCalledTimes(0);
648
- act(() => {
649
- setPath(PATH_1);
650
- setEntity({ size: 5000 });
651
- onPathChange = onPathChange2;
652
- });
653
- expect(onPathChange1).toHaveBeenCalledTimes(1);
654
- expect(onPathChange1).toHaveBeenLastCalledWith({
655
- fieldPaths: ['path'],
656
- newEntity: { ...defaultFile, path: PATH_1, ext: EXT_1 },
657
- oldEntity: defaultFile,
658
- newValue: PATH_1,
659
- oldValue: '',
660
- });
661
- act(() => {
662
- setPath('');
663
- });
664
- expect(onPathChange2).toHaveBeenCalledTimes(0);
665
- expect(onPathChange1).toHaveBeenCalledTimes(2);
666
- expect(onPathChange1).toHaveBeenLastCalledWith({
667
- fieldPaths: ['path'],
668
- newEntity: { ...defaultFile, size: 5000 },
669
- oldEntity: { ...defaultFile, path: PATH_1, ext: EXT_1, size: 5000 },
670
- newValue: '',
671
- oldValue: PATH_1,
672
- });
673
- });
674
- test('`options.watch` should work with array field path of array', () => {
675
- const onExtChange = jest.fn();
676
- const onSizeChange = jest.fn();
677
- const { result } = renderHook(() => {
678
- return useUseCase({}, fieldPathUseCase, {
679
- watch: {
680
- 'list.ext': onExtChange,
681
- 'list.size': onSizeChange,
682
- },
683
- });
684
- });
685
- const { current: cores } = result;
686
- const [, { setEntity }] = cores;
687
- act(() => {
688
- setEntity({ list: [defaultFile] });
689
- });
690
- expect(onExtChange).toHaveBeenCalledTimes(1);
691
- expect(onSizeChange).toHaveBeenCalledTimes(1);
692
- expect(onExtChange).toHaveBeenCalledWith({
693
- fieldPaths: ['list', '0', 'ext'],
694
- newEntity: { list: [defaultFile] },
695
- oldEntity: {},
696
- newValue: '',
697
- oldValue: void 0,
698
- });
699
- expect(onSizeChange).toHaveBeenCalledWith({
700
- fieldPaths: ['list', '0', 'size'],
701
- newEntity: { list: [defaultFile] },
702
- oldEntity: {},
703
- newValue: 0,
704
- oldValue: void 0,
705
- });
706
- act(() => {
707
- setEntity({ list: [{ ...defaultFile, ext: EXT_1 }] });
708
- });
709
- expect(onExtChange).toHaveBeenCalledTimes(2);
710
- expect(onSizeChange).toHaveBeenCalledTimes(1);
711
- expect(onExtChange).toHaveBeenCalledWith({
712
- fieldPaths: ['list', '0', 'ext'],
713
- newEntity: { list: [{ ...defaultFile, ext: EXT_1 }] },
714
- oldEntity: { list: [defaultFile] },
715
- newValue: EXT_1,
716
- oldValue: '',
717
- });
718
- act(() => {
719
- setEntity({
720
- list: [
721
- { ...defaultFile, ext: EXT_1 },
722
- { ...defaultFile, ext: EXT_2 },
723
- ],
724
- });
725
- });
726
- expect(onExtChange).toHaveBeenCalledTimes(3);
727
- expect(onSizeChange).toHaveBeenCalledTimes(2);
728
- expect(onExtChange).toHaveBeenCalledWith({
729
- fieldPaths: ['list', '1', 'ext'],
730
- newEntity: {
731
- list: [
732
- { ...defaultFile, ext: EXT_1 },
733
- { ...defaultFile, ext: EXT_2 },
734
- ],
735
- },
736
- oldEntity: { list: [{ ...defaultFile, ext: EXT_1 }] },
737
- newValue: EXT_2,
738
- oldValue: void 0,
739
- });
740
- expect(onSizeChange).toHaveBeenCalledWith({
741
- fieldPaths: ['list', '1', 'size'],
742
- newEntity: {
743
- list: [
744
- { ...defaultFile, ext: EXT_1 },
745
- { ...defaultFile, ext: EXT_2 },
746
- ],
747
- },
748
- oldEntity: { list: [{ ...defaultFile, ext: EXT_1 }] },
749
- newValue: 0,
750
- oldValue: void 0,
751
- });
752
- act(() => {
753
- setEntity({
754
- nestedList: [],
755
- });
756
- });
757
- expect(onExtChange).toHaveBeenCalledTimes(3);
758
- expect(onSizeChange).toHaveBeenCalledTimes(2);
759
- act(() => {
760
- setEntity(() => {
761
- return {
762
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
763
- };
764
- });
765
- });
766
- expect(onExtChange).toHaveBeenCalledTimes(6);
767
- expect(onSizeChange).toHaveBeenCalledTimes(3);
768
- expect(onExtChange).toHaveBeenNthCalledWith(4, {
769
- fieldPaths: ['list', '0', 'ext'],
770
- newEntity: {
771
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
772
- },
773
- oldEntity: {
774
- list: [
775
- { ...defaultFile, ext: EXT_1 },
776
- { ...defaultFile, ext: EXT_2 },
777
- ],
778
- nestedList: [],
779
- },
780
- newValue: EXT_2,
781
- oldValue: EXT_1,
782
- });
783
- expect(onExtChange).toHaveBeenNthCalledWith(5, {
784
- fieldPaths: ['list', '1', 'ext'],
785
- newEntity: {
786
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
787
- },
788
- oldEntity: {
789
- list: [
790
- { ...defaultFile, ext: EXT_1 },
791
- { ...defaultFile, ext: EXT_2 },
792
- ],
793
- nestedList: [],
794
- },
795
- newValue: EXT_1,
796
- oldValue: EXT_2,
797
- });
798
- expect(onExtChange).toHaveBeenNthCalledWith(6, {
799
- fieldPaths: ['list', '2', 'ext'],
800
- newEntity: {
801
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
802
- },
803
- oldEntity: {
804
- list: [
805
- { ...defaultFile, ext: EXT_1 },
806
- { ...defaultFile, ext: EXT_2 },
807
- ],
808
- nestedList: [],
809
- },
810
- newValue: '',
811
- oldValue: void 0,
812
- });
813
- expect(onSizeChange).toHaveBeenCalledWith({
814
- fieldPaths: ['list', '2', 'size'],
815
- newEntity: {
816
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
817
- },
818
- oldEntity: {
819
- list: [
820
- { ...defaultFile, ext: EXT_1 },
821
- { ...defaultFile, ext: EXT_2 },
822
- ],
823
- nestedList: [],
824
- },
825
- newValue: 0,
826
- oldValue: void 0,
827
- });
828
- act(() => {
829
- setEntity(() => {
830
- return {};
831
- });
832
- });
833
- expect(onExtChange).toHaveBeenCalledTimes(9);
834
- expect(onSizeChange).toHaveBeenCalledTimes(6);
835
- expect(onExtChange).toHaveBeenNthCalledWith(7, {
836
- fieldPaths: ['list', '0', 'ext'],
837
- newEntity: {},
838
- oldEntity: {
839
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
840
- },
841
- newValue: void 0,
842
- oldValue: EXT_2,
843
- });
844
- expect(onExtChange).toHaveBeenNthCalledWith(8, {
845
- fieldPaths: ['list', '1', 'ext'],
846
- newEntity: {},
847
- oldEntity: {
848
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
849
- },
850
- newValue: void 0,
851
- oldValue: EXT_1,
852
- });
853
- expect(onExtChange).toHaveBeenNthCalledWith(9, {
854
- fieldPaths: ['list', '2', 'ext'],
855
- newEntity: {},
856
- oldEntity: {
857
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
858
- },
859
- newValue: void 0,
860
- oldValue: '',
861
- });
862
- expect(onSizeChange).toHaveBeenNthCalledWith(4, {
863
- fieldPaths: ['list', '0', 'size'],
864
- newEntity: {},
865
- oldEntity: {
866
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
867
- },
868
- newValue: void 0,
869
- oldValue: 0,
870
- });
871
- expect(onSizeChange).toHaveBeenNthCalledWith(5, {
872
- fieldPaths: ['list', '1', 'size'],
873
- newEntity: {},
874
- oldEntity: {
875
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
876
- },
877
- newValue: void 0,
878
- oldValue: 0,
879
- });
880
- expect(onSizeChange).toHaveBeenNthCalledWith(6, {
881
- fieldPaths: ['list', '2', 'size'],
882
- newEntity: {},
883
- oldEntity: {
884
- list: [{ ...defaultFile, ext: EXT_2 }, { ...defaultFile, ext: EXT_1 }, defaultFile],
885
- },
886
- newValue: void 0,
887
- oldValue: 0,
888
- });
889
- });
890
- test('`options.watch` should work with field path of array length', () => {
891
- const onEntityLengthChange = jest.fn();
892
- const onListLengthChange = jest.fn();
893
- const lengthUseCase = () => {
894
- return entityUseCase();
895
- };
896
- const { result } = renderHook(() => {
897
- return useUseCase([], lengthUseCase, {
898
- watch: {
899
- length: onEntityLengthChange,
900
- 'list.length': onListLengthChange,
901
- },
902
- });
903
- });
904
- const { current: cores } = result;
905
- const [, { setEntity }] = cores;
906
- expect(onEntityLengthChange).toHaveBeenCalledTimes(0);
907
- expect(onListLengthChange).toHaveBeenCalledTimes(0);
908
- act(() => {
909
- setEntity([{ list: [defaultFile, defaultFile] }]);
910
- });
911
- expect(onEntityLengthChange).toHaveBeenCalledTimes(1);
912
- expect(onListLengthChange).toHaveBeenCalledTimes(1);
913
- expect(onEntityLengthChange).toHaveBeenCalledWith({
914
- fieldPaths: ['length'],
915
- newEntity: [{ list: [defaultFile, defaultFile] }],
916
- oldEntity: [],
917
- newValue: 1,
918
- oldValue: 0,
919
- });
920
- expect(onListLengthChange).toHaveBeenCalledWith({
921
- fieldPaths: ['0', 'list', 'length'],
922
- newEntity: [{ list: [defaultFile, defaultFile] }],
923
- oldEntity: [],
924
- newValue: 2,
925
- oldValue: void 0,
926
- });
927
- });
928
- test('`options.watch` should work with field path of nested array', () => {
929
- const onChange = jest.fn();
930
- const { result } = renderHook(() => {
931
- return useUseCase({}, fieldPathUseCase, {
932
- watch: {
933
- 'nestedList.size': onChange,
934
- },
935
- });
936
- });
937
- const { current: cores } = result;
938
- const [, { setEntity }] = cores;
939
- expect(onChange).toHaveBeenCalledTimes(0);
940
- act(() => {
941
- setEntity({ nestedList: [[[defaultFile]]] });
942
- });
943
- expect(onChange).toHaveBeenCalledTimes(1);
944
- expect(onChange).toHaveBeenCalledWith({
945
- fieldPaths: ['nestedList', '0', '0', '0', 'size'],
946
- newEntity: { nestedList: [[[defaultFile]]] },
947
- oldEntity: {},
948
- newValue: 0,
949
- oldValue: void 0,
950
- });
951
- act(() => {
952
- setEntity({
953
- nestedList: [
954
- [
955
- [
956
- { ...defaultFile, size: 100 },
957
- { ...defaultFile, size: 200 },
958
- ],
959
- ],
960
- [[{ ...defaultFile, size: 300 }]],
961
- ],
962
- });
963
- });
964
- expect(onChange).toHaveBeenCalledTimes(4);
965
- expect(onChange).toHaveBeenNthCalledWith(2, {
966
- fieldPaths: ['nestedList', '0', '0', '0', 'size'],
967
- newEntity: {
968
- nestedList: [
969
- [
970
- [
971
- { ...defaultFile, size: 100 },
972
- { ...defaultFile, size: 200 },
973
- ],
974
- ],
975
- [[{ ...defaultFile, size: 300 }]],
976
- ],
977
- },
978
- oldEntity: { nestedList: [[[defaultFile]]] },
979
- newValue: 100,
980
- oldValue: 0,
981
- });
982
- expect(onChange).toHaveBeenNthCalledWith(3, {
983
- fieldPaths: ['nestedList', '0', '0', '1', 'size'],
984
- newEntity: {
985
- nestedList: [
986
- [
987
- [
988
- { ...defaultFile, size: 100 },
989
- { ...defaultFile, size: 200 },
990
- ],
991
- ],
992
- [[{ ...defaultFile, size: 300 }]],
993
- ],
994
- },
995
- oldEntity: { nestedList: [[[defaultFile]]] },
996
- newValue: 200,
997
- oldValue: void 0,
998
- });
999
- expect(onChange).toHaveBeenNthCalledWith(4, {
1000
- fieldPaths: ['nestedList', '1', '0', '0', 'size'],
1001
- newEntity: {
1002
- nestedList: [
1003
- [
1004
- [
1005
- { ...defaultFile, size: 100 },
1006
- { ...defaultFile, size: 200 },
1007
- ],
1008
- ],
1009
- [[{ ...defaultFile, size: 300 }]],
1010
- ],
1011
- },
1012
- oldEntity: { nestedList: [[[defaultFile]]] },
1013
- newValue: 300,
1014
- oldValue: void 0,
1015
- });
1016
- });
1017
- test('`options.watch` should work with field path of object', () => {
1018
- const onExtChange = jest.fn();
1019
- const onSizeChange = jest.fn();
1020
- const { result } = renderHook(() => {
1021
- return useUseCase({}, fieldPathUseCase, {
1022
- watch: {
1023
- 'obj.file.ext': onExtChange,
1024
- 'obj.file.size': onSizeChange,
1025
- },
1026
- });
1027
- });
1028
- const { current: cores } = result;
1029
- const [, { setEntity }] = cores;
1030
- expect(onExtChange).toHaveBeenCalledTimes(0);
1031
- act(() => {
1032
- setEntity({
1033
- obj: {
1034
- file: {
1035
- ext: EXT_1,
1036
- },
1037
- },
1038
- });
1039
- });
1040
- expect(onExtChange).toHaveBeenCalledTimes(1);
1041
- expect(onSizeChange).toHaveBeenCalledTimes(0);
1042
- expect(onExtChange).toHaveBeenCalledWith({
1043
- fieldPaths: ['obj', 'file', 'ext'],
1044
- newEntity: {
1045
- obj: {
1046
- file: {
1047
- ext: EXT_1,
1048
- },
1049
- },
1050
- },
1051
- oldEntity: {},
1052
- newValue: EXT_1,
1053
- oldValue: void 0,
1054
- });
1055
- act(() => {
1056
- setEntity(() => {
1057
- return {};
1058
- });
1059
- });
1060
- expect(onExtChange).toHaveBeenCalledTimes(2);
1061
- expect(onSizeChange).toHaveBeenCalledTimes(0);
1062
- expect(onExtChange).toHaveBeenCalledWith({
1063
- fieldPaths: ['obj', 'file', 'ext'],
1064
- newEntity: {},
1065
- oldEntity: {
1066
- obj: {
1067
- file: {
1068
- ext: EXT_1,
1069
- },
1070
- },
1071
- },
1072
- newValue: void 0,
1073
- oldValue: EXT_1,
1074
- });
559
+ expect(onPathChange2).toHaveBeenLastCalledWith(PATH_2, PATH_1);
1075
560
  });
1076
561
  test('multiple `Provider` should work', () => {
1077
562
  const onNumberMount = jest.fn();
@@ -1319,99 +804,6 @@ describe('useUseCase', () => {
1319
804
  fireEvent.click(screen.getByText(updateButtonText));
1320
805
  expect(addReducer).toHaveBeenCalledTimes(3);
1321
806
  });
1322
- test.each([UseCaseModes.Normal, UseCaseModes.Stateless])('[mode=%s]: `options.watch` should be updated in child element after `deps` changed', (mode) => {
1323
- const onFirstExtChange = jest.fn();
1324
- const onSecondExtChange = jest.fn();
1325
- let onExtChange = onFirstExtChange;
1326
- let deps = [1];
1327
- const firstButtonText = 'first button';
1328
- const secondButtonText = 'second button';
1329
- const A = () => {
1330
- useUseCase(fileUseCase, {
1331
- watch: {
1332
- ext: onExtChange,
1333
- },
1334
- }, deps);
1335
- return _jsx(Fragment, {});
1336
- };
1337
- const B = () => {
1338
- const [file, setFile] = useState(defaultFile);
1339
- const [, { setPath }, Provider] = useUseCase(file, fileUseCase, mode, {
1340
- onChange(newFile) {
1341
- if ((mode & UseCaseModes.Stateless) !== UseCaseModes.Stateless) {
1342
- return;
1343
- }
1344
- // `stateless` 不会保存状态,所以需要手动保存
1345
- setFile(newFile);
1346
- },
1347
- });
1348
- const onFirstClick = () => {
1349
- setPath(PATH_1);
1350
- deps = [2];
1351
- onExtChange = onSecondExtChange;
1352
- };
1353
- const onSecondClick = () => {
1354
- setPath('');
1355
- };
1356
- return (_jsxs(Provider, { children: [_jsx(A, {}), _jsx("button", { onClick: onFirstClick, children: firstButtonText }), _jsx("button", { onClick: onSecondClick, children: secondButtonText })] }));
1357
- };
1358
- render(_jsx(B, {}));
1359
- expect(onFirstExtChange).toHaveBeenCalledTimes(0);
1360
- fireEvent.click(screen.getByText(firstButtonText));
1361
- expect(onFirstExtChange).toHaveBeenCalledTimes(1);
1362
- expect(onSecondExtChange).toHaveBeenCalledTimes(0);
1363
- fireEvent.click(screen.getByText(secondButtonText));
1364
- expect(onFirstExtChange).toHaveBeenCalledTimes(1);
1365
- expect(onSecondExtChange).toHaveBeenCalledTimes(1);
1366
- expect(onSecondExtChange).toHaveBeenLastCalledWith({
1367
- fieldPaths: ['ext'],
1368
- newEntity: defaultFile,
1369
- oldEntity: { ...defaultFile, ext: EXT_1, path: PATH_1 },
1370
- newValue: '',
1371
- oldValue: EXT_1,
1372
- });
1373
- });
1374
- test.each([UseCaseModes.Normal, UseCaseModes.Stateless])('`options.watch` should not be updated in child element if `deps` has not changed', (mode) => {
1375
- const onFirstExtChange = jest.fn();
1376
- const onSecondExtChange = jest.fn();
1377
- let onExtChange = onFirstExtChange;
1378
- const firstButtonText = 'first button';
1379
- const secondButtonText = 'second button';
1380
- const A = () => {
1381
- useUseCase(fileUseCase, {
1382
- watch: {
1383
- ext: onExtChange,
1384
- },
1385
- }, []);
1386
- return _jsx(Fragment, {});
1387
- };
1388
- const B = () => {
1389
- const [, { setPath }, Provider] = useUseCase(defaultFile, fileUseCase, mode);
1390
- const onFirstClick = () => {
1391
- setPath(PATH_1);
1392
- onExtChange = onSecondExtChange;
1393
- };
1394
- const onSecondClick = () => {
1395
- setPath('');
1396
- };
1397
- return (_jsxs(Provider, { children: [_jsx(A, {}), _jsx("button", { onClick: onFirstClick, children: firstButtonText }), _jsx("button", { onClick: onSecondClick, children: secondButtonText })] }));
1398
- };
1399
- render(_jsx(B, {}));
1400
- expect(onFirstExtChange).toHaveBeenCalledTimes(0);
1401
- fireEvent.click(screen.getByText(firstButtonText));
1402
- expect(onFirstExtChange).toHaveBeenCalledTimes(1);
1403
- expect(onSecondExtChange).toHaveBeenCalledTimes(0);
1404
- fireEvent.click(screen.getByText(secondButtonText));
1405
- expect(onFirstExtChange).toHaveBeenCalledTimes(2);
1406
- expect(onSecondExtChange).toHaveBeenCalledTimes(0);
1407
- expect(onFirstExtChange).toHaveBeenLastCalledWith({
1408
- fieldPaths: ['ext'],
1409
- newEntity: defaultFile,
1410
- oldEntity: { ...defaultFile, ext: EXT_1, path: PATH_1 },
1411
- newValue: '',
1412
- oldValue: EXT_1,
1413
- });
1414
- });
1415
807
  test('`options.onChange` event should be trigger in orders', () => {
1416
808
  let changeTimes = 0;
1417
809
  const updateChangeTimes = () => {
@@ -1445,79 +837,47 @@ describe('useUseCase', () => {
1445
837
  expect(onChangeB).toHaveReturnedWith(1);
1446
838
  expect(onChangeC).toHaveReturnedWith(3);
1447
839
  });
1448
- test('`options.watch` should be trigger at child elements', () => {
1449
- const onExtChange = jest.fn();
840
+ test.each([UseCaseModes.Normal, UseCaseModes.Stateless])('[mode=%s]: `options.onChange` should always trigger the latest one in child components', (mode) => {
841
+ const onFirstChange = jest.fn();
842
+ const onSecondChange = jest.fn();
843
+ let onChange = onFirstChange;
1450
844
  const firstButtonText = 'first button';
845
+ const secondButtonText = 'second button';
1451
846
  const A = () => {
1452
- useUseCase(fileUseCase, {
1453
- watch: {
1454
- ext: onExtChange,
1455
- },
847
+ const [, { setPath }] = useUseCase(fileUseCase, {
848
+ onChange,
1456
849
  });
1457
- return _jsx(Fragment, {});
1458
- };
1459
- const B = () => {
1460
- const [, { setPath }, Provider] = useUseCase(defaultFile, fileUseCase, {});
1461
850
  const onFirstClick = () => {
1462
851
  setPath(PATH_1);
852
+ onChange = onSecondChange;
1463
853
  };
1464
- return (_jsxs(Provider, { children: [_jsx(A, {}), _jsx("button", { onClick: onFirstClick, children: firstButtonText })] }));
1465
- };
1466
- render(_jsx(B, {}));
1467
- expect(onExtChange).toHaveBeenCalledTimes(0);
1468
- fireEvent.click(screen.getByText(firstButtonText));
1469
- expect(onExtChange).toHaveBeenCalledTimes(1);
1470
- expect(onExtChange).toHaveBeenLastCalledWith({
1471
- fieldPaths: ['ext'],
1472
- newEntity: { ...defaultFile, ext: EXT_1, path: PATH_1 },
1473
- oldEntity: defaultFile,
1474
- newValue: EXT_1,
1475
- oldValue: '',
1476
- });
1477
- });
1478
- test('`options.watch` should be trigger in orders', () => {
1479
- let changeTimes = 0;
1480
- const updateChangeTimes = (e) => {
1481
- void e;
1482
- return ++changeTimes;
1483
- };
1484
- const onChangeA = jest.fn(updateChangeTimes);
1485
- const onChangeB = jest.fn(updateChangeTimes);
1486
- const onChangeC = jest.fn(updateChangeTimes);
1487
- const buttonText = 'my button';
1488
- const A = ({ children }) => {
1489
- useUseCase(fileUseCase, {
1490
- watch: {
1491
- ext: onChangeA,
1492
- },
1493
- });
1494
- return _jsx(Fragment, { children: children });
854
+ const onSecondClick = () => {
855
+ setPath('');
856
+ };
857
+ return (_jsxs(Fragment, { children: [_jsx("button", { onClick: onFirstClick, children: firstButtonText }), _jsx("button", { onClick: onSecondClick, children: secondButtonText })] }));
1495
858
  };
1496
859
  const B = () => {
1497
- useUseCase(fileUseCase, {
1498
- watch: {
1499
- ext: onChangeB,
1500
- },
1501
- });
1502
- return _jsx(Fragment, {});
1503
- };
1504
- const C = () => {
1505
- const [, { setPath }, Provider] = useUseCase(defaultFile, fileUseCase, {
1506
- watch: {
1507
- ext: onChangeC,
860
+ const [file, setFile] = useState(defaultFile);
861
+ const [, , Provider] = useUseCase(file, fileUseCase, mode, {
862
+ onChange(newFile) {
863
+ if ((mode & UseCaseModes.Stateless) !== UseCaseModes.Stateless) {
864
+ return;
865
+ }
866
+ // `stateless` 不会保存状态,所以需要手动保存
867
+ setFile(newFile);
1508
868
  },
1509
869
  });
1510
- const onFirstClick = () => {
1511
- setPath(PATH_1);
1512
- };
1513
- return (_jsxs(Provider, { children: [_jsx(A, { children: _jsx(B, {}) }), _jsx("button", { onClick: onFirstClick, children: buttonText })] }));
870
+ return (_jsx(Provider, { children: _jsx(A, {}) }));
1514
871
  };
1515
- render(_jsx(C, {}));
1516
- expect(changeTimes).toBe(0);
1517
- fireEvent.click(screen.getByText(buttonText));
1518
- expect(onChangeA).toHaveReturnedWith(2);
1519
- expect(onChangeB).toHaveReturnedWith(1);
1520
- expect(onChangeC).toHaveReturnedWith(3);
872
+ render(_jsx(B, {}));
873
+ expect(onFirstChange).toHaveBeenCalledTimes(0);
874
+ fireEvent.click(screen.getByText(firstButtonText));
875
+ expect(onFirstChange).toHaveBeenCalledTimes(1);
876
+ expect(onSecondChange).toHaveBeenCalledTimes(0);
877
+ fireEvent.click(screen.getByText(secondButtonText));
878
+ expect(onFirstChange).toHaveBeenCalledTimes(1);
879
+ expect(onSecondChange).toHaveBeenCalledTimes(1);
880
+ expect(onSecondChange).toHaveBeenLastCalledWith(defaultFile, { ...defaultFile, ext: EXT_1, path: PATH_1 });
1521
881
  });
1522
882
  });
1523
883
  describe('`useUseCase` should work the same as `useReducers`', () => {