react-error-boundary 1.2.1 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +38 -15
- package/dist/commonjs/ErrorBoundary.js +13 -4
- package/dist/commonjs/__tests__/ErrorBoundary.test.js +244 -0
- package/dist/commonjs/__tests__/ErrorBoundaryFallbackComponent.test.js +27 -0
- package/dist/commonjs/__tests__/__snapshots__/ErrorBoundaryFallbackComponent.test.js.snap +213 -0
- package/dist/commonjs/setupTests.js +13 -0
- package/dist/es/ErrorBoundary.js +13 -4
- package/dist/es/__tests__/ErrorBoundary.test.js +232 -0
- package/dist/es/__tests__/ErrorBoundaryFallbackComponent.test.js +18 -0
- package/dist/es/__tests__/__snapshots__/ErrorBoundaryFallbackComponent.test.js.snap +213 -0
- package/dist/es/setupTests.js +4 -0
- package/dist/umd/react-error-boundary.js +5 -3
- package/index.d.ts +19 -0
- package/package.json +11 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright 2018 Brian Vaughn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
react-error-boundary
|
|
2
|
+
====================
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
**A simple, reusable React error boundary component for React 16+.**
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
[](https://yarnpkg.com/en/package/react-error-boundary)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
React [v16](https://reactjs.org/blog/2017/09/26/react-v16.0.html) introduced the concept of [“error boundaries”](https://reactjs.org/docs/error-boundaries.html).
|
|
10
|
+
|
|
11
|
+
This component provides a simple and reusable wrapper that you can use to wrap around your components. Any rendering errors in your components hierarchy can then be gracefully handled.
|
|
12
|
+
|
|
13
|
+
# Usage
|
|
14
|
+
|
|
15
|
+
The simplest way to use `<ErrorBoundary>` is to wrap it around any component that may throw an error.
|
|
16
|
+
This will handle errors thrown by that component and its descendants too.
|
|
7
17
|
|
|
8
18
|
```jsx
|
|
9
19
|
import ErrorBoundary from 'react-error-boundary';
|
|
@@ -13,13 +23,14 @@ import ErrorBoundary from 'react-error-boundary';
|
|
|
13
23
|
</ErrorBoundary>
|
|
14
24
|
```
|
|
15
25
|
|
|
16
|
-
You can react to errors (
|
|
26
|
+
You can react to errors (e.g. for logging) by providing an `onError` callback:
|
|
17
27
|
|
|
18
28
|
```jsx
|
|
19
29
|
import ErrorBoundary from 'react-error-boundary';
|
|
20
30
|
|
|
21
31
|
const myErrorHandler = (error: Error, componentStack: string) => {
|
|
22
|
-
//
|
|
32
|
+
// Do something with the error
|
|
33
|
+
// E.g. log to an error logging client here
|
|
23
34
|
};
|
|
24
35
|
|
|
25
36
|
<ErrorBoundary onError={myErrorHandler}>
|
|
@@ -27,26 +38,38 @@ const myErrorHandler = (error: Error, componentStack: string) => {
|
|
|
27
38
|
</ErrorBoundary>
|
|
28
39
|
```
|
|
29
40
|
|
|
30
|
-
You can also customize the fallback appearance:
|
|
41
|
+
You can also customize the fallback component’s appearance:
|
|
31
42
|
|
|
32
43
|
```jsx
|
|
44
|
+
import { ErrorBoundary } from 'react-error-boundary';
|
|
45
|
+
|
|
33
46
|
const MyFallbackComponent = ({ componentStack, error }) => (
|
|
34
|
-
<div
|
|
35
|
-
|
|
47
|
+
<div>
|
|
48
|
+
<p><strong>Oops! An error occured!</strong></p>
|
|
49
|
+
<p>Here’s what we know…</p>
|
|
50
|
+
<p><strong>Error:</strong> {error.toString()}</p>
|
|
51
|
+
<p><strong>Stacktrace:</strong> {componentStack}</p>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
36
54
|
|
|
37
55
|
<ErrorBoundary FallbackComponent={MyFallbackComponent}>
|
|
38
56
|
<ComponentThatMayError />
|
|
39
57
|
</ErrorBoundary>
|
|
40
58
|
```
|
|
41
59
|
|
|
42
|
-
You can also use it as a
|
|
60
|
+
You can also use it as a [higher-order component](https://reactjs.org/docs/higher-order-components.html):
|
|
43
61
|
|
|
44
62
|
```jsx
|
|
45
|
-
import {withErrorBoundary} from 'react-error-boundary';
|
|
63
|
+
import { ErrorBoundaryFallbackComponent, withErrorBoundary } from 'react-error-boundary';
|
|
46
64
|
|
|
47
65
|
const ComponentWithErrorBoundary = withErrorBoundary(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
onErrorHandler:
|
|
66
|
+
ComponentThatMayError,
|
|
67
|
+
ErrorBoundaryFallbackComponent, // Or pass in your own fallback component
|
|
68
|
+
onErrorHandler: (error, componentStack) => {
|
|
69
|
+
// Do something with the error
|
|
70
|
+
// E.g. log to an error logging client here
|
|
71
|
+
},
|
|
51
72
|
);
|
|
52
|
-
|
|
73
|
+
|
|
74
|
+
<ComponentWithErrorBoundary />
|
|
75
|
+
```
|
|
@@ -53,7 +53,8 @@ var ErrorBoundary = function (_Component) {
|
|
|
53
53
|
|
|
54
54
|
if (typeof onError === 'function') {
|
|
55
55
|
try {
|
|
56
|
-
|
|
56
|
+
/* istanbul ignore next: Ignoring ternary; can’t reproduce missing info in test environment. */
|
|
57
|
+
onError.call(this, error, info ? info.componentStack : '');
|
|
57
58
|
} catch (ignoredError) {}
|
|
58
59
|
}
|
|
59
60
|
|
|
@@ -72,12 +73,14 @@ var ErrorBoundary = function (_Component) {
|
|
|
72
73
|
|
|
73
74
|
if (error !== null) {
|
|
74
75
|
return _react2.default.createElement(FallbackComponent, {
|
|
75
|
-
componentStack:
|
|
76
|
+
componentStack:
|
|
77
|
+
// istanbul ignore next: Ignoring ternary; can’t reproduce missing info in test environment.
|
|
78
|
+
info ? info.componentStack : '',
|
|
76
79
|
error: error
|
|
77
80
|
});
|
|
78
81
|
}
|
|
79
82
|
|
|
80
|
-
return children;
|
|
83
|
+
return children || null;
|
|
81
84
|
}
|
|
82
85
|
}]);
|
|
83
86
|
|
|
@@ -94,13 +97,19 @@ ErrorBoundary.propTypes = {
|
|
|
94
97
|
})
|
|
95
98
|
};
|
|
96
99
|
var withErrorBoundary = exports.withErrorBoundary = function withErrorBoundary(Component, FallbackComponent, onError) {
|
|
97
|
-
|
|
100
|
+
var Wrapped = function Wrapped(props) {
|
|
98
101
|
return _react2.default.createElement(
|
|
99
102
|
ErrorBoundary,
|
|
100
103
|
{ FallbackComponent: FallbackComponent, onError: onError },
|
|
101
104
|
_react2.default.createElement(Component, props)
|
|
102
105
|
);
|
|
103
106
|
};
|
|
107
|
+
|
|
108
|
+
// Format for display in DevTools
|
|
109
|
+
var name = Component.displayName || Component.name;
|
|
110
|
+
Wrapped.displayName = name ? 'WithErrorBoundary(' + name + ')' : 'WithErrorBoundary';
|
|
111
|
+
|
|
112
|
+
return Wrapped;
|
|
104
113
|
};
|
|
105
114
|
|
|
106
115
|
withErrorBoundary.propTypes = babelPluginFlowReactPropTypes_proptype_ComponentType === require('prop-types').any ? {} : babelPluginFlowReactPropTypes_proptype_ComponentType;
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _enzyme = require('enzyme');
|
|
4
|
+
|
|
5
|
+
var _react = require('react');
|
|
6
|
+
|
|
7
|
+
var _react2 = _interopRequireDefault(_react);
|
|
8
|
+
|
|
9
|
+
var _ErrorBoundary = require('../ErrorBoundary');
|
|
10
|
+
|
|
11
|
+
var _ErrorBoundary2 = _interopRequireDefault(_ErrorBoundary);
|
|
12
|
+
|
|
13
|
+
var _ErrorBoundaryFallbackComponent = require('../ErrorBoundaryFallbackComponent');
|
|
14
|
+
|
|
15
|
+
var _ErrorBoundaryFallbackComponent2 = _interopRequireDefault(_ErrorBoundaryFallbackComponent);
|
|
16
|
+
|
|
17
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
|
+
|
|
19
|
+
describe('ErrorBoundary', function () {
|
|
20
|
+
var consoleErrorSpy = void 0;
|
|
21
|
+
var mockError = void 0;
|
|
22
|
+
|
|
23
|
+
var Spell = void 0;
|
|
24
|
+
var Wand = void 0;
|
|
25
|
+
|
|
26
|
+
beforeAll(function () {
|
|
27
|
+
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(function () {
|
|
28
|
+
// React error boundaries print the error to `console.error` stream even when it’s caught by our
|
|
29
|
+
// `ErrorBoundary` component. We suppress `console.error` to keep our test console output clean.
|
|
30
|
+
// @see #11098 Allow suppressing error boundary logs from intentionally thrown/caught errors
|
|
31
|
+
// https://github.com/facebook/react/issues/11098
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
mockError = new Error('You cast an unforgivable curse! You’ve earned a one-way ticket to Azkaban.');
|
|
35
|
+
Spell = function Spell(_ref) {
|
|
36
|
+
var incantation = _ref.incantation;
|
|
37
|
+
|
|
38
|
+
switch (incantation) {
|
|
39
|
+
case 'Avada Kedavra':
|
|
40
|
+
case 'Crucio':
|
|
41
|
+
case 'Imperio':
|
|
42
|
+
throw mockError;
|
|
43
|
+
|
|
44
|
+
default:
|
|
45
|
+
return _react2.default.createElement(
|
|
46
|
+
'p',
|
|
47
|
+
null,
|
|
48
|
+
'You cast the ' + incantation + ' spell!'
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
Wand = function Wand(_ref2) {
|
|
54
|
+
var name = _ref2.name,
|
|
55
|
+
incantation = _ref2.incantation;
|
|
56
|
+
return _react2.default.createElement(
|
|
57
|
+
'div',
|
|
58
|
+
null,
|
|
59
|
+
_react2.default.createElement(
|
|
60
|
+
'p',
|
|
61
|
+
null,
|
|
62
|
+
'Casting spell with the ' + name + ' wand'
|
|
63
|
+
),
|
|
64
|
+
_react2.default.createElement(Spell, { incantation: incantation })
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
afterAll(function () {
|
|
70
|
+
consoleErrorSpy.mockRestore();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('Renders the child component if there is no error', function () {
|
|
74
|
+
var wrapper = (0, _enzyme.mount)(_react2.default.createElement(
|
|
75
|
+
_ErrorBoundary2.default,
|
|
76
|
+
null,
|
|
77
|
+
_react2.default.createElement(Wand, { name: 'Harry\u2019s', incantation: 'Expelliarmus' })
|
|
78
|
+
));
|
|
79
|
+
|
|
80
|
+
var WandWithErrorBoundary = (0, _ErrorBoundary.withErrorBoundary)(Wand);
|
|
81
|
+
var wrapperWithErrorBoundary = (0, _enzyme.mount)(_react2.default.createElement(WandWithErrorBoundary, { name: 'Harry\u2019s', incantation: 'Expelliarmus' }));
|
|
82
|
+
|
|
83
|
+
expect(wrapper.state().error).toBe(null);
|
|
84
|
+
expect(wrapper.state().info).toBe(null);
|
|
85
|
+
expect(wrapper.containsMatchingElement(_react2.default.createElement(_ErrorBoundaryFallbackComponent2.default, null))).toBe(false);
|
|
86
|
+
expect(wrapper.contains(_react2.default.createElement(Wand, { name: 'Harry\u2019s', incantation: 'Expelliarmus' }))).toBe(true);
|
|
87
|
+
|
|
88
|
+
// Note: We use `….instance().state …` instead of `….state() …` here because…
|
|
89
|
+
// > ReactWrapper::state() can only be called on the root
|
|
90
|
+
expect(wrapperWithErrorBoundary.find(_ErrorBoundary2.default).instance().state.error).toBe(null);
|
|
91
|
+
expect(wrapperWithErrorBoundary.find(_ErrorBoundary2.default).instance().state.info).toBe(null);
|
|
92
|
+
expect(wrapperWithErrorBoundary.containsMatchingElement(_react2.default.createElement(_ErrorBoundaryFallbackComponent2.default, null))).toBe(false);
|
|
93
|
+
expect(wrapperWithErrorBoundary.contains(_react2.default.createElement(Wand, { name: 'Harry\u2019s', incantation: 'Expelliarmus' }))).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('Sets its state to an error state and renders the default fallback component', function () {
|
|
97
|
+
var wrapper = (0, _enzyme.mount)(_react2.default.createElement(
|
|
98
|
+
_ErrorBoundary2.default,
|
|
99
|
+
null,
|
|
100
|
+
_react2.default.createElement(Wand, { name: 'Voldemort\u2019s', incantation: 'Avada Kedavra' })
|
|
101
|
+
));
|
|
102
|
+
|
|
103
|
+
var WandWithErrorBoundary = (0, _ErrorBoundary.withErrorBoundary)(Wand);
|
|
104
|
+
var wrapperWithErrorBoundary = (0, _enzyme.mount)(_react2.default.createElement(WandWithErrorBoundary, { name: 'Voldemort\u2019s', incantation: 'Avada Kedavra' }));
|
|
105
|
+
|
|
106
|
+
expect(wrapper.state().error).toEqual(expect.objectContaining(mockError));
|
|
107
|
+
expect(wrapper.state().info).toEqual(expect.objectContaining({
|
|
108
|
+
componentStack: expect.any(String)
|
|
109
|
+
}));
|
|
110
|
+
expect(wrapper.containsMatchingElement(_react2.default.createElement(_ErrorBoundaryFallbackComponent2.default, null))).toBe(true);
|
|
111
|
+
|
|
112
|
+
expect(wrapperWithErrorBoundary.find(_ErrorBoundary2.default).instance().state.error).toEqual(expect.objectContaining(mockError));
|
|
113
|
+
expect(wrapperWithErrorBoundary.find(_ErrorBoundary2.default).instance().state.info).toEqual(expect.objectContaining({
|
|
114
|
+
componentStack: expect.any(String)
|
|
115
|
+
}));
|
|
116
|
+
expect(wrapperWithErrorBoundary.containsMatchingElement(_react2.default.createElement(_ErrorBoundaryFallbackComponent2.default, null))).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('Sets its state to an error state and renders a custom fallback component', function () {
|
|
120
|
+
var MockFallbackComponent = function MockFallbackComponent(_ref3) {
|
|
121
|
+
var error = _ref3.error,
|
|
122
|
+
componentStack = _ref3.componentStack;
|
|
123
|
+
return _react2.default.createElement(
|
|
124
|
+
'div',
|
|
125
|
+
null,
|
|
126
|
+
_react2.default.createElement(
|
|
127
|
+
'p',
|
|
128
|
+
null,
|
|
129
|
+
_react2.default.createElement(
|
|
130
|
+
'strong',
|
|
131
|
+
null,
|
|
132
|
+
'Wand unable to perform magic!'
|
|
133
|
+
),
|
|
134
|
+
'Please contact Ollivanders in Diagon Alley for repairs.'
|
|
135
|
+
),
|
|
136
|
+
_react2.default.createElement(
|
|
137
|
+
'p',
|
|
138
|
+
null,
|
|
139
|
+
_react2.default.createElement(
|
|
140
|
+
'strong',
|
|
141
|
+
null,
|
|
142
|
+
'Error:'
|
|
143
|
+
),
|
|
144
|
+
' ',
|
|
145
|
+
error.toString()
|
|
146
|
+
),
|
|
147
|
+
_react2.default.createElement(
|
|
148
|
+
'p',
|
|
149
|
+
null,
|
|
150
|
+
_react2.default.createElement(
|
|
151
|
+
'strong',
|
|
152
|
+
null,
|
|
153
|
+
'Stacktrace:'
|
|
154
|
+
),
|
|
155
|
+
_react2.default.createElement(
|
|
156
|
+
'pre',
|
|
157
|
+
null,
|
|
158
|
+
componentStack
|
|
159
|
+
)
|
|
160
|
+
)
|
|
161
|
+
);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
var wrapper = (0, _enzyme.mount)(_react2.default.createElement(
|
|
165
|
+
_ErrorBoundary2.default,
|
|
166
|
+
{ FallbackComponent: MockFallbackComponent },
|
|
167
|
+
_react2.default.createElement(Wand, { name: 'Voldemort\u2019s', incantation: 'Crucio' })
|
|
168
|
+
));
|
|
169
|
+
|
|
170
|
+
var WandWithErrorBoundary = (0, _ErrorBoundary.withErrorBoundary)(Wand, MockFallbackComponent);
|
|
171
|
+
var wrapperWithErrorBoundary = (0, _enzyme.mount)(_react2.default.createElement(WandWithErrorBoundary, { name: 'Voldemort\u2019s', incantation: 'Crucio' }));
|
|
172
|
+
|
|
173
|
+
expect(wrapper.state().error).toEqual(expect.objectContaining(mockError));
|
|
174
|
+
expect(wrapper.state().info).toEqual(expect.objectContaining({
|
|
175
|
+
componentStack: expect.any(String)
|
|
176
|
+
}));
|
|
177
|
+
expect(wrapper.containsMatchingElement(_react2.default.createElement(_ErrorBoundaryFallbackComponent2.default, null))).toBe(false);
|
|
178
|
+
expect(wrapper.containsMatchingElement(_react2.default.createElement(MockFallbackComponent, {
|
|
179
|
+
error: mockError /* componentStack="ignored" */
|
|
180
|
+
}))).toBe(true);
|
|
181
|
+
|
|
182
|
+
expect(wrapperWithErrorBoundary.find(_ErrorBoundary2.default).instance().state.error).toEqual(expect.objectContaining(mockError));
|
|
183
|
+
expect(wrapperWithErrorBoundary.find(_ErrorBoundary2.default).instance().state.info).toEqual(expect.objectContaining({
|
|
184
|
+
componentStack: expect.any(String)
|
|
185
|
+
}));
|
|
186
|
+
expect(wrapperWithErrorBoundary.containsMatchingElement(_react2.default.createElement(_ErrorBoundaryFallbackComponent2.default, null))).toBe(false);
|
|
187
|
+
expect(wrapperWithErrorBoundary.containsMatchingElement(_react2.default.createElement(MockFallbackComponent, {
|
|
188
|
+
error: mockError /* componentStack="ignored" */
|
|
189
|
+
}))).toBe(true);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('Sets its state to an error state and invokes the onError callback prop', function () {
|
|
193
|
+
var mockOnError = jest.fn().mockImplementation(function (error, // eslint-disable-line no-unused-vars
|
|
194
|
+
info) // eslint-disable-line no-unused-vars
|
|
195
|
+
{});
|
|
196
|
+
|
|
197
|
+
var mockOnErrorWithErrorBoundary = jest.fn().mockImplementation(function (error, // eslint-disable-line no-unused-vars
|
|
198
|
+
info) // eslint-disable-line no-unused-vars
|
|
199
|
+
{});
|
|
200
|
+
|
|
201
|
+
var wrapper = (0, _enzyme.mount)(_react2.default.createElement(
|
|
202
|
+
_ErrorBoundary2.default,
|
|
203
|
+
{ onError: mockOnError },
|
|
204
|
+
_react2.default.createElement(Wand, { name: 'Voldemort\u2019s', incantation: 'Imperio' })
|
|
205
|
+
));
|
|
206
|
+
var WandWithErrorBoundary = (0, _ErrorBoundary.withErrorBoundary)(Wand, _ErrorBoundaryFallbackComponent2.default, mockOnErrorWithErrorBoundary);
|
|
207
|
+
var wrapperWithErrorBoundary = (0, _enzyme.mount)(_react2.default.createElement(WandWithErrorBoundary, { name: 'Voldemort\u2019s', incantation: 'Imperio' }));
|
|
208
|
+
|
|
209
|
+
expect(wrapper.state().error).toEqual(expect.objectContaining(mockError));
|
|
210
|
+
expect(wrapper.state().info).toEqual(expect.objectContaining({
|
|
211
|
+
componentStack: expect.any(String)
|
|
212
|
+
}));
|
|
213
|
+
expect(mockOnError).toHaveBeenCalledWith(mockError, expect.any(String));
|
|
214
|
+
expect(wrapper.containsMatchingElement(_react2.default.createElement(_ErrorBoundaryFallbackComponent2.default, {
|
|
215
|
+
error: mockError /* componentStack="ignored" */
|
|
216
|
+
}))).toBe(true);
|
|
217
|
+
|
|
218
|
+
expect(wrapperWithErrorBoundary.find(_ErrorBoundary2.default).instance().state.error).toEqual(expect.objectContaining(mockError));
|
|
219
|
+
expect(wrapperWithErrorBoundary.find(_ErrorBoundary2.default).instance().state.info).toEqual(expect.objectContaining({
|
|
220
|
+
componentStack: expect.any(String)
|
|
221
|
+
}));
|
|
222
|
+
expect(mockOnErrorWithErrorBoundary).toHaveBeenCalledWith(mockError, expect.any(String));
|
|
223
|
+
expect(wrapperWithErrorBoundary.containsMatchingElement(_react2.default.createElement(_ErrorBoundaryFallbackComponent2.default, {
|
|
224
|
+
error: mockError /* componentStack="ignored" */
|
|
225
|
+
}))).toBe(true);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('sets the correct displayName for wrapped components', function () {
|
|
229
|
+
function NormalComponent() {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
expect((0, _ErrorBoundary.withErrorBoundary)(NormalComponent).displayName).toBe('WithErrorBoundary(NormalComponent)');
|
|
233
|
+
|
|
234
|
+
function ComponentWithDisplayNameOverride() {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
ComponentWithDisplayNameOverride.displayName = 'Override';
|
|
238
|
+
|
|
239
|
+
expect((0, _ErrorBoundary.withErrorBoundary)(ComponentWithDisplayNameOverride).displayName).toBe('WithErrorBoundary(Override)');
|
|
240
|
+
expect((0, _ErrorBoundary.withErrorBoundary)(function () {
|
|
241
|
+
return null;
|
|
242
|
+
}).displayName).toBe('WithErrorBoundary');
|
|
243
|
+
});
|
|
244
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _react = require('react');
|
|
4
|
+
|
|
5
|
+
var _react2 = _interopRequireDefault(_react);
|
|
6
|
+
|
|
7
|
+
var _enzyme = require('enzyme');
|
|
8
|
+
|
|
9
|
+
var _ErrorBoundaryFallbackComponent = require('../ErrorBoundaryFallbackComponent');
|
|
10
|
+
|
|
11
|
+
var _ErrorBoundaryFallbackComponent2 = _interopRequireDefault(_ErrorBoundaryFallbackComponent);
|
|
12
|
+
|
|
13
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
|
+
|
|
15
|
+
describe('ErrorBoundaryFallbackComponent', function () {
|
|
16
|
+
var mockError = void 0;
|
|
17
|
+
|
|
18
|
+
beforeAll(function () {
|
|
19
|
+
mockError = new Error('You cast an unforgivable curse! You’ve earned a one-way ticket to Azkaban.');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('Passes a snapshot test', function () {
|
|
23
|
+
var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(_ErrorBoundaryFallbackComponent2.default, { error: mockError, componentStack: '' }));
|
|
24
|
+
|
|
25
|
+
expect(wrapper).toMatchSnapshot();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`ErrorBoundaryFallbackComponent Passes a snapshot test 1`] = `
|
|
4
|
+
ShallowWrapper {
|
|
5
|
+
Symbol(enzyme.__root__): [Circular],
|
|
6
|
+
Symbol(enzyme.__unrendered__): <ErrorBoundaryFallbackComponent
|
|
7
|
+
componentStack=""
|
|
8
|
+
error={[Error: You cast an unforgivable curse! You’ve earned a one-way ticket to Azkaban.]}
|
|
9
|
+
/>,
|
|
10
|
+
Symbol(enzyme.__renderer__): Object {
|
|
11
|
+
"batchedUpdates": [Function],
|
|
12
|
+
"getNode": [Function],
|
|
13
|
+
"render": [Function],
|
|
14
|
+
"simulateEvent": [Function],
|
|
15
|
+
"unmount": [Function],
|
|
16
|
+
},
|
|
17
|
+
Symbol(enzyme.__node__): Object {
|
|
18
|
+
"instance": null,
|
|
19
|
+
"key": undefined,
|
|
20
|
+
"nodeType": "host",
|
|
21
|
+
"props": Object {
|
|
22
|
+
"children": <svg
|
|
23
|
+
preserveAspectRatio="xMidYMid"
|
|
24
|
+
style={
|
|
25
|
+
Object {
|
|
26
|
+
"fill": "currentColor",
|
|
27
|
+
"flex": "1 1 auto",
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
viewBox="0 0 24 24"
|
|
31
|
+
>
|
|
32
|
+
<path
|
|
33
|
+
d="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
34
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
35
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
36
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
37
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
38
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
39
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z"
|
|
40
|
+
/>
|
|
41
|
+
</svg>,
|
|
42
|
+
"style": Object {
|
|
43
|
+
"alignItems": "center",
|
|
44
|
+
"backgroundColor": "#C00",
|
|
45
|
+
"boxSizing": "border-box",
|
|
46
|
+
"color": "#FFF",
|
|
47
|
+
"cursor": "help",
|
|
48
|
+
"display": "flex",
|
|
49
|
+
"flexDirection": "column",
|
|
50
|
+
"height": "100%",
|
|
51
|
+
"maxHeight": "100vh",
|
|
52
|
+
"maxWidth": "100vw",
|
|
53
|
+
"textAlign": "center",
|
|
54
|
+
"width": "100%",
|
|
55
|
+
},
|
|
56
|
+
"title": "Error: You cast an unforgivable curse! You’ve earned a one-way ticket to Azkaban.
|
|
57
|
+
|
|
58
|
+
This is located at:",
|
|
59
|
+
},
|
|
60
|
+
"ref": null,
|
|
61
|
+
"rendered": Object {
|
|
62
|
+
"instance": null,
|
|
63
|
+
"key": undefined,
|
|
64
|
+
"nodeType": "host",
|
|
65
|
+
"props": Object {
|
|
66
|
+
"children": <path
|
|
67
|
+
d="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
68
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
69
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
70
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
71
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
72
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
73
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z"
|
|
74
|
+
/>,
|
|
75
|
+
"preserveAspectRatio": "xMidYMid",
|
|
76
|
+
"style": Object {
|
|
77
|
+
"fill": "currentColor",
|
|
78
|
+
"flex": "1 1 auto",
|
|
79
|
+
},
|
|
80
|
+
"viewBox": "0 0 24 24",
|
|
81
|
+
},
|
|
82
|
+
"ref": null,
|
|
83
|
+
"rendered": Object {
|
|
84
|
+
"instance": null,
|
|
85
|
+
"key": undefined,
|
|
86
|
+
"nodeType": "host",
|
|
87
|
+
"props": Object {
|
|
88
|
+
"d": "M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
89
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
90
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
91
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
92
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
93
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
94
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z",
|
|
95
|
+
},
|
|
96
|
+
"ref": null,
|
|
97
|
+
"rendered": null,
|
|
98
|
+
"type": "path",
|
|
99
|
+
},
|
|
100
|
+
"type": "svg",
|
|
101
|
+
},
|
|
102
|
+
"type": "div",
|
|
103
|
+
},
|
|
104
|
+
Symbol(enzyme.__nodes__): Array [
|
|
105
|
+
Object {
|
|
106
|
+
"instance": null,
|
|
107
|
+
"key": undefined,
|
|
108
|
+
"nodeType": "host",
|
|
109
|
+
"props": Object {
|
|
110
|
+
"children": <svg
|
|
111
|
+
preserveAspectRatio="xMidYMid"
|
|
112
|
+
style={
|
|
113
|
+
Object {
|
|
114
|
+
"fill": "currentColor",
|
|
115
|
+
"flex": "1 1 auto",
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
viewBox="0 0 24 24"
|
|
119
|
+
>
|
|
120
|
+
<path
|
|
121
|
+
d="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
122
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
123
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
124
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
125
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
126
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
127
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z"
|
|
128
|
+
/>
|
|
129
|
+
</svg>,
|
|
130
|
+
"style": Object {
|
|
131
|
+
"alignItems": "center",
|
|
132
|
+
"backgroundColor": "#C00",
|
|
133
|
+
"boxSizing": "border-box",
|
|
134
|
+
"color": "#FFF",
|
|
135
|
+
"cursor": "help",
|
|
136
|
+
"display": "flex",
|
|
137
|
+
"flexDirection": "column",
|
|
138
|
+
"height": "100%",
|
|
139
|
+
"maxHeight": "100vh",
|
|
140
|
+
"maxWidth": "100vw",
|
|
141
|
+
"textAlign": "center",
|
|
142
|
+
"width": "100%",
|
|
143
|
+
},
|
|
144
|
+
"title": "Error: You cast an unforgivable curse! You’ve earned a one-way ticket to Azkaban.
|
|
145
|
+
|
|
146
|
+
This is located at:",
|
|
147
|
+
},
|
|
148
|
+
"ref": null,
|
|
149
|
+
"rendered": Object {
|
|
150
|
+
"instance": null,
|
|
151
|
+
"key": undefined,
|
|
152
|
+
"nodeType": "host",
|
|
153
|
+
"props": Object {
|
|
154
|
+
"children": <path
|
|
155
|
+
d="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
156
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
157
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
158
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
159
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
160
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
161
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z"
|
|
162
|
+
/>,
|
|
163
|
+
"preserveAspectRatio": "xMidYMid",
|
|
164
|
+
"style": Object {
|
|
165
|
+
"fill": "currentColor",
|
|
166
|
+
"flex": "1 1 auto",
|
|
167
|
+
},
|
|
168
|
+
"viewBox": "0 0 24 24",
|
|
169
|
+
},
|
|
170
|
+
"ref": null,
|
|
171
|
+
"rendered": Object {
|
|
172
|
+
"instance": null,
|
|
173
|
+
"key": undefined,
|
|
174
|
+
"nodeType": "host",
|
|
175
|
+
"props": Object {
|
|
176
|
+
"d": "M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
177
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
178
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
179
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
180
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
181
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
182
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z",
|
|
183
|
+
},
|
|
184
|
+
"ref": null,
|
|
185
|
+
"rendered": null,
|
|
186
|
+
"type": "path",
|
|
187
|
+
},
|
|
188
|
+
"type": "svg",
|
|
189
|
+
},
|
|
190
|
+
"type": "div",
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
Symbol(enzyme.__options__): Object {
|
|
194
|
+
"adapter": ReactSixteenAdapter {
|
|
195
|
+
"options": Object {
|
|
196
|
+
"enableComponentDidUpdateOnSetState": true,
|
|
197
|
+
"lifecycles": Object {
|
|
198
|
+
"componentDidUpdate": Object {
|
|
199
|
+
"onSetState": true,
|
|
200
|
+
},
|
|
201
|
+
"getDerivedStateFromProps": true,
|
|
202
|
+
"getSnapshotBeforeUpdate": true,
|
|
203
|
+
"setState": Object {
|
|
204
|
+
"skipsComponentDidUpdateOnNullish": true,
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
"attachTo": undefined,
|
|
210
|
+
"hydrateIn": undefined,
|
|
211
|
+
},
|
|
212
|
+
}
|
|
213
|
+
`;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _enzyme = require('enzyme');
|
|
4
|
+
|
|
5
|
+
var _enzyme2 = _interopRequireDefault(_enzyme);
|
|
6
|
+
|
|
7
|
+
var _enzymeAdapterReact = require('enzyme-adapter-react-16');
|
|
8
|
+
|
|
9
|
+
var _enzymeAdapterReact2 = _interopRequireDefault(_enzymeAdapterReact);
|
|
10
|
+
|
|
11
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
|
+
|
|
13
|
+
_enzyme2.default.configure({ adapter: new _enzymeAdapterReact2.default() });
|
package/dist/es/ErrorBoundary.js
CHANGED
|
@@ -36,7 +36,8 @@ var ErrorBoundary = function (_Component) {
|
|
|
36
36
|
|
|
37
37
|
if (typeof onError === 'function') {
|
|
38
38
|
try {
|
|
39
|
-
|
|
39
|
+
/* istanbul ignore next: Ignoring ternary; can’t reproduce missing info in test environment. */
|
|
40
|
+
onError.call(this, error, info ? info.componentStack : '');
|
|
40
41
|
} catch (ignoredError) {}
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -55,12 +56,14 @@ var ErrorBoundary = function (_Component) {
|
|
|
55
56
|
|
|
56
57
|
if (error !== null) {
|
|
57
58
|
return React.createElement(FallbackComponent, {
|
|
58
|
-
componentStack:
|
|
59
|
+
componentStack:
|
|
60
|
+
// istanbul ignore next: Ignoring ternary; can’t reproduce missing info in test environment.
|
|
61
|
+
info ? info.componentStack : '',
|
|
59
62
|
error: error
|
|
60
63
|
});
|
|
61
64
|
}
|
|
62
65
|
|
|
63
|
-
return children;
|
|
66
|
+
return children || null;
|
|
64
67
|
}
|
|
65
68
|
}]);
|
|
66
69
|
|
|
@@ -79,13 +82,19 @@ ErrorBoundary.propTypes = {
|
|
|
79
82
|
|
|
80
83
|
|
|
81
84
|
export var withErrorBoundary = function withErrorBoundary(Component, FallbackComponent, onError) {
|
|
82
|
-
|
|
85
|
+
var Wrapped = function Wrapped(props) {
|
|
83
86
|
return React.createElement(
|
|
84
87
|
ErrorBoundary,
|
|
85
88
|
{ FallbackComponent: FallbackComponent, onError: onError },
|
|
86
89
|
React.createElement(Component, props)
|
|
87
90
|
);
|
|
88
91
|
};
|
|
92
|
+
|
|
93
|
+
// Format for display in DevTools
|
|
94
|
+
var name = Component.displayName || Component.name;
|
|
95
|
+
Wrapped.displayName = name ? 'WithErrorBoundary(' + name + ')' : 'WithErrorBoundary';
|
|
96
|
+
|
|
97
|
+
return Wrapped;
|
|
89
98
|
};
|
|
90
99
|
|
|
91
100
|
withErrorBoundary.propTypes = babelPluginFlowReactPropTypes_proptype_ComponentType === require('prop-types').any ? {} : babelPluginFlowReactPropTypes_proptype_ComponentType;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { mount } from 'enzyme';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import ErrorBoundary, { withErrorBoundary } from '../ErrorBoundary';
|
|
5
|
+
import ErrorBoundaryFallbackComponent from '../ErrorBoundaryFallbackComponent';
|
|
6
|
+
|
|
7
|
+
describe('ErrorBoundary', function () {
|
|
8
|
+
var consoleErrorSpy = void 0;
|
|
9
|
+
var mockError = void 0;
|
|
10
|
+
|
|
11
|
+
var Spell = void 0;
|
|
12
|
+
var Wand = void 0;
|
|
13
|
+
|
|
14
|
+
beforeAll(function () {
|
|
15
|
+
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(function () {
|
|
16
|
+
// React error boundaries print the error to `console.error` stream even when it’s caught by our
|
|
17
|
+
// `ErrorBoundary` component. We suppress `console.error` to keep our test console output clean.
|
|
18
|
+
// @see #11098 Allow suppressing error boundary logs from intentionally thrown/caught errors
|
|
19
|
+
// https://github.com/facebook/react/issues/11098
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
mockError = new Error('You cast an unforgivable curse! You’ve earned a one-way ticket to Azkaban.');
|
|
23
|
+
Spell = function Spell(_ref) {
|
|
24
|
+
var incantation = _ref.incantation;
|
|
25
|
+
|
|
26
|
+
switch (incantation) {
|
|
27
|
+
case 'Avada Kedavra':
|
|
28
|
+
case 'Crucio':
|
|
29
|
+
case 'Imperio':
|
|
30
|
+
throw mockError;
|
|
31
|
+
|
|
32
|
+
default:
|
|
33
|
+
return React.createElement(
|
|
34
|
+
'p',
|
|
35
|
+
null,
|
|
36
|
+
'You cast the ' + incantation + ' spell!'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
Wand = function Wand(_ref2) {
|
|
42
|
+
var name = _ref2.name,
|
|
43
|
+
incantation = _ref2.incantation;
|
|
44
|
+
return React.createElement(
|
|
45
|
+
'div',
|
|
46
|
+
null,
|
|
47
|
+
React.createElement(
|
|
48
|
+
'p',
|
|
49
|
+
null,
|
|
50
|
+
'Casting spell with the ' + name + ' wand'
|
|
51
|
+
),
|
|
52
|
+
React.createElement(Spell, { incantation: incantation })
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
afterAll(function () {
|
|
58
|
+
consoleErrorSpy.mockRestore();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('Renders the child component if there is no error', function () {
|
|
62
|
+
var wrapper = mount(React.createElement(
|
|
63
|
+
ErrorBoundary,
|
|
64
|
+
null,
|
|
65
|
+
React.createElement(Wand, { name: 'Harry\u2019s', incantation: 'Expelliarmus' })
|
|
66
|
+
));
|
|
67
|
+
|
|
68
|
+
var WandWithErrorBoundary = withErrorBoundary(Wand);
|
|
69
|
+
var wrapperWithErrorBoundary = mount(React.createElement(WandWithErrorBoundary, { name: 'Harry\u2019s', incantation: 'Expelliarmus' }));
|
|
70
|
+
|
|
71
|
+
expect(wrapper.state().error).toBe(null);
|
|
72
|
+
expect(wrapper.state().info).toBe(null);
|
|
73
|
+
expect(wrapper.containsMatchingElement(React.createElement(ErrorBoundaryFallbackComponent, null))).toBe(false);
|
|
74
|
+
expect(wrapper.contains(React.createElement(Wand, { name: 'Harry\u2019s', incantation: 'Expelliarmus' }))).toBe(true);
|
|
75
|
+
|
|
76
|
+
// Note: We use `….instance().state …` instead of `….state() …` here because…
|
|
77
|
+
// > ReactWrapper::state() can only be called on the root
|
|
78
|
+
expect(wrapperWithErrorBoundary.find(ErrorBoundary).instance().state.error).toBe(null);
|
|
79
|
+
expect(wrapperWithErrorBoundary.find(ErrorBoundary).instance().state.info).toBe(null);
|
|
80
|
+
expect(wrapperWithErrorBoundary.containsMatchingElement(React.createElement(ErrorBoundaryFallbackComponent, null))).toBe(false);
|
|
81
|
+
expect(wrapperWithErrorBoundary.contains(React.createElement(Wand, { name: 'Harry\u2019s', incantation: 'Expelliarmus' }))).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('Sets its state to an error state and renders the default fallback component', function () {
|
|
85
|
+
var wrapper = mount(React.createElement(
|
|
86
|
+
ErrorBoundary,
|
|
87
|
+
null,
|
|
88
|
+
React.createElement(Wand, { name: 'Voldemort\u2019s', incantation: 'Avada Kedavra' })
|
|
89
|
+
));
|
|
90
|
+
|
|
91
|
+
var WandWithErrorBoundary = withErrorBoundary(Wand);
|
|
92
|
+
var wrapperWithErrorBoundary = mount(React.createElement(WandWithErrorBoundary, { name: 'Voldemort\u2019s', incantation: 'Avada Kedavra' }));
|
|
93
|
+
|
|
94
|
+
expect(wrapper.state().error).toEqual(expect.objectContaining(mockError));
|
|
95
|
+
expect(wrapper.state().info).toEqual(expect.objectContaining({
|
|
96
|
+
componentStack: expect.any(String)
|
|
97
|
+
}));
|
|
98
|
+
expect(wrapper.containsMatchingElement(React.createElement(ErrorBoundaryFallbackComponent, null))).toBe(true);
|
|
99
|
+
|
|
100
|
+
expect(wrapperWithErrorBoundary.find(ErrorBoundary).instance().state.error).toEqual(expect.objectContaining(mockError));
|
|
101
|
+
expect(wrapperWithErrorBoundary.find(ErrorBoundary).instance().state.info).toEqual(expect.objectContaining({
|
|
102
|
+
componentStack: expect.any(String)
|
|
103
|
+
}));
|
|
104
|
+
expect(wrapperWithErrorBoundary.containsMatchingElement(React.createElement(ErrorBoundaryFallbackComponent, null))).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('Sets its state to an error state and renders a custom fallback component', function () {
|
|
108
|
+
var MockFallbackComponent = function MockFallbackComponent(_ref3) {
|
|
109
|
+
var error = _ref3.error,
|
|
110
|
+
componentStack = _ref3.componentStack;
|
|
111
|
+
return React.createElement(
|
|
112
|
+
'div',
|
|
113
|
+
null,
|
|
114
|
+
React.createElement(
|
|
115
|
+
'p',
|
|
116
|
+
null,
|
|
117
|
+
React.createElement(
|
|
118
|
+
'strong',
|
|
119
|
+
null,
|
|
120
|
+
'Wand unable to perform magic!'
|
|
121
|
+
),
|
|
122
|
+
'Please contact Ollivanders in Diagon Alley for repairs.'
|
|
123
|
+
),
|
|
124
|
+
React.createElement(
|
|
125
|
+
'p',
|
|
126
|
+
null,
|
|
127
|
+
React.createElement(
|
|
128
|
+
'strong',
|
|
129
|
+
null,
|
|
130
|
+
'Error:'
|
|
131
|
+
),
|
|
132
|
+
' ',
|
|
133
|
+
error.toString()
|
|
134
|
+
),
|
|
135
|
+
React.createElement(
|
|
136
|
+
'p',
|
|
137
|
+
null,
|
|
138
|
+
React.createElement(
|
|
139
|
+
'strong',
|
|
140
|
+
null,
|
|
141
|
+
'Stacktrace:'
|
|
142
|
+
),
|
|
143
|
+
React.createElement(
|
|
144
|
+
'pre',
|
|
145
|
+
null,
|
|
146
|
+
componentStack
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
var wrapper = mount(React.createElement(
|
|
153
|
+
ErrorBoundary,
|
|
154
|
+
{ FallbackComponent: MockFallbackComponent },
|
|
155
|
+
React.createElement(Wand, { name: 'Voldemort\u2019s', incantation: 'Crucio' })
|
|
156
|
+
));
|
|
157
|
+
|
|
158
|
+
var WandWithErrorBoundary = withErrorBoundary(Wand, MockFallbackComponent);
|
|
159
|
+
var wrapperWithErrorBoundary = mount(React.createElement(WandWithErrorBoundary, { name: 'Voldemort\u2019s', incantation: 'Crucio' }));
|
|
160
|
+
|
|
161
|
+
expect(wrapper.state().error).toEqual(expect.objectContaining(mockError));
|
|
162
|
+
expect(wrapper.state().info).toEqual(expect.objectContaining({
|
|
163
|
+
componentStack: expect.any(String)
|
|
164
|
+
}));
|
|
165
|
+
expect(wrapper.containsMatchingElement(React.createElement(ErrorBoundaryFallbackComponent, null))).toBe(false);
|
|
166
|
+
expect(wrapper.containsMatchingElement(React.createElement(MockFallbackComponent, {
|
|
167
|
+
error: mockError /* componentStack="ignored" */
|
|
168
|
+
}))).toBe(true);
|
|
169
|
+
|
|
170
|
+
expect(wrapperWithErrorBoundary.find(ErrorBoundary).instance().state.error).toEqual(expect.objectContaining(mockError));
|
|
171
|
+
expect(wrapperWithErrorBoundary.find(ErrorBoundary).instance().state.info).toEqual(expect.objectContaining({
|
|
172
|
+
componentStack: expect.any(String)
|
|
173
|
+
}));
|
|
174
|
+
expect(wrapperWithErrorBoundary.containsMatchingElement(React.createElement(ErrorBoundaryFallbackComponent, null))).toBe(false);
|
|
175
|
+
expect(wrapperWithErrorBoundary.containsMatchingElement(React.createElement(MockFallbackComponent, {
|
|
176
|
+
error: mockError /* componentStack="ignored" */
|
|
177
|
+
}))).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('Sets its state to an error state and invokes the onError callback prop', function () {
|
|
181
|
+
var mockOnError = jest.fn().mockImplementation(function (error, // eslint-disable-line no-unused-vars
|
|
182
|
+
info) // eslint-disable-line no-unused-vars
|
|
183
|
+
{});
|
|
184
|
+
|
|
185
|
+
var mockOnErrorWithErrorBoundary = jest.fn().mockImplementation(function (error, // eslint-disable-line no-unused-vars
|
|
186
|
+
info) // eslint-disable-line no-unused-vars
|
|
187
|
+
{});
|
|
188
|
+
|
|
189
|
+
var wrapper = mount(React.createElement(
|
|
190
|
+
ErrorBoundary,
|
|
191
|
+
{ onError: mockOnError },
|
|
192
|
+
React.createElement(Wand, { name: 'Voldemort\u2019s', incantation: 'Imperio' })
|
|
193
|
+
));
|
|
194
|
+
var WandWithErrorBoundary = withErrorBoundary(Wand, ErrorBoundaryFallbackComponent, mockOnErrorWithErrorBoundary);
|
|
195
|
+
var wrapperWithErrorBoundary = mount(React.createElement(WandWithErrorBoundary, { name: 'Voldemort\u2019s', incantation: 'Imperio' }));
|
|
196
|
+
|
|
197
|
+
expect(wrapper.state().error).toEqual(expect.objectContaining(mockError));
|
|
198
|
+
expect(wrapper.state().info).toEqual(expect.objectContaining({
|
|
199
|
+
componentStack: expect.any(String)
|
|
200
|
+
}));
|
|
201
|
+
expect(mockOnError).toHaveBeenCalledWith(mockError, expect.any(String));
|
|
202
|
+
expect(wrapper.containsMatchingElement(React.createElement(ErrorBoundaryFallbackComponent, {
|
|
203
|
+
error: mockError /* componentStack="ignored" */
|
|
204
|
+
}))).toBe(true);
|
|
205
|
+
|
|
206
|
+
expect(wrapperWithErrorBoundary.find(ErrorBoundary).instance().state.error).toEqual(expect.objectContaining(mockError));
|
|
207
|
+
expect(wrapperWithErrorBoundary.find(ErrorBoundary).instance().state.info).toEqual(expect.objectContaining({
|
|
208
|
+
componentStack: expect.any(String)
|
|
209
|
+
}));
|
|
210
|
+
expect(mockOnErrorWithErrorBoundary).toHaveBeenCalledWith(mockError, expect.any(String));
|
|
211
|
+
expect(wrapperWithErrorBoundary.containsMatchingElement(React.createElement(ErrorBoundaryFallbackComponent, {
|
|
212
|
+
error: mockError /* componentStack="ignored" */
|
|
213
|
+
}))).toBe(true);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('sets the correct displayName for wrapped components', function () {
|
|
217
|
+
function NormalComponent() {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
expect(withErrorBoundary(NormalComponent).displayName).toBe('WithErrorBoundary(NormalComponent)');
|
|
221
|
+
|
|
222
|
+
function ComponentWithDisplayNameOverride() {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
ComponentWithDisplayNameOverride.displayName = 'Override';
|
|
226
|
+
|
|
227
|
+
expect(withErrorBoundary(ComponentWithDisplayNameOverride).displayName).toBe('WithErrorBoundary(Override)');
|
|
228
|
+
expect(withErrorBoundary(function () {
|
|
229
|
+
return null;
|
|
230
|
+
}).displayName).toBe('WithErrorBoundary');
|
|
231
|
+
});
|
|
232
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { shallow } from 'enzyme';
|
|
3
|
+
|
|
4
|
+
import ErrorBoundaryFallbackComponent from '../ErrorBoundaryFallbackComponent';
|
|
5
|
+
|
|
6
|
+
describe('ErrorBoundaryFallbackComponent', function () {
|
|
7
|
+
var mockError = void 0;
|
|
8
|
+
|
|
9
|
+
beforeAll(function () {
|
|
10
|
+
mockError = new Error('You cast an unforgivable curse! You’ve earned a one-way ticket to Azkaban.');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('Passes a snapshot test', function () {
|
|
14
|
+
var wrapper = shallow(React.createElement(ErrorBoundaryFallbackComponent, { error: mockError, componentStack: '' }));
|
|
15
|
+
|
|
16
|
+
expect(wrapper).toMatchSnapshot();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`ErrorBoundaryFallbackComponent Passes a snapshot test 1`] = `
|
|
4
|
+
ShallowWrapper {
|
|
5
|
+
Symbol(enzyme.__root__): [Circular],
|
|
6
|
+
Symbol(enzyme.__unrendered__): <ErrorBoundaryFallbackComponent
|
|
7
|
+
componentStack=""
|
|
8
|
+
error={[Error: You cast an unforgivable curse! You’ve earned a one-way ticket to Azkaban.]}
|
|
9
|
+
/>,
|
|
10
|
+
Symbol(enzyme.__renderer__): Object {
|
|
11
|
+
"batchedUpdates": [Function],
|
|
12
|
+
"getNode": [Function],
|
|
13
|
+
"render": [Function],
|
|
14
|
+
"simulateEvent": [Function],
|
|
15
|
+
"unmount": [Function],
|
|
16
|
+
},
|
|
17
|
+
Symbol(enzyme.__node__): Object {
|
|
18
|
+
"instance": null,
|
|
19
|
+
"key": undefined,
|
|
20
|
+
"nodeType": "host",
|
|
21
|
+
"props": Object {
|
|
22
|
+
"children": <svg
|
|
23
|
+
preserveAspectRatio="xMidYMid"
|
|
24
|
+
style={
|
|
25
|
+
Object {
|
|
26
|
+
"fill": "currentColor",
|
|
27
|
+
"flex": "1 1 auto",
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
viewBox="0 0 24 24"
|
|
31
|
+
>
|
|
32
|
+
<path
|
|
33
|
+
d="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
34
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
35
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
36
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
37
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
38
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
39
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z"
|
|
40
|
+
/>
|
|
41
|
+
</svg>,
|
|
42
|
+
"style": Object {
|
|
43
|
+
"alignItems": "center",
|
|
44
|
+
"backgroundColor": "#C00",
|
|
45
|
+
"boxSizing": "border-box",
|
|
46
|
+
"color": "#FFF",
|
|
47
|
+
"cursor": "help",
|
|
48
|
+
"display": "flex",
|
|
49
|
+
"flexDirection": "column",
|
|
50
|
+
"height": "100%",
|
|
51
|
+
"maxHeight": "100vh",
|
|
52
|
+
"maxWidth": "100vw",
|
|
53
|
+
"textAlign": "center",
|
|
54
|
+
"width": "100%",
|
|
55
|
+
},
|
|
56
|
+
"title": "Error: You cast an unforgivable curse! You’ve earned a one-way ticket to Azkaban.
|
|
57
|
+
|
|
58
|
+
This is located at:",
|
|
59
|
+
},
|
|
60
|
+
"ref": null,
|
|
61
|
+
"rendered": Object {
|
|
62
|
+
"instance": null,
|
|
63
|
+
"key": undefined,
|
|
64
|
+
"nodeType": "host",
|
|
65
|
+
"props": Object {
|
|
66
|
+
"children": <path
|
|
67
|
+
d="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
68
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
69
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
70
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
71
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
72
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
73
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z"
|
|
74
|
+
/>,
|
|
75
|
+
"preserveAspectRatio": "xMidYMid",
|
|
76
|
+
"style": Object {
|
|
77
|
+
"fill": "currentColor",
|
|
78
|
+
"flex": "1 1 auto",
|
|
79
|
+
},
|
|
80
|
+
"viewBox": "0 0 24 24",
|
|
81
|
+
},
|
|
82
|
+
"ref": null,
|
|
83
|
+
"rendered": Object {
|
|
84
|
+
"instance": null,
|
|
85
|
+
"key": undefined,
|
|
86
|
+
"nodeType": "host",
|
|
87
|
+
"props": Object {
|
|
88
|
+
"d": "M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
89
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
90
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
91
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
92
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
93
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
94
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z",
|
|
95
|
+
},
|
|
96
|
+
"ref": null,
|
|
97
|
+
"rendered": null,
|
|
98
|
+
"type": "path",
|
|
99
|
+
},
|
|
100
|
+
"type": "svg",
|
|
101
|
+
},
|
|
102
|
+
"type": "div",
|
|
103
|
+
},
|
|
104
|
+
Symbol(enzyme.__nodes__): Array [
|
|
105
|
+
Object {
|
|
106
|
+
"instance": null,
|
|
107
|
+
"key": undefined,
|
|
108
|
+
"nodeType": "host",
|
|
109
|
+
"props": Object {
|
|
110
|
+
"children": <svg
|
|
111
|
+
preserveAspectRatio="xMidYMid"
|
|
112
|
+
style={
|
|
113
|
+
Object {
|
|
114
|
+
"fill": "currentColor",
|
|
115
|
+
"flex": "1 1 auto",
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
viewBox="0 0 24 24"
|
|
119
|
+
>
|
|
120
|
+
<path
|
|
121
|
+
d="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
122
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
123
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
124
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
125
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
126
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
127
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z"
|
|
128
|
+
/>
|
|
129
|
+
</svg>,
|
|
130
|
+
"style": Object {
|
|
131
|
+
"alignItems": "center",
|
|
132
|
+
"backgroundColor": "#C00",
|
|
133
|
+
"boxSizing": "border-box",
|
|
134
|
+
"color": "#FFF",
|
|
135
|
+
"cursor": "help",
|
|
136
|
+
"display": "flex",
|
|
137
|
+
"flexDirection": "column",
|
|
138
|
+
"height": "100%",
|
|
139
|
+
"maxHeight": "100vh",
|
|
140
|
+
"maxWidth": "100vw",
|
|
141
|
+
"textAlign": "center",
|
|
142
|
+
"width": "100%",
|
|
143
|
+
},
|
|
144
|
+
"title": "Error: You cast an unforgivable curse! You’ve earned a one-way ticket to Azkaban.
|
|
145
|
+
|
|
146
|
+
This is located at:",
|
|
147
|
+
},
|
|
148
|
+
"ref": null,
|
|
149
|
+
"rendered": Object {
|
|
150
|
+
"instance": null,
|
|
151
|
+
"key": undefined,
|
|
152
|
+
"nodeType": "host",
|
|
153
|
+
"props": Object {
|
|
154
|
+
"children": <path
|
|
155
|
+
d="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
156
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
157
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
158
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
159
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
160
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
161
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z"
|
|
162
|
+
/>,
|
|
163
|
+
"preserveAspectRatio": "xMidYMid",
|
|
164
|
+
"style": Object {
|
|
165
|
+
"fill": "currentColor",
|
|
166
|
+
"flex": "1 1 auto",
|
|
167
|
+
},
|
|
168
|
+
"viewBox": "0 0 24 24",
|
|
169
|
+
},
|
|
170
|
+
"ref": null,
|
|
171
|
+
"rendered": Object {
|
|
172
|
+
"instance": null,
|
|
173
|
+
"key": undefined,
|
|
174
|
+
"nodeType": "host",
|
|
175
|
+
"props": Object {
|
|
176
|
+
"d": "M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,
|
|
177
|
+
12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,
|
|
178
|
+
12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,
|
|
179
|
+
9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,
|
|
180
|
+
8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,
|
|
181
|
+
15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,
|
|
182
|
+
17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z",
|
|
183
|
+
},
|
|
184
|
+
"ref": null,
|
|
185
|
+
"rendered": null,
|
|
186
|
+
"type": "path",
|
|
187
|
+
},
|
|
188
|
+
"type": "svg",
|
|
189
|
+
},
|
|
190
|
+
"type": "div",
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
Symbol(enzyme.__options__): Object {
|
|
194
|
+
"adapter": ReactSixteenAdapter {
|
|
195
|
+
"options": Object {
|
|
196
|
+
"enableComponentDidUpdateOnSetState": true,
|
|
197
|
+
"lifecycles": Object {
|
|
198
|
+
"componentDidUpdate": Object {
|
|
199
|
+
"onSetState": true,
|
|
200
|
+
},
|
|
201
|
+
"getDerivedStateFromProps": true,
|
|
202
|
+
"getSnapshotBeforeUpdate": true,
|
|
203
|
+
"setState": Object {
|
|
204
|
+
"skipsComponentDidUpdateOnNullish": true,
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
"attachTo": undefined,
|
|
210
|
+
"hydrateIn": undefined,
|
|
211
|
+
},
|
|
212
|
+
}
|
|
213
|
+
`;
|
|
@@ -633,7 +633,7 @@
|
|
|
633
633
|
return null !== error ? _react2.default.createElement(FallbackComponent, {
|
|
634
634
|
componentStack: info ? info.componentStack : "",
|
|
635
635
|
error: error
|
|
636
|
-
}) : children;
|
|
636
|
+
}) : children || null;
|
|
637
637
|
}
|
|
638
638
|
} ]), ErrorBoundary;
|
|
639
639
|
}(_react.Component);
|
|
@@ -641,12 +641,14 @@
|
|
|
641
641
|
FallbackComponent: _ErrorBoundaryFallbackComponent2.default
|
|
642
642
|
};
|
|
643
643
|
exports.withErrorBoundary = function(Component, FallbackComponent, onError) {
|
|
644
|
-
|
|
644
|
+
var Wrapped = function(props) {
|
|
645
645
|
return _react2.default.createElement(ErrorBoundary, {
|
|
646
646
|
FallbackComponent: FallbackComponent,
|
|
647
647
|
onError: onError
|
|
648
648
|
}, _react2.default.createElement(Component, props));
|
|
649
|
-
};
|
|
649
|
+
}, name = Component.displayName || Component.name;
|
|
650
|
+
return Wrapped.displayName = name ? "WithErrorBoundary(" + name + ")" : "WithErrorBoundary",
|
|
651
|
+
Wrapped;
|
|
650
652
|
};
|
|
651
653
|
exports.default = ErrorBoundary;
|
|
652
654
|
}, /* 45 */
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface FallbackProps {
|
|
4
|
+
error?: Error;
|
|
5
|
+
componentStack?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ErrorBoundaryProps {
|
|
9
|
+
onError?: (error: Error, componentStack: string) => void;
|
|
10
|
+
FallbackComponent?: React.ComponentType<FallbackProps>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function withErrorBoundary<P>(
|
|
14
|
+
ComponentToDecorate: React.ComponentType<P>,
|
|
15
|
+
CustomFallbackComponent?: React.ComponentType<FallbackProps>,
|
|
16
|
+
onErrorHandler?: (error: Error, componentStack: string) => void,
|
|
17
|
+
): React.ComponentType<P>;
|
|
18
|
+
|
|
19
|
+
export default class ErrorBoundary extends React.Component<ErrorBoundaryProps>{}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-error-boundary",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "Sample reusable React error boundary component for React 16+",
|
|
5
5
|
"homepage": "https://github.com/bvaughn/react-error-boundary",
|
|
6
6
|
"repository": "bvaughn/react-error-boundary",
|
|
7
7
|
"files": [
|
|
8
|
-
"dist"
|
|
8
|
+
"dist",
|
|
9
|
+
"index.d.ts"
|
|
9
10
|
],
|
|
10
11
|
"main": "dist/commonjs/index.js",
|
|
11
12
|
"scripts": {
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
"flow": "flow check src",
|
|
21
22
|
"lint": "eslint 'src/**/*.js'",
|
|
22
23
|
"prettier": "prettier --config .prettierrc --write \"src/**/*.js\"",
|
|
23
|
-
"test": "
|
|
24
|
+
"test": "jest"
|
|
24
25
|
},
|
|
25
26
|
"author": "Brian Vaughn <brian.david.vaughn@gmail.com>",
|
|
26
27
|
"license": "MIT",
|
|
@@ -28,6 +29,7 @@
|
|
|
28
29
|
"babel-cli": "^6.24.1",
|
|
29
30
|
"babel-core": "^6.25.0",
|
|
30
31
|
"babel-eslint": "^8.0.1",
|
|
32
|
+
"babel-jest": "^23.4.2",
|
|
31
33
|
"babel-loader": "^7.1.1",
|
|
32
34
|
"babel-plugin-flow-react-proptypes": "^3.4.2",
|
|
33
35
|
"babel-plugin-transform-react-remove-prop-types": "^0.4.6",
|
|
@@ -39,6 +41,8 @@
|
|
|
39
41
|
"babel-preset-stage-1": "^6.24.1",
|
|
40
42
|
"babel-runtime": "^6.23.0",
|
|
41
43
|
"cross-env": "^5.0.1",
|
|
44
|
+
"enzyme": "^3.5.0",
|
|
45
|
+
"enzyme-adapter-react-16": "^1.3.0",
|
|
42
46
|
"eslint": "^4.2.0",
|
|
43
47
|
"eslint-config-fbjs": "^2.0.0",
|
|
44
48
|
"eslint-plugin-babel": "^4.1.2",
|
|
@@ -48,8 +52,12 @@
|
|
|
48
52
|
"eslint-plugin-react": "^7.4.0",
|
|
49
53
|
"eslint-plugin-relay": "^0.0.19",
|
|
50
54
|
"flow-bin": "^0.57.3",
|
|
55
|
+
"jest": "^23.5.0",
|
|
51
56
|
"prettier": "^1.7.4",
|
|
52
57
|
"prop-types": "^15.5.10",
|
|
58
|
+
"react": "^16.4.2",
|
|
59
|
+
"react-dom": "^16.4.2",
|
|
60
|
+
"react-test-renderer": "^16.4.2",
|
|
53
61
|
"rimraf": "^2.6.1",
|
|
54
62
|
"webpack": "^3.3.0"
|
|
55
63
|
},
|