javascript - Mocka axios i en Vue-applikation för frontend-testning


När jag testar frontend av min Vue-applikation vill jag ibland hoppa över kommunikationen med API-backend.

Jag kom på följande idé:

  • lägg till state i Vuex store: skipServerCommunication.
  • när skipServerCommunication=false: skicka axios-förfrågan som förväntat
  • när skipServerCommunication=true: returnera mockade data

Det enkla sättet skulle vara att lägga till en kontroll innan varje anrop av axios.post(...) eller axios.get(...), men jag vill inte behöva lägga till kod i varje API-funktion jag skrev. Så jag tänkte på att använda interceptors i axios, men jag tror inte att det är möjligt att stoppa en förfrågan och bara returnera påhittad data, eller hur?

Jag tänkte då på att kapsla in axios och dynamiskt returnera den verkliga axios-instansen eller en mockad sådan, som också implementerar .post(), .get() och alla andra axios-funktioner baserat på Store-tillståndet. Jag tänkte på något i stil med detta (jag arbetar med 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();

Men den här lösningen har vissa problem:

  1. Jag behöver ersätta alla axios-anrop med axiosWrapper.instance.get(...). Kan jag på något sätt undvika detta och mocka axios på ett sätt så att jag fortfarande kan arbeta med axios.get(...)?
  2. VSCode kan inte längre ge automatisk komplettering eftersom den returnerade instansen antingen är av typen AxiosStatic eller "MyMockType". Så jag funderade på att implementera AxiosStatic-gränssnittet, men jag har svårt att göra det korrekt på grund av de två anonyma funktionerna i AxiosInstance-gränssnittet. Finns det ett alternativt sätt att övervinna detta problem?

Svar #1

Använd axios-mock-adapter istället. Du kan mocka axios-anrop efter behov per test, med avancerade matchningsmönster.

Exempel på användning:

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)
  })
})