@@ -812,6 +812,111 @@ describe('ReactFlightDOM', () => {
812
812
expect ( reportedErrors ) . toEqual ( [ ] ) ;
813
813
} ) ;
814
814
815
+ it ( 'should handle streaming async server components' , async ( ) => {
816
+ const reportedErrors = [ ] ;
817
+
818
+ const Row = async ( { current, next} ) => {
819
+ const chunk = await next ;
820
+
821
+ if ( chunk . done ) {
822
+ return chunk . value ;
823
+ }
824
+
825
+ return (
826
+ < Suspense fallback = { chunk . value } >
827
+ < Row current = { chunk . value } next = { chunk . next } />
828
+ </ Suspense >
829
+ ) ;
830
+ } ;
831
+
832
+ function createResolvablePromise ( ) {
833
+ let _resolve , _reject ;
834
+
835
+ const promise = new Promise ( ( resolve , reject ) => {
836
+ _resolve = resolve ;
837
+ _reject = reject ;
838
+ } ) ;
839
+
840
+ return { promise, resolve : _resolve , reject : _reject } ;
841
+ }
842
+
843
+ function createSuspensedChunk ( initialValue ) {
844
+ const { promise, resolve, reject} = createResolvablePromise ( ) ;
845
+
846
+ return {
847
+ row : (
848
+ < Suspense fallback = { initialValue } >
849
+ < Row current = { initialValue } next = { promise } />
850
+ </ Suspense >
851
+ ) ,
852
+ resolve,
853
+ reject,
854
+ } ;
855
+ }
856
+
857
+ function Text ( { children} ) {
858
+ return < div > { children } </ div > ;
859
+ }
860
+
861
+ function makeDelayedText ( ) {
862
+ const { promise, resolve, reject} = createResolvablePromise ( ) ;
863
+ async function DelayedText ( ) {
864
+ const data = await promise ;
865
+ return < Text > { data } </ Text > ;
866
+ }
867
+ return [ DelayedText , resolve , reject ] ;
868
+ }
869
+
870
+ const [ Posts , resolvePostsData ] = makeDelayedText ( ) ;
871
+ const suspendedChunk = createSuspensedChunk ( < p > loading</ p > ) ;
872
+ const model = { rootContent : suspendedChunk . row } ;
873
+
874
+ function ProfilePage ( { response} ) {
875
+ return use ( response ) . rootContent ;
876
+ }
877
+
878
+ const { writable, readable} = getTestStream ( ) ;
879
+ const { pipe} = ReactServerDOMServer . renderToPipeableStream (
880
+ model ,
881
+ webpackMap ,
882
+ {
883
+ onError ( error ) {
884
+ reportedErrors . push ( error ) ;
885
+ } ,
886
+ } ,
887
+ ) ;
888
+ pipe ( writable ) ;
889
+ const response = ReactServerDOMClient . createFromReadableStream ( readable ) ;
890
+ const container = document . createElement ( 'div' ) ;
891
+ const root = ReactDOMClient . createRoot ( container ) ;
892
+
893
+ await act ( ( ) => {
894
+ root . render ( < ProfilePage response = { response } /> ) ;
895
+ } ) ;
896
+
897
+ expect ( container . innerHTML ) . toBe ( '<p>loading</p>' ) ;
898
+
899
+ const resolvable = createResolvablePromise ( ) ;
900
+ const value = < Posts /> ;
901
+
902
+ await act ( async ( ) => {
903
+ suspendedChunk . resolve ( { value, done : false , next : resolvable . promise } ) ;
904
+ await Promise . resolve ( ) ;
905
+ resolvable . resolve ( { value, done : true } ) ;
906
+ } ) ;
907
+
908
+ expect ( container . innerHTML ) . toBe ( '<p>loading</p>' ) ;
909
+
910
+ await act ( async ( ) => {
911
+ jest . advanceTimersByTime ( 500 ) ;
912
+ await resolvePostsData ( 'posts' ) ;
913
+ await 'the inner async function' ;
914
+ } ) ;
915
+
916
+ expect ( container . innerHTML ) . toBe ( '<div>posts</div>' ) ;
917
+ expect ( reportedErrors ) . toEqual ( [ ] ) ;
918
+ } ) ;
919
+
815
920
it ( 'should preserve state of client components on refetch' , async ( ) => {
816
921
// Client
817
922
0 commit comments