Search code examples
unit-testingvue.jsmocha.jsvuex

How to access namespaced Vuex getters in Mocha unit test


I am building a new Vue component that uses a namespaced Vuex getter to access a list of column names. The actual component compiles and runs.

In my Mocha unit tests, I created a mocked getter that returns a list of strings called "allColumns". When I run the unit tests, during ShallowMount, the component's methods try to access this.allColumns during initialization, but the value is always undefined. I can see the value I want in this.$store.getters.allColumns, but it is not getting mapped to this.allColumns like it does when I open the page in a browser.

There is a lot of information out there about how to mock getters in a test and how to use mapGetters with a namespace, but I have not found any documentation about namespaced getters in a Mocha test.

test.spec.js

  let propsData;
  let getters;
  let store;

  beforeEach(() => {
    debugger;
    propsData = {
      players: samplePlayerObject,
      metadata: sampleMetadataObject
    };

    getters = {
      allColumns: () => ["playerid","last","first","birthday","height"]
    }

    store = new Vuex.Store({
      getters
    });
  })

  it('initializes the component', () => {
    const wrapper = shallowMount(PlayerFilterTable, { propsData, localVue, store });
  });

vue component


<template>
  <div class="player-filter-table">
    <table>
      <tr>
         <th v-for="(key, index) in GetColumns()" 
            v-bind:id="'header-' + key" 
            v-bind:key="index"
            @click="HeaderClick(key)"
          >...</th>
      </tr>
    </table>
  </div>
</template>

<script>
import { mapGetters } from 'vuex';
export default {
  computed: {
    ...mapGetters({
      allColumns: 'playerFilter/allColumns'
    })
  },
GetColumns() {
  // this.allColumns is defined when running in browser, but undefined when loaded from a Mocha test
  return this.allColumns.filter(column => [*some filter criteria*]);
}
</script>

When shallowMount runs in test.spec.js, I expect the component to load successfully and then continue on to run my tests, but instead I get an error that says TypeError: Cannot read property 'filter' of undefined because this.allColumns is not defined.


Solution

  • Use modules with namespaced: true:

    import { createLocalVue, shallowMount } from '@vue/test-utils';
    import Vuex from 'vuex';
    import PlayerFilterTable from '~/whatever';
    
    const localVue = createLocalVue();
    localVue.use(Vuex);
    
    let propsData, getters, store, wrapper, consoleSpy;
    
    describe('PlayerFilterTable', () => {
    
      beforeEach(() => {
        consoleSpy = jest.spyOn(console, 'error');
        propsData = {
          players: samplePlayerObject,
          metadata: sampleMetadataObject
        };
        getters = {
          allColumns: () => ["playerid", "last", "first", "birthday", "height"]
        };
        store = new Vuex.Store({
          modules: {
            playerFilter: {
              namespaced: true,
              getters
            }
          }
        });
        wrapper = shallowMount(PlayerFilterTable, {
          propsData,
          localVue,
          store
        });
      });
    
      afterEach(() => {
        expect(consoleSpy).not.toHaveBeenCalled();
      });
    
      it('should render correctly', () => {
        expect(wrapper.is(PlayerFilterTable)).toBe(true);
        expect(wrapper.html()).toMatchSnapshot();
      })
    })
    

    If you use getters from more than one module you could group them up under different props of getters and assign to each module accordingly.