【Typescript】emit/propsの受け渡しとjestでのテスト【Vue.js】

親子間での値の受け渡しとテスト

プロダクトコード

子コンポーネント①(propsでnameを親から受け取り、ただemitする)

<template>
  <div>
    <Button @click="emitChildData">{{ name }}</Button>
  </div>
</template>

<script lang="ts">
import Vue, { PropType } from 'vue'
export default Vue.extend({
  name: 'InputChild',
  props: {
    name: {
      type: String as PropType<string>,
    },
  },
  methods: {
    emitChildData(): void {
      this.$emit('childEmit')
    },
  },
})
</script>

ボタンクリックでemitChildDataが動き、(‘childEmit’)をemitする

子コンポーネント②(propsでnameを親から受け取り、引数付きでemitする)

<template>
  <div>
    <Button @click="emitChildDataWithArgument">{{ name }}</Button>
  </div>
</template>

<script lang="ts">
import Vue, { PropType } from 'vue'
// import { SelectOptions} from '~/types/SelectOptions'
export default Vue.extend({
  name: 'InputChild',
  props: {
    name: {
      type: String as PropType<string>,
      required: false,
    },
  },
  data(): { emitData: string } {
    return { emitData: 'test' }
  },
  methods: {
    emitChildDataWithArgument(): void {
      this.$emit('childEmitWithArgument', this.emitData)
    },
  },
})
</script>

ボタンクリックでemitChildDataWithArgumentが動き、(‘childEmitWithArgumen’)を引数付きでemitする

親コンポーネント(子①、子②にnameを渡す)

<template>
  <div>
    <InputChild name="emitChildData" @childEmit="emitData"></InputChild>
    <InputChildWithArgument
      name="emitChildDataWithArgument"
      @childEmitWithArgument="emitDataWithArgument"
    ></InputChildWithArgument>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import InputChild from '@/components/atoms/InputChild.vue'
import InputChildWithArgument from '@/components/atoms/InputChildWithArgument.vue'
export default Vue.extend({
  components: {
    InputChild,
    InputChildWithArgument,
  },
  data(): {
    testData: string
  } {
    return {
      testData: '',
    }
  },
  methods: {
    emitData() {
      console.log(`getChildEmit ${this.testData}`)
    },
    emitDataWithArgument(value: string) {
      this.testData = value
      console.log(`getChildEmitWithArgument ${this.testData}`)
    },
  },
})
</script>

<style></style>

親コンポーネントの@○○=”××”で ○○がemitされたら××を実行という意味になる。@clickのemit版みたいな感じ。

childEmitWithArgumentの方はemitDataWithArgument(value:string)で引数付きで呼び出せる

テストコード

子コンポーネント①テスト

import { shallowMount } from '@vue/test-utils'
import InputChild from '@/components/atoms/InputChild.vue'
const spy = jest.fn()

describe('emit test', () => {
  it('childEmitWithArgumentがemitされていることのテスト', () => {
    const wrapper = shallowMount(InputChild, {
      mocks: {
        $emit: spy,
      },
      propsData: {
        name: 'testName',
      },
    })
    wrapper.find('Button').trigger('click')
    expect(spy).toHaveBeenCalledWith('childEmit')
    expect(wrapper.text()).toBe('testName')
  })
})

ボタンをクリックしたを擬似的に実行し、$emitにspyを置くことでemitされた値が読み取れるようになる。
クリックでchildEmitをemitしているのでexpect(spy).toHaveBeenCalledWith(‘childEmit’)で何がemitされているかを検証

expect(wrapper.text()).toBe(‘testName’)はpropsで何が渡されているのかを検証している。propsはmountする際にmockしている。

子コンポーネント②テスト

import { shallowMount } from '@vue/test-utils'
import inputChildWithArgument from '@/components/atoms/InputChildWithArgument.vue'
const spy = jest.fn()

describe('emit test', () => {
  it('childEmitがemitされていることのテスト', () => {
    const wrapper = shallowMount(inputChildWithArgument, {
      mocks: {
        $emit: spy,
      },
      propsData: {
        name: 'test1',
      },
    })
    wrapper.find('Button').trigger('click')
    expect(spy).toHaveBeenCalledWith('childEmitWithArgument', 'test')
  })
})

ほぼ子コンポーネント①テストと同じ
expect(spy).toHaveBeenCalledWith(‘childEmitWithArgument’, ‘test’)で’test’が引数にあることを確認している。

親コンポーネントテスト

import { shallowMount } from '@vue/test-utils'
import inputParent from '@/pages/InputParent.vue'
import inputChildWithArgument from '@/components/atoms/inputChildWithArgument.vue'

describe('emit test', () => {
  it('childEmitがemitされていることのテスト', async () => {
    const wrapper = shallowMount(inputParent)
    await wrapper
      .findComponent(inputChildWithArgument)
      .vm.$emit('childEmitWithArgument', 'test')
    expect(wrapper.vm.$data.testData).toEqual('test')
  })
})

今度はinputChildWithArgument(子コンポーネント)を使ってemitさせるところまでを行い、親のdataにあるtestDataがmethodsのemitDataWithArgumentと挙動が一致しているかを確認しています。

emitDataWithArgumentではtestDataを引数に変更する処理が入っているので、

await wrapper
.findComponent(inputChildWithArgument)
.vm.$emit(‘childEmitWithArgument’, ‘test’)で第二引数のtestを渡し、親コンポーネント側でtestDataが’test’になっているかを確認しています。

emitDataWithArgumentが呼ばれていることを確認するためにhaveBeenCalled()でexpectしたいのですが、vueコンポーネントのmethodsをspyするやり方がわかりませんでした。どなたかご存知であればコメント頂けると幸いです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です