Vuex with Jest - this.$store.getters.<getterName> is not a function

11,282

The getters of a store are just like computed properties on components, they are defined using functions but accessed as properties, without the parentheses.

Given this line:

return this.$store.getters.questions(this.pageNumber);

it would appear that your questions getter is returning a function that accepts a pageNumber. That isn't what you're currently defining in your test getter, you're just returning an array.

So either the invocation needs to change to use square brackets:

return this.$store.getters.questions[this.pageNumber];

or the getter needs to return a function:

getters = {
    questions: () => () => [
        { type: 'Radio', config: { label: 'Test label', options: [{ label: 'Test option label' }] }, validation: [] }
    ]
};

If it helps to clarify, this is equivalent to:

getters = {
    questions: function () {
        return function () {
            const questions = [
                { type: 'Radio', config: { label: 'Test label', options: [{ label: 'Test option label' }] }, validation: [] }
            ];

            return questions;
        };
    }
};

Note that I'm completely ignoring the passed pageNumber as I assume your test getter is hard-coded to return the correct array of questions.

You may wish to consult with the non-test version of this getter as I expect you'll see it returns an extra level of function.

Share:
11,282
Robkwood
Author by

Robkwood

Updated on June 19, 2022

Comments

  • Robkwood
    Robkwood almost 2 years

    I'm working on a survey builder in Vue, and survey questions which the user creates are committed to Vuex so they can be retrieved later like so:

    computed: {
      inputs() {
        return this.$store.getters.questions(this.pageNumber);
      },
    },
    

    pageNumber is a prop the component receives and inputs() returns an array of questions. This all seems to work in terms of rendering the correct questions on screen but I'm having trouble with Jest tests.

    In order to test I was hoping I could mock the store with getters like my attempt below (omitting some parts):

    const localVue = createLocalVue();
    localVue.use(Vuex);
    
    beforeEach(() => {
      state = {
        survey: {
          pages: [
            // pages objects
          ],
        },
      };
    
      getters = {
        questions: () => [
          { type: 'Radio', config: { label: 'Test label', options: [{ label: 'Test option label' }] }, validation: [] },
        ],
      };
    
      store = new Vuex.Store({
        state,
        getters,
      });
    });
    

    But this results in the error:

    TypeError: this.$store.getters.questions is not a function
    

    However, removing that arrow function from getters.questions gives me:

    [vuex] getters should be function but "getters.questions" is [{"type":"Radio","config":{"label":"Test label","options":[{"label":"Test option label"}]},"validation":[]}].
    

    So I think I could be completely misunderstanding. Could someone point me in the right direction?

  • Robkwood
    Robkwood over 5 years
    Thanks very much for this, that makes sense and you're right that my getter returns a function. Modifying the invocation would break a few things so I've decided to modify the test getter to return a function as you suggested, and am now getting "TypeError: Cannot read property 'questions' of undefined". I presume this is to do with the way I've structured my store/getters? However it seems to be working in the actual UI of the application. Apologies, I'm probably missing something obvious!
  • gyc
    gyc about 2 years
    "the getter needs to return a function": helped me in 2022.