Help us understand the problem. What is going on with this article?

Vueコンポーネントが発生したイベントのテスト

More than 1 year has passed since last update.

Vueコンポーネントが発生したイベントのテスト

アプリケーションが大きくなれば大きくなるほど、コンポーネントも増えていきます。親と子のコンポーネントをデータを共通するとき、子のコンポーネントがイベントを発火させて、親は反応します。

vue-test-utilswrapperAPIのemittedメソッドで発火したイベントを簡単に検証できます。ドキュメンテーションはこちらです。


これは最近作り始めたVueテストハンドブックからの記事です。貢献したい方はどうぞ。

このページのテストのソースコードはこちらにあります。


コンポーネントとテストを書く

簡単なコンポーネントを書きながら学びましょう。<Emitter>というコンポーネントを作って、このコードを書きます。

<template>
  <div>
  </div>
</template>

<script>
  export default {
    name: "Emitter",

    methods: { 
      emitEvent() {
        this.$emit("myEvent", "name", "password")
      }
    }
  }
</script>

<style scoped>
</style>

そしてemitEventを呼び出すメソッドがあるテストを書きます。

import Emitter from "@/components/Emitter.vue"
import { shallowMount } from "@vue/test-utils"

describe("Emitter", () => {
  it("2つの引数があるイベントを発火する", () => {
    const wrapper = shallowMount(Emitter)

    wrapper.vm.emitEvent()

    console.log(wrapper.emitted())
  })
})

vue-test-utilsemitted APIでコンポーネントが発生したイベントが見えます。

yarn test:unitでテストを実行してみます。

PASS  tests/unit/Emitter.spec.js
Emitter
  ✓ 2つの引数があるイベントを発火する (31ms)

console.log tests/unit/Emitter.spec.js:10
  { myEvent: [ [ 'name', 'password' ] ] }

emittedのシンタックス

emittedはオブジェクトを返します。発生したイベントはプロパティになります。emitted().[event]で検証できます:

emitted().myEvent //=>  [ [ 'name', 'password' ] ]

emitEventを二回呼び出してみます。

it("2つの引数があるイベントを発火する", () => {
  const wrapper = shallowMount(Emitter)

  wrapper.vm.emitEvent()
  wrapper.vm.emitEvent()

  console.log(wrapper.emitted().myEvent)
})

yarn test:unitで実行してみると:

console.log tests/unit/Emitter.spec.js:11
  [ [ 'name', 'password' ], [ 'name', 'password' ] ]

emitted().emitEventは配列を返します。最初に発生したイベントはemitted().emitEvent[0]でアクセスできます。イベントの引数をemitted().emitEvent[0][0]などでアクセスできます。

テストでイベントが発生したかを検証してみます。

it("2つの引数があるイベントを発火する", () => {
  const wrapper = shallowMount(Emitter)

  wrapper.vm.emitEvent()

  expect(wrapper.emitted().myEvent[0]).toEqual(["name", "password"])
})

テストはパスします。

コンポーネントをマウントせずにイベントのテスト

コンポーネントをレンダーせずにイベントが発生したかをcallで検証できます。新しいテストを書きます。

it("コンポーネントをレンダーせずにイベントを検証する", () => {
  const events = {}
  const $emit = (event, ...args) => { events[event] = [...args] }

  Emitter.methods.emitEvent.call({ $emit })

  expect(events.myEvent).toEqual(["name", "password"])
})

$emitはただのJavaScriptのオブジェクトなので、$emitをモックして、callemitEventthisにつけます。createdmountedのライフサイクルフックに重い処理をする場合、callで呼び出したらコンポーネントはマウントしないので、ライフサイクルメソッドも呼び出しません。thisを細かく指定したい時にも便利です。

まとめ

  • vue-test-utilsemittedAPIでコンポーネントによって発生したイベントを検証できます。
  • emittedは関数です。呼び出したイベントはemittedが返すオブジェクトのプロパティになります。
  • そのプロパティは配列です。イベントが数回発生したら、[0][1]などでアクセスできます。
  • 発生したイベントの引数も配列になります。[0][1]でアクセスします。
  • $emitをモックしてcallで呼び出して、レンダーせずに検証できます。

このページのテストのソースコードはこちらにあります。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away