IT이야기

Mocha 테스트에서 VueX 스토어를 라우터에 Import할 수 없음

cyworld 2022. 6. 3. 22:38
반응형

Mocha 테스트에서 VueX 스토어를 라우터에 Import할 수 없음

업데이트 2

VueX git repo에서 작성된 문제에 대한 링크: https://github.com/vuejs/vuex/issues/1509

복제할 수 있는 레포 링크: https://github.com/djam90/vuex-vue-router-issue

업데이트:

이 문제는 VueX의 이 코드에서 발생합니다.여기서 rawModule은undefined그리고 열쇠는getters점포는 라우터를 수입하고 라우터는 스토어를 수입하는 순환 의존관계 때문이라고 생각합니다.

function assertRawModule (path, rawModule) {
  Object.keys(assertTypes).forEach(function (key) {
    debugger; 
    if (!rawModule[key]) { return }

    var assertOptions = assertTypes[key];

    forEachValue(rawModule[key], function (value, type) {
      assert(
        assertOptions.assert(value),
        makeAssertionMessage(path, key, type, value, assertOptions.expected)
      );
    });
  });
}

프로젝트에서는 Vue CLI 3을 사용하여 Vue, Vue Router, VueX 및 Mocha를 테스트에 사용합니다.

라우터를 스토어에 Import할 필요가 있지만 스토어를 라우터에 Import할 필요도 있습니다.브라우저에서 앱을 실행하면 정상적으로 동작하지만 스토어 또는 라우터를 테스트에 Import하면 다음과 같은 오류가 발생합니다.

 MOCHA  Testing...

 RUNTIME EXCEPTION  Exception occurred while loading your tests

TypeError: Cannot read property 'getters' of undefined
    at /home/dan/code/garage/ui/dist/webpack:/node_modules/vuex/dist/vuex.esm.js:261:1
    at Array.forEach (<anonymous>)
    at assertRawModule (/home/dan/code/garage/ui/dist/webpack:/node_modules/vuex/dist/vuex.esm.js:260:1)
    at ModuleCollection.register (/home/dan/code/garage/ui/dist/webpack:/node_modules/vuex/dist/vuex.esm.js:186:1)
    at /home/dan/code/garage/ui/dist/webpack:/node_modules/vuex/dist/vuex.esm.js:200:1
    at /home/dan/code/garage/ui/dist/webpack:/node_modules/vuex/dist/vuex.esm.js:75:44
    at Array.forEach (<anonymous>)
    at forEachValue (/home/dan/code/garage/ui/dist/webpack:/node_modules/vuex/dist/vuex.esm.js:75:1)
    at ModuleCollection.register (/home/dan/code/garage/ui/dist/webpack:/node_modules/vuex/dist/vuex.esm.js:199:1)
    at new ModuleCollection (/home/dan/code/garage/ui/dist/webpack:/node_modules/vuex/dist/vuex.esm.js:160:1)
    at new Store (/home/dan/code/garage/ui/dist/webpack:/node_modules/vuex/dist/vuex.esm.js:311:1)
    at Module../src/store/store.js (/home/dan/code/garage/ui/dist/webpack:/src/store/store.js:12:16)
    at __webpack_require__ (/home/dan/code/garage/ui/dist/webpack:/webpack/bootstrap:25:1)
    at Module../src/router.js (/home/dan/code/garage/ui/dist/webpack:/src/router.js:1:1)
    at __webpack_require__ (/home/dan/code/garage/ui/dist/webpack:/webpack/bootstrap:25:1)
    at Module../src/store/modules/bookings.js (/home/dan/code/garage/ui/dist/webpack:/src/store/modules/bookings.js:1:1)
    at __webpack_require__ (/home/dan/code/garage/ui/dist/webpack:/webpack/bootstrap:25:1)
    at Module../tests/unit/store/bookings.spec.js (/home/dan/code/garage/ui/dist/webpack:/tests/unit/store/bookings.spec.js:1:1)
    at __webpack_require__ (/home/dan/code/garage/ui/dist/webpack:/webpack/bootstrap:25:1)
    at run (/home/dan/code/garage/ui/dist/webpack:/node_modules/mocha-webpack/lib/entry.js:3:20)
    at Array.forEach (<anonymous>)
    at Object../node_modules/mocha-webpack/lib/entry.js (/home/dan/code/garage/ui/dist/webpack:/node_modules/mocha-webpack/lib/entry.js:10:1)
    at __webpack_require__ (/home/dan/code/garage/ui/dist/webpack:/webpack/bootstrap:25:1)
    at /home/dan/code/garage/ui/dist/webpack:/webpack/bootstrap:116:1
    at Object.<anonymous> (/home/dan/code/garage/ui/dist/main.js:120:10)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object._module2.default._extensions.(anonymous function) [as .js] (/home/dan/code/garage/ui/node_modules/mocha-webpack/lib/util/registerRequireHook.js:148:12)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at /home/dan/code/garage/ui/node_modules/mocha/lib/mocha.js:250:27
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (/home/dan/code/garage/ui/node_modules/mocha/lib/mocha.js:247:14)
    at Mocha.run (/home/dan/code/garage/ui/node_modules/mocha/lib/mocha.js:576:10)

