From 9ac6c67a7ce11aaf7b10db1af3249e8bf491ffa7 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 3 Jun 2020 10:25:12 -0400 Subject: [PATCH 01/17] ref(react): Update name for Profiler The Profiler now has a mandatory name field, which describes what is being profiled --- packages/react/README.md | 2 ++ packages/react/src/profiler.tsx | 19 +++++++------------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/react/README.md b/packages/react/README.md index 8df1272d44af..c4430a6af6e0 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -7,6 +7,8 @@ # Official Sentry SDK for ReactJS +Note this library is in active development and not ready for production usage. + ## Links - [Official SDK Docs](https://docs.sentry.io/quickstart/) diff --git a/packages/react/src/profiler.tsx b/packages/react/src/profiler.tsx index 16373639c18a..c8435ba9a6d2 100644 --- a/packages/react/src/profiler.tsx +++ b/packages/react/src/profiler.tsx @@ -39,28 +39,25 @@ function afterNextFrame(callback: Function): void { timeout = window.setTimeout(done, 100); } -const getInitActivity = (componentDisplayName: string): number | null => { +const getInitActivity = (name: string): number | null => { const tracingIntegration = getCurrentHub().getIntegration(TRACING_GETTER); if (tracingIntegration !== null) { // tslint:disable-next-line:no-unsafe-any - const activity = (tracingIntegration as any).constructor.pushActivity(componentDisplayName, { - description: `<${componentDisplayName}>`, + return (tracingIntegration as any).constructor.pushActivity(name, { + description: `<${name}>`, op: 'react', }); - - // tslint:disable-next-line: no-unsafe-any - return activity; } logger.warn( - `Unable to profile component ${componentDisplayName} due to invalid Tracing Integration. Please make sure to setup the Tracing integration.`, + `Unable to profile component ${name} due to invalid Tracing Integration. Please make sure to setup the Tracing integration.`, ); return null; }; interface ProfilerProps { - componentDisplayName?: string; + name: string; } class Profiler extends React.Component { @@ -68,9 +65,7 @@ class Profiler extends React.Component { public constructor(props: ProfilerProps) { super(props); - const { componentDisplayName = UNKNOWN_COMPONENT } = this.props; - - this.activity = getInitActivity(componentDisplayName); + this.activity = getInitActivity(this.props.name); } public componentDidMount(): void { @@ -103,7 +98,7 @@ function withProfiler

