Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue with jest - Test with asynchronous call

How to make my test wait for the result of my api? I'm using vue and jest to test my components.

I want to test the method that writes a client to my database. In my component I have the following method:

methods: {

  onSubmitClient(){

   axios.post(`urlApi`, this.dados).then(res => {

      return res;
   })

  }
}

in my test

describe('login.vue', () => {

  let wrapper

  beforeAll(()=>{

    wrapper = mount(client, {
      stubs: ['router-link'],
      store,
      data() {
          return {
              dados: {
                  name: 'tes name',
                  city: 'test city'
              },
          };
      }
    })
  })

  it('store client', () => {

    res = wrapper.vm.onSubmitLogin()
    console.log(res);

  })

})

My test does not wait for the API call to complete. I need to wait for the API call to know if the test worked. How can I make my test wait for API return?

like image 609
Renato Souza de Oliveira Avatar asked Jan 27 '23 14:01

Renato Souza de Oliveira


1 Answers

There are several issues in your code.

First, you cannot return from an async call. Instead, you should be probably setting up some data in your onSubmitClient, and returning the whole axioscall, which is a Promise. for instance:

onSubmitClient(){
  return axios.post(`urlApi`, this.dados).then(res => {
      this.result = res;
      return res;
  })
}

I assume the method here is storing a result from the server. Maybe you don't want that; it is just an example. I'll come back to it later.

Ok, so now, you could call onSubmitClient in your wrapper and see if this.result is already set. As you already know, this does not work straightforward.

In order for a jest test to wait for asynchronous code, you need either to provide a done callback function or return a promise. I'll show an example with the former:

it('store client', (done) => {
  wrapper.vm.onSubmitLogin().then((res) => {
    expect(wrapper.vm.dados).toEqual(res);
    done();
  })
});

Now this code should just work, but still there is an issue with it, as @jonsharpe says in a comment.

You usually don't want to perform real network requests in unitary tests because they are slow and unrealiable. Also, unitary tests are meant to test components in isolation, and here we are testing not only that our component sets this.result properly when the request is made. We are also testing that there is a webserver up and running that is actually working.

So, what I would do in this scenario to test that single piece of functionality, is to extract the request to another method, mock it with vue-test-utils and jest.fn, and then assert that onSubmitClient does its work:

The component:

export default {
  data() {
    return {
      http: axios,
      ...
    },
    methods: {

      onSubmitClient(){
        this.http.post(`urlApi`, this.dados).then(res => {
            this.result = res;
        })
      }
    }
  }
}

The test:

it('store client', (done) => {
  const fakeResponse = {foo: 'bar'};
  var post = jest.fn();
  var http : {
    post,
  };
  var wrapper = mount(client, {
    stubs: ['router-link'],
    store,
    data() {
      return {
        dados: {
            name: 'tes name',
            city: 'test city'
        },
        http, //now, the component under test will user a mock to perform the http post request.
      }
      }
  });
  wrapper.vm.onSubmitLogin().then( () => {
    expect(post).toHaveBeenCalled();
    expect(wrapper.vm.result).toEqual(fakeResponse);
    done();
  })

});

Now, your test asserts two things:

  1. post gets called.
  2. this.result is set as it should be.

If you don't want to store anything in your component from the server, just drop the second assertion and the this.result = res line in the method.

So basically this covers why your test is not waiting for the async request and some issues in your code. There are still some things to consider (f.i. I think a global wrapper is bad idea, and I would always prefer shallowMount over mount when testing components behavior), but this answer should help you a lot.

PS: didn't test the code, so maybe I messed up something. If the thing just doesn't work, look for syntax errors or similar issues.

like image 161
Sergeon Avatar answered Feb 04 '23 08:02

Sergeon