@@ -762,6 +762,161 @@ describe('ReactFlightDOMNode', () => {
762762 }
763763 } ) ;
764764
765+ // @gate enableHalt
766+ it ( 'includes source locations in component and owner stacks for halted Client components' , async ( ) => {
767+ function SharedComponent ( { p1, p2, p3} ) {
768+ use ( p1 ) ;
769+ use ( p2 ) ;
770+ use ( p3 ) ;
771+ return < div > Hello, Dave!</ div > ;
772+ }
773+ const ClientComponent = clientExports (
774+ SharedComponent ,
775+ 123 ,
776+ 'path/to/chunk.js' ,
777+ ) ;
778+
779+ let resolvePendingPromise ;
780+ function ServerComponent ( ) {
781+ const p1 = Promise . resolve ( ) ;
782+ const p2 = new Promise ( resolve => {
783+ resolvePendingPromise = value => {
784+ p2 . status = 'fulfilled' ;
785+ p2 . value = value ;
786+ } ;
787+ } ) ;
788+ const p3 = new Promise ( ( ) => { } ) ;
789+ return ReactServer . createElement ( ClientComponent , {
790+ p1 : p1 ,
791+ p2 : p2 ,
792+ p3 : p3 ,
793+ } ) ;
794+ }
795+
796+ function App ( ) {
797+ return ReactServer . createElement (
798+ 'html' ,
799+ null ,
800+ ReactServer . createElement (
801+ 'body' ,
802+ null ,
803+ ReactServer . createElement (
804+ ReactServer . Suspense ,
805+ { fallback : 'Loading...' } ,
806+ ReactServer . createElement ( ServerComponent , null ) ,
807+ ) ,
808+ ) ,
809+ ) ;
810+ }
811+
812+ const errors = [ ] ;
813+ const serverAbortController = new AbortController ( ) ;
814+ const { pendingResult} = await serverAct ( async ( ) => {
815+ // destructure trick to avoid the act scope from awaiting the returned value
816+ return {
817+ pendingResult : ReactServerDOMStaticServer . prerender (
818+ ReactServer . createElement ( App , null ) ,
819+ webpackMap ,
820+ {
821+ signal : serverAbortController . signal ,
822+ onError ( error ) {
823+ errors . push ( error ) ;
824+ } ,
825+ } ,
826+ ) ,
827+ } ;
828+ } ) ;
829+
830+ await serverAct (
831+ async ( ) =>
832+ new Promise ( resolve => {
833+ setImmediate ( ( ) => {
834+ resolve ( ) ;
835+ } ) ;
836+ } ) ,
837+ ) ;
838+
839+ const { prelude} = await pendingResult ;
840+
841+ expect ( errors ) . toEqual ( [ ] ) ;
842+
843+ function ClientRoot ( { response} ) {
844+ return use ( response ) ;
845+ }
846+
847+ const prerenderResponse = ReactServerDOMClient . createFromReadableStream (
848+ await createBufferedUnclosingStream ( prelude ) ,
849+ {
850+ serverConsumerManifest : {
851+ moduleMap : null ,
852+ moduleLoading : null ,
853+ } ,
854+ } ,
855+ ) ;
856+
857+ let componentStack ;
858+ let ownerStack ;
859+
860+ const clientAbortController = new AbortController ( ) ;
861+
862+ const fizzPrerenderStreamResult = ReactDOMFizzStatic . prerender (
863+ React . createElement ( ClientRoot , { response : prerenderResponse } ) ,
864+ {
865+ signal : clientAbortController . signal ,
866+ onError ( error , errorInfo ) {
867+ componentStack = errorInfo . componentStack ;
868+ ownerStack = React . captureOwnerStack
869+ ? React . captureOwnerStack ( )
870+ : null ;
871+ } ,
872+ } ,
873+ ) ;
874+
875+ await serverAct (
876+ async ( ) =>
877+ new Promise ( resolve => {
878+ setImmediate ( ( ) => {
879+ resolvePendingPromise ( ) ;
880+ serverAbortController . abort ( ) ;
881+ clientAbortController . abort ( ) ;
882+ resolve ( ) ;
883+ } ) ;
884+ } ) ,
885+ ) ;
886+
887+ const fizzPrerenderStream = await fizzPrerenderStreamResult ;
888+ const prerenderHTML = await readWebResult ( fizzPrerenderStream . prelude ) ;
889+
890+ expect ( prerenderHTML ) . toContain ( 'Loading...' ) ;
891+
892+ if ( __DEV__ ) {
893+ expect ( normalizeCodeLocInfo ( componentStack ) ) . toBe (
894+ '\n' +
895+ ' in Component (at **)\n' +
896+ ' in Suspense\n' +
897+ ' in body\n' +
898+ ' in html\n' +
899+ ' in App (at **)\n' +
900+ ' in ClientRoot (at **)' ,
901+ ) ;
902+ } else {
903+ expect ( normalizeCodeLocInfo ( componentStack ) ) . toBe (
904+ '\n in Suspense\n' +
905+ ' in body\n' +
906+ ' in html\n' +
907+ ' in ClientRoot (at **)' ,
908+ ) ;
909+ }
910+
911+ if ( __DEV__ ) {
912+ expect ( normalizeCodeLocInfo ( ownerStack ) ) . toBe (
913+ '\n in Component (at **)\n in App (at **)' ,
914+ ) ;
915+ } else {
916+ expect ( ownerStack ) . toBeNull ( ) ;
917+ }
918+ } ) ;
919+
765920 // @gate enableHalt
766921 it ( 'includes deeper location for aborted stacks' , async ( ) => {
767922 async function getData ( ) {
0 commit comments