单元测试依赖于全局事件总线的Vue组件

时间:2017-05-10 07:49:23

标签: javascript unit-testing vue.js ava

我在全球app.js中声明了一个事件总线,如下所示:

window.Event = new Vue();

该组件看起来像

export default {
    data() {
        return {
            hasError: false,
            zip: '',
        };
    },

    methods: {
        setZip: function() {
            this.hasError = false;
            this.$emit('setZip', this.zip);
        },
    },

    mounted() {
        Event.$on('showErrors', (errors) => {
            this.hasError = errors.zip ? true : false;
        });

        this.zip = this.editZip;
    },

    props: [
        'editZip'
    ],
}

我使用ava helpers/setup.js对我的组件进行单元测试:

const browserEnv = require('browser-env');
const hook = require('vue-node');
const { join } = require('path');

// Setup a fake browser environment
browserEnv();

// Pass an absolute path to your webpack configuration to the hook function.
hook(join(__dirname, './webpack.config.js'));

webpack.config.js看起来像:

module.exports = {
    module: {
      loaders: [
          {
            test: /\.vue$/,
            loader: 'vue-loader',
          },
        {
          test: /\.js$/,
            loader: 'babel',
            exclude: /node_modules/,
          },
      ],
    },
  resolve: {
      extensions: ['.js', '.vue'],
      },
};

运行以下测试时

import Vue from 'vue/dist/vue.js';
import test from 'ava';
import Zip from '../../resources/assets/js/components/Company/Zip.vue';

let vm;

test.beforeEach(t => {
    let Z = Vue.extend(Zip);

    vm = new Z({ propsData: {
        editZip: 1220
    }}).$mount();
});

test('that it renders a div with class form-group', t => {
    t.is(vm.$el.className, 'form-group');
});

它通过,但会抛出以下错误:

[Vue warn]: Error in mounted hook: "TypeError: Event.$on is not a function"

(found in <Root>)
TypeError: Event.$on is not a function
    at VueComponent.mounted (/mnt/c/code/leaflets/resources/assets/js/components/Company/City.vue:107:15)
    at callHook (/mnt/c/code/leaflets/node_modules/vue/dist/vue.js:2530:21)
    at mountComponent (/mnt/c/code/leaflets/node_modules/vue/dist/vue.js:2424:5)
    at VueComponent.Vue$3.$mount (/mnt/c/code/leaflets/node_modules/vue/dist/vue.js:7512:10)
    at VueComponent.Vue$3.$mount (/mnt/c/code/leaflets/node_modules/vue/dist/vue.js:9592:16)
    at Test._ava2.default.beforeEach.t [as fn] (/mnt/c/code/leaflets/tests/js/CompanyCity.js:12:9)
    at Test.callFn (/mnt/c/code/leaflets/node_modules/ava/lib/test.js:281:18)
    at Test.run (/mnt/c/code/leaflets/node_modules/ava/lib/test.js:294:23)
    at runNext (/mnt/c/code/leaflets/node_modules/ava/lib/sequence.js:58:44)
    at Sequence.run (/mnt/c/code/leaflets/node_modules/ava/lib/sequence.js:90:10)
    at Concurrent.run (/mnt/c/code/leaflets/node_modules/ava/lib/concurrent.js:41:37)
    at runNext (/mnt/c/code/leaflets/node_modules/ava/lib/sequence.js:58:44)
    at Sequence.run (/mnt/c/code/leaflets/node_modules/ava/lib/sequence.js:90:10)
    at runNext (/mnt/c/code/leaflets/node_modules/ava/lib/sequence.js:58:44)
    at Sequence.run (/mnt/c/code/leaflets/node_modules/ava/lib/sequence.js:90:10)
    at Bluebird.try (/mnt/c/code/leaflets/node_modules/ava/lib/runner.js:214:48)
    at tryCatcher (/mnt/c/code/leaflets/node_modules/bluebird/js/release/util.js:16:23)
    at Function.Promise.attempt.Promise.try (/mnt/c/code/leaflets/node_modules/bluebird/js/release/method.js:39:29)
    at Runner.run (/mnt/c/code/leaflets/node_modules/ava/lib/runner.js:214:22)
    at process.on.options (/mnt/c/code/leaflets/node_modules/ava/lib/main.js:82:10)
    at emitOne (events.js:96:13)
    at process.emit (events.js:191:7)
    at process.on.message (/mnt/c/code/leaflets/node_modules/ava/lib/process-adapter.js:14:10)
    at emitTwo (events.js:106:13)
    at process.emit (events.js:194:7)
    at process.nextTick (internal/child_process.js:766:12)
    at _combinedTickCallback (internal/process/next_tick.js:73:7)
    at process._tickCallback (internal/process/next_tick.js:104:9)

我无法弄清楚在我的测试中声明window.Event = new Vue()的位置,以便测试的组件可以访问Event变量。

1 个答案:

答案 0 :(得分:2)

首先,我建议从窗口对象中删除全局EventBus(如果可以的话),因为依赖于全局props可能会被代码的其他某些部分覆盖而导致不期望的情况并不常见效果。

您可以只创建一个event-bus.js文件并在其中创建事件总线:

import Vue from 'vue';
export const EventBus = new Vue();

然后,您可以从需要访问事件总线的任何其他组件中导入该文件,例如

import {EventBus} from '/path/to/event-bus.js'

从那里,您可以完全按照当前使用的方式使用它。

但是,如果出于某种原因必须将EventBus保留在窗口对象中,则还必须对其进行模拟,以便对其进行测试。

首先,当您调用browserEnv函数时,您需要执行以下操作mock the window object

browserEnv(['window']);

然后,窗口将作为全局变量可用,但是您将需要更改组件的实现以从窗口对象中显式获取EventBus,例如:

window.EventBus

您还可以在组件中全局定义它,例如:

const { EventBus } = window

让我知道这是否可行。

谢谢