How to unit test Vuex modules defined with the vuex-module-decorators syntax in Nuxt, using vue-test-utils and Jest?

Cover photo by Tien Vu Ngoc on Unsplash

The problem

To find the answer to my question I went through the official Nuxt documentation and through the existing Stack Overflow and Github issue discussions.

But with no luck.

It appeared as i…

Cover photo by Tien Vu Ngoc on Unsplash



The problem

To find the answer to my question I went through the official Nuxt documentation and through the existing Stack Overflow and Github issue discussions.

But with no luck.

It appeared as if no one before me stumbled upon this issue (which I find somewhat hard to believe).

My AuthModule looks something like this:

@Module({
  stateFactory: true,
  namespaced: true,
})
export default class AuthModule extends VuexModule {
  userData?: UserData | undefined = undefined;
  prevRouteList: Routes[] = [];
  error?: services.ICognitoError | undefined = undefined;
  isLoading = false;
  ...

  @VuexMutation
  setIsLoading(isLoading: boolean) {
    this.isLoading = isLoading;
  }

  ...

   @VuexAction({ rawError: true })
  async register(registerData: { email: string; password: string }): Promise<any> {
    this.context.commit('setIsLoading', true);
    this.context.commit('setError', undefined);
    this.context.commit('setInitiateRegistration', false);
    this.context.dispatch('setEmail', registerData.email);

    try {
      const { user } = await services.register(registerData.email, registerData.password);

      if (user) {
        this.context.dispatch('pushPrevRoute', Routes.emailVerification);
        this.context.commit('setInitiateRegistration', true);
      }
    } catch (error: any) {
      this.context.commit('setError', error);
      this.context.commit('setInitiateRegistration', false);
    }

    this.context.commit('setIsLoading', false);
  }

  ...

  @MutationAction
  setEmail(email: string)  { ... }

  ... 

  get getEmail() {
    return this.email;
  }

  ... 

}



Solution

After some trial and error I finally discovered the answer to my question.

The implementation looks like this:

// auth.spec.ts

import Vuex, { Store } from 'vuex';
import { createLocalVue } from '@vue/test-utils';

import AuthModule, { IState } from './auth';

jest.mock('@/services');

const localVue = createLocalVue();
localVue.use(Vuex);

const storeOptions = {
  modules: {
    auth: AuthModule,
  },
};

const createStore = (storeOptions: any = {}): Store<{ auth: IState }> => new Vuex.Store({ ...storeOptions });

describe('AuthModule', () => {
  let store: Store<{ auth: IState }>;

  beforeEach(() => {
    store = createStore(storeOptions);
  });

  describe('mutations', () => {
    // ...

    it('auth/setIsLoading', () => {
      expect(store.state.auth.isLoading).toBe(false);
      store.commit('auth/setIsLoading', true);
      expect(store.state.auth.isLoading).toBe(true);
    });

    // ...
  });

  describe('actions', () => {
    // ...

    it('register success', async () => {
      const registerData = {
        email: 'dummy@email.com',
        password: 'dummy',
      };

      expect(store.state.auth.registrationInitiated).toBe(false);

      try {
        await store.dispatch('auth/register', registerData);
        expect(store.state.auth.registrationInitiated).toBe(true);
      } catch (error) {}
    });

    // ...
  });

  describe('mutation-actions', () => {
    // ...

    it('setEmail', async () => {
      const dummyEmail = 'dummy@email.com';

      expect(store.state.auth.email).toBe('');
      await store.dispatch('auth/setEmail', dummyEmail);
      expect(store.state.auth.email).toBe(dummyEmail);
    });

    // ...
  });

  describe('getters', () => {
    // ...

    it('auth/getError', () => {
      expect(store.state.auth.error).toBe(undefined);
      expect(store.getters['auth/getError']).toBe(undefined);

      (store.state.auth.error as any) = 'Demmo error';
      expect(store.getters['auth/getError']).toBe('Demmo error');
    });

    // ...
  });
});

// services/auth

export async function register(email: string, password: string, attr: any = {}): Promise<any> {
  try {
    return await Auth.signUp({
      username: email,
      password,
      attributes: {
        ...attr,
      },
    });
  } catch (err: any) {
    return Promise.reject(createError(err, 'register'));
  }
}

// createError is just a util method for formatting the error message and wiring to the correct i18n label

// services/__mock__/auth

import { createError } from '../auth';

export const register = (registerData: { email: string; password: string }) => {
  try {
    if (!registerData) {
      throw new Error('dummy error');
    }

    return new Promise((resolve) => resolve({ response: { user: registerData.email } }));
  } catch (err) {
    return Promise.reject(createError(err, 'register'));
  }
};

