BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Airbnb Transfers Ownership of Enzyme, Its React Testing Library

Airbnb Transfers Ownership of Enzyme, Its React Testing Library

This item in japanese

Bookmarks

Airbnb transferred ownership of Enzyme, its React testing library, to the new enzymejs GitHub organization. Airbnb still plans to continue to use and contribute to Enzyme.

Airbnb decided to put the responsibility for the development of its Enzyme testing library in a community-led enzymejs GitHub organization. Airbnb mentioned that the existence and the support from the community of developers and contributors as a key driver behind the decision:

[The] community is largely the reason why we are excited to announce that we will transfer ownership of Enzyme to the new enzymejs GitHub organization. We believe that this new home will help the project continue to support the community’s needs well into the future. The success here has moved beyond Airbnb as a single org […].

The four-year-old React component testing library has over 340 contributors. Since its inception, Enzyme grew in popularity among developers, as illustrated by key statistics: two-million weekly downloads (growing 8% annually) on npm, 18,000+ GitHub stars, 1,400 packages dependent on Enzyme. Enzyme is additionally used by over 238,000 repositories and 25,000 packages.

While Airbnb mentioned that it uses Enzyme internally in over 17,000 tests, it also revealed that the React Testing Library has been increasingly used within the organization. Nonetheless, Airbnb sees continued usage and contributions to Enzyme in the future.

The React Testing Library (RTL) is officially recommended by React, and has grown since its inception to over 1.3M downloads on npm. RTL describes itself as a very lightweight solution for testing React components, whose structuring goal is to allow writing maintainable tests by avoiding testing against implementation details. RTL seeks to achieve its goal by encouraging testing against the application behavior rather than against the application’s component tree. Kent C. Dodds, RTL’s key contributor, explains:

We try to only expose methods and utilities that encourage you to write tests that closely resemble how your React components are used.

A typical RTL test consists of rendering a component tree exactly as a user would see it in the browser (full rendering or mount). Developers may then query the displayed content and simulate user events by leveraging the RTL’s API. User scenarios can thus be tested by recreating the appropriate events through the interface and observing changes in the interface as a user of the application under test would.

An abbreviated example of RTL test is as follows:

(...)
import '@testing-library/jest-dom'
import {render, fireEvent, screen} from '@testing-library/react'
(...)

test('shows the children when the checkbox is checked', () => {
  const testMessage = 'Test Message'
  render(<HiddenMessage>{testMessage}</HiddenMessage>)

  // query* functions will return the element or null if it cannot be found
  // get* functions will return the element or throw an error if it cannot be found
  expect(screen.queryByText(testMessage)).toBeNull()

  // the queries can accept a regex to make your selectors more resilient to content tweaks and changes.
  fireEvent.click(screen.getByLabelText(/show/i))

  // .toBeInTheDocument() is an assertion that comes from jest-dom
  // otherwise you could use .toBeDefined()
  expect(screen.getByText(testMessage)).toBeInTheDocument()
})

Conversely, developers using the Enzyme library may use shallow rendering to run tests against a component tree. Shallow rendering only renders a component tree a single level deep. Enzyme’s Shallow Rendering API is a higher level abstraction on top of that of React.

Shallow rendering is useful when testing a component as a unit, while not also testing indirectly the behavior of children components. It is thus particularly useful to unit-test wrapper components. Wasura Wattearachchi illustrates shallow rendering with an example. Shallow rendering the <Add> component:

class Add extends Component {  
  render() {  
    return (  
      <div>  
        <h1>Add Function</h1>  
        <Form operator='+'/>  
      </div>  
    );  
  }  
}

Assuming that <Form> is defined as follows:

<form className='form-group'>
  <fieldset className='form-group'>
    <label className='form-label'>
      First Number:
    </label>
    <input type="text" id="number1" className='form-input' value={firstNumber} onChange={this.handleFirstNumber}/>
  </fieldset>
   ...
</form>

This will not render the <label> elements inside <Form>.

The following test file:

import Add from '../src/components/Add';  
import Form from '../src/components/Form';
let wrapper;

beforeEach(() => {  
    wrapper = shallow(<Add />);  
});

describe('<Add /> rendering', () => {  
    it('should render one <h1>', () => {  
        expect(wrapper.find('h1')).toHaveLength(1);  
    });
    it('should render one <Form>', () => {  
        expect(wrapper.find(Form)).toHaveLength(1);  
    });
    it('should render 2 <label>s', () => {  
        expect(wrapper.find('label')).toHaveLength(2);  
    });  
});

The first two tests will pass, and the third one will fail.

Both Enzyme and RTL have their usage contexts, as recognized by developers, some of which favor Enzyme and its shallow rendering, while others rather constantly use RTL and its full mount.

Developers seeking to support Enzyme may consult Enzyme’s open issues and pull requests — with a special focus on the “help wanted” tag.

Rate this Article

Adoption
Style

BT