135

prior to posting this question, I tried to search in sqa stackexchange but I found no post about shallow and render there, so I hope someone can help me out here.

When should I use shallow and render in testing react components? Based on the airbnb docs, I've made some opinions on the difference of the two:

  1. Since shallow is testing components as a unit, so it should be used for 'parent' components. (ex. Tables, Wrappers, etc.)

  2. Render is for child components.

The reason I asked this question, is that I'm having a hard time to figure out which one I should use (though the docs say that they're very similar)

So, how do I know which one to use in a specific scenario?

4m1r
  • 12,234
  • 9
  • 46
  • 58
Cyval
  • 2,429
  • 4
  • 16
  • 27
  • 4
    The difference between shallow() and mount() is that shallow() tests components in isolation from the child components they render while mount()goes deeper and tests a component's children. For shallow() this means that if the parent component renders another component that fails to render, then a shallow() rendering on the parent will still pass. – Shyam Kumar Oct 10 '18 at 07:00
  • "It is better to stick to Mount testing because it is more reliable and it breaks even if you refactored your code, instead of using shallow, it may not break and also lulls you into a false sense of security." from https://medium.com/@aminebenkeroum/enzyme-understand-render-mount-and-shallow-6b2a7ee9a7 – Michael Freidgeim Aug 25 '22 at 00:43

3 Answers3

203

As per the Enzyme docs:

mount(<Component />) for Full DOM rendering is ideal for use cases where you have components that may interact with DOM apis, or may require the full lifecycle in order to fully test the component (ie, componentDidMount etc.)

vs.

shallow(<Component />) for Shallow rendering is useful to constrain yourself to testing a component as a unit, and to ensure that your tests aren't indirectly asserting on behavior of child components.

vs.

render which is used to render react components to static HTML and analyze the resulting HTML structure.

You can still see the underlying "nodes" in a shallow render, so for example, you can do something like this (slightly contrived) example using AVA as the spec runner:

let wrapper = shallow(<TagBox />);

const props = {
    toggleValue: sinon.spy()
};

test('it should render two top level nodes', t => {
    t.is(wrapper.children().length, 2);
});

test('it should safely set all props and still render two nodes', t => {
    wrapper.setProps({...props});
    t.is(wrapper.children().length, 2);
});

test('it should call toggleValue when an x class is clicked', t => {
    wrapper.setProps({...props});
    wrapper.find('.x').last().simulate('click');
    t.true(props.toggleValue.calledWith(3));
});

Notice that rendering, setting props and finding selectors and even synthetic events are all supported by shallow rendering, so most times you can just use that.

But, you won't be able to get the full lifecycle of the component, so if you expect things to happen in componentDidMount, you should use mount(<Component />);

This test uses Sinon to spy on the component's componentDidMount

test.only('mount calls componentDidMount', t => {

    class Test extends Component {
        constructor (props) {
            super(props);
        }
        componentDidMount() {
            console.log('componentDidMount!');
        }
        render () {
            return (
                <div />
            );
        }
    };

    const componentDidMount = sinon.spy(Test.prototype, 'componentDidMount');
    const wrapper = mount(<Test />);

    t.true(componentDidMount.calledOnce);

    componentDidMount.restore();
});

The above will not pass with shallow rendering or render

render will provide you with the html only, so you can still do stuff like this:

test.only('render works', t => {

    // insert Test component here...

    const rendered = render(<Test />);
    const len = rendered.find('div').length;
    t.is(len, 1);
});
starball
  • 20,030
  • 7
  • 43
  • 238
4m1r
  • 12,234
  • 9
  • 46
  • 58
  • 1
    i still dont get 100%, why the three verbs bring different methods with them. For example one can use wrapper.getNode() in shallow but not in render. any explanations/link/docs/blogs, that help me getting this togehter? – Paulquappe Jul 18 '17 at 08:06
  • @HenryZhu it should be clear from the docs that render is more involved than shallow, as it actually tries to mimic the DOM tree for that particular component node – AGE Mar 05 '18 at 18:42
  • 15
    enzyme migration from v2 to v3 has made lifecycle methods on by default in shallow as well https://github.com/airbnb/enzyme/blob/master/docs/guides/migration-from-2-to-3.md – Abhinav Singi Apr 26 '18 at 09:16
  • 2
    Good additional explanation of the differences is here https://github.com/airbnb/enzyme/issues/465#issuecomment-227697726 and here https://github.com/airbnb/enzyme/issues/465#issuecomment-229116418 – Dmitry Gonchar Jul 11 '18 at 22:20
18

The difference between shallow() and mount() is that  shallow() tests components in isolation from the child components they render while mount()goes deeper and tests a component's children.

For shallow() this means that if the parent component renders another component that fails to render, then a shallow() rendering on the parent will still pass.

Shyam Kumar
  • 586
  • 3
  • 17
0

From Why I Never Use Shallow Rendering by  Kent C. Dodds

With shallow rendering, I can refactor my component's implementation and my tests break. With shallow rendering, I can break my application and my tests say everything's still working.

The more your tests resemble the way your software is used, the more confidence they can give you.

Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170