라우터는 다음과 같습니다.

import Vue from 'vue'
import Router from 'vue-router'
import store from '@/store/store'
import storage from '@/services/storage'

import Login from './views/Login.vue'
import Dashboard from './views/Dashboard.vue'
import Bookings from './views/Bookings'

Vue.use(Router)

const router = new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/login',
      name: 'login',
      meta: {
        layout: 'login'
      },
      component: Login
    },
    {
      path: '/',
      name: 'home',
      component: Dashboard
    },
    {
      path: '/bookings',
      name: 'bookings',
      component: Bookings
    }
  ]
})

router.beforeEach((to, from, next) => {
  const token = storage.get('token')
  if (token && !store.state.auth.token) {
    store.commit('auth/setAuthToken', token)
  }

  next()
})

export default router

다음은 매장 예약 모듈입니다.

import api from '@/api/bookings'
import router from '@/router'

const state = {
  bookings: [],
  lastAdded: null,
  lastEdited: null,
  errors: {
    get: null,
    add: null,
    edit: null,
    getById: null
  },
  booking: {}
}

export const getters = {
  booking: state => {
    return state.booking
  }
}

export const actions = {
  async getAll ({ commit }) {
    try {
      const response = await api.getAll()
      commit('SET_BOOKINGS', response.data)
    } catch (e) {
      commit('SET_ERROR_FOR_GET', e)
    }
  },

  async create ({ commit, state }, { booking }) {
    try {
      const response = await api.create(booking)
      commit('SET_LAST_CREATED', response.data)
      router.push({ name: 'bookings' })
    } catch (e) {
      commit('SET_ERROR_FOR_CREATE', e)
    }
  },

  async getById ({ commit, state }, { id }) {
    try {
      const response = await api.getById(id)
      commit('SET_BOOKING', response.data)
    } catch (e) {
      commit('SET_ERROR_FOR_GET_BY_ID', e)
    }
  }
}

export const mutations = {
  SET_VEHICLES (state, vehicles) {
    state.all = vehicles
  },
  SET_ERROR_FOR_GET (state, error) {
    state.errors.get = error
  },
  SET_LAST_CREATED (state, customer) {
    state.lastAdded = customer
  },
  SET_ERROR_FOR_CREATE (state, error) {
    state.errors.add = error
  },
  SET_BOOKING (state, vehicle) {
    state.vehicle = vehicle
  },
  SET_ERROR_FOR_GET_BY_ID (state, error) {
    state.errors.getById = error
  }
}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}

제 테스트는 다음과 같습니다.

import chai from 'chai'
import sinon from 'sinon'
import sinonChai from 'sinon-chai'
import bookingsStore from '@/store/modules/bookings'
import api from '@/api/bookings'
// import router from '@/router'
import { stubBooking } from '../stubs/stubs'

chai.use(sinonChai)
const expect = chai.expect

const { getters, actions, mutations } = bookingsStore

// test getters
describe('getters', () => {
  describe('booking', () => {
    it('should return booking from state', () => {
      const state = {
        booking: {}
      }

      const actual = getters.booking(state)

      expect(actual).to.deep.equal(state.booking)
    })
  })
})

// test actions
describe('actions', () => {

  describe('create', () => {
    let apiStub
    let routerStub

    beforeEach(() => {
      apiStub = sinon.stub(api, 'create')
      routerStub = sinon.stub(router, 'push')
    })

    afterEach(() => {
      apiStub.restore()
      routerStub.restore()
    })

    it('create success', async () => {
      const commit = sinon.spy()
      const state = {}

      apiStub.resolves({
        data: stubBooking
      })

      await actions.create({ commit, state }, { stubBooking })

      expect(commit.args).to.deep.equal([
        ['SET_LAST_CREATED', stubBooking]
      ])

      expect(router.push).to.have.been.called
    })
  })
})

보다시피, 그냥...import bookingsStore from '@/store/modules/bookings'내 테스트에서 오류가 발생합니다.이것을 제거하면 테스트는 정상적으로 실행됩니다.

라우터에 Import 했을 때 스토어가 정의되어 있지 않은 것과 같은 문제가 있었습니다.

최종적으로 라우터 인스턴스 자체를 사용하여 스토어에 액세스하기로 했습니다.

router.beforeEach((to, from, next) => {
  console.log('authenticated?', router.app.$store.getters['auth/isAuthenticated'])

// ...

})

Namesched 스토어를 사용하고 있기 때문에, 그것이 문제인 것 같습니다.어쨌든 저는 이 솔루션이 상당히 마음에 듭니다.

언급URL : https://stackoverflow.com/questions/54691789/unable-to-import-vuex-store-into-router-and-router-into-store-in-mocha-tests

반응형