diff --git a/.eslintrc.yaml b/.eslintrc.yaml index fda49f7..bfcc560 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -10,38 +10,38 @@ extends: - plugin:react-hooks/recommended - plugin:jest/recommended - plugin:jest-dom/recommended -parser: "@babel/eslint-parser" +parser: '@babel/eslint-parser' plugins: - - "@babel" + - '@babel' - jest - react - react-hooks - testing-library overrides: - files: - - "**/__tests__/**/*.[jt]s?(x)" - - "**/?(*.)+(spec|test).[jt]s?(x)" + - '**/__tests__/**/*.[jt]s?(x)' + - '**/?(*.)+(spec|test).[jt]s?(x)' extends: - - "plugin:testing-library/react" + - 'plugin:testing-library/react' - files: - - "**/*.ts?(x)" - parser: "@typescript-eslint/parser" + - '**/*.ts?(x)' + parser: '@typescript-eslint/parser' parserOptions: - tsconfigRootDir: . - project: ['./tsconfig.json'] + tsconfigRootDir: . + project: ['./tsconfig.json'] extends: - eslint:recommended - plugin:@typescript-eslint/eslint-recommended - plugin:@typescript-eslint/recommended - plugin:@typescript-eslint/recommended-requiring-type-checking rules: - "@typescript-eslint/no-unused-vars": + '@typescript-eslint/no-unused-vars': - error - - varsIgnorePattern: "^_" - argsIgnorePattern: "^_" + - varsIgnorePattern: '^_' + argsIgnorePattern: '^_' # For compat with jest: https://typescript-eslint.io/rules/unbound-method/ - "@typescript-eslint/unbound-method": "off" - "jest/unbound-method": "error" + '@typescript-eslint/unbound-method': 'off' + 'jest/unbound-method': 'error' rules: quotes: - error diff --git a/README.md b/README.md index 3677847..bc8495c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ --- - React features to enhance using Rollbar.js in React Applications. This SDK provides a wrapper around the base [Rollbar.js] SDK in order to provide an @@ -18,12 +17,12 @@ SDK that matches the intention of how to build React Apps with a declarative API hooks and ErrorBoundaries, as well as simplify using Rollbar within a React SPA. ## Key benefits of using Rollbar React are: + - **Telemetry:** The telemetry timeline provides a list of “breadcrumbs” events that can help developers understand and fix problems in their client-side javascript. Learn more about telemetry. - **Automatic error grouping:** Rollbar aggregates Occurrences caused by the same error into Items that represent application issues. Learn more about reducing log noise. - **Advanced search:** Filter items by many different properties. Learn more about search. - **Customizable notifications:** Rollbar supports several messaging and incident management tools where your team can get notified about errors and important events by real-time alerts. Learn more about Rollbar notifications. - ### In Beta It is currently in a public Beta release right now as we push towards a 1.0 release that will have all of the features @@ -143,21 +142,17 @@ The simplest way to use the `Provider` is to provide a configuration as the `con instance of Rollbar for you and provide that to its child tree: ```javascript -import React from 'react'; -import { Provider } from '@rollbar/react'; +import React from 'react' +import { Provider } from '@rollbar/react' // same configuration you would create for the Rollbar.js SDK const rollbarConfig = { accessToken: 'POST_CLIENT_ITEM_ACCESS_TOKEN', environment: 'production', -}; +} export function App(props) { - return ( - - … - - ); + return } ``` @@ -167,24 +162,20 @@ Sometimes you may need to instantiate an instance of Rollbar before adding it to `instance` prop to pass it to the `Provider` like this: ```javascript -import React from 'react'; -import Rollbar from 'rollbar'; -import { Provider } from '@rollbar/react'; +import React from 'react' +import Rollbar from 'rollbar' +import { Provider } from '@rollbar/react' // same configuration you would create for the Rollbar.js SDK const rollbarConfig = { accessToken: 'POST_CLIENT_ITEM_ACCESS_TOKEN', environment: 'production', -}; +} -const rollbar = new Rollbar(rollbarConfig); +const rollbar = new Rollbar(rollbarConfig) export function App(props) { - return ( - - … - - ); + return } ``` @@ -199,18 +190,14 @@ To use the Rollbar React SDK with the [React Native SDK], pass the instance that `instance` prop, like this: ```javascript -import React from 'react'; -import { Client } from 'rollbar-react-native'; -import { Provider } from '@rollbar/react'; +import React from 'react' +import { Client } from 'rollbar-react-native' +import { Provider } from '@rollbar/react' -const rollbarClient = new Client('POST_CLIENT_ITEM_ACCESS_TOKEN'); +const rollbarClient = new Client('POST_CLIENT_ITEM_ACCESS_TOKEN') export function App(props) { - return ( - - … - - ); + return } ``` @@ -231,23 +218,21 @@ You can add an `ErrorBoundary` component to the top of your tree right after the and it will just work: ```javascript -import React from 'react'; -import { Provider, ErrorBoundary } from '@rollbar/react'; +import React from 'react' +import { Provider, ErrorBoundary } from '@rollbar/react' // same configuration you would create for the Rollbar.js SDK const rollbarConfig = { accessToken: 'POST_CLIENT_ITEM_ACCESS_TOKEN', environment: 'production', -}; +} export function App(props) { return ( - - … - + - ); + ) } ``` @@ -260,23 +245,31 @@ These `prop`s take either a value or a function that will be invoked with the `e API's `componentDidCatch` method (i.e. signature is `(error, info)`). ```javascript -import React from 'react'; -import { Provider, ErrorBoundary, LEVEL_WARN } from '@rollbar/react'; +import React from 'react' +import { Provider, ErrorBoundary, LEVEL_WARN } from '@rollbar/react' // same configuration you would create for the Rollbar.js SDK const rollbarConfig = { accessToken: 'POST_CLIENT_ITEM_ACCESS_TOKEN', environment: 'production', -}; +} export function App(props) { return ( - info.componentStack.includes('Experimental') ? { experiment: true } : {} }> + + info.componentStack.includes('Experimental') + ? { experiment: true } + : {} + } + > … - ); + ) } ``` @@ -288,21 +281,23 @@ UI caused during the render cycle of React. It can accept a value that is a React Component ```javascript -import React from 'react'; -import { Provider, ErrorBoundary, LEVEL_WARN } from '@rollbar/react'; +import React from 'react' +import { Provider, ErrorBoundary, LEVEL_WARN } from '@rollbar/react' // same configuration you would create for the Rollbar.js SDK const rollbarConfig = { accessToken: 'POST_CLIENT_ITEM_ACCESS_TOKEN', environment: 'production', -}; +} -const ErrorDisplay = ({ error, resetError }) => ( // <-- props passed to fallbackUI component +const ErrorDisplay = ( + { error, resetError } // <-- props passed to fallbackUI component +) => (

A following error has occured:

{error.toString()}

