What is the correct way of unit testing a React component prop update.
Here is my test fixture;
describe('updating the value', function(){ var component; beforeEach(function(){ component = TestUtils.renderIntoDocument(<MyComponent value={true} />); }); it('should update the state of the component when the value prop is changed', function(){ // Act component.props.value = false; component.forceUpdate(); // Assert expect(component.state.value).toBe(false); }); });
This works fine and the test passes, however this displays a react warning message
'Warning: Dont set .props.value of the React component <exports />. Instead specify the correct value when initially creating the element or use React.cloneElement to make a new element with updated props.'
All i want to test is the update of a property, not to create a new instance of the element with a different property. Is there a better way to do this property update?
A component cannot update its own props unless they are arrays or objects (having a component update its own props even if possible is an anti-pattern), but can update its state and the props of its children.
React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.
To update state when props change in React: Pass the props as dependencies to the useEffect hook. Every time the props change, the logic in useEffect is reran.
AirBnB's Enzyme library provides an elegant solution to this question.
it provides a setProps method, that can be called on either a shallow or jsdom wrapper.
it("Component should call componentWillReceiveProps on update", () => { const spy = sinon.spy(Component.prototype, "componentWillReceiveProps"); const wrapper = shallow(<Component {...props} />); expect(spy.calledOnce).to.equal(false); wrapper.setProps({ prop: 2 }); expect(spy.calledOnce).to.equal(true); });
If you re-render the element with different props in the same container node, it will be updated instead of re-mounted. See React.render.
In your case, you should use ReactDOM.render
directly instead of TestUtils.renderIntoDocument
. The later creates a new container node every time it is called, and thus a new component too.
var node, component; beforeEach(function(){ node = document.createElement('div'); component = ReactDOM.render(<MyComponent value={true} />, node); }); it('should update the state of the component when the value prop is changed', function(){ // `component` will be updated instead of remounted ReactDOM.render(<MyComponent value={false} />, node); // Assert that `component` has updated its state in response to a prop change expect(component.state.value).toBe(false); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With