@@ -757,3 +757,207 @@ test('avoid unnecessary reaction', () => {
757757
758758 expect ( fn1 ) . toBeCalledTimes ( 1 )
759759} )
760+
761+ test ( 'avoid missing reaction' , ( ) => {
762+ const obs = observable < any > ( {
763+ res : 0 ,
764+ } )
765+
766+ const fn1 = jest . fn ( )
767+ const fn2 = jest . fn ( )
768+
769+ let value
770+ autorun ( ( ) => {
771+ fn1 ( )
772+ value = obs . res
773+ } )
774+
775+ autorun ( ( ) => {
776+ fn2 ( )
777+ obs . res
778+ if ( obs . res !== 0 ) obs . res = obs . res + 1
779+ } )
780+
781+ expect ( value ) . toBe ( 0 )
782+
783+ obs . res = 1
784+
785+ expect ( value ) . toBe ( 2 )
786+
787+ expect ( fn1 ) . toBeCalledTimes ( 3 )
788+ expect ( fn2 ) . toBeCalledTimes ( 2 )
789+ } )
790+
791+ test ( 'avoid reaction twice' , ( ) => {
792+ const obs = observable < any > ( {
793+ res : 0 ,
794+ } )
795+
796+ const fn1 = jest . fn ( )
797+ const fn2 = jest . fn ( )
798+
799+ let value
800+ autorun ( ( ) => {
801+ fn1 ( )
802+ obs . res
803+ if ( obs . res !== 0 ) obs . res = obs . res + 1
804+ } )
805+
806+ autorun ( ( ) => {
807+ fn2 ( )
808+ value = obs . res
809+ } )
810+
811+ expect ( value ) . toBe ( 0 )
812+
813+ obs . res = 1
814+
815+ expect ( value ) . toBe ( 2 )
816+ expect ( fn1 ) . toBeCalledTimes ( 2 )
817+ expect ( fn2 ) . toBeCalledTimes ( 2 )
818+ } )
819+
820+ test ( 'computed reaction' , ( ) => {
821+ const obs = observable < any > ( {
822+ aa : 1 ,
823+ bb : 1 ,
824+ } )
825+
826+ const computed = observable . computed ( ( ) => {
827+ return obs . aa + obs . bb
828+ } )
829+
830+ autorun ( ( ) => {
831+ if ( obs . bb === 3 ) {
832+ obs . aa = 3
833+ }
834+ } )
835+
836+ batch ( ( ) => {
837+ obs . aa = 2 // 会触发 computed 发生变化
838+
839+ obs . bb = 3
840+ } )
841+
842+ expect ( computed . value ) . toBe ( 6 )
843+ } )
844+
845+ test ( 'accurate boundary' , ( ) => {
846+ const obs = observable < any > ( {
847+ a : '' ,
848+ b : '' ,
849+ c : '' ,
850+ } )
851+
852+ autorun ( ( ) => {
853+ obs . c = obs . a + obs . b
854+ } )
855+
856+ autorun ( ( ) => {
857+ obs . b = obs . a
858+ } )
859+
860+ obs . a = 'a'
861+ expect ( obs . a ) . toBe ( 'a' )
862+ expect ( obs . b ) . toBe ( 'a' )
863+ expect ( obs . c ) . toBe ( 'aa' )
864+ } )
865+
866+ test ( 'multiple source update' , ( ) => {
867+ const obs = observable < any > ( { } )
868+
869+ const fn1 = jest . fn ( )
870+ const fn2 = jest . fn ( )
871+
872+ autorun ( ( ) => {
873+ const A = obs . A
874+ const B = obs . B
875+ if ( A !== undefined && B !== undefined ) {
876+ obs . C = A / B
877+ fn1 ( )
878+ }
879+ } )
880+
881+ autorun ( ( ) => {
882+ const C = obs . C
883+ const B = obs . B
884+ if ( C !== undefined && B !== undefined ) {
885+ obs . D = C * B
886+ fn2 ( )
887+ }
888+ } )
889+
890+ obs . A = 1
891+ obs . B = 2
892+
893+ expect ( fn1 ) . toBeCalledTimes ( 1 )
894+ expect ( fn2 ) . toBeCalledTimes ( 1 )
895+ } )
896+
897+ test ( 'same source in nest update' , ( ) => {
898+ const obs = observable < any > ( { } )
899+
900+ const fn1 = jest . fn ( )
901+
902+ autorun ( ( ) => {
903+ const B = obs . B
904+ obs . B = 'B'
905+ fn1 ( )
906+ return B
907+ } )
908+
909+ obs . B = 'B2'
910+
911+ expect ( fn1 ) . toBeCalledTimes ( 2 )
912+ } )
913+
914+ test ( 'batch execute autorun cause by deep indirect dependency' , ( ) => {
915+ const obs : any = observable ( { aa : 1 , bb : 1 , cc : 1 } )
916+ const fn = jest . fn ( )
917+ const fn2 = jest . fn ( )
918+ const fn3 = jest . fn ( )
919+
920+ autorun ( ( ) => fn ( ( obs . aa = obs . bb + obs . cc ) ) )
921+ autorun ( ( ) => fn2 ( ( obs . bb = obs . aa + obs . cc ) ) )
922+ autorun ( ( ) => fn3 ( ( obs . cc = obs . aa + obs . bb ) ) )
923+
924+ // 嵌套写法重复调用没意义,只需要确保最新被触发的 reaction 执行,已过时的 reaction 可以忽略
925+ // 比如 fn3 执行,触发 fn 和 fn2,fn 执行又触发 fn2,之前触发的 fn2 是过时的,忽略处理,fn2 只执行一次
926+ expect ( fn ) . toBeCalledTimes ( 3 )
927+ expect ( fn2 ) . toBeCalledTimes ( 2 )
928+ expect ( fn3 ) . toBeCalledTimes ( 1 )
929+
930+ fn . mockClear ( )
931+ fn2 . mockClear ( )
932+ fn3 . mockClear ( )
933+
934+ batch ( ( ) => {
935+ obs . aa = 100
936+ obs . bb = 100
937+ obs . cc = 100
938+ } )
939+
940+ expect ( fn ) . toBeCalledTimes ( 1 )
941+ expect ( fn2 ) . toBeCalledTimes ( 1 )
942+ expect ( fn3 ) . toBeCalledTimes ( 1 )
943+ } )
944+
945+ test ( 'multiple update should trigger only one' , ( ) => {
946+ const obs = observable ( { aa : 1 , bb : 1 } )
947+
948+ autorun ( ( ) => {
949+ obs . aa = obs . bb + 1
950+ obs . bb = obs . aa + 1
951+ } )
952+
953+ expect ( obs . aa ) . toBe ( 2 )
954+ expect ( obs . bb ) . toBe ( 3 )
955+
956+ autorun ( ( ) => {
957+ obs . aa = obs . bb + 1
958+ obs . bb = obs . aa + 1
959+ } )
960+
961+ expect ( obs . aa ) . toBe ( 6 )
962+ expect ( obs . bb ) . toBe ( 7 )
963+ } )
0 commit comments