首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Vue.js Jest单元测试失败:[vuex]未知操作类型& TypeError:无法读取未定义的属性(读取‘of’)“

Vue.js Jest单元测试失败:[vuex]未知操作类型& TypeError:无法读取未定义的属性(读取‘of’)“
EN

Stack Overflow用户
提问于 2022-02-19 14:40:21
回答 1查看 1.2K关注 0票数 1

我正在为Vue应用编写我的第一个单元测试,它使用Jest和vue- test -utils来检查Vuex状态是否正在更新。该应用程序向端点发送axios请求,检查是否有活动警报,然后分发Vuex操作,然后提交突变,将任何新的警报添加到状态。我的问题是,我不知道如何将所有的Vuex突变和操作与axios连接起来,以使测试正常工作。

ApiClient.js (全局axios)

代码语言:javascript
运行
复制
import axios from "axios";

const apiClient = axios.create({
    baseURL: process.env.VUE_APP_API_URL
})

AlertService.js (使用上面的ApiClient )

代码语言:javascript
运行
复制
import apiClient from './ApiClient'

export default {

    getActiveAlerts() {
        return apiClient.get('/alerts');
    }
}

Vuex alert.module.js

代码语言:javascript
运行
复制
import AlertsService from '@/services/AlertsService.js'

export const namespaced = true

export const state = {
    type: null,
    message: null,
    dismissible: false,
    countdown: 0,
    activeAlerts: []
}

export const mutations = {
    SUCCESS(state, message) {
        state.type = 'success';
        state.message = message;
        state.dismissible = false;
        state.countdown = 0;
    },
    ERROR(state, message) {
        state.type = 'danger';
        state.message = message;
        state.dismissible = false;
        state.countdown = 0;
    },
    DISMISSIBLE(state, message) {
        state.type = 'success';
        state.message = message;
        state.dismissible = true;
        state.countdown = 5;
    },
    CLEAR(state) {
        state.type = null;
        state.message = null;
        state.dismissible = false;
        state.countdown = 0;
    },
    SET_ACTIVE_ALERTS(state, alerts) {
        state.activeAlerts = alerts;
    }
}

export const actions = {
    success({ commit }, message) {
        commit('SUCCESS', message);
    },
    error({ commit }, message) {
        commit('ERROR', message);
    },
    dismissible({ commit }, message) {
        commit('DISMISSIBLE', message);
    },
    clear({ commit }) {
        commit('CLEAR');
    },
    getActiveAlerts({ commit, dispatch }) {
        return AlertsService.getActiveAlerts()
            .then(response => {
                commit('SET_ACTIVE_ALERTS', response.data)
                dispatch('alert/clear', null, { root: true });
                return response.data;
            })
            .catch(error => {
                dispatch('alert/error', 'Unable to get active alerts: ' + error, { root: true });
                throw error
            })
    }
}

AlertPanel Vue组件

代码语言:javascript
运行
复制
<template>
  <div>
    <div v-show="isBusy">
      <div class="d-flex align-items-center">
        <b-spinner variant="primary" label="Checking for alerts"></b-spinner>
        <span class="ml-2 font-weight-bold text-primary"
          >Checking for alerts...</span
        >
      </div>
    </div>
    <div v-if="alerts.length > 0">
      <b-alert show dismissible>
        <div v-for="alert in alerts" :key="alert.id">
          <h4 class="alert-heading">{{ alert.title }}</h4>
          <p>{{ alert.text }}</p>
        </div>
      </b-alert>
    </div>
  </div>
</template>

<script>
export default {
  name: "AlertPanel",
  data() {
    return {
      isBusy: true,
      alerts: [],
    };
  },
  created() {
    this.getActiveAlerts();
  },
  methods: {
    getActiveAlerts: function() {
      this.isBusy = true;
      this.$store.dispatch("alert/getActiveAlerts").then(
        (response) => {
          this.alerts = response;
          this.isBusy = false;
        },
        () => {
          this.isBusy = false;
        }
      );
    },
  },
};
</script>

测试文件alerts.spec.js

代码语言:javascript
运行
复制
import { mount, createLocalVue } from "@vue/test-utils";
import BootstrapVue from "bootstrap-vue";
import Vuex from "vuex";
import axios from "axios";
import AlertPanel from "@/components/layout/AlertPanel.vue";

const localVue = createLocalVue();
localVue.use(BootstrapVue);
localVue.use(Vuex);

jest.mock("axios");

describe("AlertPanel", () => {
  let alerts;
  let state;
  let mutations;
  let actions;
  let store;

  jest.mock("axios");

  beforeEach(() => {
    alerts = {
      id: "1",
      title: "Mock alert title",
      text: "Mock alert text",
    };

    state = {
      activeAlerts: [],
    };

    mutations = {
      SET_ACTIVE_ALERTS: jest.fn(),
    };

    actions = {
      getActiveAlerts: jest.fn().mockResolvedValue(),
    };

    store = new Vuex.Store({
      modules: {
        alertModule: {
          namespaced: true,
          state,
          actions,
          mutations,
        },
      },
    });
  });

  it('dispatch "getActiveAlerts" action', () => {
    jest.spyOn(AlertPanel.methods, "getActiveAlerts");
    mount(AlertPanel, { store, localVue });
    axios.get.mockImplementation(() =>
      Promise.resolve({ data: { ...alerts } })
    );
    expect(store.modules.alertModule.actions.getActiveAlerts).toBeCalledWith(
      alerts
    );
  });
});

我收到的错误

