ctimmerm / axios-mock-adapter

Axios adapter that allows to easily mock requests
MIT License
3.47k stars 245 forks source link

Cannot reliably flush promises when using delayResponse #230

Open andreixk opened 4 years ago

andreixk commented 4 years ago

I have a component that makes an API call to get token and stores it if the call is successful, or shows an error to the user otherwise. I'm mocking this call in a test and using delayResponse to simulate realistic network delay. I'm using await flushPromises() (from flush-promises package) to wait for promises to be resolved in the test. However, the test skips over that and finishes before the promise gets resolved (hence it's failing). I noticed that in the axios-mock-adapter source code, when there's a delay, it doesn't return a new promise and resolves inside setTimeout() (as i would normally simulate a delay) but rather recursively calls the same settle function again. Although I didn't look deeply into this, I think that might be the cause of flushPromises not being able to catch it.

Here's my test code:

it('Receives and stores JWT after sending valid credentials', async () => {
  const mockAxios = new AxiosMockAdapter(axios, {delayResponse: 100});
  const validToken = 'valid-token';
  mockAxios.onPost().reply(200, { payload: validToken });

  wrapper.find('[test-id="LoginPasswordField"]').vm.$emit('input', 'valid-pass');
  wrapper.find('[test-id="LoginSubmitBtn"]').trigger('click');

  await flushPromises(); // - this moves on without waiting 100ms

  expect(localStore.state.user.token).toBe(validToken);
});

When I remove delayResponse, everything works properly.

Here's a code that works with setTimeout:

const delayedPromise = () => new Promise(resolve => setTimeout(resolve, 100));

it('...', async () => {
   await delayedPromise(); // - this waits 100ms before proceeding
});

For completeness sake, here's the code under test:

async login() {
    try {
      const response = await axios.post(this.url, this.credentials);
      console.log('got response', response);
      const token = response.data.payload;
      this.$store.dispatch('setUser', { token });
    } catch (error) {
      console.warn('caught error', error);
      this.error = error;
    }
}
sureshvv commented 1 year ago

Any update?