@@ -795,6 +795,172 @@ describe('ReactIncrementalSideEffects', () => {
795
795
// moves to "current" without flushing due to having lower priority. Does this
796
796
// even happen? Maybe a child doesn't get processed because it is lower prio?
797
797
798
+ it ( 'does not drop priority from a progressed subtree' , ( ) => {
799
+ let ops = [ ] ;
800
+ let lowPri ;
801
+ let highPri ;
802
+
803
+ function LowPriDidComplete ( ) {
804
+ ops . push ( 'LowPriDidComplete' ) ;
805
+ // Because this is terminal, beginning work on LowPriDidComplete implies
806
+ // that LowPri will be completed before the scheduler yields.
807
+ return null ;
808
+ }
809
+
810
+ class LowPri extends React . Component {
811
+ state = { step : 0 } ;
812
+ render ( ) {
813
+ ops . push ( 'LowPri' ) ;
814
+ lowPri = this ;
815
+ return [
816
+ < span key = "1" prop = { this . state . step } /> ,
817
+ < LowPriDidComplete key = "2" /> ,
818
+ ] ;
819
+ }
820
+ }
821
+
822
+ function LowPriSibling ( ) {
823
+ ops . push ( 'LowPriSibling' ) ;
824
+ return null ;
825
+ }
826
+
827
+ class HighPri extends React . Component {
828
+ state = { step : 0 } ;
829
+ render ( ) {
830
+ ops . push ( 'HighPri' ) ;
831
+ highPri = this ;
832
+ return < span prop = { this . state . step } /> ;
833
+ }
834
+ }
835
+
836
+ function App ( ) {
837
+ ops . push ( 'App' ) ;
838
+ return [
839
+ < div key = "1" >
840
+ < LowPri />
841
+ < LowPriSibling />
842
+ </ div > ,
843
+ < div key = "2" > < HighPri /> </ div > ,
844
+ ] ;
845
+ }
846
+
847
+ ReactNoop . render ( < App /> ) ;
848
+ ReactNoop . flush ( ) ;
849
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ div ( span ( 0 ) ) , div ( span ( 0 ) ) ] ) ;
850
+ ops = [ ] ;
851
+
852
+ lowPri . setState ( { step : 1 } ) ;
853
+ // Do just enough work to begin LowPri
854
+ ReactNoop . flushDeferredPri ( 30 ) ;
855
+ expect ( ops ) . toEqual ( [ 'LowPri' ] ) ;
856
+ // Now we'll do one more tick of work to complete LowPri. Because LowPri
857
+ // has a sibling, the parent div of LowPri has not yet completed.
858
+ ReactNoop . flushDeferredPri ( 10 ) ;
859
+ expect ( ops ) . toEqual ( [ 'LowPri' , 'LowPriDidComplete' ] ) ;
860
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
861
+ div ( span ( 0 ) ) , // Complete, but not yet updated
862
+ div ( span ( 0 ) ) ,
863
+ ] ) ;
864
+ ops = [ ] ;
865
+
866
+ // Interrupt with high pri update
867
+ ReactNoop . performAnimationWork ( ( ) => highPri . setState ( { step : 1 } ) ) ;
868
+ ReactNoop . flushAnimationPri ( ) ;
869
+ expect ( ops ) . toEqual ( [ 'HighPri' ] ) ;
870
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
871
+ div ( span ( 0 ) ) , // Completed, but not yet updated
872
+ div ( span ( 1 ) ) ,
873
+ ] ) ;
874
+ ops = [ ] ;
875
+
876
+ ReactNoop . flush ( ) ;
877
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ div ( span ( 1 ) ) , div ( span ( 1 ) ) ] ) ;
878
+ } ) ;
879
+
880
+ it ( 'does not complete already completed work' , ( ) => {
881
+ let ops = [ ] ;
882
+ let lowPri ;
883
+ let highPri ;
884
+
885
+ function LowPriDidComplete ( ) {
886
+ ops . push ( 'LowPriDidComplete' ) ;
887
+ // Because this is terminal, beginning work on LowPriDidComplete implies
888
+ // that LowPri will be completed before the scheduler yields.
889
+ return null ;
890
+ }
891
+
892
+ class LowPri extends React . Component {
893
+ state = { step : 0 } ;
894
+ render ( ) {
895
+ ops . push ( 'LowPri' ) ;
896
+ lowPri = this ;
897
+ return [
898
+ < span key = "1" prop = { this . state . step } /> ,
899
+ < LowPriDidComplete key = "2" /> ,
900
+ ] ;
901
+ }
902
+ }
903
+
904
+ function LowPriSibling ( ) {
905
+ ops . push ( 'LowPriSibling' ) ;
906
+ return null ;
907
+ }
908
+
909
+ class HighPri extends React . Component {
910
+ state = { step : 0 } ;
911
+ render ( ) {
912
+ ops . push ( 'HighPri' ) ;
913
+ highPri = this ;
914
+ return < span prop = { this . state . step } /> ;
915
+ }
916
+ }
917
+
918
+ function App ( ) {
919
+ ops . push ( 'App' ) ;
920
+ return [
921
+ < div key = "1" >
922
+ < LowPri />
923
+ < LowPriSibling />
924
+ </ div > ,
925
+ < div key = "2" > < HighPri /> </ div > ,
926
+ ] ;
927
+ }
928
+
929
+ ReactNoop . render ( < App /> ) ;
930
+ ReactNoop . flush ( ) ;
931
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ div ( span ( 0 ) ) , div ( span ( 0 ) ) ] ) ;
932
+ ops = [ ] ;
933
+
934
+ lowPri . setState ( { step : 1 } ) ;
935
+ // Do just enough work to begin LowPri
936
+ ReactNoop . flushDeferredPri ( 30 ) ;
937
+ expect ( ops ) . toEqual ( [ 'LowPri' ] ) ;
938
+ // Now we'll do one more tick of work to complete LowPri. Because LowPri
939
+ // has a sibling, the parent div of LowPri has not yet completed.
940
+ ReactNoop . flushDeferredPri ( 10 ) ;
941
+ expect ( ops ) . toEqual ( [ 'LowPri' , 'LowPriDidComplete' ] ) ;
942
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
943
+ div ( span ( 0 ) ) , // Complete, but not yet updated
944
+ div ( span ( 0 ) ) ,
945
+ ] ) ;
946
+ ops = [ ] ;
947
+
948
+ // Interrupt with high pri update
949
+ ReactNoop . performAnimationWork ( ( ) => highPri . setState ( { step : 1 } ) ) ;
950
+ ReactNoop . flushAnimationPri ( ) ;
951
+ expect ( ops ) . toEqual ( [ 'HighPri' ] ) ;
952
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
953
+ div ( span ( 0 ) ) , // Completed, but not yet updated
954
+ div ( span ( 1 ) ) ,
955
+ ] ) ;
956
+ ops = [ ] ;
957
+
958
+ // If this is not enough to commit the rest of the work, that means we're
959
+ // not bailing out on the already-completed LowPri tree.
960
+ ReactNoop . flushDeferredPri ( 45 ) ;
961
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ div ( span ( 1 ) ) , div ( span ( 1 ) ) ] ) ;
962
+ } ) ;
963
+
798
964
it ( 'calls callback after update is flushed' , ( ) => {
799
965
let instance ;
800
966
class Foo extends React . Component {
0 commit comments