Skip to content

Commit

Permalink
JS Error Tracking: Allow custom error reporting logic to be called in…
Browse files Browse the repository at this point in the history
… Error Boundaries via a WP action hook (#42024)

* Call WP action hook that allow other consuming code to set a custom additional error reporting logic for Error Boundaries

* Remove doAction from edit navigation error boundary

Separate navigation editor screen development is on hold.

* Rename action

* Add unit tests

* Document the new action

* Update editor-actions.md
  • Loading branch information
fullofcaffeine authored Jul 12, 2022
1 parent 64baf53 commit d68dedb
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 0 deletions.
24 changes: 24 additions & 0 deletions docs/reference-guides/actions/editor-actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Editor Actions

To help you hook into the editor lifecycle and extend it, the following Actions are exposed:

### Error Boundaries

#### `editor.ErrorBoundary.errorLogged`

Allows you to hook into the editor Error Boundaries' `componentDidCatch` and gives you access to the error object.

You can use if you want to get hold of the error object that's handled by the boundaries, i.e to send them to an external error tracking tool.

_Example_:

```js
addAction(
'editor.ErrorBoundary.errorLogged',
'mu-plugin/error-capture-setup',
( error ) => {
// error is the exception's error object
ErrorCaptureTool.captureError( error );
}
);
```
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { Warning } from '@wordpress/block-editor';
import { useCopyToClipboard } from '@wordpress/compose';
import { doAction } from '@wordpress/hooks';

function CopyButton( { text, children } ) {
const ref = useCopyToClipboard( text );
Expand All @@ -26,6 +27,8 @@ export default class ErrorBoundary extends Component {

componentDidCatch( error ) {
this.setState( { error } );

doAction( 'editor.ErrorBoundary.errorLogged', error );
}

render() {
Expand Down
38 changes: 38 additions & 0 deletions packages/customize-widgets/src/components/test/error-boundary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* WordPress dependencies
*/
import * as wpHooks from '@wordpress/hooks';
/**
* Internal dependencies
*/
import ErrorBoundary from '../error-boundary';
/**
* External dependencies
*/
import { render } from '@testing-library/react';

const theError = new Error( 'Kaboom' );

const ChildComponent = () => {
throw theError;
};

describe( 'Error Boundary', () => {
describe( 'when error is thrown from a Child component', () => {
it( 'calls the `editor.ErrorBoundary.errorLogged` hook action with the error object', () => {
const doAction = jest.spyOn( wpHooks, 'doAction' );

render(
<ErrorBoundary>
<ChildComponent />
</ErrorBoundary>
);

expect( doAction ).toHaveBeenCalledWith(
'editor.ErrorBoundary.errorLogged',
theError
);
expect( console ).toHaveErrored();
} );
} );
} );
5 changes: 5 additions & 0 deletions packages/edit-site/src/components/error-boundary/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import { Component } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { doAction } from '@wordpress/hooks';

/**
* Internal dependencies
Expand All @@ -20,6 +21,10 @@ export default class ErrorBoundary extends Component {
};
}

componentDidCatch( error ) {
doAction( 'editor.ErrorBoundary.errorLogged', error );
}

static getDerivedStateFromError( error ) {
return { error };
}
Expand Down
38 changes: 38 additions & 0 deletions packages/edit-site/src/components/test/error-boundary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* WordPress dependencies
*/
import * as wpHooks from '@wordpress/hooks';
/**
* Internal dependencies
*/
import ErrorBoundary from '../error-boundary';
/**
* External dependencies
*/
import { render } from '@testing-library/react';

const theError = new Error( 'Kaboom' );

const ChildComponent = () => {
throw theError;
};

describe( 'Error Boundary', () => {
describe( 'when error is thrown from a Child component', () => {
it( 'calls the `editor.ErrorBoundary.errorLogged` hook action with the error object', () => {
const doAction = jest.spyOn( wpHooks, 'doAction' );

render(
<ErrorBoundary>
<ChildComponent />
</ErrorBoundary>
);

expect( doAction ).toHaveBeenCalledWith(
'editor.ErrorBoundary.errorLogged',
theError
);
expect( console ).toHaveErrored();
} );
} );
} );
3 changes: 3 additions & 0 deletions packages/edit-widgets/src/components/error-boundary/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { Warning } from '@wordpress/block-editor';
import { useCopyToClipboard } from '@wordpress/compose';
import { doAction } from '@wordpress/hooks';

function CopyButton( { text, children } ) {
const ref = useCopyToClipboard( text );
Expand All @@ -29,6 +30,8 @@ export default class ErrorBoundary extends Component {

componentDidCatch( error ) {
this.setState( { error } );

doAction( 'editor.ErrorBoundary.errorLogged', error );
}

reboot() {
Expand Down
38 changes: 38 additions & 0 deletions packages/edit-widgets/src/components/test/error-boundary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* WordPress dependencies
*/
import * as wpHooks from '@wordpress/hooks';
/**
* Internal dependencies
*/
import ErrorBoundary from '../error-boundary';
/**
* External dependencies
*/
import { render } from '@testing-library/react';

const theError = new Error( 'Kaboom' );

const ChildComponent = () => {
throw theError;
};

describe( 'Error Boundary', () => {
describe( 'when error is thrown from a Child component', () => {
it( 'calls the `editor.ErrorBoundary.errorLogged` hook action with the error object', () => {
const doAction = jest.spyOn( wpHooks, 'doAction' );

render(
<ErrorBoundary>
<ChildComponent />
</ErrorBoundary>
);

expect( doAction ).toHaveBeenCalledWith(
'editor.ErrorBoundary.errorLogged',
theError
);
expect( console ).toHaveErrored();
} );
} );
} );
3 changes: 3 additions & 0 deletions packages/editor/src/components/error-boundary/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Button } from '@wordpress/components';
import { select } from '@wordpress/data';
import { Warning } from '@wordpress/block-editor';
import { useCopyToClipboard } from '@wordpress/compose';
import { doAction } from '@wordpress/hooks';

/**
* Internal dependencies
Expand Down Expand Up @@ -36,6 +37,8 @@ class ErrorBoundary extends Component {

componentDidCatch( error ) {
this.setState( { error } );

doAction( 'editor.ErrorBoundary.errorLogged', error );
}

reboot() {
Expand Down

0 comments on commit d68dedb

Please sign in to comment.