enzyme vs jest-dom vs chai-dom vs react-testing-library
Testing React Components Comparison
3 Years
enzymejest-domchai-domreact-testing-librarySimilar Packages:
What's Testing React Components?

Testing libraries for React components provide tools and utilities to verify that components render correctly, behave as expected, and interact properly with user inputs and other components. These libraries help developers write automated tests that can catch bugs early in the development process, ensure code quality, and facilitate refactoring by providing a safety net of tests. They often include features for simulating user interactions, asserting on the rendered output, and mocking dependencies, making it easier to test components in isolation or within a larger application.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
enzyme1,413,221
19,914-2816 years agoMIT
jest-dom117,356
---6 years ago-
chai-dom89,939
7768 kB147 months agoMIT
react-testing-library52,927
---6 years ago-
Feature Comparison: enzyme vs jest-dom vs chai-dom vs react-testing-library

Integration with Testing Frameworks

  • enzyme:

    enzyme can be used with any testing framework, but it is commonly paired with Jest or Mocha. It requires some configuration, especially when using it with React 16 and above, due to changes in how React handles rendering.

  • jest-dom:

    jest-dom is designed to work specifically with Jest, leveraging its built-in assertion capabilities. It requires no additional setup beyond installing the package and importing the matchers in your test files.

  • chai-dom:

    chai-dom integrates seamlessly with Chai, allowing you to use its DOM assertions alongside other Chai matchers. It requires minimal setup and works well with any testing framework that supports Chai, such as Mocha or Jasmine.

  • react-testing-library:

    react-testing-library is framework-agnostic but is often used with Jest due to its popularity and ease of use. It integrates well with any testing framework and encourages a user-centric approach to testing.

Type of Assertions

  • enzyme:

    enzyme allows for a wide range of assertions based on the type of rendering you choose (shallow, deep, or full). It provides utilities for inspecting component state, props, and lifecycle methods, enabling detailed assertions about component behavior.

  • jest-dom:

    jest-dom focuses on enhancing assertions related to the DOM, providing custom matchers like toBeInTheDocument, toHaveAttribute, and toHaveTextContent. These matchers make assertions more intuitive and improve test readability.

  • chai-dom:

    chai-dom provides a rich set of assertions for testing DOM elements, including checks for attributes, classes, styles, and more. It enhances the readability of assertions by providing clear and descriptive error messages when tests fail.

  • react-testing-library:

    react-testing-library encourages assertions that focus on the rendered output and user interactions. It promotes the use of queries that mimic how users find elements on the page, leading to more meaningful and resilient assertions.

Focus on Implementation vs. Behavior

  • enzyme:

    enzyme allows for both implementation and behavior-focused testing. You can inspect the internal structure of components (especially useful for class components) while also simulating user interactions and testing how components behave in response.

  • jest-dom:

    jest-dom is primarily focused on the final rendered output of components, making it more behavior-oriented. It encourages tests that verify how elements appear and behave in the DOM, rather than how they are implemented internally.

  • chai-dom:

    chai-dom focuses on the implementation of the DOM, allowing you to make detailed assertions about the structure and properties of DOM elements. It is more suited for tests that require a deep understanding of the DOM hierarchy and element attributes.

  • react-testing-library:

    react-testing-library strongly emphasizes behavior over implementation. It encourages testing components as users would interact with them, leading to tests that are less brittle and more reflective of real-world usage.

Example Code

  • enzyme:

    enzyme Example

    import { shallow } from 'enzyme';
    import MyComponent from './MyComponent';
    
    // Shallow render the component
    const wrapper = shallow(<MyComponent />);
    
    // Assert on the component's state
    expect(wrapper.state('count')).toBe(0);
    
    // Simulate a button click
    wrapper.find('button').simulate('click');
    
    // Assert on the updated state
    expect(wrapper.state('count')).toBe(1);
    
    // Assert on the rendered output
    expect(wrapper.find('h1').text()).toBe('Count: 1');
    
  • jest-dom:

    jest-dom Example

    import { render } from '@testing-library/react';
    import '@testing-library/jest-dom/extend-expect'; // Import jest-dom matchers
    import MyComponent from './MyComponent';
    
    // Render the component
    const { getByTestId } = render(<MyComponent />);
    const element = getByTestId('my-element');
    
    // Use jest-dom matchers
    expect(element).toBeInTheDocument();
    expect(element).toHaveAttribute('aria-label', 'my-label');
    expect(element).toHaveTextContent('Hello, World!');
    
  • chai-dom:

    chai-dom Example

    import { expect } from 'chai';
    import 'chai-dom'; // Import chai-dom
    import { render } from '@testing-library/react';
    import MyComponent from './MyComponent';
    
    // Render the component
    const { getByTestId } = render(<MyComponent />);
    const element = getByTestId('my-element');
    
    // Use chai-dom assertions
    expect(element).to.have.class('active');
    expect(element).to.have.attribute('aria-label', 'my-label');
    expect(element).to.be.visible;
    
  • react-testing-library:

    react-testing-library Example

    import { render, screen } from '@testing-library/react';
    import MyComponent from './MyComponent';
    
    // Render the component
    render(<MyComponent />);
    
    // Assert on the rendered output
    const element = screen.getByText('Hello, World!');
    expect(element).toBeInTheDocument();
    
    // Simulate a user event
    fireEvent.click(screen.getByRole('button'));
    
    // Assert on the updated output
    expect(screen.getByText('Count: 1')).toBeInTheDocument();
    
