Jest: 我应该如何在每次测试中更改 Vuex 的模拟数据?

Jest: How I should change the mock data of Vuex in each test?

我一直在进行测试,我需要来自 Vuex 的数据。但是,我遇到了一些问题,我需要在每次测试中更改该数据以测试组件的功能。 这是我的组件:

<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>

这是测试:

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')
  })
    

})

我的问题是我需要在第二次测试中将 [filters/get${capitalize('categories')}Many] 的值更改为 ["1"]。 我尝试了几件事来更改模拟数据,但它们不起作用。 如何在每次测试中更改模拟商店数据? 谢谢!

您可以通过 lazy loading 您的 vue 组件实现此目的:

  1. beforeEach中添加jest.resetModules();以在每次测试前重置所有导入的模块,因此它们可以是re-evaluated和re-mocked:
beforeEach(() => {
    jest.resetModules();
  1. 在每个单元测试中,首先需要使用require语法导入vue组件,如下:
const ItemsDisplayer = require('./ItemsDisplayer.vue').default;
  1. 然后在导入后直接添加模拟,[`filters/get${capitalize('categories')}Many`] 值设置为您想要的任何值:
jest.mock('vuex', () => ({
  ...jest.requireActual('vuex'),
  useStore: () => ({
    getters: {
      [`filters/get${capitalize('categories')}Many`]: ["1"],
    },
    commit: mockStoreCommit,
  }),
}));
  1. 我注意到您在 beforeEach 中进行渲染。不幸的是,因为您在测试期间导入和模拟了您的模块,渲染将需要在这些发生之后完成 - 因此您需要将该逻辑移动到您的单元测试中或将其提取到另一个可以从内部调用的函数中单元测试。

每个单元测试应该如下所示:

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('-')
})