diff --git a/src/components/errorboundary/errorboundary.jsx b/src/components/errorboundary/errorboundary.jsx index 90bd7b368..a1c320e36 100644 --- a/src/components/errorboundary/errorboundary.jsx +++ b/src/components/errorboundary/errorboundary.jsx @@ -17,6 +17,10 @@ class ErrorBoundary extends React.Component { componentDidCatch (error, errorInfo) { // Display fallback UI Sentry.withScope(scope => { + scope.setTag('project', 'scratch-www'); + if (this.props.componentName) { + scope.setTag('component', this.props.componentName); + } Object.keys(errorInfo).forEach(key => { scope.setExtra(key, errorInfo[key]); }); @@ -46,7 +50,8 @@ class ErrorBoundary extends React.Component { } } ErrorBoundary.propTypes = { - children: PropTypes.node + children: PropTypes.node, + componentName: PropTypes.string }; module.exports = ErrorBoundary; diff --git a/src/components/page/www/page.jsx b/src/components/page/www/page.jsx index d20e8fda6..77f3712ba 100644 --- a/src/components/page/www/page.jsx +++ b/src/components/page/www/page.jsx @@ -10,7 +10,7 @@ const Page = ({ children, className }) => ( - +
( - +
-
- -
- +
+ +
); } diff --git a/src/views/preview/embed.jsx b/src/views/preview/embed.jsx index f458948be..ba992fab4 100644 --- a/src/views/preview/embed.jsx +++ b/src/views/preview/embed.jsx @@ -13,7 +13,9 @@ const UnsupportedBrowser = require('./unsupported-browser.jsx'); if (isSupportedBrowser()) { const EmbedView = require('./embed-view.jsx'); render( - , + + + , document.getElementById('app'), { preview: previewActions.previewReducer, @@ -26,5 +28,8 @@ if (isSupportedBrowser()) { EmbedView.guiMiddleware ); } else { - render(, document.getElementById('app')); + render( + , + document.getElementById('app') + ); } diff --git a/test/unit/components/errorboundary.test.jsx b/test/unit/components/errorboundary.test.jsx new file mode 100644 index 000000000..fbcaf2006 --- /dev/null +++ b/test/unit/components/errorboundary.test.jsx @@ -0,0 +1,76 @@ +import React from 'react'; +const {mountWithIntl} = require('../../helpers/intl-helpers.jsx'); + +jest.mock('@sentry/browser', () => { + const setExtra = jest.fn(); + const setTag = jest.fn(); + + const makeScope = (setExtraParam, setTagParam) => { + const thisScope = { + setExtra: setExtraParam, + setTag: setTagParam + }; + return thisScope; + }; + const Sentry = { + captureException: jest.fn(), + lastEventId: function () { + return 0; + }, + setExtra: setExtra, + setTag: setTag, + withScope: jest.fn(cb => { + cb(makeScope(setExtra, setTag)); + }) + }; + return Sentry; +}); + +const Sentry = require('@sentry/browser'); +import ErrorBoundary from '../../../src/components/errorboundary/errorboundary.jsx'; + +describe('ErrorBoundary', () => { + let errorBoundaryWrapper; + + const ChildClass = () => ( +
+ Children here +
+ ); + + beforeEach(() => { + errorBoundaryWrapper = mountWithIntl( + + + + ); + }); + + test('calling ErrorBoundary\'s componentDidCatch() calls Sentry.withScope()', () => { + const errorBoundaryInstance = errorBoundaryWrapper.instance(); + errorBoundaryInstance.componentDidCatch('error', {}); + expect(Sentry.withScope).toHaveBeenCalled(); + }); + + test('calling ErrorBoundary\'s componentDidCatch() calls Sentry.captureException()', () => { + const errorBoundaryInstance = errorBoundaryWrapper.instance(); + errorBoundaryInstance.componentDidCatch('error', {}); + expect(Sentry.captureException).toHaveBeenCalledWith('error'); + }); + + test('throwing error under ErrorBoundary calls Sentry.withScope()', () => { + const child = errorBoundaryWrapper.find('#childClass'); + expect(child.exists()).toEqual(true); + child.simulateError({}, {}); + expect(Sentry.withScope).toHaveBeenCalled(); + }); + + test('ErrorBoundary with name prop causes Sentry to setTag with that name', () => { + const child = errorBoundaryWrapper.find('#childClass'); + expect(child.exists()).toEqual(true); + child.simulateError({}); + expect(Sentry.setTag).toHaveBeenCalledWith('component', 'TestEBName'); + }); +});