Merge pull request #7353 from cwillisf/remove-sentry

fix: remove Sentry and rewrite ErrorBoundary tests
This commit is contained in:
Christopher Willis-Ford 2023-01-30 09:00:15 -08:00 committed by GitHub
commit ecdd686c7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 42 additions and 265 deletions

View file

@ -165,7 +165,6 @@ the beginning of the command, before `npm start`:
| `ASSET_HOST` | `https://assets.scratch.mit.edu` | Hostname for asset requests |
| `BACKPACK_HOST` | `https://backpack.scratch.mit.edu` | Hostname for backpack requests |
| `PROJECT_HOST` | `https://projects.scratch.mit.edu` | Hostname for project requests |
| `SENTRY_DSN` | `''` | DSN for Sentry |
| `FALLBACK` | `''` | Pass-through location for old site |
| `GA_TRACKER` | `''` | Where to log Google Analytics data |
| `NODE_ENV` | `null` | If not `production`, app acts like development |

152
package-lock.json generated
View file

@ -9,7 +9,6 @@
"version": "1.0.0",
"license": "BSD-3-Clause",
"dependencies": {
"@sentry/browser": "4.4.2",
"bunyan": "1.8.15",
"clipboard-copy": "2.0.1",
"express": "4.16.1",
@ -93,6 +92,7 @@
"react-slick": "0.16.0",
"react-string-replace": "0.4.1",
"react-telephone-input": "4.3.4",
"react-test-renderer": "16.14.0",
"redux": "3.5.2",
"redux-mock-store": "1.5.4",
"redux-thunk": "2.0.1",
@ -1645,81 +1645,6 @@
"node": ">=8.0.0"
}
},
"node_modules/@sentry/browser": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-4.4.2.tgz",
"integrity": "sha512-km5p3hPz+aoY4UiEvYxAdRJAbIK30urZSuMs/3zAUVe+8Zij0IHjHmdi9JtrMqpn+rAcWCxtRmFSYlkiKjdSUg==",
"dependencies": {
"@sentry/core": "4.4.2",
"@sentry/types": "4.4.2",
"@sentry/utils": "4.4.2",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/core": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-4.4.2.tgz",
"integrity": "sha512-hJyAodTCf4sZfVdf41Rtuzj4EsyzYq5rdMZ+zc2Vinwdf8D0/brHe91fHeO0CKXEb2P0wJsrjwMidG/ccq/M8A==",
"dependencies": {
"@sentry/hub": "4.4.2",
"@sentry/minimal": "4.4.2",
"@sentry/types": "4.4.2",
"@sentry/utils": "4.4.2",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/hub": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-4.4.2.tgz",
"integrity": "sha512-oe9ytXkTWyD+QmOpVzHAqTbRV4Hc0ee2Nt6HvrDtRmlXzQxfvTWG2F8KYT6w8kzqg5klnuRpnsmgTTV3KuNBVQ==",
"dependencies": {
"@sentry/types": "4.4.2",
"@sentry/utils": "4.4.2",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/minimal": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-4.4.2.tgz",
"integrity": "sha512-GEZZiNvVgqFAESZhAe3vjwTInn13lI2bSI3ItQN4RUWKL/W4n/fwVoDJbkb1U8aWxanuMnRDEpKwyQv6zYTZfw==",
"dependencies": {
"@sentry/hub": "4.4.2",
"@sentry/types": "4.4.2",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/types": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-4.4.2.tgz",
"integrity": "sha512-QyQd6PKKIyjJgaq/RQjsxPJEWbXcuiWZ9RvSnhBjS5jj53HEzkM1qkbAFqlYHJ1DTJJ1EuOM4+aTmGzHe93zuA==",
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/utils": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-4.4.2.tgz",
"integrity": "sha512-j/Ad8G1abHlJdD2q7aWWbSOSeWB5M5v1R1VKL8YPlwEbSvvmEQWePhBKFI0qlnKd2ObdUQsj86pHEXJRSFNfCw==",
"dependencies": {
"@sentry/types": "4.4.2",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sindresorhus/is": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
@ -20568,15 +20493,6 @@
"react-is": "^16.8.1"
}
},
"node_modules/react-test-renderer/node_modules/scheduler": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
},
"node_modules/react-tooltip": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-3.8.0.tgz",
@ -33054,63 +32970,6 @@
"integrity": "sha512-cphYw/y/l36UJ8fv/LXyK+lHlxMXtoydJUsgA4u5QnaUaSZYepuSHik6PewJGT4qvaPwT5ImvHWwX2kElWXvoQ==",
"dev": true
},
"@sentry/browser": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-4.4.2.tgz",
"integrity": "sha512-km5p3hPz+aoY4UiEvYxAdRJAbIK30urZSuMs/3zAUVe+8Zij0IHjHmdi9JtrMqpn+rAcWCxtRmFSYlkiKjdSUg==",
"requires": {
"@sentry/core": "4.4.2",
"@sentry/types": "4.4.2",
"@sentry/utils": "4.4.2",
"tslib": "^1.9.3"
}
},
"@sentry/core": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-4.4.2.tgz",
"integrity": "sha512-hJyAodTCf4sZfVdf41Rtuzj4EsyzYq5rdMZ+zc2Vinwdf8D0/brHe91fHeO0CKXEb2P0wJsrjwMidG/ccq/M8A==",
"requires": {
"@sentry/hub": "4.4.2",
"@sentry/minimal": "4.4.2",
"@sentry/types": "4.4.2",
"@sentry/utils": "4.4.2",
"tslib": "^1.9.3"
}
},
"@sentry/hub": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-4.4.2.tgz",
"integrity": "sha512-oe9ytXkTWyD+QmOpVzHAqTbRV4Hc0ee2Nt6HvrDtRmlXzQxfvTWG2F8KYT6w8kzqg5klnuRpnsmgTTV3KuNBVQ==",
"requires": {
"@sentry/types": "4.4.2",
"@sentry/utils": "4.4.2",
"tslib": "^1.9.3"
}
},
"@sentry/minimal": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-4.4.2.tgz",
"integrity": "sha512-GEZZiNvVgqFAESZhAe3vjwTInn13lI2bSI3ItQN4RUWKL/W4n/fwVoDJbkb1U8aWxanuMnRDEpKwyQv6zYTZfw==",
"requires": {
"@sentry/hub": "4.4.2",
"@sentry/types": "4.4.2",
"tslib": "^1.9.3"
}
},
"@sentry/types": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-4.4.2.tgz",
"integrity": "sha512-QyQd6PKKIyjJgaq/RQjsxPJEWbXcuiWZ9RvSnhBjS5jj53HEzkM1qkbAFqlYHJ1DTJJ1EuOM4+aTmGzHe93zuA=="
},
"@sentry/utils": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-4.4.2.tgz",
"integrity": "sha512-j/Ad8G1abHlJdD2q7aWWbSOSeWB5M5v1R1VKL8YPlwEbSvvmEQWePhBKFI0qlnKd2ObdUQsj86pHEXJRSFNfCw==",
"requires": {
"@sentry/types": "4.4.2",
"tslib": "^1.9.3"
}
},
"@sindresorhus/is": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
@ -49108,15 +48967,6 @@
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
}
},
"scheduler": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
}
}
},

