Testing VueX getters that rely on other getters in unit tests

I have successfully tested Vuex getters in isolation from other code, but I am encountering challenges when a getter relies on other getters. Here is an example to illustrate this situation:

getters.js

export const getters = {

  getFoo(state) => prefix {
    return `${prefix}: ${state.name}`;
  },

  getFancyNames(state, getters) {
    return [
      getters.getFoo('foo'),
      getters.getFoo('bar')
    ]
  }
}

getters.spec.js

import { getters } = './getters';

const state = {
  name: 'stackoverflow'
};

describe('getFoo', () => {

  it('return name with prefix', () => {
    expect(getters.getFoo(state)('name')).toBe('name: stackoverflow');
  });

});

describe('getFancyNames', () => {

  // mock getters
  const _getters = {
    getFoo: getters.getFoo(state)
  }

  it('returns a collection of fancy names', () => {
    expect(getters.getFancyNames(state, _getters)).toEqual([
      'foo: stackoverflow',
      'bar: stackoverflow'
    ]);
  });
});

When a tested getter depends on another getter that requires arguments, it leads to referencing the original getter.getFoo in the mock, breaking the purpose of mocking and creating interdependent tests. As the dependency graph of getters becomes more complex, the tests become harder to manage.

Perhaps this is the correct approach, but I want to ensure that I am not overlooking any other solutions...

Answer №1

I completely agree that including the actual collaborator in your mock defeats the purpose of a mock. Instead, it is more effective to directly return the desired result from the collaborator.

For instance, instead of coding mock getters like this:

// mock getters
const _getters = {
  getFoo: getters.getFoo(state)
}

You can simply assign the expected return value directly:

const _getters = {
    getFoo: 'foobar' 
}

If your getter requires an additional argument, you can create a function that always returns a constant value:

const _getters = {
    getFoo: x => 'foobar',
}

Answer №2

When utilizing Jest, there is a convenient option available in the jest mock function that allows for specifying the return value when called:

mockReturnValueOnce or mockReturnValue

For more detailed information on this feature, refer to: https://facebook.github.io/jest/docs/en/mock-functions.html#mock-return-values

To implement this with the same code provided in the question, one could address it as follows:

const state = {
  name: 'stackoverflow'
}

describe('getFancyNames', () => {
  const getFoo = jest.fn()
  getFoo.mockReturnValueOnce('foo: stackoverflow')
  getFoo.mockReturnValueOnce('bar: stackoverflow')

  it('returns a collection of fancy names', () => {
    expect(getters.getFancyNames(state, { getFoo })).toEqual([
      'foo: stackoverflow',
      'bar: stackoverflow'
    ])
  })
})

Answer №3

A more organized approach that I have discovered involves creating a custom mocked getters object. This method is effective when the getter function relies solely on the original state without any modifications.

const state = {
  name: 'stackoverflow'
}

describe('getFancyNames', () => {
  const mockedGetters = {
    ...getters,  // You can exclude this line if not necessary
    getFoo: getters.getFoo(state),  // Only override what is essential
  };

  it('returns a collection of fancy names', () => {
    expect(getters.getFancyNames(state, mockedGetters)).toEqual([
      'foo: stackoverflow',
      'bar: stackoverflow'
    ])
  })
})

Additional Info

In scenarios where you need to utilize other getter functions, pass the mocked getters objects into another mock getters object. It may sound complicated but is actually quite simple.

getters.py

export const getters = {

  getBar(state) = {   // Handle with care!
    return state.bar,
  },

  getFoo(state, getters) => prefix {
    return `${prefix}: ${state.name} with some ${getters.getBar}`;
  },

  getFancyNames(state, getters) {
    return [
      getters.getFoo('foo'),
      getters.getFoo('bar')
    ]
  }
}
const _mockedGetters = {
  ...getters,  // Exclude if unnecessary
  getFoo: getters.getFoo(state),  // Only include required overrides
};

const mockedGetters = {
  .._mockedGetters,  // Utilize the mocked object!
  getBar: getters.getBar(state, _mockedGetters),  // Only extend as needed
};

// Proceed accordingly!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using ng-repeat can cause conflicts with jQuery function calls

I implemented a combination of AngularJS and MaterializeCSS to display images using ng-repeat. MaterializeCSS comes with a jQuery-based materiabox function that triggers an animation to open a modal for each element with the materialbox class. However, I ...

PhpStorm does not currently support types in JavaScript

Currently, I am using PhpStorm for a Vue 2 / TypeScript project. However, whenever I attempt to add return types to functions, I encounter the error message "Types are not supported by current JavaScript version": https://i.sstatic.net/ct3gu.png In the " ...

