Skip to content

Commit

Permalink
Devtools: add feature to trigger an error boundary
Browse files Browse the repository at this point in the history
  • Loading branch information
baopham committed May 29, 2021
1 parent d75105f commit 182ba9e
Show file tree
Hide file tree
Showing 24 changed files with 567 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,7 @@ Object {
0,
1,
0,
0,
4,
2,
12000,
Expand All @@ -729,6 +730,7 @@ Object {
2,
2,
3,
0,
4,
4,
0,
Expand All @@ -739,6 +741,7 @@ Object {
2,
2,
4,
0,
4,
5,
1000,
Expand All @@ -749,6 +752,7 @@ Object {
2,
2,
0,
0,
4,
6,
1000,
Expand All @@ -772,6 +776,7 @@ Object {
2,
1,
2,
0,
4,
7,
2000,
Expand Down Expand Up @@ -1178,6 +1183,7 @@ Object {
0,
1,
0,
0,
4,
2,
11000,
Expand All @@ -1188,6 +1194,7 @@ Object {
2,
2,
3,
0,
4,
4,
0,
Expand All @@ -1198,6 +1205,7 @@ Object {
2,
2,
0,
0,
4,
5,
1000,
Expand All @@ -1221,6 +1229,7 @@ Object {
2,
1,
2,
0,
4,
6,
1000,
Expand Down Expand Up @@ -1256,6 +1265,7 @@ Object {
2,
1,
2,
0,
4,
7,
2000,
Expand Down Expand Up @@ -1455,6 +1465,7 @@ Object {
2,
1,
2,
0,
4,
12,
2000,
Expand Down Expand Up @@ -1647,6 +1658,7 @@ Object {
0,
1,
0,
0,
4,
14,
11000,
Expand All @@ -1657,6 +1669,7 @@ Object {
14,
2,
3,
0,
4,
16,
0,
Expand All @@ -1667,6 +1680,7 @@ Object {
14,
2,
0,
0,
4,
17,
1000,
Expand Down Expand Up @@ -2036,6 +2050,7 @@ Object {
2,
1,
2,
0,
4,
12,
2000,
Expand Down Expand Up @@ -2273,6 +2288,7 @@ Object {
0,
1,
0,
0,
4,
14,
11000,
Expand All @@ -2283,6 +2299,7 @@ Object {
14,
2,
3,
0,
4,
16,
0,
Expand All @@ -2293,6 +2310,7 @@ Object {
14,
2,
0,
0,
4,
17,
1000,
Expand Down Expand Up @@ -2472,6 +2490,7 @@ Object {
0,
1,
0,
0,
4,
2,
0,
Expand Down Expand Up @@ -2968,6 +2987,7 @@ Object {
0,
1,
0,
0,
4,
2,
0,
Expand All @@ -2978,6 +2998,7 @@ Object {
0,
2,
0,
0,
4,
3,
0,
Expand Down Expand Up @@ -4176,6 +4197,7 @@ Object {
0,
1,
0,
0,
4,
2,
0,
Expand All @@ -4186,6 +4208,7 @@ Object {
2,
2,
0,
0,
4,
3,
0,
Expand All @@ -4196,6 +4219,7 @@ Object {
2,
3,
0,
0,
4,
4,
0,
Expand All @@ -4206,6 +4230,7 @@ Object {
4,
4,
0,
0,
4,
5,
0,
Expand All @@ -4216,6 +4241,7 @@ Object {
2,
5,
0,
0,
4,
6,
0,
Expand All @@ -4226,6 +4252,7 @@ Object {
6,
4,
0,
0,
4,
7,
0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2380,4 +2380,62 @@ describe('InspectedElement', () => {
`);
});
});

describe('error boundary', () => {
it('can toggle error', async () => {
class ErrorBoundary extends React.Component<any> {
state = {hasError: false};
static getDerivedStateFromError(error) {
return {hasError: true};
}
render() {
const {hasError} = this.state;
return hasError ? 'has-error' : this.props.children;
}
}
const Example = () => 'example';

await utils.actAsync(() =>
ReactDOM.render(
<ErrorBoundary>
<Example />
</ErrorBoundary>,
document.createElement('div'),
),
);

const errorBoundaryID = ((store.getElementIDAtIndex(0): any): number);
const toggleError = async forceError => {
await withErrorsOrWarningsIgnored(['ErrorBoundary'], async () => {
await utils.actAsync(() => {
bridge.send('overrideError', {
id: errorBoundaryID,
rendererID: store.getRendererIDForElement(errorBoundaryID),
forceError,
});
});
});

TestUtilsAct(() => {
jest.runOnlyPendingTimers();
});
};

let inspectedElement = await inspectElementAtIndex(1);
expect(inspectedElement.canToggleError).toBe(true);
expect(inspectedElement.isErrored).toBe(false);

await toggleError(true);

inspectedElement = await inspectElementAtIndex(0);
expect(inspectedElement.canToggleError).toBe(true);
expect(inspectedElement.isErrored).toBe(true);

await toggleError(false);

inspectedElement = await inspectElementAtIndex(0);
expect(inspectedElement.canToggleError).toBe(true);
expect(inspectedElement.isErrored).toBe(false);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function test(maybeInspectedElement) {
hasOwnProperty('canEditFunctionProps') &&
hasOwnProperty('canEditHooks') &&
hasOwnProperty('canToggleSuspense') &&
hasOwnProperty('canToggleError') &&
hasOwnProperty('canViewSource')
);
}
Expand Down
35 changes: 35 additions & 0 deletions packages/react-devtools-shared/src/__tests__/store-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,41 @@ describe('Store', () => {
`);
});

it('should detect if element is an error boundary', async () => {
class ErrorBoundary extends React.Component {
state = {hasError: false};
static getDerivedStateFromError(error) {
return {hasError: true};
}
render() {
return this.props.children;
}
}
class ClassComponent extends React.Component {
render() {
return null;
}
}
const FunctionalComponent = () => null;

const App = () => (
<React.Fragment>
<ErrorBoundary>
<ClassComponent />
<FunctionalComponent />
</ErrorBoundary>
</React.Fragment>
);

const container = document.createElement('div');

act(() => ReactDOM.render(<App />, container));

expect(store.getElementAtIndex(1).isErrorBoundary).toBe(true);
expect(store.getElementAtIndex(2).isErrorBoundary).toBe(false);
expect(store.getElementAtIndex(3).isErrorBoundary).toBe(false);
});

describe('Lazy', () => {
async function fakeImport(result) {
return {default: result};
Expand Down
16 changes: 16 additions & 0 deletions packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ type OverrideValueAtPathParams = {|
value: any,
|};

type OverrideErrorParams = {|
id: number,
rendererID: number,
forceError: boolean,
|};

type OverrideSuspenseParams = {|
id: number,
rendererID: number,
Expand Down Expand Up @@ -183,6 +189,7 @@ export default class Agent extends EventEmitter<{|
bridge.addListener('getOwnersList', this.getOwnersList);
bridge.addListener('inspectElement', this.inspectElement);
bridge.addListener('logElementToConsole', this.logElementToConsole);
bridge.addListener('overrideError', this.overrideError);
bridge.addListener('overrideSuspense', this.overrideSuspense);
bridge.addListener('overrideValueAtPath', this.overrideValueAtPath);
bridge.addListener('reloadAndProfile', this.reloadAndProfile);
Expand Down Expand Up @@ -381,6 +388,15 @@ export default class Agent extends EventEmitter<{|
}
};

overrideError = ({id, rendererID, forceError}: OverrideErrorParams) => {
const renderer = this._rendererInterfaces[rendererID];
if (renderer == null) {
console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
} else {
renderer.overrideError(id, forceError);
}
};

overrideSuspense = ({
id,
rendererID,
Expand Down
Loading

0 comments on commit 182ba9e

Please sign in to comment.