简体   繁体   中英

How to organize Vue unit test with factory functions?

I'm trying to write unit tests for my Dashboard.vue component using factory functions so that I could overwrite the store and wrapper as per needed.

Here is the code

import { mount, createLocalVue } from '@vue/test-utils'
import mergeWith from 'lodash.mergewith'
import mutationobserver from 'mutationobserver-shim'
import Vuex from 'vuex'
import BootstrapVue from 'bootstrap-vue'
import Dashboard from '@/views/dashboard/Dashboard'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { library as faLibrary } from '@fortawesome/fontawesome-svg-core'
import { faUser, faThumbsUp, faSignOutAlt, faBorderAll, faAlignJustify, faTrashAlt, faRandom } from '@fortawesome/free-solid-svg-icons'
import flushPromises from 'flush-promises'

jest.mock('@/services/app.service.js')

faLibrary.add(faUser, faThumbsUp, faSignOutAlt, faBorderAll, faAlignJustify, faTrashAlt, faRandom)

const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(BootstrapVue)
localVue.use(mutationobserver) // This is a necessary polyfill for Bootstrap-Vue
localVue.component('font-awesome-icon', FontAwesomeIcon)

function customizer (ovjValue, srcValue) {
  /*
      If the property that takes precedence is an array,
      overwrite the value rather than merging the arrays
    */
  if (Array.isArray(srcValue)) {
    return srcValue
  }
  /*
      If the property that takes precedence is an empty object,
      overwrite the property with an empty object
     */
  if (srcValue instanceof Object && Object.keys(srcValue).length === 0) {
    return srcValue
  }
}

describe('DashBoard component tests', () => {
  let state
  // let actions
  // let getters
  let store
  let wrapper

  let dashBoardData = [
    { db_name: 'Jobs', dxp_dashboardref: 1, dxp_hidden: 0, dxp_position: 1, dxp_ref: 926 },
    { db_name: 'Firms', dxp_dashboardref: 2, dxp_hidden: 0, dxp_position: 2, dxp_ref: 927 },
    { db_name: 'CRM', dxp_dashboardref: 5, dxp_hidden: 0, dxp_position: 3, dxp_ref: 987 }
  ]

  // beforeEach(() => {
  state = {
    auth: {
      user: {
        auids: '',
        md_clock: 0,
        md_picture: '',
        ps_fname1: '',
        ps_surname: '',
        psname: 'Test Test',
        psref: 0
      }
    },
    app: {
      dashBoardData: []
    }
  }

  function createStore (overrides) {
    const defaultStoreConfig = {
      // state: {
      //   state
      // },
      getters: {
        getDashBoardData: () => dashBoardData
      },
      actions: {
        loadDashboard: jest.fn(),
        updateDashBoardData: jest.fn()
      }
    }
    return new Vuex.Store(
      state,
      mergeWith(defaultStoreConfig, overrides, customizer)
    )
  }

  function createWrapper (overrrides) {
    const defaultMountingOptions = {
      localVue,
      store: createStore()
    }
    return mount(
      Dashboard,
      mergeWith(
        defaultMountingOptions,
        overrrides,
        customizer)
    )
  }

  // START: Testing existence of DOM Elements tests
  it('is a Vue instance', () => {
    const wrapper = createWrapper({})
    expect(wrapper.isVueInstance).toBeTruthy()
  })
})

Essentially, I'm trying to use a createWrapper method which has a default store unless overrides or customizer are passed. When I run the test I get the following errors

console.error node_modules/vuex/dist/vuex.common.js:899

[vuex] unknown getter: getDashBoardData

console.error node_modules/vue/dist/vue.runtime.common.dev.js:621

[Vue warn]: Error in render: "TypeError: Cannot read property 'length' of undefined"

Now, I have two questions:

  1. Why am I being thrown unknown getter when I have declared it in the defaultStoreConfig ?
  2. The second error comes from the state . For some reason it doesn't recognize the state variable I'm passing. Any ideas why?

If I simply declare the wrapper inside a beforeEach like so I can pass some of my test but for others which I need to overwrite either getters or actions , I'm not able to do that unless I have the factory functions

    getters = {
      getDashBoardData: () => dashBoardData
   },
    actions = {
    loadDashboard: jest.fn(),
    updateDashBoardData: jest.fn()
  }

  store = new Vuex.Store({
    state,
    actions,
    getters
  })
  })

Any help will be highly appreciated!

Solved this by passing the state inside defaultStoreConfig rather than separately when creating the store

Code:

    const defaultStoreConfig = {
      state: {
        auth: {
          user: {
            auids: '',
            md_clock: 0,
            md_picture: '',
            ps_fname1: '',
            ps_surname: '',
            psname: 'Test Test',
            psref: 0
          }
        },
        app: {
          dashBoardData: []
        }
      },
      getters: {
        getDashBoardData: () => dashBoardData
      },
      actions: {
        loadDashboard: jest.fn(),
        updateDashBoardData: jest.fn()
      }
    }

Test:

  it('is a Vue instance', () => {
    const wrapper = createWrapper()
    expect(wrapper.isVueInstance).toBeTruthy()
  })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM