Give unresolved lazy() a name in component stack (#16104)
* Give unresolved lazy() a name in component stack * Normalize stack in tests Co-authored-by: Sebastian Markbage <sema@fb.com>
Moti Zilberman committed
May 2, 2020 at 00:41 UTC
3c7d52c3d6d316d09d5c2479c6851acecccc6325
1 file changed
+90
packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
+90
@@ -6,6 +6,15 @@ let ReactFeatureFlags;
6
let Suspense;
7
let lazy;
8
9
+function normalizeCodeLocInfo(str) {
10
+ return (
11
+ str &&
12
+ str.replace(/\n +(?:at|in) ([\S]+)[^\n]*/g, function(m, name) {
13
+ return '\n in ' + name + ' (at **)';
14
+ })
15
+ );
16
+}
17
+
18
describe('ReactLazy', () => {
19
beforeEach(() => {
20
jest.resetModules();
@@ -1183,4 +1192,85 @@ describe('ReactLazy', () => {
1192
expect(Scheduler).toFlushAndYield([]);
1193
}).toErrorDev('Function components cannot be given refs');
1194
});
1195
+
1196
+ it('should error with a component stack naming the resolved component', async () => {
1197
+ let componentStackMessage;
1198
+
1199
+ const LazyText = lazy(() =>
1200
+ fakeImport(function ResolvedText() {
1201
+ throw new Error('oh no');
1202
+ }),
1203
+ );
1204
+
1205
+ class ErrorBoundary extends React.Component {
1206
+ state = {error: null};
1207
+
1208
+ componentDidCatch(error, errMessage) {
1209
+ componentStackMessage = normalizeCodeLocInfo(errMessage.componentStack);
1210
+ this.setState({
1211
+ error,
1212
+ });
1213
+ }
1214
+
1215
+ render() {
1216
+ return this.state.error ? null : this.props.children;
1217
+ }
1218
+ }
1219
+
1220
+ ReactTestRenderer.create(
1221
+ <ErrorBoundary>
1222
+ <Suspense fallback={<Text text="Loading..." />}>
1223
+ <LazyText text="Hi" />
1224
+ </Suspense>
1225
+ </ErrorBoundary>,
1226
+ {unstable_isConcurrent: true},
1227
+ );
1228
+
1229
+ expect(Scheduler).toFlushAndYield(['Loading...']);
1230
+
1231
+ try {
1232
+ await Promise.resolve();
1233
+ } catch (e) {}
1234
+
1235
+ expect(Scheduler).toFlushAndYield([]);
1236
+
1237
+ expect(componentStackMessage).toContain('in ResolvedText');
1238
+ });
1239
+
1240
+ it('should error with a component stack containing Lazy if unresolved', () => {
1241
+ let componentStackMessage;
1242
+
1243
+ const LazyText = lazy(() => ({
1244
+ then(resolve, reject) {
1245
+ reject(new Error('oh no'));
1246
+ },
1247
+ }));
1248
+
1249
+ class ErrorBoundary extends React.Component {
1250
+ state = {error: null};
1251
+
1252
+ componentDidCatch(error, errMessage) {
1253
+ componentStackMessage = normalizeCodeLocInfo(errMessage.componentStack);
1254
+ this.setState({
1255
+ error,
1256
+ });
1257
+ }
1258
+
1259
+ render() {
1260
+ return this.state.error ? null : this.props.children;
1261
+ }
1262
+ }
1263
+
1264
+ ReactTestRenderer.create(
1265
+ <ErrorBoundary>
1266
+ <Suspense fallback={<Text text="Loading..." />}>
1267
+ <LazyText text="Hi" />
1268
+ </Suspense>
1269
+ </ErrorBoundary>,
1270
+ );
1271
+
1272
+ expect(Scheduler).toHaveYielded([]);
1273
+
1274
+ expect(componentStackMessage).toContain('in Lazy');
1275
+ });
1276
});