1
+/**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @emails react-core
8
+ * @jest-environment node
9
+ */
10
+'use strict';
11
+
12
+let React;
13
+let ReactNoop;
14
+let waitForAll;
15
+
16
+describe('ReactFragment', () => {
17
+ beforeEach(function () {
18
+ jest.resetModules();
19
+
20
+ React = require('react');
21
+ ReactNoop = require('react-noop-renderer');
22
+ const InternalTestUtils = require('internal-test-utils');
23
+ waitForAll = InternalTestUtils.waitForAll;
24
+ });
25
+
26
+ function componentStack(components) {
27
+ return components
28
+ .map(component => `\n in ${component} (at **)`)
29
+ .join('');
30
+ }
31
+
32
+ function normalizeCodeLocInfo(str) {
33
+ return (
34
+ str &&
35
+ str.replace(/\n +(?:at|in) ([\S]+)[^\n]*/g, function (m, name) {
36
+ return '\n in ' + name + ' (at **)';
37
+ })
38
+ );
39
+ }
40
+
41
+ it('retains component stacks when rethrowing an error', async () => {
42
+ function Foo() {
43
+ return (
44
+ <RethrowingBoundary>
45
+ <Bar />
46
+ </RethrowingBoundary>
47
+ );
48
+ }
49
+ function Bar() {
50
+ return <SomethingThatErrors />;
51
+ }
52
+ function SomethingThatErrors() {
53
+ throw new Error('uh oh');
54
+ }
55
+
56
+ class RethrowingBoundary extends React.Component {
57
+ static getDerivedStateFromError(error) {
58
+ throw error;
59
+ }
60
+
61
+ render() {
62
+ return this.props.children;
63
+ }
64
+ }
65
+
66
+ const errors = [];
67
+ class CatchingBoundary extends React.Component {
68
+ constructor() {
69
+ super();
70
+ this.state = {};
71
+ }
72
+ static getDerivedStateFromError(error) {
73
+ return {errored: true};
74
+ }
75
+ componentDidCatch(err, errInfo) {
76
+ errors.push(err.message, normalizeCodeLocInfo(errInfo.componentStack));
77
+ }
78
+ render() {
79
+ if (this.state.errored) {
80
+ return null;
81
+ }
82
+ return this.props.children;
83
+ }
84
+ }
85
+
86
+ ReactNoop.render(
87
+ <CatchingBoundary>
88
+ <Foo />
89
+ </CatchingBoundary>,
90
+ );
91
+ await waitForAll([]);
92
+ expect(errors).toEqual([
93
+ 'uh oh',
94
+ componentStack([
95
+ 'SomethingThatErrors',
96
+ 'Bar',
97
+ 'RethrowingBoundary',
98
+ 'Foo',
99
+ 'CatchingBoundary',
100
+ ]),
101
+ ]);
102
+ });
103
+});