6

I'm working with Jest and snapshot testing. What I'd like to do is render a component with ReactTestRenderer, then simulate clicking a button inside it, then verify the snapshot.

The object returned by ReactTestRenderer's create call has a getInstance function that allows me to call its methods directly, but it does not seem to work with any of the find/scry methods in ReactTestUtils.

I can manually traverse the tree and click the button, but it seems like there must be a better way:

import React from 'react';
import ReactDOM from 'react-dom';
import MyCounter from './MyCounter';
import renderer from 'react-test-renderer';
import {Simulate, findRenderedDOMComponentWithClass} from 'react-addons-test-utils';

it('should render 0', () => {
  const component = renderer.create(<MyCounter/>);
  const inst = component.getInstance();

  // Calling methods directly works, but that's not the same as
  // simulating a click on the button...
  inst.increment();

  // This also works, but it's awfully verbose...
  component.toJSON().children[1].props.onClick();

  // I'm looking for something like...
  //   inst.find('.increment').click()
  // or:
  //   Simulate.click(inst.find('.increment'))
  // or:
  //   Simulate.click(findRenderedDOMComponentWithClass(inst, 'increment'))

  // Finally, verify the snapshot
  expect(component.toJSON()).toMatchSnapshot();
});

Does something like this exist?

Dave Ceddia
  • 1,480
  • 2
  • 17
  • 24
  • what you're looking for is Enzyme: http://airbnb.io/enzyme/ ...but jest really needs a tool to transverse snapshots as Enzyme introduces a lot more unnecessary things and potential bottlenecks. I think the goal in 2017 is to just be using Jest. Simulating clicks (through the DOM) isn't really needed when React is so dependable. In addition, you barely need css style selectors when snapshots are so powerful in combination with stateless components. So that only leaves needing selectors for quickly calling a function used as a prop. There's gotta be a lib that has basic selectors by now.. – faceyspacey.com Dec 30 '16 at 04:42

2 Answers2

6

I know this is an old question, but in case you still need the answer, you should use component.root (instead of component.getInstance()), which has a find() method on it. However, this differs from enzyme's find() in that it doesn't accept a selector, instead it accepts a function, that gets the element as argument. So it would look something like this:

it('should render 0', () => {
  const component = renderer.create(<MyCounter/>);
  const root = component.root;

  const incrementButton = root.find(element => element.props.className === 'increment');
  incrementButton.props.onClick();

  expect(component.toJSON()).toMatchSnapshot();
});
András Geiszl
  • 966
  • 2
  • 16
  • 36
-1

The problem is that find returns an array, so you have to use first to get the first element or closest:

inst.find('.increment').first().click()
inst.closest('.increment').click()

If you don't want the first element use childAt(index)

Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297