3 min read

Quasar unit test with vitest - Axios Mock and vuex test

Quasar unit test with vitest - Axios Mock and vuex test
Quasar logo https://quasar.dev

When we want to test the vuex store, and we have calls to APIs using axios, we need to create a mock to simulate those calls, in this article we will see how to do it and some use cases.

Vuex test

Vuex has the advantage that they are simple java script files, so they are easy to integrate and even test. The following example is a test on a vuex module for user authentication.

Module: https://github.com/ta-vivo/ta-vivo/tree/master/src/store/Auth
import { describe, it, expect } from 'vitest'
import { createStore } from 'vuex'

import Auth from 'stores/Auth/index.js'

const user = {
  id: 1,
  email: 'jhon@doe.com',
  fullname: 'Jhon Doe',
  active: true, enabled: true,
  role: 'pro',
  settings: {},
  timezone: 'UTC'
}

const store = createStore({
  modules: {
    Auth
  }
});

describe('Auth store', () => {
  it('should set user', () => {

    store.commit('Auth/SET_USER', user);
    expect(store.state.Auth.user).toEqual(user);
  })

  it('should get user', () => {
    expect(store.getters['Auth/getUser']).toEqual(user);
  })

  it('should be login success', () => {
    store.dispatch('Auth/login', { email: 'jhon@doe.com', password: '123456' })
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })

  })

  it('should be login with google', () => {
    store.dispatch('Auth/google', { access_token: '123456', timezone: 'UTC' })
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })
  })

  it('should be login with discord', () => {
    store.dispatch('Auth/discord', { access_token: '123456', timezone: 'UTC' })
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })
  })

  it('should be login with slack', () => {
    store.dispatch('Auth/slack', { access_token: '123456', timezone: 'UTC' })
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })
  })

  it('should be login with github', () => {
    store.dispatch('Auth/github', { access_token: '123456', timezone: 'UTC' })
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })
  })

  it('should be register', () => {
    store.dispatch('Auth/register', { email: 'jhon@doe.com', password: '123456', confirmPassword: '123456', fullname: 'Jhon Doe' })
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })

  })

  it('should be register email confirmation', () => {
    store.dispatch('Auth/registerEmailConfirmation', { uniqueCode: '123456' })
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })
  })

  it('should be request register email confirmation', () => {
    store.dispatch('Auth/requestRegisterEmailConfirmation')
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })
  })

  it('should be request reset password', () => {
    store.dispatch('Auth/forgotPassword', { email: 'jhon@doe.com' })
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })
  })

  it('should be change password', () => {
    store.dispatch('Auth/recoverPassword', { email: 'jhon@doe.com', oldPassword: '123456', password: '123456', confirmPassword: '123456' })
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })
  })

  it('should be recover password', () => {
    store.dispatch('Auth/recoverPassword', { email: 'jhon@doe.com', uniqueCode: '123456', password: '123456', confirmPassword: '123456' })
      .then(() => {
        expect(store.state.Auth.user).toEqual(user);
      })
  })

})

We run the yarn test command, and we will not see anything wrong in the console and all the tests will be green, but if you go to an environment like GitHub actions you will see a series of errors and false positives.

⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯

Vitest caught 11 unhandled errors during the test run.
This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.

⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
Error: connect ECONNREFUSED 127.0.0.1:80
 ❯ TCPConnectWrap.afterConnect [as oncomplete] node:net:1247:16


⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
Error: connect ECONNREFUSED 127.0.0.1:80
 ❯ TCPConnectWrap.afterConnect [as oncomplete] node:net:1247:16

...
Example: https://github.com/ta-vivo/ta-vivo/actions/runs/3277700198/jobs/5395282378

For this we will create a mock for axios inside the /tests/mosks/ directory

  import { vi } from 'vitest'

  vi.mock('axios', () => ({
    default: ({
      create: () => ({
        interceptors: {
          request: { use: vi.fn(), eject: vi.fn() },
          response: { use: vi.fn(), eject: vi.fn() }
        },
        get: vi.fn((route) => {
          return Promise.resolve({ route: route, data: [] })
        }),
        post: vi.fn((route, data) => {
          return Promise.resolve({ route: route, data: data })
        }),
        put: vi.fn((route, data) => {
          return Promise.resolve({ route: route, data: data })
        }),
        delete: vi.fn((route) => {
          return Promise.resolve({ route: route, data: [] })
        })
      })
    })
  }))

As soon as we have the mock we will only have to import it in our test

import { describe, it, expect } from 'vitest'
import { createStore } from 'vuex'
import '../mocks/axios' // the mock

// rest of the code...
Example: https://github.com/ta-vivo/ta-vivo/blob/master/tests/store/auth.test.js