Home > front end >  Jest: How I should change the mock data of Vuex in each test?
Jest: How I should change the mock data of Vuex in each test?

Time:06-03

I've been working in a test where I need the data from Vuex. However, I'm having some problems, I need to change that data in each test in order to test the functionality of the component. Here is my component:

<template>
  <div id="cb-items-displayer" @click="textClick">
    <span>(</span>
    <p>{{ text }}</p>
    <span>)</span>
  </div>
</template>

<script lang="ts" setup>
import { capitalize } from '@/utils/capitalize'
import { ItemsDisplayer } from '@/models/ItemsDisplayer'
import { computed, PropType } from 'vue'
import { useStore } from 'vuex'

const store = useStore()

const props = defineProps({
  type: {
    type: String,
    default: '',
  },
  menuType: {
    type: String,
    default: '',
  },
  items: {
    type: Array as PropType<ItemsDisplayer[]>,
    default: () => [],
  }
})

const emit = defineEmits<{
  (event: 'textClicked'): void
}>()

const text = computed(() => {
  const param = props.menuType === 'radio' ? 'One' : 'Many'
  console.log( "TYPEEE ", props.type, " ", param )
  const itemsIds = store.getters['filters/get'   capitalize(props.type)   param]
  console.log("ITEMSSS", JSON.stringify(itemsIds))
  return getTextToShow(itemsIds)
})

const getTextToShow = (itemsIds: string) => {
  //TODO - improve it
  if (itemsIds === 'all') {
    return 'all'
  } else if (itemsIds.length === 0) {
    return '-'
  } else if (itemsIds.length === 1) {
    return getName(itemsIds[0], props.items)
  } else {
    return itemsIds.length
  }
}

const textClick = () => {
  emit('textClicked')
}

const getName = (id: string, items: ItemsDisplayer[]) => {
  const found: ItemsDisplayer = items.find((x) => x.id! === id) as ItemsDisplayer
  console.log("GETNAME ", found.name)
  return found?.name
}
</script>

And this is the test:

import { render, screen, click, waitFor } from '@tests/app-test-utils'
import ItemsDisplayer from './ItemsDisplayer.vue'
import { capitalize } from '@/utils/capitalize'

let mockStoreCommit: jest.Mock

jest.mock('vuex', () => ({
  ...jest.requireActual('vuex'),
  useStore: () => ({
    getters: {
      [`filters/get${capitalize('categories')}Many`]: [],
    },
    commit: mockStoreCommit,
  }),
}))

describe('ItemsDisplayer', () => {
  beforeEach(() => {
    mockStoreCommit = jest.fn()
    render(
      ItemsDisplayer,
      {},
      {
        props: {
          type: 'categories',
          menuType: 'checkbox',
          items: [
          {
            box_templates:"",
            id:"1",
            name:"Culture"
          }, 
          {
            box_templates:"",
            id:"2",
            name:"Economy"
          }, 
          {
            box_templates:"",
            id:"3",
            name:"Education"
          }
        ]},
      }
    ) 
  })

  it('renders the component', async() => {
    await screen.getByText('-')
  })

  it('renders the component with one item', async() => {
    //DON'T WORK HERE THERE SHOULD BE A CHANGE OF DATA IN THE MOCKED STORE IN ORDER TO WORK
    await screen.getByText('Culture')
  })
    

})

My problem is that I need to change the value of [filters/get${capitalize('categories')}Many] to ["1"] in the second test. I tried several things in order to change the mocked data but they don't work. How can I change the mocked store data in each test? Thanks!

CodePudding user response:

You can achieve this by lazy loading your vue component:

  1. Add jest.resetModules(); in the beforeEach to reset all of the imported modules before each test so they can be re-evaluated and re-mocked:
beforeEach(() => {
    jest.resetModules();
  1. In each unit test, you will first need to import the vue component using the require syntax as follows:
const ItemsDisplayer = require('./ItemsDisplayer.vue').default;
  1. Then add the mock directly after the import with the [`filters/get${capitalize('categories')}Many`] value being set to whatever you want it to be:
jest.mock('vuex', () => ({
  ...jest.requireActual('vuex'),
  useStore: () => ({
    getters: {
      [`filters/get${capitalize('categories')}Many`]: ["1"],
    },
    commit: mockStoreCommit,
  }),
}));
  1. I have noticed that you do your rendering in the beforeEach. Unfortunately because you import and mock your modules during the test, the rendering will need to be done after these have taken place - hence you will need to either move that logic into your unit test or extract it into another function which can be called from within the unit test.

Each unit test should look something like this:

it('renders the component', async() => {
  const ItemsDisplayer = require('./ItemsDisplayer.vue').default;
  
  jest.mock('vuex', () => ({
    ...jest.requireActual('vuex'),
    useStore: () => ({
      getters: {
        [`filters/get${capitalize('categories')}Many`]: ["1"],
      },
      commit: mockStoreCommit,
    }),
  }));
  
  // beforeEach logic here or a call to a function that contains it

  await screen.getByText('-')
})
  • Related