-); +) export function App(props) { return ( @@ -311,7 +306,7 @@ export function App(props) { … - ); + ) } ``` @@ -331,15 +326,11 @@ To use the `RollbarContext` you must provide the `context` prop, a `String` that [Rollbar.js] to the value while mounted. ```javascript -import React from 'react'; -import { RollbarContext } from '@rollbar/react'; +import React from 'react' +import { RollbarContext } from '@rollbar/react' function HomePage() { - return ( - - … - - ) + return } ``` @@ -352,10 +343,10 @@ to achieve the same result. Here is an example of using `RollbarContext` with [React Router] if you have a top level set of routes: ```javascript -import React from 'react'; -import { Router, Switch, Route } from 'react-router-dom'; -import { RollbarContext } from '@rollbar/react'; -import { About, ContactDetails, ContactsList } from './pages'; +import React from 'react' +import { Router, Switch, Route } from 'react-router-dom' +import { RollbarContext } from '@rollbar/react' +import { About, ContactDetails, ContactsList } from './pages' const Routes = () => ( @@ -379,22 +370,20 @@ const Routes = () => ( ) -export default Routes; +export default Routes ``` Here's another example of using `RollbarContext` within a component that manages its own route: ```javascript -import React from 'react'; -import { Route } from 'react-router-dom'; -import { RollbarContext } from '@rollbar/react'; +import React from 'react' +import { Route } from 'react-router-dom' +import { RollbarContext } from '@rollbar/react' export default function About(props) { return ( - - … - + ) } @@ -422,21 +411,21 @@ By default, if no options (see below) are provided, all history updates will upd `location.pathname` as the value. ```javascript -import Rollbar from 'rollbar'; -import { createBrowserHistory } from 'history'; -import { Provider } from '@rollbar/react'; +import Rollbar from 'rollbar' +import { createBrowserHistory } from 'history' +import { Provider } from '@rollbar/react' // same configuration you would create for the Rollbar.js SDK const rollbarConfig = { accessToken: 'POST_CLIENT_ITEM_ACCESS_TOKEN', environment: 'production', -}; +} -const rollbar = new Rollbar(rollbarConfig); +const rollbar = new Rollbar(rollbarConfig) -const history = createBrowserHistory(); +const history = createBrowserHistory() -history.listen(historyContext(rollbar)); +history.listen(historyContext(rollbar)) ``` #### Controlling `historyContext` behavior with options @@ -458,27 +447,28 @@ The signature is `filter(location, action): Boolean` where `location` is [histor Here's an example of using both: ```javascript -import Rollbar from 'rollbar'; -import { createBrowserHistory } from 'history'; -import { Provider } from '@rollbar/react'; +import Rollbar from 'rollbar' +import { createBrowserHistory } from 'history' +import { Provider } from '@rollbar/react' // same configuration you would create for the Rollbar.js SDK const rollbarConfig = { accessToken: 'POST_CLIENT_ITEM_ACCESS_TOKEN', environment: 'production', -}; +} -const rollbar = new Rollbar(rollbarConfig); +const rollbar = new Rollbar(rollbarConfig) -const ROUTE_PARAMS_RE = /\/\d+/g; +const ROUTE_PARAMS_RE = /\/\d+/g const historyListener = historyContext(rollbar, { // optional: default uses location.pathname - formatter: (location, action) => location.pathname.replace(ROUTE_PARAMS_RE, ''), + formatter: (location, action) => + location.pathname.replace(ROUTE_PARAMS_RE, ''), // optional: true return sets Rollbar context filter: (location, action) => !location.pathname.includes('admin'), -}); -const unlisten = history.listen(historyListener); +}) +const unlisten = history.listen(historyListener) ``` ## Hooks @@ -498,26 +488,22 @@ your [Functional Component], use the `useRollbar` hook which will return the ins Here is a basic example: ```javascript -import { useRollbar } from '@rollbar/react'; +import { useRollbar } from '@rollbar/react' function ContactDetails({ contactId }) { - const rollbar = useRollbar(); // <-- must have parent Provider - const [contact, setContact] = useState(); + const rollbar = useRollbar() // <-- must have parent Provider + const [contact, setContact] = useState() useEffect(async () => { try { - const { data } = await getContactFromApi(contactId); - setContact(data.contact); + const { data } = await getContactFromApi(contactId) + setContact(data.contact) } catch (error) { - rollbar.error('Error fetching contact', error, { contactId }); + rollbar.error('Error fetching contact', error, { contactId }) } - }, [contactId]); + }, [contactId]) - return ( -
- … -
- ); + return
} ``` @@ -530,40 +516,32 @@ Here's an example of using it in several components: ```javascript // src/pages/HomePage.js -import { useRollbarContext } from '@rollbar/react'; +import { useRollbarContext } from '@rollbar/react' function HomePage(props) { - useRollbarContext('home#index'); + useRollbarContext('home#index') - return ( -
- … -
- ); + return
} // src/pages/UsersPage.js -import { useRollbarContext } from '@rollbar/react'; -import UserTable from '../components/users/UserTable'; +import { useRollbarContext } from '@rollbar/react' +import UserTable from '../components/users/UserTable' function UsersPage(props) { - useRollbarContext('users#list'); + useRollbarContext('users#list') - return ( - - ); + return } // src/pages/UserDetailsPage.js -import { useRollbarContext } from '@rollbar/react'; -import UserDetails from '../components/users/UserDetails'; +import { useRollbarContext } from '@rollbar/react' +import UserDetails from '../components/users/UserDetails' function UserDetailsPage(props) { - useRollbarContext('users#details'); + useRollbarContext('users#details') - return ( - - ); + return } ``` @@ -583,27 +561,27 @@ and for any future events or messages logged to [Rollbar] will include that pers Here is a simple example of using it once the current user has been determined: ```javascript -import { useState } from 'react'; -import { useRollbarPerson } from '@rollbar/react'; -import LoggedInHome from './LoggedInHome'; -import LoggedOutHome from './LoggedOutHome'; +import { useState } from 'react' +import { useRollbarPerson } from '@rollbar/react' +import LoggedInHome from './LoggedInHome' +import LoggedOutHome from './LoggedOutHome' function Home() { - const [currentUser, setCurrentUser] = useState(); - useRollbarPerson(currentUser); + const [currentUser, setCurrentUser] = useState() + useRollbarPerson(currentUser) useEffect(() => { - (async () => { - const user = await Auth.getCurrentUser(); - setCurrentUser(user); + ;(async () => { + const user = await Auth.getCurrentUser() + setCurrentUser(user) })() - }); + }) if (currentUser != null) { - return ; + return } - return ; + return } ``` @@ -624,46 +602,41 @@ Here is an example of using `useRollbarCaptureEvent` in the render cycle of a [F event related to the data that will be rendered in the component ```javascript -import { useEffect, useState } from 'react'; -import { useRollbar, useRollbarCaptureEvent, LEVEL_INFO } from '@rollbar/react'; +import { useEffect, useState } from 'react' +import { useRollbar, useRollbarCaptureEvent, LEVEL_INFO } from '@rollbar/react' function BookDetails({ bookId }) { - const rollbar = useRollbar(); // <-- must have ancestor Provider, same with useRollbarCaptureEvent - const [book, setBook] = useState(); + const rollbar = useRollbar() // <-- must have ancestor Provider, same with useRollbarCaptureEvent + const [book, setBook] = useState() useEffect(async () => { try { - const { data } = await getBook(bookId); - setBook(data.book); + const { data } = await getBook(bookId) + setBook(data.book) } catch (error) { - rollbar.error('Error fetching book', error, { bookId }); // <-- use rollbar to log errors as normal + rollbar.error('Error fetching book', error, { bookId }) // <-- use rollbar to log errors as normal } - }, [bookId]); + }, [bookId]) - useRollbarCaptureEvent(book, LEVEL_INFO); // <-- only fires when book changes + useRollbarCaptureEvent(book, LEVEL_INFO) // <-- only fires when book changes - return ( -
- … -
- ) + return
} ``` - -[Rollbar]: https://rollbar.com -[Rollbar Docs]: https://docs.rollbar.com -[Rollbar.js]: https://github.com/rollbar/rollbar.js -[Rollbar.js Setup Instructions]: https://github.com/rollbar/rollbar.js/#setup-instructions -[React Native SDK]: https://github.com/rollbar/rollbar-react-native -[Telemetry]: https://docs.rollbar.com/docs/rollbarjs-telemetry -[`Provider`]: #provider-component -[`ErrorBoundary`]: #errorboundary-component -[`RollbarContext`]: #rollbarcontext-component -[Functional Components]: https://reactjs.org/docs/components-and-props.html#function-and-class-components -[React Context]: https://reactjs.org/docs/context.html -[Error Boundaries]: https://reactjs.org/docs/error-boundaries.html -[React Hooks API]: https://reactjs.org/docs/hooks-intro.html +[rollbar]: https://rollbar.com +[rollbar docs]: https://docs.rollbar.com +[rollbar.js]: https://github.com/rollbar/rollbar.js +[rollbar.js setup instructions]: https://github.com/rollbar/rollbar.js/#setup-instructions +[react native sdk]: https://github.com/rollbar/rollbar-react-native +[telemetry]: https://docs.rollbar.com/docs/rollbarjs-telemetry +[`provider`]: #provider-component +[`errorboundary`]: #errorboundary-component +[`rollbarcontext`]: #rollbarcontext-component +[functional components]: https://reactjs.org/docs/components-and-props.html#function-and-class-components +[react context]: https://reactjs.org/docs/context.html +[error boundaries]: https://reactjs.org/docs/error-boundaries.html +[react hooks api]: https://reactjs.org/docs/hooks-intro.html [history]: https://www.npmjs.com/package/history [history.location]: https://github.com/ReactTraining/history/blob/master/docs/api-reference.md#location [history.action]: https://github.com/ReactTraining/history/blob/master/docs/api-reference.md#action diff --git a/babel.config.js b/babel.config.js index 311b920..b654684 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,18 +1,15 @@ module.exports = { - presets: [ - '@babel/preset-env', - '@babel/preset-react' - ], + presets: ['@babel/preset-env', '@babel/preset-react'], plugins: [ '@babel/plugin-proposal-class-properties', - '@babel/plugin-syntax-class-properties' + '@babel/plugin-syntax-class-properties', ], env: { test: { plugins: [ '@babel/plugin-transform-modules-commonjs', - 'babel-plugin-istanbul' - ] - } - } + 'babel-plugin-istanbul', + ], + }, + }, } diff --git a/index.d.ts b/index.d.ts index 692e721..0016f77 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,90 +1,96 @@ -import { Component, Context as ReactContext, ErrorInfo, ReactNode, ComponentType } from 'react'; -import Rollbar, { Callback, Configuration } from 'rollbar'; +import { + Component, + Context as ReactContext, + ErrorInfo, + ReactNode, + ComponentType, +} from 'react' +import Rollbar, { Callback, Configuration } from 'rollbar' -export const LEVEL_DEBUG = 'debug'; -export const LEVEL_INFO = 'info'; -export const LEVEL_WARN = 'warn'; -export const LEVEL_ERROR = 'error'; -export const LEVEL_CRITICAL = 'critical'; +export const LEVEL_DEBUG = 'debug' +export const LEVEL_INFO = 'info' +export const LEVEL_WARN = 'warn' +export const LEVEL_ERROR = 'error' +export const LEVEL_CRITICAL = 'critical' export type LEVEL = | typeof LEVEL_DEBUG | typeof LEVEL_INFO | typeof LEVEL_WARN | typeof LEVEL_ERROR - | typeof LEVEL_CRITICAL; + | typeof LEVEL_CRITICAL -type Extra = Record; +type Extra = Record export interface ErrorBoundaryProps { - children: ReactNode; - fallbackUI?: ComponentType<{ error: Error | null, resetError: () => void }>; - errorMessage?: string | (() => string); - extra?: - | Extra - | ((error: Error, errorInfo: ErrorInfo) => Extra); - level?: LEVEL | (() => LEVEL); - callback?: Callback; + children: ReactNode + fallbackUI?: ComponentType<{ error: Error | null; resetError: () => void }> + errorMessage?: string | (() => string) + extra?: Extra | ((error: Error, errorInfo: ErrorInfo) => Extra) + level?: LEVEL | (() => LEVEL) + callback?: Callback } interface ErrorBoundaryState { - hasError: boolean; - error: Error | null; + hasError: boolean + error: Error | null } export class ErrorBoundary extends Component< ErrorBoundaryProps, ErrorBoundaryState > { - resetError: () => void; + resetError: () => void } export class RollbarContext extends Component<{ - children: ReactNode; - context?: string; + children: ReactNode + context?: string }> {} export interface ProviderProps { - Rollbar?: new (options: Configuration) => Rollbar; - children: ReactNode; - config?: Configuration | (() => Configuration); - instance?: Rollbar; + Rollbar?: new (options: Configuration) => Rollbar + children: ReactNode + config?: Configuration | (() => Configuration) + instance?: Rollbar } interface ProviderState { - rollbar: Rollbar; - options: Configuration; + rollbar: Rollbar + options: Configuration } export class Provider extends Component {} -declare const RollbarInstance: unique symbol; -declare const BaseOptions: unique symbol; -declare const RollbarCtor: unique symbol; +declare const RollbarInstance: unique symbol +declare const BaseOptions: unique symbol +declare const RollbarCtor: unique symbol interface ContextInterface { - [RollbarInstance]: Rollbar; - [BaseOptions]: Configuration; - [RollbarCtor]: new (options: Configuration) => Rollbar; + [RollbarInstance]: Rollbar + [BaseOptions]: Configuration + [RollbarCtor]: new (options: Configuration) => Rollbar } -export const Context: ReactContext; +export const Context: ReactContext -export function getRollbarFromContext(context: ReactContext): Rollbar; -export function useRollbar(): Rollbar; -export function useRollbarConfiguration(config: Rollbar.Configuration): void; -export function useRollbarContext(ctx?: string, isLayout?: boolean): void; -export function useRollbarPerson(person: object): void; -export function useRollbarCaptureEvent(metadata: object, level?: LEVEL): void; -export function isValidLevel(level: LEVEL): boolean; +export function getRollbarFromContext( + context: ReactContext +): Rollbar +export function useRollbar(): Rollbar +export function useRollbarConfiguration(config: Rollbar.Configuration): void +export function useRollbarContext(ctx?: string, isLayout?: boolean): void +export function useRollbarPerson(person: object): void +export function useRollbarCaptureEvent(metadata: object, level?: LEVEL): void +export function isValidLevel(level: LEVEL): boolean export function historyContext( rollbar: Rollbar, args: { - formatter: (location: string, action: string) => string; - filter: (location: string, action: string) => boolean; + formatter: (location: string, action: string) => string + filter: (location: string, action: string) => boolean } ): ( v4Location: { - action: string; - filter: (location: string, action: string) => boolean; + action: string + filter: (location: string, action: string) => boolean }, v4action: string -) => void; +) => void diff --git a/jest.config.js b/jest.config.js index 848a7da..7d04564 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,16 +1,12 @@ /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ module.exports = { - roots: [ - 'src/tests' - ], - setupFilesAfterEnv: [ - './src/tests/jest-setup.ts' - ], + roots: ['src/tests'], + setupFilesAfterEnv: ['./src/tests/jest-setup.ts'], preset: 'ts-jest/presets/js-with-babel', testEnvironment: 'jsdom', globals: { 'ts-jest': { - tsconfig: './tsconfig.json' - } - } -}; + tsconfig: './tsconfig.json', + }, + }, +} diff --git a/prettier.config.js b/prettier.config.js index abaf674..73ceb66 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -6,4 +6,4 @@ module.exports = { semi: false, singleQuote: true, arrowParens: 'always', -}; +} diff --git a/rollup.config.js b/rollup.config.js index 2c39bf8..45853e0 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,8 +1,8 @@ -import commonjs from '@rollup/plugin-commonjs'; -import resolve from '@rollup/plugin-node-resolve'; -import peerDepsExternal from 'rollup-plugin-peer-deps-external'; -import babel from '@rollup/plugin-babel'; -import pkg from './package.json'; +import commonjs from '@rollup/plugin-commonjs' +import resolve from '@rollup/plugin-node-resolve' +import peerDepsExternal from 'rollup-plugin-peer-deps-external' +import babel from '@rollup/plugin-babel' +import pkg from './package.json' const COMMON_PLUGINS = [ resolve(), @@ -24,12 +24,9 @@ export default [ react: 'React', 'prop-types': 'PropTypes', rollbar: 'Rollbar', - } + }, }, - plugins: [ - ...COMMON_PLUGINS, - commonjs(), - ], + plugins: [...COMMON_PLUGINS, commonjs()], }, { @@ -61,9 +58,6 @@ export default [ exports: 'named', }, ], - plugins: [ - ...COMMON_PLUGINS, - ], + plugins: [...COMMON_PLUGINS], }, -]; - +] diff --git a/src/constants.js b/src/constants.js index 710d443..8eddde6 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,8 +1,8 @@ -export const LEVEL_DEBUG = 'debug'; -export const LEVEL_INFO = 'info'; -export const LEVEL_WARN = 'warn'; -export const LEVEL_ERROR = 'error'; -export const LEVEL_CRITICAL = 'critical'; +export const LEVEL_DEBUG = 'debug' +export const LEVEL_INFO = 'info' +export const LEVEL_WARN = 'warn' +export const LEVEL_ERROR = 'error' +export const LEVEL_CRITICAL = 'critical' export default { [LEVEL_DEBUG]: 1, diff --git a/src/error-boundary.js b/src/error-boundary.js index 4527afe..475045b 100644 --- a/src/error-boundary.js +++ b/src/error-boundary.js @@ -1,14 +1,14 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import invariant from 'tiny-invariant'; -import { LEVEL_ERROR } from './constants'; -import { Context, getRollbarFromContext } from './provider'; -import * as utils from './utils'; +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import invariant from 'tiny-invariant' +import { LEVEL_ERROR } from './constants' +import { Context, getRollbarFromContext } from './provider' +import * as utils from './utils' -const INITIAL_ERROR_STATE = { hasError: false, error: null }; +const INITIAL_ERROR_STATE = { hasError: false, error: null } export class ErrorBoundary extends Component { - static contextType = Context; + static contextType = Context static propTypes = { fallbackUI: PropTypes.elementType, @@ -24,45 +24,48 @@ export class ErrorBoundary extends Component { } constructor(props) { - super(props); - invariant(utils.isValidLevel(props.level), `${props.level} is not a valid level setting for Rollbar`); - this.state = { ...INITIAL_ERROR_STATE }; + super(props) + invariant( + utils.isValidLevel(props.level), + `${props.level} is not a valid level setting for Rollbar` + ) + this.state = { ...INITIAL_ERROR_STATE } } static getDerivedStateFromError(error) { - return { hasError: true, error }; + return { hasError: true, error } } componentDidCatch(error, info) { - const { errorMessage, extra, level: targetLevel, callback } = this.props; - const custom = utils.value(extra, {}, error, info); - const data = { ...info, ...custom }; - const level = utils.value(targetLevel, LEVEL_ERROR, error, info); - const rollbar = getRollbarFromContext(this.context); + const { errorMessage, extra, level: targetLevel, callback } = this.props + const custom = utils.value(extra, {}, error, info) + const data = { ...info, ...custom } + const level = utils.value(targetLevel, LEVEL_ERROR, error, info) + const rollbar = getRollbarFromContext(this.context) if (!errorMessage) { - rollbar[level](error, data, callback); + rollbar[level](error, data, callback) } else { - let logMessage = utils.value(errorMessage, '', error, info); - rollbar[level](logMessage, error, data, callback); + let logMessage = utils.value(errorMessage, '', error, info) + rollbar[level](logMessage, error, data, callback) } } resetError = () => { - this.setState(INITIAL_ERROR_STATE); + this.setState(INITIAL_ERROR_STATE) } render() { - const { hasError, error } = this.state; - const { fallbackUI: FallbackUI, children } = this.props; + const { hasError, error } = this.state + const { fallbackUI: FallbackUI, children } = this.props if (!hasError) { - return children; + return children } if (!FallbackUI) { - return null; + return null } - return ; + return } } diff --git a/src/history-context.js b/src/history-context.js index 5d330da..2aaa7bf 100644 --- a/src/history-context.js +++ b/src/history-context.js @@ -1,24 +1,36 @@ -import Rollbar from 'rollbar'; -import invariant from 'tiny-invariant'; +import Rollbar from 'rollbar' +import invariant from 'tiny-invariant' export function historyContext(rollbar, { formatter, filter } = {}) { - invariant(rollbar instanceof Rollbar, 'historyContext must have an instance of Rollbar'); - invariant(formatter == null || typeof formatter === 'function', `formatter option must be a function, received ${typeof formatter} instead`); - invariant(filter == null || typeof filter === 'function', `filter option must be a function, received ${typeof filter} instead`); + invariant( + rollbar instanceof Rollbar, + 'historyContext must have an instance of Rollbar' + ) + invariant( + formatter == null || typeof formatter === 'function', + `formatter option must be a function, received ${typeof formatter} instead` + ) + invariant( + filter == null || typeof filter === 'function', + `filter option must be a function, received ${typeof filter} instead` + ) // v4 of history.listen callback signature is (location, action) // v5 of history.listen callback signature is ({ location, action }) // this implementation translates it to work for both return (v4location, v4action) => { - let { action, location } = v4location; + let { action, location } = v4location if (v4action) { - action = v4action; - location = v4location; + action = v4action + location = v4location } if (filter && !filter(location, action)) { - return; + return } - const context = formatter ? formatter(location, action) : location.pathname; - invariant(typeof context === 'string', 'formatter must return a string value to set the context'); - rollbar.configure({ payload: { context }}); + const context = formatter ? formatter(location, action) : location.pathname + invariant( + typeof context === 'string', + 'formatter must return a string value to set the context' + ) + rollbar.configure({ payload: { context } }) } } diff --git a/src/hooks/index.js b/src/hooks/index.js index 26a27de..72940ed 100644 --- a/src/hooks/index.js +++ b/src/hooks/index.js @@ -1,5 +1,5 @@ -export { useRollbar } from './use-rollbar'; -export { useRollbarConfiguration } from './use-rollbar-config'; -export { useRollbarContext } from './use-rollbar-context'; -export { useRollbarPerson } from './use-rollbar-person'; -export { useRollbarCaptureEvent } from './use-rollbar-capture-event'; +export { useRollbar } from './use-rollbar' +export { useRollbarConfiguration } from './use-rollbar-config' +export { useRollbarContext } from './use-rollbar-context' +export { useRollbarPerson } from './use-rollbar-person' +export { useRollbarCaptureEvent } from './use-rollbar-capture-event' diff --git a/src/hooks/use-rollbar-capture-event.js b/src/hooks/use-rollbar-capture-event.js index 0002d5a..fc6388f 100644 --- a/src/hooks/use-rollbar-capture-event.js +++ b/src/hooks/use-rollbar-capture-event.js @@ -1,13 +1,16 @@ -import { useEffect } from 'react'; -import invariant from 'tiny-invariant'; -import { LEVEL_INFO } from '../constants'; -import { useRollbar } from './use-rollbar'; -import { isValidLevel } from '../utils'; +import { useEffect } from 'react' +import invariant from 'tiny-invariant' +import { LEVEL_INFO } from '../constants' +import { useRollbar } from './use-rollbar' +import { isValidLevel } from '../utils' export function useRollbarCaptureEvent(metadata, level = LEVEL_INFO) { - invariant(isValidLevel(level), `${level} is not a valid level setting for Rollbar`); - const rollbar = useRollbar(); + invariant( + isValidLevel(level), + `${level} is not a valid level setting for Rollbar` + ) + const rollbar = useRollbar() useEffect(() => { - rollbar.captureEvent(metadata, level); - }, [metadata, level, rollbar]); + rollbar.captureEvent(metadata, level) + }, [metadata, level, rollbar]) } diff --git a/src/hooks/use-rollbar-config.js b/src/hooks/use-rollbar-config.js index 2b6d480..9c10213 100644 --- a/src/hooks/use-rollbar-config.js +++ b/src/hooks/use-rollbar-config.js @@ -1,6 +1,6 @@ -import { useRollbar } from './use-rollbar'; +import { useRollbar } from './use-rollbar' export function useRollbarConfiguration(config) { - const rollbar = useRollbar(); - rollbar.configure(config); + const rollbar = useRollbar() + rollbar.configure(config) } diff --git a/src/hooks/use-rollbar-context.js b/src/hooks/use-rollbar-context.js index 0a8bf90..9eeeb5b 100644 --- a/src/hooks/use-rollbar-context.js +++ b/src/hooks/use-rollbar-context.js @@ -1,6 +1,6 @@ -import invariant from 'tiny-invariant'; -import { useEffect, useLayoutEffect } from 'react'; -import { useRollbar } from './use-rollbar'; +import invariant from 'tiny-invariant' +import { useEffect, useLayoutEffect } from 'react' +import { useRollbar } from './use-rollbar' // Simple version does its job // export function useRollbarContext(context) { @@ -9,13 +9,13 @@ import { useRollbar } from './use-rollbar'; // Complex version will set the context when part of the tree and reset back to original context when removed export function useRollbarContext(ctx = '', isLayout = false) { - invariant(typeof ctx === 'string', '`ctx` must be a string'); - const rollbar = useRollbar(); - (isLayout ? useLayoutEffect : useEffect)(() => { - const origCtx = rollbar.options.payload.context; - rollbar.configure({ payload: { context: ctx }}); + invariant(typeof ctx === 'string', '`ctx` must be a string') + const rollbar = useRollbar() + ;(isLayout ? useLayoutEffect : useEffect)(() => { + const origCtx = rollbar.options.payload.context + rollbar.configure({ payload: { context: ctx } }) return () => { - rollbar.configure({ payload: { context: origCtx }}); - }; - }, [ctx]); + rollbar.configure({ payload: { context: origCtx } }) + } + }, [ctx]) } diff --git a/src/hooks/use-rollbar-logs.js b/src/hooks/use-rollbar-logs.js index bc364f0..ee63e5e 100644 --- a/src/hooks/use-rollbar-logs.js +++ b/src/hooks/use-rollbar-logs.js @@ -2,42 +2,51 @@ // NOT EXPORTED AS PART OF PUBLIC API YET // NO TEST COVERAGE -import { useEffect, useLayoutEffect } from 'react'; -import invariant from 'tiny-invariant'; -import { LEVEL_DEBUG, LEVEL_INFO, LEVEL_WARN, LEVEL_ERROR, LEVEL_CRITICAL } from '../constants'; -import { useRollbar } from './use-rollbar'; -import { isValidLevel } from '../utils'; - -const LOG = 'log'; +import { useEffect, useLayoutEffect } from 'react' +import invariant from 'tiny-invariant' +import { + LEVEL_DEBUG, + LEVEL_INFO, + LEVEL_WARN, + LEVEL_ERROR, + LEVEL_CRITICAL, +} from '../constants' +import { useRollbar } from './use-rollbar' +import { isValidLevel } from '../utils' + +const LOG = 'log' function useRollbarNotify(type, isLayout, ...args) { - invariant(type === LOG || isValidLevel(type), `cannot notify rollbar using method '${type}'`); - const rollbar = useRollbar(); - (isLayout ? useLayoutEffect : useEffect)(() => { - rollbar[type](...args); + invariant( + type === LOG || isValidLevel(type), + `cannot notify rollbar using method '${type}'` + ) + const rollbar = useRollbar() + ;(isLayout ? useLayoutEffect : useEffect)(() => { + rollbar[type](...args) }, args) } export function useRollbarLog(isLayout, ...args) { - useRollbarNotify(LOG, isLayout, ...args); + useRollbarNotify(LOG, isLayout, ...args) } export function useRollbarDebug(isLayout, ...args) { - useRollbarNotify(LEVEL_DEBUG, isLayout, ...args); + useRollbarNotify(LEVEL_DEBUG, isLayout, ...args) } export function useRollbarInfo(isLayout, ...args) { - useRollbarNotify(LEVEL_INFO, isLayout, ...args); + useRollbarNotify(LEVEL_INFO, isLayout, ...args) } export function useRollbarWarn(isLayout, ...args) { - useRollbarNotify(LEVEL_WARN, isLayout, ...args); + useRollbarNotify(LEVEL_WARN, isLayout, ...args) } export function useRollbarError(isLayout, ...args) { - useRollbarNotify(LEVEL_ERROR, isLayout, ...args); + useRollbarNotify(LEVEL_ERROR, isLayout, ...args) } export function useRollbarCritical(isLayout, ...args) { - useRollbarNotify(LEVEL_CRITICAL, isLayout, ...args); + useRollbarNotify(LEVEL_CRITICAL, isLayout, ...args) } diff --git a/src/hooks/use-rollbar-person.js b/src/hooks/use-rollbar-person.js index f6bd24b..43ae2de 100644 --- a/src/hooks/use-rollbar-person.js +++ b/src/hooks/use-rollbar-person.js @@ -1,5 +1,5 @@ -import { useRollbarConfiguration } from './use-rollbar-config'; +import { useRollbarConfiguration } from './use-rollbar-config' export function useRollbarPerson(person) { - useRollbarConfiguration({ payload: { person }}); + useRollbarConfiguration({ payload: { person } }) } diff --git a/src/hooks/use-rollbar.js b/src/hooks/use-rollbar.js index 666b52f..1055d61 100644 --- a/src/hooks/use-rollbar.js +++ b/src/hooks/use-rollbar.js @@ -1,7 +1,7 @@ -import { useContext } from 'react'; -import { Context, getRollbarFromContext } from '../provider'; +import { useContext } from 'react' +import { Context, getRollbarFromContext } from '../provider' export function useRollbar() { - const context = useContext(Context); - return getRollbarFromContext(context); + const context = useContext(Context) + return getRollbarFromContext(context) } diff --git a/src/hooks/use-scoped-rollbar-config.js b/src/hooks/use-scoped-rollbar-config.js index 80e7f0d..147bea0 100644 --- a/src/hooks/use-scoped-rollbar-config.js +++ b/src/hooks/use-scoped-rollbar-config.js @@ -2,14 +2,18 @@ // NOT EXPORTED AS PART OF PUBLIC API YET // NO TEST COVERAGE -import { useContext } from 'react'; -import { Context, getRollbarFromContext, getRollbarConstructorFromContext } from '../provider'; +import { useContext } from 'react' +import { + Context, + getRollbarFromContext, + getRollbarConstructorFromContext, +} from '../provider' export function useScopedConfiguration(config) { - const ctx = useContext(Context); - const base = getRollbarFromContext(ctx); - const ctor = getRollbarConstructorFromContext(ctx); - const rollbar = new ctor(base.options); - rollbar.configure(config); - return rollbar; + const ctx = useContext(Context) + const base = getRollbarFromContext(ctx) + const ctor = getRollbarConstructorFromContext(ctx) + const rollbar = new ctor(base.options) + rollbar.configure(config) + return rollbar } diff --git a/src/hooks/utils.js b/src/hooks/utils.js index 274a7c9..f6079c0 100644 --- a/src/hooks/utils.js +++ b/src/hooks/utils.js @@ -1,8 +1,8 @@ -import { useRef } from 'react'; +import { useRef } from 'react' // EXPERIMENTAL (NOT IN USE): wrap the instance of rollbar to prevent modification export function useWrappedRollbar(rollbar) { - const rb = useRef(rollbar); + const rb = useRef(rollbar) return { log: (...args) => rb.current.log(...args), debug: (...args) => rb.current.debug(...args), diff --git a/src/index.js b/src/index.js index e9c9d00..f254e6e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,13 @@ -export { LEVEL_DEBUG, LEVEL_INFO, LEVEL_WARN, LEVEL_ERROR, LEVEL_CRITICAL } from './constants'; -export { historyContext } from './history-context'; -export { Provider, Context, getRollbarFromContext } from './provider'; -export { ErrorBoundary } from './error-boundary'; -export { RollbarContext } from './rollbar-context'; -export { isValidLevel } from './utils'; -export * from './hooks'; +export { + LEVEL_DEBUG, + LEVEL_INFO, + LEVEL_WARN, + LEVEL_ERROR, + LEVEL_CRITICAL, +} from './constants' +export { historyContext } from './history-context' +export { Provider, Context, getRollbarFromContext } from './provider' +export { ErrorBoundary } from './error-boundary' +export { RollbarContext } from './rollbar-context' +export { isValidLevel } from './utils' +export * from './hooks' diff --git a/src/provider.js b/src/provider.js index 4b99f2c..5bc00f4 100644 --- a/src/provider.js +++ b/src/provider.js @@ -1,24 +1,24 @@ -import React, { Component, createContext } from 'react'; -import PropTypes from 'prop-types'; -import Rollbar from 'rollbar'; -import invariant from 'tiny-invariant'; -import { isRollbarInstance } from './utils'; +import React, { Component, createContext } from 'react' +import PropTypes from 'prop-types' +import Rollbar from 'rollbar' +import invariant from 'tiny-invariant' +import { isRollbarInstance } from './utils' -export const Context = createContext(); -Context.displayName = 'Rollbar'; +export const Context = createContext() +Context.displayName = 'Rollbar' -export const RollbarInstance = Symbol('RollbarInstance'); -export const BaseOptions = Symbol('BaseOptions'); -export const RollbarCtor = Symbol('RollbarCtor'); +export const RollbarInstance = Symbol('RollbarInstance') +export const BaseOptions = Symbol('BaseOptions') +export const RollbarCtor = Symbol('RollbarCtor') export function getRollbarFromContext(context) { - const { [RollbarInstance]: rollbar } = context; - return rollbar; + const { [RollbarInstance]: rollbar } = context + return rollbar } export function getRollbarConstructorFromContext(context) { - const { [RollbarCtor]: ctor } = context; - return ctor; + const { [RollbarCtor]: ctor } = context + return ctor } export class Provider extends Component { @@ -26,51 +26,62 @@ export class Provider extends Component { Rollbar: PropTypes.func, config: (props, propName, componentName) => { if (!props.config && !props.instance) { - return new Error(`One of the required props 'config' or 'instance' must be set for ${componentName}.`) + return new Error( + `One of the required props 'config' or 'instance' must be set for ${componentName}.` + ) } if (props.config) { - const configType = typeof props.config; - if (configType === 'function' || configType === 'object' && !Array.isArray(configType)) { - return; + const configType = typeof props.config + if ( + configType === 'function' || + (configType === 'object' && !Array.isArray(configType)) + ) { + return } - return new Error(`${propName} must be either an Object or a Function`); + return new Error(`${propName} must be either an Object or a Function`) } }, instance: (props, propName, componentName) => { if (!props.config && !props.instance) { - return new Error(`One of the required props 'config' or 'instance' must be set for ${componentName}.`) + return new Error( + `One of the required props 'config' or 'instance' must be set for ${componentName}.` + ) } if (props.instance && !isRollbarInstance(props.instance)) { - return new Error(`${propName} must be a configured instance of Rollbar`); + return new Error(`${propName} must be a configured instance of Rollbar`) } }, - children: PropTypes.node + children: PropTypes.node, } constructor(props) { - super(props); - const { config, Rollbar: ctor = Rollbar, instance } = this.props; + super(props) + const { config, Rollbar: ctor = Rollbar, instance } = this.props invariant( !instance || isRollbarInstance(instance), '`instance` must be a configured instance of Rollbar' - ); - const options = typeof config === 'function' ? config() : config; - const rollbar = instance || new ctor(options); + ) + const options = typeof config === 'function' ? config() : config + const rollbar = instance || new ctor(options) // TODO: use isUncaught to filter if this is 2nd Provider added // unless customer wants that - this.state = { rollbar, options }; + this.state = { rollbar, options } } - - // componentDidUpdate() render() { - const { children, Rollbar: ctor = Rollbar } = this.props; - const { rollbar, options } = this.state; + const { children, Rollbar: ctor = Rollbar } = this.props + const { rollbar, options } = this.state return ( - + {children} ) diff --git a/src/rollbar-configuration.js b/src/rollbar-configuration.js index 07bfa70..736dbb7 100644 --- a/src/rollbar-configuration.js +++ b/src/rollbar-configuration.js @@ -3,9 +3,9 @@ // PURPOSE provide a wrapping around Rollbar configuration for a subtree -import { Component } from 'react'; -import PropTypes from 'prop-types'; -import { Context, getRollbarFromContext } from './provider'; +import { Component } from 'react' +import PropTypes from 'prop-types' +import { Context, getRollbarFromContext } from './provider' export class RollbarConfiguration extends Component { static propTypes = { @@ -13,29 +13,29 @@ export class RollbarConfiguration extends Component { children: PropTypes.node, } - static contextType = Context; + static contextType = Context constructor(props) { - super(props); - this.state = { parentConfig: null }; + super(props) + this.state = { parentConfig: null } } componentDidMount() { - const rollbar = getRollbarFromContext(this.context); - const { options } = this.props; + const rollbar = getRollbarFromContext(this.context) + const { options } = this.props // TODO: need to clone this somehow to prevent downstream changes from manipulating it - const parentConfig = (o => o)(rollbar.options); - this.setState({ parentConfig }); - rollbar.configure(options); + const parentConfig = ((o) => o)(rollbar.options) + this.setState({ parentConfig }) + rollbar.configure(options) } componentWillUnmount() { - const rollbar = getRollbarFromContext(this.context); - const { parentConfig } = this.state; - rollbar.configure(parentConfig); + const rollbar = getRollbarFromContext(this.context) + const { parentConfig } = this.state + rollbar.configure(parentConfig) } render() { - return this.props.children; + return this.props.children } } diff --git a/src/rollbar-context.js b/src/rollbar-context.js index 5ddf66c..536be1b 100644 --- a/src/rollbar-context.js +++ b/src/rollbar-context.js @@ -1,6 +1,6 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; -import { Context, getRollbarFromContext } from './provider'; +import { Component } from 'react' +import PropTypes from 'prop-types' +import { Context, getRollbarFromContext } from './provider' export class RollbarContext extends Component { static propTypes = { @@ -13,50 +13,50 @@ export class RollbarContext extends Component { onRender: false, } - static contextType = Context; + static contextType = Context - firstRender = true; + firstRender = true constructor(props) { - super(props); - this.state = { previousContext: null }; + super(props) + this.state = { previousContext: null } } changeContext = (storePrevious = true) => { - const rollbar = getRollbarFromContext(this.context); - const { context } = this.props; + const rollbar = getRollbarFromContext(this.context) + const { context } = this.props if (storePrevious) { - this.setState({ previousContext: rollbar.options.payload.context }); + this.setState({ previousContext: rollbar.options.payload.context }) } - rollbar.configure({ payload: { context }}); + rollbar.configure({ payload: { context } }) } componentDidMount() { - const { onRender } = this.props; + const { onRender } = this.props if (!onRender) { - this.changeContext(true); + this.changeContext(true) } } componentDidUpdate() { - const { onRender } = this.props; + const { onRender } = this.props if (!onRender) { - this.changeContext(false); + this.changeContext(false) } } componentWillUnmount() { - const rollbar = getRollbarFromContext(this.context); - const { previousContext } = this.state; - rollbar.configure({ payload: { context: previousContext }}); + const rollbar = getRollbarFromContext(this.context) + const { previousContext } = this.state + rollbar.configure({ payload: { context: previousContext } }) } render() { - const { onRender } = this.props; + const { onRender } = this.props if (onRender && this.firstRender) { - this.changeContext(true); + this.changeContext(true) } - this.firstRender = false; - return this.props.children; + this.firstRender = false + return this.props.children } } diff --git a/src/tests/components/error-boundary.test.tsx b/src/tests/components/error-boundary.test.tsx index 179effc..9738930 100644 --- a/src/tests/components/error-boundary.test.tsx +++ b/src/tests/components/error-boundary.test.tsx @@ -1,44 +1,39 @@ -import React from 'react'; -import { screen } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import Rollbar = require('rollbar'); -import { - ErrorBoundary, ErrorBoundaryProps, useRollbar -} from '../rollbar-react'; -import { renderWithProviderProps } from '../utils/provider-util'; +import React from 'react' +import { screen } from '@testing-library/react' +import '@testing-library/jest-dom' +import Rollbar = require('rollbar') +import { ErrorBoundary, ErrorBoundaryProps, useRollbar } from '../rollbar-react' +import { renderWithProviderProps } from '../utils/provider-util' describe('ErrorBoundary', () => { - const accessToken = 'POST_CLIENT_ITEM_TOKEN'; + const accessToken = 'POST_CLIENT_ITEM_TOKEN' const config: Rollbar.Configuration = { accessToken: accessToken, - captureUncaught: true - }; + captureUncaught: true, + } - let rollbar: Rollbar; - const error: Error = new Error('Test'); + let rollbar: Rollbar + const error: Error = new Error('Test') const ThrowError = () => { - throw error; - }; - const fallbackMessage = 'Test fallback'; - const errorMessage = 'Test error'; - const extra = { foo: 'bar' }; - const level = 'warn'; + throw error + } + const fallbackMessage = 'Test fallback' + const errorMessage = 'Test error' + const extra = { foo: 'bar' } + const level = 'warn' const callback: Rollbar.Callback = (_err, _resp) => 'foo' const Fallback = () =>
{fallbackMessage}
const TestComponent = (props: Omit) => { - rollbar = useRollbar(); - rollbar.warn = jest - .fn() - .mockReturnValue({}) - .mockName('Rollbar.warn'); + rollbar = useRollbar() + rollbar.warn = jest.fn().mockReturnValue({}).mockName('Rollbar.warn') return ( - ); - }; + ) + } it('should display the fallback UI and send rollbar on error', () => { renderWithProviderProps( @@ -50,24 +45,27 @@ describe('ErrorBoundary', () => { callback={callback} />, {}, - {config: config} - ); + { config: config } + ) - expect(screen.getByText(fallbackMessage)).toBeInTheDocument(); + expect(screen.getByText(fallbackMessage)).toBeInTheDocument() expect(rollbar.warn).toHaveBeenLastCalledWith( - errorMessage, error, expect.objectContaining(extra), callback - ); - }); + errorMessage, + error, + expect.objectContaining(extra), + callback + ) + }) describe('with extra prop as a fn', () => { it('should send extra value to rollbar on error', () => { const extraFn: ErrorBoundaryProps['extra'] = (error, errorInfo) => { expect(error).toBeInstanceOf(Error) expect(errorInfo).toHaveProperty('componentStack') - return extra; - }; - + return extra + } + renderWithProviderProps( { callback={callback} />, {}, - {config: config} - ); - + { config: config } + ) + expect(rollbar.warn).toHaveBeenLastCalledWith( - errorMessage, error, expect.objectContaining(extra), callback - ); - }); - }); -}); + errorMessage, + error, + expect.objectContaining(extra), + callback + ) + }) + }) +}) diff --git a/src/tests/components/provider.test.tsx b/src/tests/components/provider.test.tsx index aaff2ce..6be57d9 100644 --- a/src/tests/components/provider.test.tsx +++ b/src/tests/components/provider.test.tsx @@ -1,39 +1,42 @@ -import React, { Context as ReactContext, ReactNode } from 'react'; -import { waitFor, screen } from '@testing-library/react'; -import Rollbar = require('rollbar'); +import React, { Context as ReactContext, ReactNode } from 'react' +import { waitFor, screen } from '@testing-library/react' +import Rollbar = require('rollbar') import { - Context, ContextInterface, getRollbarFromContext, useRollbar -} from '../rollbar-react'; -import { renderWithProviderProps } from '../utils/provider-util'; + Context, + ContextInterface, + getRollbarFromContext, + useRollbar, +} from '../rollbar-react' +import { renderWithProviderProps } from '../utils/provider-util' describe('Provider', () => { - const accessToken = 'POST_CLIENT_ITEM_TOKEN'; + const accessToken = 'POST_CLIENT_ITEM_TOKEN' const config: Rollbar.Configuration = { accessToken: accessToken, - captureUncaught: true - }; + captureUncaught: true, + } - const screenText = 'Hello'; + const screenText = 'Hello' const TestComponent = () => { - const rollbar = useRollbar(); + const rollbar = useRollbar() return (
{screenText}
{rollbar?.options?.accessToken}
- ); + ) } class TestClassConponent extends React.Component { - static contextType = Context; - declare context: ReactContext; - rollbar: Rollbar | undefined; + static contextType = Context + declare context: ReactContext + rollbar: Rollbar | undefined render(): ReactNode { - this.rollbar = getRollbarFromContext(this.context); + this.rollbar = getRollbarFromContext(this.context) return (
@@ -44,53 +47,49 @@ describe('Provider', () => { } } - const instance: Rollbar = new Rollbar(config); + const instance: Rollbar = new Rollbar(config) it('should provide a Rollbar instance, given a config', async () => { - renderWithProviderProps( - , {}, { config: config } - ); + renderWithProviderProps(, {}, { config: config }) await waitFor(() => { - screen.getByText(screenText); - }); + screen.getByText(screenText) + }) - expect(screen.getByText(accessToken)).toBeInTheDocument(); - }); + expect(screen.getByText(accessToken)).toBeInTheDocument() + }) it('should provide a Rollbar instance, given a constructor', async () => { renderWithProviderProps( - , {}, { Rollbar: Rollbar, config: config } - ); + , + {}, + { Rollbar: Rollbar, config: config } + ) await waitFor(() => { - screen.getByText(screenText); - }); + screen.getByText(screenText) + }) - expect(screen.getByText(accessToken)).toBeInTheDocument(); - }); + expect(screen.getByText(accessToken)).toBeInTheDocument() + }) it('should provide a Rollbar instance, given the instance', async () => { - renderWithProviderProps( - , {}, { instance: instance } - ); + renderWithProviderProps(, {}, { instance: instance }) await waitFor(() => { - screen.getByText(screenText); - }); + screen.getByText(screenText) + }) - expect(screen.getByText(accessToken)).toBeInTheDocument(); - }); + expect(screen.getByText(accessToken)).toBeInTheDocument() + }) it('should provide a Rollbar instance to class components', async () => { - renderWithProviderProps( - , {}, { config: config } - ); + renderWithProviderProps(, {}, { config: config }) await waitFor(() => { - screen.getByText(screenText); - }); + screen.getByText(screenText) + }) - expect(screen.getByText(accessToken)).toBeInTheDocument(); - }); -}); + expect(screen.getByText(accessToken)).toBeInTheDocument() + }) +}) diff --git a/src/tests/jest-setup.ts b/src/tests/jest-setup.ts index 7de749a..5e85b99 100644 --- a/src/tests/jest-setup.ts +++ b/src/tests/jest-setup.ts @@ -1,9 +1,9 @@ -import '@testing-library/jest-dom'; -import 'regenerator-runtime'; +import '@testing-library/jest-dom' +import 'regenerator-runtime' // Let propType errors cause test failure. -const originalConsoleError = console.error; +const originalConsoleError = console.error console.error = (message: string) => { - if (/(Failed prop type)/.test(message)) throw new Error(message); - originalConsoleError(message); -}; + if (/(Failed prop type)/.test(message)) throw new Error(message) + originalConsoleError(message) +} diff --git a/src/tests/utils/provider-util.tsx b/src/tests/utils/provider-util.tsx index ff58442..ebf2ffe 100644 --- a/src/tests/utils/provider-util.tsx +++ b/src/tests/utils/provider-util.tsx @@ -1,17 +1,14 @@ -import React, { ReactElement } from 'react'; -import { render, RenderOptions } from '@testing-library/react'; -import { Provider } from '../rollbar-react'; +import React, { ReactElement } from 'react' +import { render, RenderOptions } from '@testing-library/react' +import { Provider } from '../rollbar-react' export const renderWithProviderProps = ( ui: ReactElement, options: RenderOptions, providerProps: any ) => { - return render( - ui, - { - wrapper: props => , - ...options - } - ); + return render(ui, { + wrapper: (props) => , + ...options, + }) } diff --git a/src/utils.js b/src/utils.js index 354359a..f340517 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,23 +1,26 @@ -import * as constants from './constants'; +import * as constants from './constants' -const VALID_LEVELS = constants.default; +const VALID_LEVELS = constants.default export function value(val, defaultTo, ...args) { if (typeof val === 'function') { - return val(...args); + return val(...args) } - return val; + return val } export function wrapValue(val, defaultAs) { - return (defaultTo, ...args) => value(val, defaultAs === undefined ? defaultTo : defaultAs, ...args); + return (defaultTo, ...args) => + value(val, defaultAs === undefined ? defaultTo : defaultAs, ...args) } export function isValidLevel(level) { - return VALID_LEVELS[level] >= VALID_LEVELS[constants.LEVEL_DEBUG] - && VALID_LEVELS[level] <= VALID_LEVELS[constants.LEVEL_CRITICAL]; + return ( + VALID_LEVELS[level] >= VALID_LEVELS[constants.LEVEL_DEBUG] && + VALID_LEVELS[level] <= VALID_LEVELS[constants.LEVEL_CRITICAL] + ) } export function isRollbarInstance(instance) { - return !!instance?.options?.accessToken; + return !!instance?.options?.accessToken }