VUE

How to Mock an AXIOS call with Jest in vue tests utils

In this post, we will see how to mock an Axios call with Jest in vue-test-utils library.

For this article, let’s create a Posts.vue component which will call the JSONPlaceholder’s /posts API. The /posts API will return an array of objects. Each object in the array is a post with id, title and body.

Here is our posts component

<template>
  <ul v-if="posts && posts.length">
    <li v-for="post of posts" :key="post.id">
      <p>
        {{ post.id }}: <strong>{{ post.title }}</strong>
      </p>
      <p>{{ post.body }}</p>
    </li>
  </ul>
</template>

<script>
import axios from "axios";

export default {
  name: "Posts",
  data() {
    return {
      posts: []
    };
  },

  async created() {
    const response = await axios.get(
      `http://jsonplaceholder.typicode.com/posts`
    );
    this.posts = response.data;
  }
};
</script>

So, in the created hook we will make a call to the REST API and assign the response data to the posts variable. If we run the app, it should work fine.

Let’s mock the API call.

Mocking an AXIOS call

Calling axios.get will return a promise and will resolve to either a response object or an error object.

To mock the get call on axios in our component, we have to resolve the promise and set up our custom response data in the test file (*.spec.js).

jest.mock("axios", () => ({
  get: () => Promise.resolve({ data: [{ val: 1 }] })
}));

We should add the above snippet before we write anything to test.

Let’s write our test now to see check the data in posts.

jest.mock("axios", () => ({
  get: () => Promise.resolve({ data: [{ val: 1 }] })
}));

describe("Posts.vue", () => {
  it("mocking the axios call to get posts should work", () => {
    var wrapper = shallowMount(Posts);
    expect(wrapper.vm.posts.length).toBe(1);
  });
});

The wrapper object contains events, data, and everything related to the component. The vm on the wrapper will have the data in the posts variable.

We will assert the length of the posts to be 1. But, if we run the above tests, it will fail.

 Expected: 1
 Received: 0

Asynchronous behavior caused the test to fail

The test failed because our mocked promise has not resolved by the time we assert the data in the posts.

There are two ways to fix this. (If you know any other way around, please leave it in the comments)

1. using a $nextTick or setTimeout to assert

If we assert in the $nextTick or in setTimeout callbacks then the test will succeed.

it("mocking the axios call to get posts should work", () => {
    var wrapper = shallowMount(Posts);
    wrapper.vm.$nextTick(() => {
      expect(wrapper.vm.posts.length).toBe(1);
    });
  });

This is because $nextTick schedules a micro task (runs after the function or program that created exits), and by the time it executes our callback code, the promise is resolved.

A similar thing happens for the setTimeout, except that setTimeout queues a task. This task will be executed after it’s time out is complete and after the microtask is completed. So, we will have the promise resolved by the time we get to the setTimeout callback code.

So, asserting in a setTimeout or $nextTick would pass the test as we will have our promise resolved and the posts variable is loaded with the response data.

If you want to understand more about micro tasks, tasks, queues, etc. Read this article.

2. using flushPromises library

The flushPromises library resolves all the pending promise handlers. This is an alternative to using setTimeout or $nextTick.

First, we have to install the flushPromises library with the following command in NPM:

npm i flush-promises

After installing, import the library into the tests and call flushPromises function before asserting.

import { shallowMount } from "@vue/test-utils";
import flushPromises from "flush-promises";
import Posts from "@/components/Posts";

jest.mock("axios", () => ({
  get: () => Promise.resolve({ data: [{ val: 1 }] })
}));

describe("Posts.vue", () => {
  it("mocking the axios call to get posts should work", async () => {
    var wrapper = shallowMount(Posts);
    await flushPromises();
    expect(wrapper.vm.posts.length).toBe(1);
  });
});

Be sure to mock what we expect while mocking the axios calls

Technically, you can mock anything as the return value of the axios call and assert what you’ve set as mock data.

In this blog post, we have taken the example of blog posts from Json placeholder’s API. The API will return an array of objects. Each object will have an id, title, and body.

The typical response would be

[
  {
    "userId": 1,
    "id": 1,
    "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
    "body": "abc"
  },
  {
    "userId": 1,
    "id": 2,
    "title": "qui est esse",
    "body": "xyz"
  }
]

But, in our test (s) we mocked our Axios call to return an array of a single item with val property.

Our created hook does not have any logic in it. So, the tests worked out. But, if the code has anything to do with the response from Axios then our tests may have failed. Or instead of checking for the data in the posts variable, if we assert the rendered values, then our test would have failed.

So, better mock with the data you expect from the axios response.

References

Disqus Comments Loading...
Share
Published by
Karthik Chintala

Recent Posts

2 Good Tools To Test gRPC Server Applications

In this post, we’ll see how to test gRPC Server applications using different clients. And… Read More

2 years ago

Exploring gRPC project in ASP.NET Core

In this post, we'll create a new gRPC project in ASP.NET Core and see what's… Read More

2 years ago

Run dotnet core projects without opening visual studio

In this blog post, we’ll see how to run dotnet core projects without opening visual… Read More

2 years ago

Programmatically evaluating policies in ASP.NET Core

Programmatically evaluating policies is useful when we want to provide access or hide some data… Read More

2 years ago

Multiple authorization handlers for the same requirement in ASP.NET Core

We saw how we could set up policy-based authorization in our previous article. In this… Read More

2 years ago

Policy-Based Authorization in ASP.NET Core

What is policy-based authorization and how to set up policy-based authorization with handlers and policies… Read More

2 years ago

This website uses cookies.