winklerrr
winklerrr

Reputation: 14737

Mock axios in a Vue application for frontend testing

When testing the frontend of my Vue application, I sometimes want to skip the communication with the API backend.

I came up with the following idea:

The easy way would be to add an check before every call of axios.post(...) or axios.get(...), but I don't want to have to add code in every api function I wrote. So I thought about using the interceptors of axios, but I think it's not possible to stop a request, and just return mocked data, right?

I then thought about wrapping axios, and dynamically returning the real axios instance or a mocked one, which also implements the .post(), .get() and all the other axios functions based on the Store state. I thought about something like this (I'm working with TypeScript):

import store from '@/vuex-store'

const axios = Axios.create( // real store config );
const axiosMock = {
  get(path: string) {
    if (path == '/test') {
      return Promise.resolve( // mocked data );
    }

    return Promise.resolve(true)
  }
}

class AxiosWrapper {
  get instance() {
    if (store.state.skipServerCommunication) {
      return axiosMock;
    }

    return axios
  }
}

export default new AxiosWrapper();

But this solution has some problems:

  1. I need to replace all axios calls with axiosWrapper.instance.get(...). Can I somehow avoid this and mock axios in a way that I can still work with axios.get(...)?
  2. VSCode isn't able to provide autocompletion anymore because the returned instance is either of type AxiosStatic or "MyMockType". So I thought about implementing the AxiosStatic interface, but I struggle to do that correctly because of the two anonymous functions in the AxiosInstance interface. Is there an alternative way to overcome this problem?

Upvotes: 2

Views: 3496

Answers (1)

tony19
tony19

Reputation: 138286

Use axios-mock-adapter instead. You can mock axios calls as needed per test, using advanced matching patterns.

Example usage:

import axios from 'axios'
import MockAdapter from 'axios-mock-adapter'

describe('UserList', () => {
  it('gets users on mount', async () => {
    const mock = new MockAdapter(axios)
    mock.onGet('/users').reply(200, {
      users: [{ id: 1, name: 'John Smith' }],
    })

    const wrapper = shallowMount(UserList)
    await wrapper.find('.getUsersBtn').trigger('click')
    expect(wrapper.vm.users[0].id).toBe(1)
  })
})

Upvotes: 3

Related Questions