Exploring the dichotomy between controlled and uncontrolled elements within React. The _class attribute causing unexpected changes in an un

I created a custom Checkbox component that is essentially a styled checkbox with a 'fake element' acting as the original one. Custom Checkbox Component import React, {Component} from 'react'; import FormGroup from 'react-bootstra ...

Error encountered in Vue code, lacks default export on Editor Terminal

I'm not experiencing any issues in the browser, I am getting the desired output. However, why does this keep showing up in the editor terminal? Any assistance would be greatly appreciated. Error - No Default Export: The module "/vue3/src/components/ ...

Tips for showcasing several thumbnails simultaneously as you upload images on a webpage with HTML and JavaScript

function displayImage(input) { if (input.files && input.files[0]) { var reader = new FileReader(); reader.onload = function(e) { $('#selectedImage') .attr('src', e.target.result) }; reader.read ...

Does React JS set initial value after re-rendering its state?

Every time the state is updated, the function is triggered once more (please correct me if I am mistaken). And since the initial line of the App function sets the state, the values of data and setData will not revert to their defaults. For instance, i ...

In what scenarios would you choose to use "class" instead of "id"?

I am currently utilizing Bootstrap to style my table, which serves as a basic to-do list. My intention is to insert a form input into one cell and place a check button in the cell adjacent to it on the right side. To achieve this, I plan to utilize id="che ...

The audio directory is not included in the build of the Ionic framework, causing it to be skipped and absent

Recently, I've been working on an Ionic/Cordova app and came across a folder labeled /audio which consists of mp3 files: /www /assets /audio file.mp3 /css /js config.xml index.html The issue at hand is that the /audio directory is n ...

Safeguard your Firebase database listeners against potential web DOS attacks and unauthorized access to sensitive credentials

Firebase is such a game-changer on mobile devices, but it's not always the best fit for web applications. This is common knowledge. I rely on firebase My users are aware of the database URL They can view certain aspects of the database that I'v ...

Updating the active navbar link with JavaScript in ASP.NET Core Razor Pages

When navigating through my Razor Pages, I need to dynamically change the color of the navbar links. I attempted using JavaScript, but encountered issues with the pages getting rerendered each time, preventing me from toggling the elements. Here's wha ...

Create custom AngularJS directives for validation and store them in a variable

Through the use of AngularJS, I've developed a directive called "integer" that invalidates a form if anything other than integers are entered. Because I'm generating the page dynamically by fetching data from the database, it would be helpful to ...

Ensure that the class is applied only when the current object in VUE is not functioning properly

Currently, I am attempting to create a dynamic class in Vue that will only be triggered if the selected category matches the current category. https://i.sstatic.net/w64za.png Even though I have set it up so that when a user clicks on any category, the cl ...

Asynchronous JavaScript function within a loop fails to refresh the document object model (DOM) despite

I have been working on a function that utilizes ajax to retrieve instructions from a backend server while the page is loading. The ajax code I've written retrieves the instructions based on the number provided and displays them using the response.setT ...

How can I locally store 3D models and textures using three.js?

Currently working on a game using three.js, where each game level is on a different page. However, when transitioning from one level to another, the browser reloads the page which can be quite slow. Is there a way to store 3D models locally so they don&apo ...

Utilize jQuery to restrict decimal places to only 1

Whether to round or truncate: <div class="my-val">1.334</div> <div class="my-val">12.133</div> The output should be: 1.3 12.1 ...

From HTML to Mat Table: Transforming tables for Angular

I am currently facing a challenge with my HTML table, as it is being populated row by row from local storage using a for loop. I am seeking assistance in converting this into an Angular Material table. Despite trying various suggestions and codes recommend ...

Obtaining JSON Data Using WinJS.xhr():

I'm encountering difficulties with retrieving chat messages using winjs.xhr: function getMessage() { var time = MESSAGE_RETURNED.unixtime; if (time == 0) { time= window.parent.SESSION.unixtime; } WinJS.x ...

AJAX request stops functioning once the page is reloaded

As a beginner in JavaScript, I am facing an issue with my AJAX call. I have set up the call to process a back-end function when a button is clicked and expect to receive a response once the function is completed. However, whenever I refresh the page whil ...

Next.js experiences slowdown when initializing props on the server side

I've been working on implementing SSR with Next.js. In my code, I'm fetching JSON data and using them as initial props. Everything works fine in development mode, but when I deploy to the server, fetching only works on the client-side (when navi ...

Utilize Ramda.js to transform commands into a functional programming approach

I have written a code to convert an array of numbers into a new datalist using imperative style. However, I am looking to convert it to functional style using a JavaScript library like ramdajs. Code Background: Let's say we have 5 coins in total with ...