代码语言:javascript
运行
复制
by-file-test-pattern-5 is scheduled
  console.error node_modules/vuex/dist/vuex.common.js:495
    [vuex] unknown action type: alert/getActiveAlerts

  console.error node_modules/vue/dist/vue.runtime.common.dev.js:621
    [Vue warn]: Error in created hook: "TypeError: Cannot read properties of undefined (reading 'then')"
    
    found in
    
    ---> <AlertPanel>
           <Root>

  console.error node_modules/vue/dist/vue.runtime.common.dev.js:1884
    TypeError: Cannot read properties of undefined (reading 'then')
        at VueComponent.getActiveAlerts (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\src\components\layout\AlertPanel.vue:35:1)
        at VueComponent.<anonymous> (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\jest-mock\build\index.js:866:25)
        at C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\jest-mock\build\index.js:480:41
        at VueComponent.<anonymous> (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\jest-mock\build\index.js:489:13)
        at VueComponent.mockConstructor (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\jest-mock\build\index.js:182:19)
        at VueComponent.call (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\src\components\layout\AlertPanel.vue:30:1)
        at invokeWithErrorHandling (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:1850:57)
        at callHook (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:4207:7)
        at VueComponent._init (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:4989:5)
        at new VueComponent (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:5134:12)
        at createComponentInstanceForVnode (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:3277:10)
        at i (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:3108:45)
        at createComponent (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:5958:9)
        at createElm (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:5905:9)
        at VueComponent.__patch__ (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:6455:7)
        at VueComponent._update (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:3933:19)
        at VueComponent.call (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:4054:10)
        at Watcher.get (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:4465:25)
        at new Watcher (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:4454:12)
        at mountComponent (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:4061:3)
        at VueComponent.$mount (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\vue\dist\vue.runtime.common.dev.js:8392:10)
        at mount (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\@vue\test-utils\dist\vue-test-utils.js:14057:21)
        at Object.<anonymous> (C:\Users\USER_NAME\source\lcat\PROJECT_NAME\__tests__\unit\alerts.spec.js:52:5)
        at Object.asyncJestTest (c:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\jest-jasmine2\build\jasmineAsyncInstall.js:102:37)
        at c:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\jest-jasmine2\build\queueRunner.js:43:12
        at new Promise (<anonymous>)
        at mapper (c:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\jest-jasmine2\build\queueRunner.js:26:19)
        at c:\Users\USER_NAME\source\lcat\PROJECT_NAME\node_modules\jest-jasmine2\build\queueRunner.js:73:41
        at processTicksAndRejections (node:internal/process/task_queues:96:5)

 FAIL  __tests__/unit/alerts.spec.js
  AlertPanel
    × dispatch "getActiveAlerts" action (472ms)

  ● AlertPanel › dispatch "getActiveAlerts" action

    TypeError: Cannot read properties of undefined (reading 'then')

      33 |             getActiveAlerts: function () {
      34 |                 this.isBusy = true;
    > 35 |                 this.$store.dispatch('alert/getActiveAlerts').then(
         | ^
      36 |                     (response) => {
      37 |                         this.alerts = response;
      38 |                         this.isBusy = false;

      at VueComponent.getActiveAlerts (src/components/layout/AlertPanel.vue:35:1)
      at VueComponent.call (src/components/layout/AlertPanel.vue:30:1)
      at invokeWithErrorHandling (node_modules/vue/dist/vue.runtime.common.dev.js:1850:57)
      at callHook (node_modules/vue/dist/vue.runtime.common.dev.js:4207:7)
      at VueComponent._init (node_modules/vue/dist/vue.runtime.common.dev.js:4989:5)
      at new VueComponent (node_modules/vue/dist/vue.runtime.common.dev.js:5134:12)
      at createComponentInstanceForVnode (node_modules/vue/dist/vue.runtime.common.dev.js:3277:10)
      at i (node_modules/vue/dist/vue.runtime.common.dev.js:3108:45)
      at createComponent (node_modules/vue/dist/vue.runtime.common.dev.js:5958:9)
      at createElm (node_modules/vue/dist/vue.runtime.common.dev.js:5905:9)
      at VueComponent.__patch__ (node_modules/vue/dist/vue.runtime.common.dev.js:6455:7)
      at VueComponent._update (node_modules/vue/dist/vue.runtime.common.dev.js:3933:19)
      at VueComponent.call (node_modules/vue/dist/vue.runtime.common.dev.js:4054:10)
      at Watcher.get (node_modules/vue/dist/vue.runtime.common.dev.js:4465:25)
      at new Watcher (node_modules/vue/dist/vue.runtime.common.dev.js:4454:12)
      at mountComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4061:3)
      at VueComponent.$mount (node_modules/vue/dist/vue.runtime.common.dev.js:8392:10)
      at mount (node_modules/@vue/test-utils/dist/vue-test-utils.js:14057:21)
      at Object.<anonymous> (__tests__/unit/alerts.spec.js:52:5)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        4.413s
Ran all test suites matching /c:\\Users\\USER_NAME\\source\\lcat\\MilGears\.Tcat\.WebUI\\__tests__\\unit\\alerts\.spec\.js/i with tests matching "AlertPanel".

编辑:按照Estus的建议对alerts.spec.js测试文件进行编辑。仍然很不幸地收到了错误。

EN

回答 1

Stack Overflow用户

发布于 2022-02-19 16:10:47

getActiveAlerts操作不能被删节,因为操作总是被期望返回一个承诺。它应该被嘲弄以回报一个未定义的承诺:

代码语言:javascript
运行
复制
getActiveAlerts: jest.fn().mockResolvedValue(),

describe函数范围内初始化模拟存储也是不正确的,这将导致测试交叉污染。这需要用beforeEach来代替。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71185992

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档