@@ -83,7 +83,16 @@ describe('ReactFlight', () => {
8383 ' builds to avoid leaking sensitive details. A digest property is included on this error instance which' +
8484 ' may provide additional details about the nature of the error.' ,
8585 ) ;
86- expect ( this . state . error . digest ) . toContain ( this . props . expectedMessage ) ;
86+ let expectedDigest = this . props . expectedMessage ;
87+ if (
88+ expectedDigest . startsWith ( 'Error: {' ) ||
89+ expectedDigest . startsWith ( 'Error: <' )
90+ ) {
91+ expectedDigest = '{}' ;
92+ } else if ( expectedDigest . startsWith ( 'Error: [' ) ) {
93+ expectedDigest = '[]' ;
94+ }
95+ expect ( this . state . error . digest ) . toContain ( expectedDigest ) ;
8796 expect ( this . state . error . stack ) . toBe (
8897 'Error: ' + this . state . error . message ,
8998 ) ;
@@ -776,6 +785,106 @@ describe('ReactFlight', () => {
776785 } ) ;
777786 } ) ;
778787
788+ it ( 'should emit descriptions of errors in dev' , async ( ) => {
789+ const ClientErrorBoundary = clientReference ( ErrorBoundary ) ;
790+
791+ function Throw ( { value} ) {
792+ throw value ;
793+ }
794+
795+ const testCases = (
796+ < >
797+ < ClientErrorBoundary expectedMessage = "This is a real Error." >
798+ < div >
799+ < Throw value = { new TypeError ( 'This is a real Error.' ) } />
800+ </ div >
801+ </ ClientErrorBoundary >
802+ < ClientErrorBoundary expectedMessage = "Error: This is a string error." >
803+ < div >
804+ < Throw value = "This is a string error." />
805+ </ div >
806+ </ ClientErrorBoundary >
807+ < ClientErrorBoundary expectedMessage = "Error: {message: ..., extra: ..., nested: ...}" >
808+ < div >
809+ < Throw
810+ value = { {
811+ message : 'This is a long message' ,
812+ extra : 'properties' ,
813+ nested : { more : 'prop' } ,
814+ } }
815+ />
816+ </ div >
817+ </ ClientErrorBoundary >
818+ < ClientErrorBoundary
819+ expectedMessage = {
820+ 'Error: {message: "Short", extra: ..., nested: ...}'
821+ } >
822+ < div >
823+ < Throw
824+ value = { {
825+ message : 'Short' ,
826+ extra : 'properties' ,
827+ nested : { more : 'prop' } ,
828+ } }
829+ />
830+ </ div >
831+ </ ClientErrorBoundary >
832+ < ClientErrorBoundary expectedMessage = "Error: Symbol(hello)" >
833+ < div >
834+ < Throw value = { Symbol ( 'hello' ) } />
835+ </ div >
836+ </ ClientErrorBoundary >
837+ < ClientErrorBoundary expectedMessage = "Error: 123" >
838+ < div >
839+ < Throw value = { 123 } />
840+ </ div >
841+ </ ClientErrorBoundary >
842+ < ClientErrorBoundary expectedMessage = "Error: undefined" >
843+ < div >
844+ < Throw value = { undefined } />
845+ </ div >
846+ </ ClientErrorBoundary >
847+ < ClientErrorBoundary expectedMessage = "Error: <div/>" >
848+ < div >
849+ < Throw value = { < div /> } />
850+ </ div >
851+ </ ClientErrorBoundary >
852+ < ClientErrorBoundary expectedMessage = "Error: function Foo() {}" >
853+ < div >
854+ < Throw value = { function Foo ( ) { } } />
855+ </ div >
856+ </ ClientErrorBoundary >
857+ < ClientErrorBoundary expectedMessage = { 'Error: ["array"]' } >
858+ < div >
859+ < Throw value = { [ 'array' ] } />
860+ </ div >
861+ </ ClientErrorBoundary >
862+ </ >
863+ ) ;
864+
865+ const transport = ReactNoopFlightServer . render ( testCases , {
866+ onError ( x ) {
867+ if ( __DEV__ ) {
868+ return 'a dev digest' ;
869+ }
870+ if ( x instanceof Error ) {
871+ return `digest("${ x . message } ")` ;
872+ } else if ( Array . isArray ( x ) ) {
873+ return `digest([])` ;
874+ } else if ( typeof x === 'object' && x !== null ) {
875+ return `digest({})` ;
876+ }
877+ return `digest(Error: ${ String ( x ) } )` ;
878+ } ,
879+ } ) ;
880+
881+ await act ( ( ) => {
882+ startTransition ( ( ) => {
883+ ReactNoop . render ( ReactNoopFlightClient . read ( transport ) ) ;
884+ } ) ;
885+ } ) ;
886+ } ) ;
887+
779888 it ( 'should trigger the inner most error boundary inside a Client Component' , async ( ) => {
780889 function ServerComponent ( ) {
781890 throw new Error ( 'This was thrown in the Server Component.' ) ;
0 commit comments