Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write test case for ErrorBoundary in React using Jest / Enzyme

Tags:

I have been trying (without success) to write a test case for ErrorBoundary component that is handling errors via componentDidCatch lifecycle method. Despite the error produced by child component inside the <ErrorBoundry> component, <ErrorBoundry> does not render info about error in code but the content of faulty component if it would work correct. Component works as expected in production/development but not when it is executed by Jest / Enzyme for testing.

Error from testing:

 PASS  src/ErrorBoundary.test.js   ● Console      console.error node_modules/fbjs/lib/warning.js:33       Warning: `value` prop on `input` should not be null. Consider using an empty string to clear the component or `undefined` for uncontrolled components.           in input (at ErrorBoundary.test.js:11)           in div (at ErrorBoundary.test.js:10)           in ComponentWithError (at ErrorBoundary.test.js:26)           in ErrorBoundry (created by WrapperComponent)           in WrapperComponent     console.log src/ErrorBoundary.test.js:29       <ErrorBoundry>         <ComponentWithError>           <div>             <input type="text" value={{...}} />           </div>         </ComponentWithError>       </ErrorBoundry> 

ErrorBoundry.js:

import React, { Component } from 'react' import Raven from 'raven-js' import { Segment, Button } from 'semantic-ui-react'  export default class ErrorBoundry extends Component {     state = {         hasError: false     }      componentDidCatch(error, info) {         this.setState({ hasError: true })         Raven.captureException(error, { extra: info });     }      render() {         if(this.state.hasError) {             return (                 <div className='error-boundry'>                     <Segment>                         <h2> Oh no! Somethin went wrong </h2>                         <p>Our team has been notified, but click                               <Button  onClick={() => Raven.lastEventId() && Raven.showReportDialog()}>                              here </Button> to fill out a report.                         </p>                     </Segment>                 </div>             );         } else {             return this.props.children;         }     } } 

ErrorBoundry.test.js:

import React, { Component } from 'react' import ReactDOM from 'react-dom' import renderer from 'react-test-renderer' import { shallow, mount } from 'enzyme' import ErrorBoundary from './ErrorBoundary'  class ComponentWithError extends Component {   render() {     return (       <div>         <input type = "text" value = {null}/>         </div>     );   } }  describe('<ErrorBoundary> window',()=> {   it('should match the snapshot', () => {     const tree = renderer.create(<ErrorBoundary>Test</ErrorBoundary> ).toJSON()     expect(tree).toMatchSnapshot()   })    it('displays error message on error generated by child', () => {     const wrapper = mount(       <ErrorBoundary >          <ComponentWithError />       </ErrorBoundary>        )     console.log(wrapper.debug() )   }) }) 
like image 244
Sylwek Avatar asked Apr 07 '18 13:04

Sylwek


People also ask

How do you test Errorboundary in React?

With the new feature in React, developers can test the Error Boundaries by a toggle error button, added to the DevTools. When we click on the toggle error button on the component labeled 'Inner Component', Error boundary is triggered. We see the An error was thrown text.


2 Answers

Enzyme has simulateError helper now.

So this works very well for me:

const Something = () => null;  describe('ErrorBoundary', () => {   it('should display an ErrorMessage if wrapped component throws', () => {     const wrapper = mount(       <ErrorBoundary>         <Something />       </ErrorBoundary>     );      const error = new Error('test');      wrapper.find(Something).simulateError(error);      /* The rest fo your test */   } } 
like image 107
Daniil Ivanov Avatar answered Sep 28 '22 07:09

Daniil Ivanov


After additional research I found that it is an open issue that has to be solved by Enzyme. https://github.com/airbnb/enzyme/issues/1255

I have implemented it as follows:

function ProblemChild() {   throw new Error('Error thrown from problem child');   return <div>Error</div>; // eslint-disable-line }  describe('<ErrorBoundary> window',()=> {     it('displays error message on error generated by child', () => {     const spy = sinon.spy(ErrorBoundary.prototype, 'componentDidCatch')     mount(<ErrorBoundary><ProblemChild /></ErrorBoundary>)     chaiExpect(ErrorBoundary.prototype.componentDidCatch).to.have.property('callCount', 1)   }) }) 

Proposed workaround works anyhow

  1. it is still not possible to test error message rendered to the app user by <ErrorBoundary>
  2. test console displays warnings:

    PASS src/ErrorBoundary.test.js ● Console

    console.error node_modules/react-dom/cjs/react-dom.development.js:9627   The above error occurred in the <ProblemChild> component:       in ProblemChild (at ErrorBoundary.test.js:37)       in ErrorBoundry (created by WrapperComponent)       in WrapperComponent    React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundry. 
like image 30
Sylwek Avatar answered Sep 28 '22 06:09

Sylwek