How to Choose: enzyme vs jest-dom vs chai-dom vs react-testing-library
  • enzyme:

    Choose enzyme if you need a comprehensive testing utility that allows for shallow, deep, and full rendering of React components. It is ideal for projects that require detailed testing of component behavior, state, and lifecycle methods, especially in class components.

  • jest-dom:

    Choose jest-dom if you are using Jest as your testing framework and want to improve your DOM assertions. It provides a set of custom matchers that make your tests more readable and expressive, focusing on the final rendered output of components.

  • chai-dom:

    Choose chai-dom if you are already using Chai for assertions and want to enhance your tests with additional DOM-related assertions. It is particularly useful for projects that require expressive and readable assertions about the DOM structure and properties.

  • react-testing-library:

    Choose react-testing-library if you want to test React components in a way that simulates real user interactions and focuses on the component's behavior rather than its implementation details. It encourages best practices by promoting tests that are more resilient to changes in the component's internal structure.

README for enzyme

Enzyme

Join the chat at https://gitter.im/airbnb/enzyme

npm Version License Build Status Coverage Status

Enzyme is a JavaScript Testing utility for React that makes it easier to test your React Components' output. You can also manipulate, traverse, and in some ways simulate runtime given the output.

Enzyme's API is meant to be intuitive and flexible by mimicking jQuery's API for DOM manipulation and traversal.

Upgrading from Enzyme 2.x or React < 16

Are you here to check whether or not Enzyme is compatible with React 16? Are you currently using Enzyme 2.x? Great! Check out our migration guide for help moving on to Enzyme v3 where React 16 is supported.

Installation

To get started with enzyme, you can simply install it via npm. You will need to install enzyme along with an Adapter corresponding to the version of react (or other UI Component library) you are using. For instance, if you are using enzyme with React 16, you can run:

npm i --save-dev enzyme enzyme-adapter-react-16

Each adapter may have additional peer dependencies which you will need to install as well. For instance, enzyme-adapter-react-16 has peer dependencies on react and react-dom.

At the moment, Enzyme has adapters that provide compatibility with React 16.x, React 15.x, React 0.14.x and React 0.13.x.

The following adapters are officially provided by enzyme, and have the following compatibility with React:

| Enzyme Adapter Package | React semver compatibility | | --- | --- | | enzyme-adapter-react-16 | ^16.4.0-0 | | enzyme-adapter-react-16.3 | ~16.3.0-0 | | enzyme-adapter-react-16.2 | ~16.2 | | enzyme-adapter-react-16.1 | ~16.0.0-0 \|\| ~16.1 | | enzyme-adapter-react-15 | ^15.5.0 | | enzyme-adapter-react-15.4 | 15.0.0-0 - 15.4.x | | enzyme-adapter-react-14 | ^0.14.0 | | enzyme-adapter-react-13 | ^0.13.0 |

Finally, you need to configure enzyme to use the adapter you want it to use. To do this, you can use the top level configure(...) API.

import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({ adapter: new Adapter() });

3rd Party Adapters

It is possible for the community to create additional (non-official) adapters that will make enzyme work with other libraries. If you have made one and it's not included in the list below, feel free to make a PR to this README and add a link to it! The known 3rd party adapters are:

| Adapter Package | For Library | Status | | --- | --- | --- | | enzyme-adapter-preact-pure | preact | (stable) | |enzyme-adapter-inferno|inferno|(work in progress)|

