Vipul Panth
Vipul Panth

Reputation: 5801

Enzyme- How to set state of inner component?

I need to access the state of the inner component, to make it active for click event, my problem is Enzyme does not allow this when using mount, this can only be achieved by shallow rendering of enzyme as mentioned over here, also as mentioned I have tried to use dive to fetch the Form component and again from Form to get Button component which I need to reach, the problem is that my test case keeps on failing as Form component length is zero.

enzyme: 3.1.0

enzyme-adapter-react-15: 1.0.1"

I am pretty new to Enzyme, Any help will be appreciated, Thanks

contactus.test.js :

 test('It should simulate submit action ', ()=>{
   let contactUs = shallow(<ContactUs />);
   sinon.spy(ContactUs.prototype, 'submitMessage');// Verify this method call
   let form = contactUs.find(Form)
   expect(form.length).toBe(1);//Failing over here
   let button = form.dive().find(Button);
   expect(button.length).toBe(1);
   button.setState({disabled : false});//Need to achieve this 
   expect(button).toBeDefined();
   expect(button.length).toBe(1);
   expect(button.props().label).toBe('SEND MESSAGE');

   button.find('a').get(0).simulate('click');
  expect(ContactUs.prototype.submitMessage).toHaveProperty('callCount', 
 1);
});

contactus.js :

import React, {Component,PropTypes} from 'react';
import Form from './form';
import {sendSubscriptionMessage} from '../../network';
import Button from '../Fields/Button';

export default class ContactUs extends Component {

constructor(props) {
    super(props);
    this.state = {
        contactData: {}
    }
}

onChangeHandler(event) {
    let value = event.target.value;
    this.state.contactData[event.target.name] = value;
}

submitMessage(event) {
    event.preventDefault();
    sendSubscriptionMessage(this.state.contactData);
}

render() {
    return (<div className = "row pattern-black contact logo-container" id = "contact">
        <div className = "container" >
        <h2 className = "sectionTitle f-damion c-white mTop100" >
        Get in Touch!

       <Form onChangeHandler = {
            this.onChangeHandler.bind(this)
        } >
        <Button onClick = {
            this.submitMessage.bind(this)
        }
        className = "gradientButton pink inverse mTop50"
        label = "SEND MESSAGE" / >
        </Form> </div> 
        </div>
    );
  }
 }

Upvotes: 6

Views: 5824

Answers (1)

ValentinVoilean
ValentinVoilean

Reputation: 1392

First of all I think you should not test the Button and the Form functionalities here. In this file you should test only the ContactForm component.

For the first fail, this should work:

find('Form') (the Form should have quotes)

Same for the button: find('Button');

In this way you don't even have to import the Form and the Button components in your test file at all;

Then, you don't have to set any state for that button. You test the button functionality in the Button.test.js file. All you have to do here is to call its method like this: button.nodes[0].props.onClick();

Overall, this is how your test should look like ( note that I didn't test it, I've been using Jest for testing my components, but the logic should be the same ):

 test('It should simulate submit action ', ()=>{
   const wrapper = shallow(<ContactUs />);
   const spy = sinon.spy(ContactUs.prototype, 'submitMessage'); // Save the spy into a new variable

   const form = wrapper.find('Form') // I don't know if is the same, but in jest is enough to pass the component name as a string, so you don't have to import it in your test file anymore.

   expect(form).to.have.length(1);

   const button = wrapper.find('Button'); // from what I see in your code, the Button is part of the ContactUs component, not of the Form.

   expect(button).to.have.length(1);

   /* These lines should not be part of this test file. Create a test file only for the Button component.
   button.setState({disabled : false}); 
   expect(button).toBeDefined();
   expect(button.length).toBe(1);
   expect(button.props().label).toBe('SEND MESSAGE');
   */

   button.nodes[0].props.onClick(); // Here you call its method directly, cause we don't care about its internal functionality; we want to check if the "submitMessage" method has been called.


  assert(spy.called); // Here I'm not very sure... I'm a Jest fan and i would have done it like this "expect(spy).toHaveBeenCalled();"
});

Upvotes: 2

Related Questions