web-dev-qa-db-ja.com

Vue Test Utilsを使用してグローバルイベントバスをテストする方法は?

グローバルイベントバスを介して発行されたイベントをテストする方法を学習しようとしています。これは、私が何をすべきかわからない場所にいくつかのコメントが付いたコードです。

// EvtBus.js
import Vue from 'vue';
export const EvtBus = new Vue();
<!-- CouponCode.vue -->
<template>
    <div>
        <input
            class="coupon-code"
            type="text"
            v-model="code"
            @input="validate">
        <p v-if="valid">
            Coupon Redeemed: {{ message }}
        </p>
    </div>
</template>

<script>

import { EvtBus } from '../EvtBus.js';

export default {
    data () {
        return {
            code: '',
            valid: false,

            coupons: [
                {
                    code: '50OFF',
                    discount: 50,
                    message: '50% Off!'
                },
                {
                    code: 'FREE',
                    discount: 100,
                    message: 'Entirely Free!'
                }
            ]
        };
    },

    created () {
        EvtBus.$on('coupon-applied', () => {
            //console.info('had a coupon applied event on component');
        });
    },

    methods: {
        validate () {
            // Extract the coupon codes into an array and check if that array
            // includes the typed in coupon code.
            this.valid = this.coupons.map(coupon => coupon.code).includes(this.code);
            if (this.valid) {
                this.$emit('applied');
                // I NEVER see this on the coupon-code.spec.js
                EvtBus.$emit('coupon-applied');
            }
        }
    },

    computed: {
        message () {
            return this.coupons.find(coupon => coupon.code === this.code).message;
        }
    }
}
</script>
// tests/coupon-code.spec.js
import expect from 'expect';
import { mount } from '@vue/test-utils';
import CouponCode from '../src/components/CouponCode.vue';
import { EvtBus } from '../src/EvtBus.js';

describe('Reminders', () => {
    let wrp;

    beforeEach(() => {
        wrp = mount(CouponCode);
    });

    it('broadcasts the percentage discount when a valid coupon code is applied', () => {
        let code = wrp.find('input.coupon-code');
        code.element.value = '50OFF';
        code.trigger('input');

        console.log(wrp.emitted('applied'));

        //
        // I NEVER see this on the outpout.
        // How can I test it through a global event bus rather than
        // an event emitted from the component instance?
        //
        EvtBus.$on('coupon-applied', () => {
            console.log('coupon was applied through event bus');
        });

        // Passes, but not using EvtBus instance.
        expect(wrp.emitted('applied')).toBeTruthy;

    });
});

したがって、私の疑問は、グローバルイベントバスがそのイベントバスを使用するコンポーネント内のイベントを発行およびリッスンしていることをテストする方法です。

それで、Vue Test Utilsを使用してグローバルイベントバスをテストすることは可能ですか、それとも別のアプローチを使用する必要がありますか?

11
Fernando Basso

コンポーネントがグローバルEventBusを使用している場合、たとえば、特定のコンポーネントの外部にインポートされ、window.EventBusに割り当てられている場合、グローバルVueインスタンスを使用して、$ onまたは$ emitイベントをラッパーにリダイレクトすることができます。 vmインスタンス。これにより、コンポーネントがthis.$emitではなくEventBus.$emitを介して出力しているようにテストの記述を進めることができます。

it('clicking "Settings" button emits "openSettings"', () => {
    global.EventBus = new Vue();
    global.EventBus.$on('openSettings', (data) => {
        wrapper.vm.$emit('openSettings', data);
    });

    // component emits `EventBus.$emit('openSettings')`

    expect(wrapper.emitted('openSettings')).toBeTruthy(); // pass
});
4
ego

単体テストは、単一のコンポーネントを分離してテストすることに焦点を当てる必要があります。この場合、CouponCode.vueのジョブであるため、イベントが発行されるかどうかをテストする必要があります。単体テストは、コードの最小単位のテストに焦点を合わせ、一度に1つのことだけをテストする必要があることを忘れないでください。この場合、イベントが発行されることに注意してください--EventBus.test.jsは、何が起こるかをテストする場所ですwhenイベントが発行されます。

いいえ、toBeTruthyは関数です-_()_が必要です。 expect(wrp.emitted('applied')).toBeTruthyは実際にはnot合格です。_()_が必要なので、現時点では実際には何もしていません-アサーションは行われません。

アサーションは次のようになります。

expect(wrp.emitted('applied')).toBeTruthy()

さらに一歩進んで、expect(wrp.emitted().applied.length).toBe(1)のようなことをすることで、それが1回だけ発行されたことを確認できます。

次に、InputBusも個別にテストします。そのコンポーネントのコードを投稿できれば、テスト方法を検討できます。

私は最近大きなVueアプリに取り組み、メインのリポジトリとドキュメントに多大な貢献をしたので、できる限りお手伝いさせていただきます。

それが役立つか、さらにガイダンスが必要かどうかをお知らせください。可能であれば、EventBus.vueも投稿してください。

2
xenetics

上手、

EvtBus.$on('coupon-applied', () => {
    console.log('coupon was applied through event bus');
});

マウントされたwrpコンポーネントが、上記のスペックファイルにインポートしたものと同じEvtBusを使用していないため、スペックファイル内のこのコードは呼び出されません。

これをテストするために必要なのは、クーポンコードコンポーネントのEvtBus依存関係の独自の実装(スタブ)を提供できるように、inject-loaderという名前のnpmパッケージです。

ややこんな感じ

const couponCodeInjector = require('!!vue-loader?inject!src/views/CouponCode');

const stubbedModules = {
   '../EvtBus.js': {
        $on : sandbox.spy((evtName, cb) => cb()); 
    }
};

const couponCode = couponCodeInjector(stubbedModules);

次に、ユニットテストで、code.trigger( 'input');のときにstubbedModules ['../ EvtBus.js']。$ onが呼び出されたかどうかをアサートできます。

PS:私はvue-test-utilsを使用していません。したがって、このnpmパッケージでスタブする方法が正確にはわかりません。

しかし、あなたがする必要がある主なことは、CouponCodeコンポーネントでEvtBus依存関係をスタブ化する方法を見つけて、スパイを適用し、そのスパイが呼び出されたかどうかを確認できるようにすることです。

2
fullmetal

Vue-test-utilsとJestでも同じ問題が発生しました。私の場合、vue-test-utilsライブラリのcreateLocalVue()で問題が修正されました。この関数は、コンポーネントをマウントするときに使用するVueのローカルコピーを作成します。このVueのコピーにプラグインをインストールすると、元のVueコピーの汚染を防ぎます。(- https://vue-test-utils.vuejs.org/api/options.html#localvue

これをテストファイルに追加すると、問題が修正されます。

const EventBus = new Vue();

const GlobalPlugins = {
  install(v) {
    // Event bus
    v.prototype.$bus = EventBus;
  },
};

// create a local instance of the global bus
const localVue = createLocalVue();
localVue.use(GlobalPlugins);
1
Harinder Kaur