The most important thing to realise is that the vuex-module-decorators class-based model behaves just like a vue-class-component under the hood.

All of the class-based stuff is just syntactic sugar – a wrapper around the vue-class-component API.

To quote the docs:

In your store, you use the MyModule class itself as a module…The way we use the MyModule class is different from classical object-oriented programming and similar to how vue-class-component works. We use the class itself as module, not an object constructed by the class

Another thing to keep in mind is to use createLocalVue, which enables us to use Vue classes, plugins, components etc. without polluting the global Vue class.

Adding the Vuex plugin to createLocalVue:

localVue.use(Vuex);

The AuthModule class is declared as a Vuex (namespaced) module inside the Vuex.Store constructor (as per docs).

const storeOptions = {
  modules: {
    auth: AuthModule,
  },
};

const createStore = (storeOptions: any = {}): Store<{ auth: IState }> => new Vuex.Store({ ...storeOptions });

In the implementation above, AuthModule (incl. store, actions, mutations, getters…) is re-created inside every test case with the help of the beforeEach hook (to have a clean store in every new iteration).

The rest is pretty straightforward.

You can clearly see how I tested each part of the AuthModule (actions, mutations, getters..).

That’s it. Happy testing 🙂


Print Share Comment Cite Upload Translate
APA
Ivan Spoljaric | Sciencx (2024-03-28T19:35:02+00:00) » How to unit test Vuex modules defined with the vuex-module-decorators syntax in Nuxt, using vue-test-utils and Jest?. Retrieved from https://www.scien.cx/2021/09/28/how-to-unit-test-vuex-modules-defined-with-the-vuex-module-decorators-syntax-in-nuxt-using-vue-test-utils-and-jest/.
MLA
" » How to unit test Vuex modules defined with the vuex-module-decorators syntax in Nuxt, using vue-test-utils and Jest?." Ivan Spoljaric | Sciencx - Tuesday September 28, 2021, https://www.scien.cx/2021/09/28/how-to-unit-test-vuex-modules-defined-with-the-vuex-module-decorators-syntax-in-nuxt-using-vue-test-utils-and-jest/
HARVARD
Ivan Spoljaric | Sciencx Tuesday September 28, 2021 » How to unit test Vuex modules defined with the vuex-module-decorators syntax in Nuxt, using vue-test-utils and Jest?., viewed 2024-03-28T19:35:02+00:00,<https://www.scien.cx/2021/09/28/how-to-unit-test-vuex-modules-defined-with-the-vuex-module-decorators-syntax-in-nuxt-using-vue-test-utils-and-jest/>
VANCOUVER
Ivan Spoljaric | Sciencx - » How to unit test Vuex modules defined with the vuex-module-decorators syntax in Nuxt, using vue-test-utils and Jest?. [Internet]. [Accessed 2024-03-28T19:35:02+00:00]. Available from: https://www.scien.cx/2021/09/28/how-to-unit-test-vuex-modules-defined-with-the-vuex-module-decorators-syntax-in-nuxt-using-vue-test-utils-and-jest/
CHICAGO
" » How to unit test Vuex modules defined with the vuex-module-decorators syntax in Nuxt, using vue-test-utils and Jest?." Ivan Spoljaric | Sciencx - Accessed 2024-03-28T19:35:02+00:00. https://www.scien.cx/2021/09/28/how-to-unit-test-vuex-modules-defined-with-the-vuex-module-decorators-syntax-in-nuxt-using-vue-test-utils-and-jest/
IEEE
" » How to unit test Vuex modules defined with the vuex-module-decorators syntax in Nuxt, using vue-test-utils and Jest?." Ivan Spoljaric | Sciencx [Online]. Available: https://www.scien.cx/2021/09/28/how-to-unit-test-vuex-modules-defined-with-the-vuex-module-decorators-syntax-in-nuxt-using-vue-test-utils-and-jest/. [Accessed: 2024-03-28T19:35:02+00:00]
rf:citation
» How to unit test Vuex modules defined with the vuex-module-decorators syntax in Nuxt, using vue-test-utils and Jest? | Ivan Spoljaric | Sciencx | https://www.scien.cx/2021/09/28/how-to-unit-test-vuex-modules-defined-with-the-vuex-module-decorators-syntax-in-nuxt-using-vue-test-utils-and-jest/ | 2024-03-28T19:35:02+00:00
https://github.com/addpipe/simple-recorderjs-demo