Running Enzyme Tests

Enzyme is unopinionated regarding which test runner or assertion library you use, and should be compatible with all major test runners and assertion libraries out there. The documentation and examples for enzyme use mocha and chai, but you should be able to extrapolate to your framework of choice.

If you are interested in using enzyme with custom assertions and convenience functions for testing your React components, you can consider using:

Using Enzyme with Mocha

Using Enzyme with Karma

Using Enzyme with Browserify

Using Enzyme with SystemJS

Using Enzyme with Webpack

Using Enzyme with JSDOM

Using Enzyme with React Native

Using Enzyme with Jest

Using Enzyme with Lab

Using Enzyme with Tape and AVA

Basic Usage

Shallow Rendering

import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import sinon from 'sinon';

import MyComponent from './MyComponent';
import Foo from './Foo';

describe('<MyComponent />', () => {
  it('renders three <Foo /> components', () => {
    const wrapper = shallow(<MyComponent />);
    expect(wrapper.find(Foo)).to.have.lengthOf(3);
  });

  it('renders an `.icon-star`', () => {
    const wrapper = shallow(<MyComponent />);
    expect(wrapper.find('.icon-star')).to.have.lengthOf(1);
  });

  it('renders children when passed in', () => {
    const wrapper = shallow((
      <MyComponent>
        <div className="unique" />
      </MyComponent>
    ));
    expect(wrapper.contains(<div className="unique" />)).to.equal(true);
  });

  it('simulates click events', () => {
    const onButtonClick = sinon.spy();
    const wrapper = shallow(<Foo onButtonClick={onButtonClick} />);
    wrapper.find('button').simulate('click');
    expect(onButtonClick).to.have.property('callCount', 1);
  });
});

Read the full API Documentation

Full DOM Rendering

import React from 'react';
import sinon from 'sinon';
import { expect } from 'chai';
import { mount } from 'enzyme';

import Foo from './Foo';

describe('<Foo />', () => {
  it('allows us to set props', () => {
    const wrapper = mount(<Foo bar="baz" />);
    expect(wrapper.props().bar).to.equal('baz');
    wrapper.setProps({ bar: 'foo' });
    expect(wrapper.props().bar).to.equal('foo');
  });

  it('simulates click events', () => {
    const onButtonClick = sinon.spy();
    const wrapper = mount((
      <Foo onButtonClick={onButtonClick} />
    ));
    wrapper.find('button').simulate('click');
    expect(onButtonClick).to.have.property('callCount', 1);
  });

  it('calls componentDidMount', () => {
    sinon.spy(Foo.prototype, 'componentDidMount');
    const wrapper = mount(<Foo />);
    expect(Foo.prototype.componentDidMount).to.have.property('callCount', 1);
    Foo.prototype.componentDidMount.restore();
  });
});

Read the full API Documentation

Static Rendered Markup

import React from 'react';
import { expect } from 'chai';
import { render } from 'enzyme';

import Foo from './Foo';

describe('<Foo />', () => {
  it('renders three `.foo-bar`s', () => {
    const wrapper = render(<Foo />);
    expect(wrapper.find('.foo-bar')).to.have.lengthOf(3);
  });

  it('renders the title', () => {
    const wrapper = render(<Foo title="unique" />);
    expect(wrapper.text()).to.contain('unique');
  });
});

Read the full API Documentation

React Hooks support

Enzyme supports react hooks with some limitations in .shallow() due to upstream issues in React's shallow renderer:

  • useEffect() and useLayoutEffect() don't get called in the React shallow renderer. Related issue

  • useCallback() doesn't memoize callback in React shallow renderer. Related issue

ReactTestUtils.act() wrap

If you're using React 16.8+ and .mount(), Enzyme will wrap apis including .simulate(), .setProps(), .setContext(), .invoke() with ReactTestUtils.act() so you don't need to manually wrap it.

A common pattern to trigger handlers with .act() and assert is:

const wrapper = mount(<SomeComponent />);
act(() => wrapper.prop('handler')());
wrapper.update();
expect(/* ... */);

We cannot wrap the result of .prop() (or .props()) with .act() in Enzyme internally since it will break the equality of the returned value. However, you could use .invoke() to simplify the code:

const wrapper = mount(<SomeComponent />);
wrapper.invoke('handler')();
expect(/* ... */);

Future

Enzyme Future

Contributing

See the Contributors Guide

In the wild

Organizations and projects using enzyme can list themselves here.

License

MIT