(WrappedComponent: React.ComponentType

const componentDisplayName = WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT; const Wrapped: React.FC

= (props: P) => ( - + ); From 40c23d1b000ddd02cb0a4ef5b697c4e712438557 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 3 Jun 2020 13:00:43 -0400 Subject: [PATCH 02/17] feat(react): Add initial error boundary component --- packages/react/src/errorboundary.tsx | 36 ++++++++++++++++++++++ packages/react/test/errorboundary.test.tsx | 18 +++++++++++ 2 files changed, 54 insertions(+) create mode 100644 packages/react/src/errorboundary.tsx create mode 100644 packages/react/test/errorboundary.test.tsx diff --git a/packages/react/src/errorboundary.tsx b/packages/react/src/errorboundary.tsx new file mode 100644 index 000000000000..545d97b86bb3 --- /dev/null +++ b/packages/react/src/errorboundary.tsx @@ -0,0 +1,36 @@ +import * as React from 'react'; +import * as Sentry from '@sentry/browser'; + +interface ErrorBoundaryProps {} + +interface ErrorBoundaryState { + hasError: boolean; +} + +class ErrorBoundary extends React.Component { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { + hasError: false, + }; + } + + public static getDerivedStateFromError(_: Error): ErrorBoundaryState { + return { hasError: true }; + } + + public componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void { + Sentry.captureException(Error); + console.log(error); + console.log(errorInfo.componentStack); + } + + public render(): React.ReactNode { + if (this.state.hasError) { + return null; + } + return this.props.children; + } +} + +export { ErrorBoundary }; diff --git a/packages/react/test/errorboundary.test.tsx b/packages/react/test/errorboundary.test.tsx new file mode 100644 index 000000000000..f63932b23532 --- /dev/null +++ b/packages/react/test/errorboundary.test.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { create } from 'react-test-renderer'; + +import { ErrorBoundary } from '../src/errorboundary'; + +describe('ErrorBoundary', () => { + it('Does not fail', () => { + function Bomb() { + return

{new Error('💥 CABOOM 💥')}

; + } + + create( + + + , + ); + }); +}); From 4688e6398b22222d4e8d5794cf084aa33cc3a9f7 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 3 Jun 2020 15:25:28 -0400 Subject: [PATCH 03/17] chore(react): use @testing-library/react --- packages/react/package.json | 3 +- packages/react/test/errorboundary.test.tsx | 1 - packages/react/test/profiler.test.tsx | 6 +- yarn.lock | 195 +++++++++++++++++++-- 4 files changed, 184 insertions(+), 21 deletions(-) diff --git a/packages/react/package.json b/packages/react/package.json index 6154493f260b..a0e8501e6cf5 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -27,16 +27,15 @@ "react-dom": "^16.0.0" }, "devDependencies": { + "@testing-library/react": "^10.0.6", "@types/hoist-non-react-statics": "^3.3.1", "@types/react": "^16.9.35", - "@types/react-test-renderer": "^16.9.2", "jest": "^24.7.1", "npm-run-all": "^4.1.2", "prettier": "^1.17.0", "prettier-check": "^2.0.0", "react": "^16.0.0", "react-dom": "^16.0.0", - "react-test-renderer": "^16.13.1", "rimraf": "^2.6.3", "tslint": "^5.16.0", "tslint-react": "^5.0.0", diff --git a/packages/react/test/errorboundary.test.tsx b/packages/react/test/errorboundary.test.tsx index f63932b23532..8379c3f86246 100644 --- a/packages/react/test/errorboundary.test.tsx +++ b/packages/react/test/errorboundary.test.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import { create } from 'react-test-renderer'; import { ErrorBoundary } from '../src/errorboundary'; diff --git a/packages/react/test/profiler.test.tsx b/packages/react/test/profiler.test.tsx index fa208211010c..008803e38ac4 100644 --- a/packages/react/test/profiler.test.tsx +++ b/packages/react/test/profiler.test.tsx @@ -1,5 +1,5 @@ +import { render } from '@testing-library/react'; import * as React from 'react'; -import { create } from 'react-test-renderer'; import { UNKNOWN_COMPONENT, withProfiler } from '../src/profiler'; @@ -44,7 +44,7 @@ describe('withProfiler', () => { expect(mockPopActivity).toHaveBeenCalledTimes(0); - const profiler = create(); + const profiler = render(); profiler.unmount(); jest.runAllTimers(); @@ -58,7 +58,7 @@ describe('withProfiler', () => { const ProfiledComponent = withProfiler(() =>

Testing

); expect(mockPushActivity).toHaveBeenCalledTimes(0); - create(); + render(); expect(mockPushActivity).toHaveBeenCalledTimes(1); expect(mockPushActivity).toHaveBeenLastCalledWith(UNKNOWN_COMPONENT, { description: `<${UNKNOWN_COMPONENT}>`, diff --git a/yarn.lock b/yarn.lock index abf8e70b088b..59040bf54b46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -111,6 +111,21 @@ core-js "^2.5.7" regenerator-runtime "^0.12.0" +"@babel/runtime-corejs3@^7.7.4": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.10.2.tgz#3511797ddf9a3d6f3ce46b99cc835184817eaa4e" + integrity sha512-+a2M/u7r15o3dV1NEizr9bRi+KUVnrs/qYxF0Z06DAPx/4VCWaz1WA7EcbE+uqGgt39lp5akWGmHsTseIkHkHg== + dependencies: + core-js-pure "^3.0.0" + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.10.2", "@babel/runtime@^7.7.4": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839" + integrity sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" @@ -379,6 +394,16 @@ "@types/istanbul-lib-coverage" "^2.0.0" "@types/yargs" "^12.0.9" +"@jest/types@^25.5.0": + version "25.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" + integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + "@lerna/add@3.13.3": version "3.13.3" resolved "https://registry.yarnpkg.com/@lerna/add/-/add-3.13.3.tgz#f4c1674839780e458f0426d4f7b6d0a77b9a2ae9" @@ -1160,6 +1185,25 @@ highlight.js "^9.15.6" marked "^0.6.1" +"@testing-library/dom@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.9.0.tgz#3805cda47ab691645775c59c93c9044a2cad4c91" + integrity sha512-WYnJx9I94cYKib/Ber2BU3v1dUB+4n5wnJpvWJLTiwgERRTSElsivEtfX5S0LSljS122One6Bewhx2kgoZKXzA== + dependencies: + "@babel/runtime" "^7.10.2" + aria-query "^4.0.2" + dom-accessibility-api "^0.4.4" + pretty-format "^25.5.0" + +"@testing-library/react@^10.0.6": + version "10.0.6" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-10.0.6.tgz#e1e569135badb7367cc6ac9823e376eccb0280e0" + integrity sha512-7cZ2sHN6zTW1b/pNKzA0icZozshOOuiEQq/zCcf4LUCNGKAOnGCxZDQI7qjpO6lMITmi4Qs0VU1j9Cd4Z36e+w== + dependencies: + "@babel/runtime" "^7.10.2" + "@testing-library/dom" "^7.9.0" + "@types/testing-library__react" "^10.0.1" + "@tootallnate/once@1": version "1.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.0.0.tgz#9c13c2574c92d4503b005feca8f2e16cc1611506" @@ -1215,6 +1259,11 @@ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a" integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA== +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + "@types/connect@*": version "3.4.32" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28" @@ -1303,11 +1352,31 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" +"@types/istanbul-lib-coverage@*": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.2.tgz#79d7a78bad4219f4c03d6557a1c72d9ca6ba62d5" + integrity sha512-rsZg7eL+Xcxsxk2XlBt9KcG8nOp9iYdKCOikY9x2RFJCyOdNj4MKPQty0e8oZr29vVAzKXr1BmR+kZauti3o1w== + "@types/istanbul-lib-coverage@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz#1eb8c033e98cf4e1a4cedcaf8bcafe8cb7591e85" integrity sha512-eAtOAFZefEnfJiRFQBGw1eYqa5GTLCZ1y86N0XSI/D6EB+E8z6VPV/UL7Gi5UEclFqoQk+6NRqEDsfmDLXn8sg== +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" + integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== + dependencies: + "@types/istanbul-lib-coverage" "*" + "@types/istanbul-lib-report" "*" + "@types/jest-diff@*": version "20.0.1" resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-20.0.1.tgz#35cc15b9c4f30a18ef21852e255fdb02f6d59b89" @@ -1377,10 +1446,10 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== -"@types/react-test-renderer@^16.9.2": - version "16.9.2" - resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.9.2.tgz#e1c408831e8183e5ad748fdece02214a7c2ab6c5" - integrity sha512-4eJr1JFLIAlWhzDkBCkhrOIWOvOxcCAfQh+jiKg7l/nNZcCIL2MHl2dZhogIFKyHzedVWHaVP1Yydq/Ruu4agw== +"@types/react-dom@*": + version "16.9.8" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" + integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA== dependencies: "@types/react" "*" @@ -1435,15 +1504,43 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/testing-library__dom@*": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/testing-library__dom/-/testing-library__dom-7.0.2.tgz#2906f8a0dce58b0746c6ab606f786bd06fe6940e" + integrity sha512-8yu1gSwUEAwzg2OlPNbGq+ixhmSviGurBu1+ivxRKq1eRcwdjkmlwtPvr9VhuxTq2fNHBWN2po6Iem3Xt5A6rg== + dependencies: + pretty-format "^25.1.0" + +"@types/testing-library__react@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@types/testing-library__react/-/testing-library__react-10.0.1.tgz#92bb4a02394bf44428e35f1da2970ed77f803593" + integrity sha512-RbDwmActAckbujLZeVO/daSfdL1pnjVqas25UueOkAY5r7vriavWf0Zqg7ghXMHa8ycD/kLkv8QOj31LmSYwww== + dependencies: + "@types/react-dom" "*" + "@types/testing-library__dom" "*" + pretty-format "^25.1.0" + "@types/tough-cookie@*": version "2.3.4" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.4.tgz#821878b81bfab971b93a265a561d54ea61f9059f" +"@types/yargs-parser@*": + version "15.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" + integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== + "@types/yargs@^12.0.2", "@types/yargs@^12.0.9": version "12.0.9" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.9.tgz#693e76a52f61a2f1e7fb48c0eef167b95ea4ffd0" integrity sha512-sCZy4SxP9rN2w30Hlmg5dtdRwgYQfYRiLo9usw8X9cxlf+H4FqM1xX7+sNH7NNKVdbXMJWqva7iyy+fxh/V7fA== +"@types/yargs@^15.0.0": + version "15.0.5" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.5.tgz#947e9a6561483bdee9adffc983e91a6902af8b79" + integrity sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w== + dependencies: + "@types/yargs-parser" "*" + "@webassemblyjs/ast@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" @@ -1786,6 +1883,11 @@ ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -1797,6 +1899,14 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + ansi-wrap@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" @@ -1877,6 +1987,14 @@ argv@0.0.2: resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" integrity sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas= +aria-query@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.0.2.tgz#250687b4ccde1ab86d127da0432ae3552fc7b145" + integrity sha512-S1G1V790fTaigUSM/Gd0NngzEfiMy9uTUfMyHhKhVyy4cH5O/eTuR01ydhGL0z4Za1PXFTRGH3qL8VhUQuEO5w== + dependencies: + "@babel/runtime" "^7.7.4" + "@babel/runtime-corejs3" "^7.7.4" + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -3151,6 +3269,14 @@ chalk@^2.1.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -3349,11 +3475,23 @@ color-convert@^1.9.0: dependencies: color-name "1.1.3" +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + colors@^1.1.0: version "1.3.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.2.tgz#2df8ff573dfbf255af562f8ce7181d6b971a359b" @@ -3663,6 +3801,11 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +core-js-pure@^3.0.0: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" + integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA== + core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.0: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" @@ -4137,6 +4280,11 @@ dir-glob@2.0.0: arrify "^1.0.1" path-type "^3.0.0" +dom-accessibility-api@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.4.4.tgz#c2f9fb8b591bc19581e7ef3e6fe35baf1967c498" + integrity sha512-XBM62jdDc06IXSujkqw6BugEWiDkp6jphtzVJf1kgPQGvfzaU7/jRtRSF/mxc8DBCIm2LS3bN1dCa5Sfxx982A== + dom-serialize@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" @@ -5396,6 +5544,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + has-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" @@ -8889,6 +9042,16 @@ pretty-format@^24.7.0: ansi-styles "^3.2.0" react-is "^16.8.4" +pretty-format@^25.1.0, pretty-format@^25.5.0: + version "25.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" + integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== + dependencies: + "@jest/types" "^25.5.0" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -9140,7 +9303,7 @@ react-dom@^16.0.0: prop-types "^15.6.2" scheduler "^0.19.1" -react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6: +react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -9150,16 +9313,6 @@ react-is@^16.8.4: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.4.tgz#90f336a68c3a29a096a3d648ab80e87ec61482a2" integrity sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA== -react-test-renderer@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.1.tgz#de25ea358d9012606de51e012d9742e7f0deabc1" - integrity sha512-Sn2VRyOK2YJJldOqoh8Tn/lWQ+ZiKhyZTPtaO0Q6yNj+QDbmRkVFap6pZPy3YQk8DScRDfyqm/KxKYP9gCMRiQ== - dependencies: - object-assign "^4.1.1" - prop-types "^15.6.2" - react-is "^16.8.6" - scheduler "^0.19.1" - react@^16.0.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" @@ -9355,6 +9508,11 @@ regenerator-runtime@^0.12.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== +regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" @@ -10551,6 +10709,13 @@ supports-color@^6.0.0, supports-color@^6.1.0: dependencies: has-flag "^3.0.0" +supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + supports-hyperlinks@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz#71daedf36cc1060ac5100c351bb3da48c29c0ef7" From 3e9c8f9d4fdf81588d219f5d2b7373093c50a760 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Thu, 4 Jun 2020 14:13:57 -0400 Subject: [PATCH 04/17] feat(react): Setup basic error boundary props --- packages/react/src/errorboundary.tsx | 67 +++++++++++++++------- packages/react/src/profiler.tsx | 4 +- packages/react/test/errorboundary.test.tsx | 24 ++++++-- packages/react/tslint.json | 3 +- 4 files changed, 70 insertions(+), 28 deletions(-) diff --git a/packages/react/src/errorboundary.tsx b/packages/react/src/errorboundary.tsx index 545d97b86bb3..dee96bd6238b 100644 --- a/packages/react/src/errorboundary.tsx +++ b/packages/react/src/errorboundary.tsx @@ -1,34 +1,61 @@ -import * as React from 'react'; import * as Sentry from '@sentry/browser'; +import * as React from 'react'; -interface ErrorBoundaryProps {} +export type ErrorBoundaryProps = { + fallback?: React.ReactNode; + fallbackRender?(error: Error | null, componentStack: string | null, resetErrorBoundary: () => void): React.ReactNode; + onError?(error: Error, componentStack: string): void; + onReset?(error: Error | null, componentStack: string | null): void; +}; -interface ErrorBoundaryState { - hasError: boolean; -} +type ErrorBoundaryState = { + error: Error | null; + componentStack: string | null; +}; + +const INITIAL_STATE = { + componentStack: null, + error: null, +}; class ErrorBoundary extends React.Component { - constructor(props: ErrorBoundaryProps) { - super(props); - this.state = { - hasError: false, - }; - } + public state: ErrorBoundaryState = INITIAL_STATE; - public static getDerivedStateFromError(_: Error): ErrorBoundaryState { - return { hasError: true }; + public componentDidCatch(error: Error, { componentStack }: React.ErrorInfo): void { + Sentry.withScope(scope => { + scope.setExtra('componentStack', componentStack); + Sentry.captureException(error); + }); + const { onError } = this.props; + if (onError) { + onError(error, componentStack); + } + this.setState({ error, componentStack }); } - public componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void { - Sentry.captureException(Error); - console.log(error); - console.log(errorInfo.componentStack); - } + public resetErrorBoundary = () => { + const { onReset } = this.props; + if (onReset) { + onReset(this.state.error, this.state.componentStack); + } + this.setState(INITIAL_STATE); + }; public render(): React.ReactNode { - if (this.state.hasError) { - return null; + const { fallback, fallbackRender } = this.props; + const { error, componentStack } = this.state; + + if (error) { + if (typeof fallbackRender === 'function') { + return fallbackRender(error, componentStack, this.resetErrorBoundary); + } + if (React.isValidElement(fallback)) { + return fallback; + } + + throw new Error('No fallback component has been set'); } + return this.props.children; } } diff --git a/packages/react/src/profiler.tsx b/packages/react/src/profiler.tsx index c8435ba9a6d2..00f404ce5a65 100644 --- a/packages/react/src/profiler.tsx +++ b/packages/react/src/profiler.tsx @@ -56,9 +56,9 @@ const getInitActivity = (name: string): number | null => { return null; }; -interface ProfilerProps { +export type ProfilerProps = { name: string; -} +}; class Profiler extends React.Component { public activity: number | null; diff --git a/packages/react/test/errorboundary.test.tsx b/packages/react/test/errorboundary.test.tsx index 8379c3f86246..8b2646837ae0 100644 --- a/packages/react/test/errorboundary.test.tsx +++ b/packages/react/test/errorboundary.test.tsx @@ -1,14 +1,28 @@ +import { render } from '@testing-library/react'; import * as React from 'react'; -import { ErrorBoundary } from '../src/errorboundary'; +import { ErrorBoundary, ErrorBoundaryProps } from '../src/errorboundary'; describe('ErrorBoundary', () => { - it('Does not fail', () => { - function Bomb() { - return

{new Error('💥 CABOOM 💥')}

; + const DEFAULT_PROPS: ErrorBoundaryProps = { + fallback:

Error Component

, + fallbackRender: (error: Error, componentStack: string, resetErrorBoundary: () => void) => ( + +

{error.toString()}

+

{componentStack}

+