简体   繁体   中英

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

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

component.setState = jest.fn()
    })

how about removing this?

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()
})

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()
   })
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM