Reputation: 10029
I'm using the React Test Utilities to unit test some of my code. I call renderIntoDocument
to render a custom component and then use findDOMNode
to test out what got rendered. The trouble I'm running into is that I'm not sure how to update the state and effectively trigger a re-render within the context of a unit test.
Here's some sample code -- pay attention to the code comment:
import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-dom/test-utils';
import MyCustomComponent from '../../app/components/MyCustomComponent';
describe('My Test Suite', () => {
let component, node;
test('verify state change', () => {
const items = [{'value': '1'}];
component = TestUtils.renderIntoDocument(
<MyCustomComponent items={items} />
);
node = ReactDOM.findDOMNode(component);
expect(node.querySelector('input[type=text]').value).toEqual('1');
component.state.items = [{'value': '2'}];
// do something here to trigger a re-render?
expect(node.querySelector('input[type=text]').value).toEqual('2');
});
});
Unfortunately it seems simply changing the state variable doesn't do anything. And I can't call component.componentWillReceiveProps()
because that doesn't seem to be defined.
Please note that I do want the same component to call its render function rather than replacing it with, effectively, a brand new component. The reason is because I found a bug where the component was rendering things based on this.props
instead of this.state
, and I want a test to show that it's always using data from the state and not from the initial values.
Upvotes: 1
Views: 7121
Reputation: 1020
Enzyme from AirBnb has some great utilities for this. You'll need to install the dependencies but it's simple enough to get it configured. Then, you can simply call Enzyme's setState
method on your component instance. An important note – your "component instance" in this case is a shallow rendered component. Your code would look something like this:
import React from 'react';
import MyCustomComponent from '../../app/components/MyCustomComponent';
import { shallow, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
// configure your adapter
configure({ adapter: new Adapter() });
describe('My Test Suite', () => {
test('verify state change', () => {
const items = [{'value': '1'}];
const wrapper = shallow(<MyCustomComponent items={items} />);
// find your shallow rendered component and check its value
expect(wrapper.find('input[type="text"]').value).toEqual('1');
// set the state of the component
wrapper.setState({ items: [{'value': '2'}] });
// state should be updated, make sure its value was properly set
expect(wrapper.find('input[type="text"]').value).toEqual('2');
});
});
All of this assumes that you are using state
in your component properly. In your case, items
appears to be passed in as a prop
. If you are setting state
by just copying props
, you may want to rethink your strategy. In any case, this approach should be identical to how state
updates in React work – you're operating on the same component instance without unmounting and remounting the component. Hope this helps.
Upvotes: 7