90
});
91
92
function expectErrors(errorsArr, toBeDevArr, toBeProdArr) {
93
- const mappedErrows = errorsArr.map(error => {
94
- if (error.componentStack) {
95
- return [
96
- error.message,
97
- error.hash,
98
- normalizeCodeLocInfo(error.componentStack),
99
- ];
100
- } else if (error.hash) {
101
- return [error.message, error.hash];
93
+ const mappedErrows = errorsArr.map(({error, errorInfo}) => {
94
+ const stack = errorInfo && errorInfo.componentStack;
95
+ const digest = errorInfo && errorInfo.digest;
96
+ if (stack) {
97
+ return [error.message, digest, normalizeCodeLocInfo(stack)];
98
+ } else if (digest) {
99
+ return [error.message, digest];
100
}
101
return error.message;
102
});
103
if (__DEV__) {
106
- expect(mappedErrows).toEqual(
107
- toBeDevArr,
108
- // .map(([errorMessage, errorHash, errorComponentStack]) => {
109
- // if (typeof error === 'string' || error instanceof String) {
110
- // return error;
111
- // }
112
- // let str = JSON.stringify(error).replace(/\\n/g, '\n');
113
- // // this gets stripped away by normalizeCodeLocInfo...
114
- // // Kind of hacky but lets strip it away here too just so they match...
115
- // // easier than fixing the regex to account for this edge case
116
- // if (str.endsWith('at **)"}')) {
117
- // str = str.replace(/at \*\*\)\"}$/, 'at **)');
118
- // }
119
- // return str;
120
- // }),
121
- );
104
+ expect(mappedErrows).toEqual(toBeDevArr);
105
} else {
106
expect(mappedErrows).toEqual(toBeProdArr);
107
}
108
}
109
127
- // @TODO we will use this in a followup change once we start exposing componentStacks from server errors
128
- // function componentStack(components) {
129
- // return components
130
- // .map(component => `\n in ${component} (at **)`)
131
- // .join('');
132
- // }
110
+ function componentStack(components) {
111
+ return components
112
+ .map(component => `\n in ${component} (at **)`)
113
+ .join('');
114
+ }
115
116
async function act(callback) {
117
await callback();
453
bootstrapped = true;
454
// Attempt to hydrate the content.
455
ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
474
- onRecoverableError(error) {
475
- errors.push(error);
456
+ onRecoverableError(error, errorInfo) {
457
+ errors.push({error, errorInfo});
458
},
459
});
460
};
465
loggedErrors.push(x);
466
return 'Hash of (' + x.message + ')';
467
}
486
- // const expectedHash = onError(theError);
487
- // loggedErrors.length = 0;
468
+ const expectedDigest = onError(theError);
469
+ loggedErrors.length = 0;
470
471
await act(async () => {
472
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
501
expect(Scheduler).toFlushAndYield([]);
502
expectErrors(
503
errors,
522
- [theError.message],
504
[
524
- 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
505
+ [
506
+ theError.message,
507
+ expectedDigest,
508
+ componentStack(['Lazy', 'Suspense', 'div', 'App']),
509
+ ],
510
+ ],
511
+ [
512
+ [
513
+ 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
514
+ expectedDigest,
515
+ ],
516
],
517
);
518
568
loggedErrors.push(x);
569
return 'hash of (' + x.message + ')';
570
}
580
- // const expectedHash = onError(theError);
581
- // loggedErrors.length = 0;
571
+ const expectedDigest = onError(theError);
572
+ loggedErrors.length = 0;
573
574
function App({isClient}) {
575
return (
596
const errors = [];
597
// Attempt to hydrate the content.
598
ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
608
- onRecoverableError(error) {
609
- errors.push(error);
599
+ onRecoverableError(error, errorInfo) {
600
+ errors.push({error, errorInfo});
601
},
602
});
603
Scheduler.unstable_flushAll();
621
622
expectErrors(
623
errors,
633
- [theError.message],
624
[
635
- 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
625
+ [
626
+ theError.message,
627
+ expectedDigest,
628
+ componentStack(['Suspense', 'div', 'App']),
629
+ ],
630
+ ],
631
+ [
632
+ [
633
+ 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
634
+ expectedDigest,
635
+ ],
636
],
637
);
638
675
loggedErrors.push(x);
676
return 'hash(' + x.message + ')';
677
}
678
- // const expectedHash = onError(theError);
679
- // loggedErrors.length = 0;
678
+ const expectedDigest = onError(theError);
679
+ loggedErrors.length = 0;
680
681
await act(async () => {
682
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
693
const errors = [];
694
// Attempt to hydrate the content.
695
ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
696
- onRecoverableError(error) {
697
- errors.push(error);
696
+ onRecoverableError(error, errorInfo) {
697
+ errors.push({error, errorInfo});
698
},
699
});
700
Scheduler.unstable_flushAll();
703
704
expectErrors(
705
errors,
706
- [theError.message],
706
[
708
- 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
707
+ [
708
+ theError.message,
709
+ expectedDigest,
710
+ componentStack(['Erroring', 'Suspense', 'div', 'App']),
711
+ ],
712
+ ],
713
+ [
714
+ [
715
+ 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
716
+ expectedDigest,
717
+ ],
718
],
719
);
720
});
744
loggedErrors.push(x);
745
return 'hash(' + x.message + ')';
746
}
738
- // const expectedHash = onError(theError);
739
- // loggedErrors.length = 0;
747
+ const expectedDigest = onError(theError);
748
+ loggedErrors.length = 0;
749
750
await act(async () => {
751
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
762
const errors = [];
763
// Attempt to hydrate the content.
764
ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
756
- onRecoverableError(error) {
757
- errors.push(error);
765
+ onRecoverableError(error, errorInfo) {
766
+ errors.push({error, errorInfo});
767
},
768
});
769
Scheduler.unstable_flushAll();
782
783
expectErrors(
784
errors,
776
- [theError.message],
785
[
778
- 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
786
+ [
787
+ theError.message,
788
+ expectedDigest,
789
+ componentStack(['Lazy', 'Suspense', 'div', 'App']),
790
+ ],
791
+ ],
792
+ [
793
+ [
794
+ 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
795
+ expectedDigest,
796
+ ],
797
],
798
);
799
1071
}
1072
1073
const loggedErrors = [];
1074
+ const expectedDigest = 'Hash for Abort';
1075
function onError(error) {
1076
loggedErrors.push(error);
1058
- return `Hash of (${error.message})`;
1077
+ return expectedDigest;
1078
}
1079
1080
let controls;
1088
const errors = [];
1089
// Attempt to hydrate the content.
1090
ReactDOMClient.hydrateRoot(container, <App />, {
1072
- onRecoverableError(error) {
1073
- errors.push(error);
1091
+ onRecoverableError(error, errorInfo) {
1092
+ errors.push({error, errorInfo});
1093
},
1094
});
1095
Scheduler.unstable_flushAll();
1106
expect(Scheduler).toFlushAndYield([]);
1107
expectErrors(
1108
errors,
1090
- ['This Suspense boundary was aborted by the server'],
1109
+ [['This Suspense boundary was aborted by the server.', expectedDigest]],
1110
[
1092
- 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
1111
+ [
1112
+ 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
1113
+ expectedDigest,
1114
+ ],
1115
],
1116
);
1117
expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
1777
loggedErrors.push(x);
1778
return `hash of (${x.message})`;
1779
}
1758
- // const expectedHash = onError(theError);
1759
- // loggedErrors.length = 0;
1780
+ const expectedDigest = onError(theError);
1781
+ loggedErrors.length = 0;
1782
1783
let controls;
1784
await act(async () => {
1797
const errors = [];
1798
// Attempt to hydrate the content.
1799
ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
1778
- onRecoverableError(error) {
1779
- errors.push(error);
1800
+ onRecoverableError(error, errorInfo) {
1801
+ errors.push({error, errorInfo});
1802
},
1803
});
1804
Scheduler.unstable_flushAll();
1831
expect(Scheduler).toFlushAndYield([]);
1832
expectErrors(
1833
errors,
1812
- [theError.message],
1834
[
1814
- 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
1835
+ [
1836
+ theError.message,
1837
+ expectedDigest,
1838
+ componentStack([
1839
+ 'AsyncText',
1840
+ 'h1',
1841
+ 'Suspense',
1842
+ 'div',
1843
+ 'Suspense',
1844
+ 'App',
1845
+ ]),
1846
+ ],
1847
+ ],
1848
+ [
1849
+ [
1850
+ 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
1851
+ expectedDigest,
1852
+ ],
1853
],
1854
);
1855
3180
loggedErrors.push(x);
3181
return x.message.replace('bad message', 'bad hash');
3182
}
3145
- // const expectedHash = onError(theError);
3146
- // loggedErrors.length = 0;
3183
+ const expectedDigest = onError(theError);
3184
+ loggedErrors.length = 0;
3185
3186
await act(async () => {
3187
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />, {
3194
3195
const errors = [];
3196
ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
3159
- onRecoverableError(error) {
3160
- errors.push(error);
3197
+ onRecoverableError(error, errorInfo) {
3198
+ errors.push({error, errorInfo});
3199
},
3200
});
3201
expect(Scheduler).toFlushAndYield([]);
3203
// If escaping were not done we would get a message that says "bad hash"
3204
expectErrors(
3205
errors,
3168
- [theError.message],
3206
[
3170
- 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
3207
+ [
3208
+ theError.message,
3209
+ expectedDigest,
3210
+ componentStack(['Erroring', 'Suspense', 'div', 'App']),
3211
+ ],
3212
+ ],
3213
+ [
3214
+ [
3215
+ 'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
3216
+ expectedDigest,
3217
+ ],
3218
],
3219
);
3220
});