@@ -15,6 +15,7 @@ let ReactNoop;
1515let Scheduler ;
1616let Suspense ;
1717let useState ;
18+ let useLayoutEffect ;
1819let useTransition ;
1920let startTransition ;
2021let act ;
@@ -30,6 +31,7 @@ describe('ReactTransition', () => {
3031 ReactNoop = require ( 'react-noop-renderer' ) ;
3132 Scheduler = require ( 'scheduler' ) ;
3233 useState = React . useState ;
34+ useLayoutEffect = React . useLayoutEffect ;
3335 useTransition = React . unstable_useTransition ;
3436 Suspense = React . Suspense ;
3537 startTransition = React . unstable_startTransition ;
@@ -773,4 +775,204 @@ describe('ReactTransition', () => {
773775 } ) ;
774776 } ,
775777 ) ;
778+
779+ // @gate experimental
780+ // @gate enableCache
781+ it ( 'should render normal pri updates scheduled after transitions before transitions' , async ( ) => {
782+ let updateTransitionPri ;
783+ let updateNormalPri ;
784+ function App ( ) {
785+ const [ normalPri , setNormalPri ] = useState ( 0 ) ;
786+ const [ transitionPri , setTransitionPri ] = useState ( 0 ) ;
787+ updateTransitionPri = ( ) =>
788+ startTransition ( ( ) => setTransitionPri ( n => n + 1 ) ) ;
789+ updateNormalPri = ( ) => setNormalPri ( n => n + 1 ) ;
790+
791+ useLayoutEffect ( ( ) => {
792+ Scheduler . unstable_yieldValue ( 'Commit' ) ;
793+ } ) ;
794+
795+ return (
796+ < Suspense fallback = { < Text text = "Loading..." /> } >
797+ < Text text = { 'Transition pri: ' + transitionPri } />
798+ { ', ' }
799+ < Text text = { 'Normal pri: ' + normalPri } />
800+ </ Suspense >
801+ ) ;
802+ }
803+
804+ const root = ReactNoop . createRoot ( ) ;
805+ await act ( async ( ) => {
806+ root . render ( < App /> ) ;
807+ } ) ;
808+
809+ // Initial render.
810+ expect ( Scheduler ) . toHaveYielded ( [
811+ 'Transition pri: 0' ,
812+ 'Normal pri: 0' ,
813+ 'Commit' ,
814+ ] ) ;
815+ expect ( root ) . toMatchRenderedOutput ( 'Transition pri: 0, Normal pri: 0' ) ;
816+
817+ await act ( async ( ) => {
818+ updateTransitionPri ( ) ;
819+ updateNormalPri ( ) ;
820+ } ) ;
821+
822+ expect ( Scheduler ) . toHaveYielded ( [
823+ // Normal update first.
824+ 'Transition pri: 0' ,
825+ 'Normal pri: 1' ,
826+ 'Commit' ,
827+
828+ // Then transition update.
829+ 'Transition pri: 1' ,
830+ 'Normal pri: 1' ,
831+ 'Commit' ,
832+ ] ) ;
833+ expect ( root ) . toMatchRenderedOutput ( 'Transition pri: 1, Normal pri: 1' ) ;
834+ } ) ;
835+
836+ // @gate experimental
837+ // @gate enableCache
838+ it ( 'should render normal pri updates before transition suspense retries' , async ( ) => {
839+ let updateTransitionPri ;
840+ let updateNormalPri ;
841+ function App ( ) {
842+ const [ transitionPri , setTransitionPri ] = useState ( false ) ;
843+ const [ normalPri , setNormalPri ] = useState ( 0 ) ;
844+
845+ updateTransitionPri = ( ) => startTransition ( ( ) => setTransitionPri ( true ) ) ;
846+ updateNormalPri = ( ) => setNormalPri ( n => n + 1 ) ;
847+
848+ useLayoutEffect ( ( ) => {
849+ Scheduler . unstable_yieldValue ( 'Commit' ) ;
850+ } ) ;
851+
852+ return (
853+ < Suspense fallback = { < Text text = "Loading..." /> } >
854+ { transitionPri ? < AsyncText text = "Async" /> : < Text text = "(empty)" /> }
855+ { ', ' }
856+ < Text text = { 'Normal pri: ' + normalPri } />
857+ </ Suspense >
858+ ) ;
859+ }
860+
861+ const root = ReactNoop . createRoot ( ) ;
862+ await act ( async ( ) => {
863+ root . render ( < App /> ) ;
864+ } ) ;
865+
866+ // Initial render.
867+ expect ( Scheduler ) . toHaveYielded ( [ '(empty)' , 'Normal pri: 0' , 'Commit' ] ) ;
868+ expect ( root ) . toMatchRenderedOutput ( '(empty), Normal pri: 0' ) ;
869+
870+ await act ( async ( ) => {
871+ updateTransitionPri ( ) ;
872+ } ) ;
873+
874+ expect ( Scheduler ) . toHaveYielded ( [
875+ // Suspend.
876+ 'Suspend! [Async]' ,
877+ 'Normal pri: 0' ,
878+ 'Loading...' ,
879+ ] ) ;
880+ expect ( root ) . toMatchRenderedOutput ( '(empty), Normal pri: 0' ) ;
881+
882+ await act ( async ( ) => {
883+ await resolveText ( 'Async' ) ;
884+ updateNormalPri ( ) ;
885+ } ) ;
886+
887+ expect ( Scheduler ) . toHaveYielded ( [
888+ // Normal pri update.
889+ '(empty)' ,
890+ 'Normal pri: 1' ,
891+ 'Commit' ,
892+
893+ // Promise resolved, retry flushed.
894+ 'Async' ,
895+ 'Normal pri: 1' ,
896+ 'Commit' ,
897+ ] ) ;
898+ expect ( root ) . toMatchRenderedOutput ( 'Async, Normal pri: 1' ) ;
899+ } ) ;
900+
901+ // @gate experimental
902+ // @gate enableCache
903+ it ( 'should not interrupt transitions with normal pri updates' , async ( ) => {
904+ let updateNormalPri ;
905+ let updateTransitionPri ;
906+ function App ( ) {
907+ const [ transitionPri , setTransitionPri ] = useState ( 0 ) ;
908+ const [ normalPri , setNormalPri ] = useState ( 0 ) ;
909+ updateTransitionPri = ( ) =>
910+ startTransition ( ( ) => setTransitionPri ( n => n + 1 ) ) ;
911+ updateNormalPri = ( ) => setNormalPri ( n => n + 1 ) ;
912+
913+ useLayoutEffect ( ( ) => {
914+ Scheduler . unstable_yieldValue ( 'Commit' ) ;
915+ } ) ;
916+ return (
917+ < >
918+ < Text text = { 'Transition pri: ' + transitionPri } />
919+ { ', ' }
920+ < Text text = { 'Normal pri: ' + normalPri } />
921+ </ >
922+ ) ;
923+ }
924+
925+ const root = ReactNoop . createRoot ( ) ;
926+ await ReactNoop . act ( async ( ) => {
927+ root . render ( < App /> ) ;
928+ } ) ;
929+ expect ( Scheduler ) . toHaveYielded ( [
930+ 'Transition pri: 0' ,
931+ 'Normal pri: 0' ,
932+ 'Commit' ,
933+ ] ) ;
934+ expect ( root ) . toMatchRenderedOutput ( 'Transition pri: 0, Normal pri: 0' ) ;
935+
936+ await ReactNoop . act ( async ( ) => {
937+ updateTransitionPri ( ) ;
938+
939+ expect ( Scheduler ) . toFlushAndYieldThrough ( [
940+ // Start transition update.
941+ 'Transition pri: 1' ,
942+ ] ) ;
943+
944+ // Schedule normal pri update during transition update.
945+ // This should not interrupt.
946+ updateNormalPri ( ) ;
947+ } ) ;
948+
949+ if ( gate ( flags => flags . enableNonInterruptingNormalPri ) ) {
950+ expect ( Scheduler ) . toHaveYielded ( [
951+ // Finish transition update.
952+ 'Normal pri: 0' ,
953+ 'Commit' ,
954+
955+ // Normal pri update.
956+ 'Transition pri: 1' ,
957+ 'Normal pri: 1' ,
958+ 'Commit' ,
959+ ] ) ;
960+
961+ expect ( root ) . toMatchRenderedOutput ( 'Transition pri: 1, Normal pri: 1' ) ;
962+ } else {
963+ expect ( Scheduler ) . toHaveYielded ( [
964+ // Interrupt! Render normal pri update.
965+ 'Transition pri: 0' ,
966+ 'Normal pri: 1' ,
967+ 'Commit' ,
968+
969+ // Restart transition update.
970+ 'Transition pri: 1' ,
971+ 'Normal pri: 1' ,
972+ 'Commit' ,
973+ ] ) ;
974+
975+ expect ( root ) . toMatchRenderedOutput ( 'Transition pri: 1, Normal pri: 1' ) ;
976+ }
977+ } ) ;
776978} ) ;
0 commit comments