View file

@ -44,7 +44,6 @@
},
"homepage": "https://github.com/llk/scratch-www#readme",
"dependencies": {
"@sentry/browser": "4.4.2",
"bunyan": "1.8.15",
"clipboard-copy": "2.0.1",
"express": "4.16.1",
@ -128,6 +127,7 @@
"react-slick": "0.16.0",
"react-string-replace": "0.4.1",
"react-telephone-input": "4.3.4",
"react-test-renderer": "16.14.0",
"redux": "3.5.2",
"redux-mock-store": "1.5.4",
"redux-thunk": "2.0.1",

View file

@ -1,6 +1,5 @@
const PropTypes = require('prop-types');
const React = require('react');
const Sentry = require('@sentry/browser');
const CrashMessageComponent = require('../crashmessage/crashmessage.jsx');
import log from '../../lib/log.js';
@ -9,28 +8,37 @@ class ErrorBoundary extends React.Component {
constructor (props) {
super(props);
this.state = {
hasError: false,
errorId: null
error: null,
errorInfo: null
};
}
/**
* Handle an error caught by this ErrorBoundary component.
* @param {Error} error - the error that was caught.
* @param {React.ErrorInfo} errorInfo - the React error info associated with the error.
*/
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]);
error = error || {
stack: 'Unknown stack',
message: 'Unknown error'
};
errorInfo = errorInfo || {
componentStack: 'Unknown component stack'
};
// only remember the first error: later errors might just be side effects of that first one
if (!this.state.error) {
// store error & errorInfo for debugging
this.setState({
error,
errorInfo
});
Sentry.captureException(error);
});
this.setState({
hasError: true,
errorId: Sentry.lastEventId()
});
log.error(`Unhandled Error: ${error}, info: ${errorInfo}`);
}
// report every error in the console
const componentInfo = this.props.componentName ? ` in ${this.props.componentName}` : '';
log.error(`Unhandled Error${componentInfo}: ${error.stack}\nComponent stack: ${errorInfo.componentStack}`);
}
handleBack () {
@ -38,10 +46,9 @@ class ErrorBoundary extends React.Component {
}
render () {
if (this.state.hasError) {
if (this.state.error) {
return (
<CrashMessageComponent
eventId={this.state.errorId}
onBack={this.handleBack}
/>
);

View file

@ -1,18 +0,0 @@
const initSentry = () => {
// initialize Sentry instance, making sure it hasn't been initialized already
if (!window.Sentry && `${process.env.SENTRY_DSN}` !== '') {
const Sentry = require('@sentry/browser');
Sentry.init({
dsn: `${process.env.SENTRY_DSN}`,
// Do not collect global onerror, only collect specifically from React error boundaries.
// TryCatch plugin also includes errors from setTimeouts (i.e. the VM)
integrations: integrations => integrations.filter(i =>
!(i.name === 'GlobalHandlers' || i.name === 'TryCatch'))
});
window.Sentry = Sentry; // Allow GUI access to Sentry via window
}
};
module.exports = initSentry;

View file

@ -3,9 +3,6 @@ const render = require('../../lib/render.jsx');
const Scratch3Registration = require('../../components/registration/scratch3-registration.jsx');
const ErrorBoundary = require('../../components/errorboundary/errorboundary.jsx');
const initSentry = require('../../lib/sentry.js');
initSentry();
require('./join.scss');
const Register = () => (
<ErrorBoundary componentName="Join">

View file

@ -14,9 +14,6 @@ const previewActions = require('../../redux/preview.js');
const GUI = require('scratch-gui');
const IntlGUI = injectIntl(GUI.default);
const initSentry = require('../../lib/sentry.js');
initSentry();
class EmbedView extends React.Component {
constructor (props) {
super(props);

View file

@ -39,9 +39,7 @@ const IntlGUI = injectIntl(GUI.default);
const localStorageAvailable = 'localStorage' in window && window.localStorage !== null;
const initSentry = require('../../lib/sentry.js');
const xhr = require('xhr');
initSentry();
class Preview extends React.Component {
constructor (props) {

View file

@ -1,76 +1,24 @@
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 CrashMessageComponent from '../../../src/components/crashmessage/crashmessage.jsx';
import ErrorBoundary from '../../../src/components/errorboundary/errorboundary.jsx';
const ChildComponent = () => <div>hello</div>;
describe('ErrorBoundary', () => {
let errorBoundaryWrapper;
const ChildClass = () => (
<div>
Children here
</div>
);
test('ErrorBoundary shows children before error and CrashMessageComponent after', () => {
const child = <ChildComponent />;
const wrapper = mountWithIntl(<ErrorBoundary>{child}</ErrorBoundary>);
const childWrapper = wrapper.childAt(0);
beforeEach(() => {
errorBoundaryWrapper = mountWithIntl(
<ErrorBoundary
componentName="TestEBName"
>
<ChildClass id="childClass" />
</ErrorBoundary>
);
});
expect(wrapper.containsMatchingElement(child)).toBeTruthy();
expect(wrapper.containsMatchingElement(<CrashMessageComponent />)).toBeFalsy();
test('calling ErrorBoundary\'s componentDidCatch() calls Sentry.withScope()', () => {
const errorBoundaryInstance = errorBoundaryWrapper.instance();
errorBoundaryInstance.componentDidCatch('error', {});
expect(Sentry.withScope).toHaveBeenCalled();
});
childWrapper.simulateError(new Error('fake error for testing purposes'));
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');
expect(wrapper.containsMatchingElement(child)).toBeFalsy();
expect(wrapper.containsMatchingElement(<CrashMessageComponent />)).toBeTruthy();
});
});

View file

@ -230,8 +230,7 @@ module.exports = {
'process.env.CLOUDDATA_HOST': '"' + (process.env.CLOUDDATA_HOST || 'clouddata.scratch.mit.edu') + '"',
'process.env.PROJECT_HOST': '"' + (process.env.PROJECT_HOST || 'https://projects.scratch.mit.edu') + '"',
'process.env.STATIC_HOST': '"' + (process.env.STATIC_HOST || 'https://uploads.scratch.mit.edu') + '"',
'process.env.SCRATCH_ENV': '"' + (process.env.SCRATCH_ENV || 'development') + '"',
'process.env.SENTRY_DSN': '"' + (process.env.SENTRY_DSN || '') + '"'
'process.env.SCRATCH_ENV': '"' + (process.env.SCRATCH_ENV || 'development') + '"'
})
])
.concat(process.env.ANALYZE_BUNDLE === 'true' ? [