@@ -57,7 +57,7 @@ describe('ExceptionsManager', () => {
5757 test ( 'forwards error instance to reportException' , ( ) => {
5858 const error = new ReferenceError ( 'Some error happened' ) ;
5959 // Copy all the data we care about before any possible mutation.
60- const { message} = error ;
60+ const { message, name } = error ;
6161
6262 const logToConsoleInReact = ReactFiberErrorDialog . showErrorDialog ( {
6363 ...capturedErrorDefaults ,
@@ -73,6 +73,11 @@ describe('ExceptionsManager', () => {
7373 'This error is located at:' +
7474 capturedErrorDefaults . componentStack ;
7575 expect ( exceptionData . message ) . toBe ( formattedMessage ) ;
76+ expect ( exceptionData . originalMessage ) . toBe ( message ) ;
77+ expect ( exceptionData . name ) . toBe ( name ) ;
78+ expect ( exceptionData . componentStack ) . toBe (
79+ capturedErrorDefaults . componentStack ,
80+ ) ;
7681 expect ( getLineFromFrame ( exceptionData . stack [ 0 ] ) ) . toBe (
7782 "const error = new ReferenceError('Some error happened');" ,
7883 ) ;
@@ -149,6 +154,10 @@ describe('ExceptionsManager', () => {
149154 'This error is located at:' +
150155 capturedErrorDefaults . componentStack ;
151156 expect ( exceptionData . message ) . toBe ( formattedMessage ) ;
157+ expect ( exceptionData . originalMessage ) . toBe ( message ) ;
158+ expect ( exceptionData . componentStack ) . toBe (
159+ capturedErrorDefaults . componentStack ,
160+ ) ;
152161 expect ( exceptionData . stack [ 0 ] . file ) . toMatch ( / R e a c t F i b e r E r r o r D i a l o g \. j s $ / ) ;
153162 expect ( exceptionData . isFatal ) . toBe ( false ) ;
154163 expect ( logToConsoleInReact ) . toBe ( false ) ;
@@ -164,8 +173,16 @@ describe('ExceptionsManager', () => {
164173 expect ( nativeReportException . mock . calls . length ) . toBe ( 1 ) ;
165174 const exceptionData = nativeReportException . mock . calls [ 0 ] [ 0 ] ;
166175 const formattedMessage =
167- 'Unspecified error at:' + capturedErrorDefaults . componentStack ;
176+ 'Unspecified error' +
177+ '\n\n' +
178+ 'This error is located at:' +
179+ capturedErrorDefaults . componentStack ;
168180 expect ( exceptionData . message ) . toBe ( formattedMessage ) ;
181+ expect ( exceptionData . originalMessage ) . toBe ( 'Unspecified error' ) ;
182+ expect ( exceptionData . name ) . toBe ( null ) ;
183+ expect ( exceptionData . componentStack ) . toBe (
184+ capturedErrorDefaults . componentStack ,
185+ ) ;
169186 expect ( exceptionData . stack [ 0 ] . file ) . toMatch ( / R e a c t F i b e r E r r o r D i a l o g \. j s $ / ) ;
170187 expect ( exceptionData . isFatal ) . toBe ( false ) ;
171188 expect ( logToConsoleInReact ) . toBe ( false ) ;
@@ -186,6 +203,55 @@ describe('ExceptionsManager', () => {
186203 "const error = Object.freeze(new Error('Some error happened'));" ,
187204 ) ;
188205 } ) ;
206+
207+ test ( 'does not mutate the message' , ( ) => {
208+ const error = new ReferenceError ( 'Some error happened' ) ;
209+ const { message} = error ;
210+
211+ ReactFiberErrorDialog . showErrorDialog ( {
212+ ...capturedErrorDefaults ,
213+ error,
214+ } ) ;
215+
216+ expect ( nativeReportException ) . toHaveBeenCalled ( ) ;
217+ expect ( error . message ) . toBe ( message ) ;
218+ } ) ;
219+
220+ test ( 'can safely process the same error multiple times' , ( ) => {
221+ const error = new ReferenceError ( 'Some error happened' ) ;
222+ // Copy all the data we care about before any possible mutation.
223+ const { message} = error ;
224+ const componentStacks = [
225+ '\n in A\n in B\n in C' ,
226+ '\n in X\n in Y\n in Z' ,
227+ ] ;
228+ for ( const componentStack of componentStacks ) {
229+ nativeReportException . mockClear ( ) ;
230+ const formattedMessage =
231+ 'ReferenceError: ' +
232+ message +
233+ '\n\n' +
234+ 'This error is located at:' +
235+ componentStack ;
236+ const logToConsoleInReact = ReactFiberErrorDialog . showErrorDialog ( {
237+ ...capturedErrorDefaults ,
238+ componentStack,
239+ error,
240+ } ) ;
241+
242+ expect ( nativeReportException . mock . calls . length ) . toBe ( 1 ) ;
243+ const exceptionData = nativeReportException . mock . calls [ 0 ] [ 0 ] ;
244+ expect ( exceptionData . message ) . toBe ( formattedMessage ) ;
245+ expect ( exceptionData . originalMessage ) . toBe ( message ) ;
246+ expect ( exceptionData . componentStack ) . toBe ( componentStack ) ;
247+ expect ( getLineFromFrame ( exceptionData . stack [ 0 ] ) ) . toBe (
248+ "const error = new ReferenceError('Some error happened');" ,
249+ ) ;
250+ expect ( exceptionData . isFatal ) . toBe ( false ) ;
251+ expect ( logToConsoleInReact ) . toBe ( false ) ;
252+ expect ( console . error ) . toBeCalledWith ( formattedMessage ) ;
253+ }
254+ } ) ;
189255 } ) ;
190256
191257 describe ( 'console.error handler' , ( ) => {
@@ -208,19 +274,22 @@ describe('ExceptionsManager', () => {
208274
209275 test ( 'logging an Error' , ( ) => {
210276 const error = new Error ( 'Some error happened' ) ;
211- const { message} = error ;
277+ const { message, name } = error ;
212278
213279 console . error ( error ) ;
214280
215281 expect ( nativeReportException . mock . calls . length ) . toBe ( 1 ) ;
216282 const exceptionData = nativeReportException . mock . calls [ 0 ] [ 0 ] ;
217- expect ( exceptionData . message ) . toBe ( message ) ;
283+ const formattedMessage = 'Error: ' + message ;
284+ expect ( exceptionData . message ) . toBe ( formattedMessage ) ;
285+ expect ( exceptionData . originalMessage ) . toBe ( message ) ;
286+ expect ( exceptionData . name ) . toBe ( name ) ;
218287 expect ( getLineFromFrame ( exceptionData . stack [ 0 ] ) ) . toBe (
219288 "const error = new Error('Some error happened');" ,
220289 ) ;
221290 expect ( exceptionData . isFatal ) . toBe ( false ) ;
222291 expect ( mockError . mock . calls [ 0 ] ) . toHaveLength ( 1 ) ;
223- expect ( mockError . mock . calls [ 0 ] [ 0 ] ) . toBe ( error ) ;
292+ expect ( mockError . mock . calls [ 0 ] [ 0 ] ) . toBe ( formattedMessage ) ;
224293 } ) ;
225294
226295 test ( 'logging a string' , ( ) => {
@@ -230,8 +299,11 @@ describe('ExceptionsManager', () => {
230299
231300 expect ( nativeReportException . mock . calls . length ) . toBe ( 1 ) ;
232301 const exceptionData = nativeReportException . mock . calls [ 0 ] [ 0 ] ;
233- const formattedMessage = 'console.error: "Some error happened"' ;
234- expect ( exceptionData . message ) . toBe ( formattedMessage ) ;
302+ expect ( exceptionData . message ) . toBe (
303+ 'console.error: "Some error happened"' ,
304+ ) ;
305+ expect ( exceptionData . originalMessage ) . toBe ( '"Some error happened"' ) ;
306+ expect ( exceptionData . name ) . toBe ( 'console.error' ) ;
235307 expect ( getLineFromFrame ( exceptionData . stack [ 0 ] ) ) . toBe (
236308 'console.error(message);' ,
237309 ) ;
@@ -249,6 +321,10 @@ describe('ExceptionsManager', () => {
249321 expect ( exceptionData . message ) . toBe (
250322 'console.error: 42, true, ["symbol" failed to stringify], {"y":null}' ,
251323 ) ;
324+ expect ( exceptionData . originalMessage ) . toBe (
325+ '42, true, ["symbol" failed to stringify], {"y":null}' ,
326+ ) ;
327+ expect ( exceptionData . name ) . toBe ( 'console.error' ) ;
252328 expect ( getLineFromFrame ( exceptionData . stack [ 0 ] ) ) . toBe (
253329 'console.error(...args);' ,
254330 ) ;
@@ -317,13 +393,16 @@ describe('ExceptionsManager', () => {
317393
318394 expect ( nativeReportException . mock . calls . length ) . toBe ( 1 ) ;
319395 const exceptionData = nativeReportException . mock . calls [ 0 ] [ 0 ] ;
320- expect ( exceptionData . message ) . toBe ( message ) ;
396+ const formattedMessage = 'Error: ' + message ;
397+ expect ( exceptionData . message ) . toBe ( formattedMessage ) ;
398+ expect ( exceptionData . originalMessage ) . toBe ( message ) ;
399+ expect ( exceptionData . name ) . toBe ( 'Error' ) ;
321400 expect ( getLineFromFrame ( exceptionData . stack [ 0 ] ) ) . toBe (
322401 "const error = new Error('Some error happened');" ,
323402 ) ;
324403 expect ( exceptionData . isFatal ) . toBe ( true ) ;
325404 expect ( console . error . mock . calls [ 0 ] ) . toHaveLength ( 1 ) ;
326- expect ( console . error . mock . calls [ 0 ] [ 0 ] ) . toBe ( message ) ;
405+ expect ( console . error . mock . calls [ 0 ] [ 0 ] ) . toBe ( formattedMessage ) ;
327406 } ) ;
328407
329408 test ( 'handling a non-fatal Error' , ( ) => {
@@ -334,13 +413,16 @@ describe('ExceptionsManager', () => {
334413
335414 expect ( nativeReportException . mock . calls . length ) . toBe ( 1 ) ;
336415 const exceptionData = nativeReportException . mock . calls [ 0 ] [ 0 ] ;
337- expect ( exceptionData . message ) . toBe ( message ) ;
416+ const formattedMessage = 'Error: ' + message ;
417+ expect ( exceptionData . message ) . toBe ( formattedMessage ) ;
418+ expect ( exceptionData . originalMessage ) . toBe ( message ) ;
419+ expect ( exceptionData . name ) . toBe ( 'Error' ) ;
338420 expect ( getLineFromFrame ( exceptionData . stack [ 0 ] ) ) . toBe (
339421 "const error = new Error('Some error happened');" ,
340422 ) ;
341423 expect ( exceptionData . isFatal ) . toBe ( false ) ;
342424 expect ( console . error . mock . calls [ 0 ] ) . toHaveLength ( 1 ) ;
343- expect ( console . error . mock . calls [ 0 ] [ 0 ] ) . toBe ( message ) ;
425+ expect ( console . error . mock . calls [ 0 ] [ 0 ] ) . toBe ( formattedMessage ) ;
344426 } ) ;
345427
346428 test ( 'handling a thrown string' , ( ) => {
@@ -351,6 +433,8 @@ describe('ExceptionsManager', () => {
351433 expect ( nativeReportException . mock . calls . length ) . toBe ( 1 ) ;
352434 const exceptionData = nativeReportException . mock . calls [ 0 ] [ 0 ] ;
353435 expect ( exceptionData . message ) . toBe ( message ) ;
436+ expect ( exceptionData . originalMessage ) . toBe ( null ) ;
437+ expect ( exceptionData . name ) . toBe ( null ) ;
354438 expect ( exceptionData . stack [ 0 ] . file ) . toMatch ( / E x c e p t i o n s M a n a g e r \. j s $ / ) ;
355439 expect ( exceptionData . isFatal ) . toBe ( true ) ;
356440 expect ( console . error . mock . calls [ 0 ] ) . toEqual ( [ message ] ) ;
0 commit comments