Saurav Dutta
Saurav Dutta

Reputation: 81

react state is not updating in jest

In my react component I have two functions. handleChangeInput(e) is called on 'OnChange' of input field and checkFields() is called from handleChangeInput(e)

constructor(){
    super()
    this.state={
      email: '',
      password:'',
      validFields: false
    }
  }

handleChangeInput(e){
    const name = e.target.name;
    const value = e.target.value;
    this.setState({[name]: value},()=>{
      this.checkFields();
    });
  }

  checkFields(){
    if (this.state.email.length>0 && this.state.password.length>0 ) {
      this.setState({validFields: true});
    }else {
      this.setState({validFields: false});
    }
  }

And in my index.test.js I have

describe('<Login />', () => {
	
	describe('handleChangeInput', () => {

        const component = new Login()
        const wrapper = shallow(<Login />);

        beforeEach(() => {
            component.setState = jest.fn()
        })

        test('calls setState validFields false when no email/password', () => {
            const state = { state : { email: '', password: ''} }
            const args = { target : { name: 'name', value: 'value' } }
            component.handleChangeInput.call(state, args)
            expect(component.setState.mock.calls.length).toBe(1)
            expect(wrapper.state().validFields).toEqual(false)
        })

        test('calls setState validFields true when email/password are ok', () => {
            const state = { state : { email: 'email', password: 'password' } }
            const args = { target : { name: 'name', value: 'value' } }
            component.handleChangeInput.call(state, args)
            expect(component.setState.mock.calls.length).toBe(1)
            expect(wrapper.state().validFields).toEqual(false)
        })
	})
});

But my state is not being updated. As a result, 'validFields' is not set to true and my second test is failing. I tried wrapper.update() and wrapper.instance().forceUpdate() but still no success. Any help would be appreciated

Upvotes: 0

Views: 8497

Answers (3)

Sameer Tanuj
Sameer Tanuj

Reputation: 213

I found this answer in one of the git forums. It worked for me.

// somewhere in your test setup code
global.flushPromises = () => {
   return new Promise(resolve => setImmediate(resolve))
}

test('something with unreachable promises', () => {
   expect.hasAssertions()
   const component = mount(<Something />)

   // do something to your component here that waits for a promise to return

   return flushPromises().then(() => {
       component.update() // still may be needed depending on your implementation
       expect(component.html()).toMatchSnapshot()
   })
})

Upvotes: 0

Moyote
Moyote

Reputation: 1217

hope my answer does not come too late, but you are trying to update the state in a wrong way.

First of all, remove these two:

const component = new Login()

beforeEach(() => {
  component.setState = jest.fn()
})

And most likely you want to change this:

handleChangeInput(e){
    const name = e.target.name;
    const value = e.target.value;
    this.setState({[name]: value},()=>{
      this.checkFields();
    });
}

handleChangeInput(e){
  const name = e.target.name;
  const value = e.target.value;
  this.setState(()=>{
    return { email: name}
  });
  this.setState(()=>{
    return { password: value }
  });
  this.checkFields();
}

const component = new Login() does not bring any value to this test and you should not mock the setState if you want that it's actually changed.

Instead you should test the actual component (like you partially already do here)

Change the code like this:

test('calls setState validFields true when email/password are ok', () => {
  const args = { target : { email: 'email', password: 'password' } }
  wrapper.instance().handleChangeInput(args)

  expect(wrapper.state('email')).toEqual('email')
  expect(wrapper.state('password')).toEqual('password')

  expect(wrapper.state('validFields')).toBeTruthy()
})

Upvotes: 0

Emil Re&#241;a Enriquez
Emil Re&#241;a Enriquez

Reputation: 2961

I am guessing it might be because you override the setState function with jest.fn()

component.setState = jest.fn()
    })

how about removing this?

Upvotes: 1

Related Questions