もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

Vue.js入門 基礎から実践アプリケーション開発までを読んだ vol.10

はじめに

こんにちは。

Kojirockの1人アドベントカレンダー Advent Calendar 2018の10日目の記事です。

以下の本を読んで勉強できたことを記載していきます。

今回は第10章です。

Vue.js入門 基礎から実践アプリケーション開発まで

Vue.js入門 基礎から実践アプリケーション開発まで

前回の懸念の通り本章は、コードを写経する事が多かったので、あまり載せられることがありませんでした。

なので今回は、javascriptユニットテストの方法をピックアップしようと思います。

やってみた

jsのテストコードはほぼほぼ書いたことなかったので、勉強になりました。

本書では プロジェクト作成は vue init でテストツールは mocha だったのですが、自分で作成したものは

vue create + jest となっています。

以下は、今回のサンプルアプリケーションの1つのコンポーネントである KbnButton.vue です。

KbnButton.vue

<template>
  <button
    :class="classes"
    :disabled="disabled"
    type="button"
    @click="handleClick"
  >
    <slot />
  </button>
</template>

<script>
export default {
  name: 'KbnButton',

  props: {
    type: {
      type: String,
      default: 'button'
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },

  computed: {
    classes() {
      const cls = this.type === 'text' ? ('-' + this.type) : ''
      return [`kbn-button${cls}`]
    }
  },

  methods: {
    handleClick(ev) {
      this.$emit('click', ev)
    }
  }
}
</script>

<style scoped>
.kbn-button {
  padding: .6em 1.3em;
}
.kbn-button-text {
  border: none;
  padding-right: 0;
  padding-left: 0;
}
</style>

このコンポーネントを、プロジェクト作成時にできている example.spec.js を参考にテストコードを作成しました。

それが以下です。

KbnButton.spec.js

import { mount } from '@vue/test-utils'
import KbnButton from '@/components/atoms/KbnButton.vue'

describe('KbnButton.vue', () => {
  it ('kbn-buttonクラスを持つbutton要素で構成されること', () => {
    const wrapper = mount(KbnButton)
    expect(wrapper.is('button')).toEqual(true)
    expect(wrapper.classes()).toContain('kbn-button')
  })

  it ('kbn-button-textクラスを持つbutton要素で構成されること', () => {
    const wrapper = mount(KbnButton, {
      propsData: { type: 'text' }
    })
    expect(wrapper.is('button')).toEqual(true)
    expect(wrapper.classes()).toContain('kbn-button-text')
  })

  it ('disabled属性が付与されていること', () => {
    const wrapper = mount(KbnButton, {
      propsData: { disabled: true }
    })
    expect(wrapper.is('button')).toEqual(true)
    expect(wrapper.attributes().disabled).toEqual('disabled')
  })

  it ('クリックイベントが発行されていること', () => {
    const wrapper = mount(KbnButton)
    wrapper.trigger('click')
    expect(wrapper.emitted().click.length).toEqual(1)
  })

  it ('スロットにコンテンツが挿入されていること', () => {
    const wrapper = mount(KbnButton, {
      slots: { default : '<p>hello</p>' }
    })
    expect(wrapper.text()).toEqual('hello')
  })
})

実行すると以下のようになります。

$ yarn vue-cli-service test:unit
yarn run v1.12.3
$ /path/to/node_modules/.bin/vue-cli-service test:unit
 PASS  tests/unit/specs/components/atoms/KbnButton.spec.js
  KbnButton.vue
    ✓ kbn-buttonクラスを持つbutton要素で構成されること (23ms)
    ✓ kbn-button-textクラスを持つbutton要素で構成されること (2ms)
    ✓ disabled属性が付与されていること (2ms)
    ✓ クリックイベントが発行されていること (3ms)
    ✓ スロットにコンテンツが挿入されていること (11ms)

Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        1.788s, estimated 2s
Ran all test suites.
✨  Done in 3.19s.

単純なテストだったので、実行方法も記述方法もそこまで難しくありませんでした。

ただ、一点わからなかったことが、example.spec.js で使用されていた shallowMount() と、本書のテストコードで使用されている mount() の違いでした。

調べると以下の説明がとてもわかり易かったです。

コンポーネントをレンダーする二つのメソッド - mountとshallowMount

shallowMount は通常のhtml要素をレンダーしますが、Vue componentsに対しては描画せずスタブに置き換えることが分かりました。

こちらでも書いているのですが、axiosで通信している部分などをスタブに置き換えることができるみたいです。

今回みたいなatoms単位のコンポーネントユニットテストの場合は mount() で問題ないと理解しました。

終わりに

簡単ですが、以上です。

流石にその日中にpostしきれなくなりました。。。

ただ、25日分は確実にやり遂げようと思います。

次からは、nuxtの本に移ります!!

ではまた~。