user3142695
user3142695

Reputation: 17332

Jest/enzyme: How to test for .then and .catch of an nested asynchronous function

I'm trying to do some enzyme/jest unit testing for a asynchronous function in my reactJS component, which gets injected as prop.

My Problem is to test for a value in the then() part of the function and to test for catch() if an error occures.

This is how the function of my component (<CreateAccount />) looks like:

_onSubmit = (event) => {
  event.preventDefault()
  const { username, password } = this.state

  this.props.createUserMutation({
    variables: { username, password }
  }).then(response => {
    const token = response.data.createUser.token
    if (token) {
      Cookies.set('auth-token', token, { expires: 1 })
    }
  }).catch(error => {
    console.warn(error)
  })
}

The first test should check for .catch(error => {}) as data is undefined:

it('_onSubmit() should throw error if data is missing', () => {
  const createUserMutation = () => {
    return Promise.resolve({})
  }
  const wrapper = shallow(<CreateAccount createUserMutation={createUserMutation} />)
  wrapper.update().find(Form).simulate('submit', {
    preventDefault: () => {}
  })
  const state = wrapper.instance().state
  expect(wrapper).toThrow() // <-- How to do it correctly?
})

And the second test should check if cookie is set correctly. Here I don't know how to do that? I think I have to mock Cookie

it('_onSubmit() should get token', () => {
  const createUserMutation = () => {
    return Promise.resolve({
      data: {
        createUser: { token: 'token' }
      }
    })
  }
  const wrapper = shallow(<CreateAccount createUserMutation={createUserMutation} />)
  wrapper.find(Form).simulate('submit', {
    preventDefault: () => {}
  })
  // How to check for token value and Cookies?
})

Upvotes: 1

Views: 6500

Answers (2)

sebastianf182
sebastianf182

Reputation: 9978

What I usually have to do when I want to see if the spy worked on the catch or then, is to add another then() on the test. For example:

it('_onSubmit() should throw error if data is missing', () => {
  const createUserMutation = jest.fn(() => Promise.reject(new Error()));
  const spy = jest.spyOn(console,"warn");
  const wrapper = shallow(<CreateAccount createUserMutation={createUserMutation} />)
  wrapper.update().find(Form).simulate('submit', {
    preventDefault: () => {}
  });
  return createUserMutation.catch(() => {
    expect(wrapper).toMatchSnapshot();
})
.then(() => {
  expect(spy).toHaveBeenCalledTimes(1);
});
})

I guess it is somehow related to how NodeJS handles the queues, promises, ticks, etc, internally.

That is the rejected/catch branch. If you want to test the IF path, just use a Promise.resolve and return a promise.then() instead of catch.

Upvotes: 1

Martin Dawson
Martin Dawson

Reputation: 7656

Why are you using console.warn for an error? Use console.error instead. You will need to mock it out to a spy as well to test it.

First test:

it('_onSubmit() should throw error if data is missing', (done) => {
  const createUserMutation = () => new Promise();
  const wrapper = shallow(<CreateAccount createUserMutation={createUserMutation} />)
  wrapper.update().find(Form).simulate('submit', {
    preventDefault: () => {}
  })

  const state = wrapper.instance().state

  createUserMutation.resolve().then(() => {
    expect(console.warn).toHaveBeenCalled();
    done();
  });
})

If you are running this in a mock browser environment and not a real browser then you must mock out Cookies.set.

Second test:

it('_onSubmit() should get token', (done) => {
  const createUserMutation = () => new Promise();
  const wrapper = shallow(<CreateAccount createUserMutation={createUserMutation} />)

  wrapper.find(Form).simulate('submit', {
    preventDefault: () => {}
  });

  jest.spyOn(window.Cookies, 'set');

  const response  = {
      data: {
        createUser: { token: 'token' }
      }
  }

  createUserMutation.resolve(response).then(() => {
    expect(window.Cookies.set).toHaveBeenCalled();
    done();
  });
})

afterEach(() => {
    // Reset the spies so that they don't leak to other tests
    jest.restoreAllMocks();
});

Upvotes: 0

Related Questions