算出プロパティなAtomコンポーネントを自動テストしてみよう

#はじめに
Vue.jsを使うのもなんか慣れてきたし、AtomicDesignに基づいたComponentも作れるようになってきたな…
せや！そろそろ自動テストやってみるか！
てなことで、AtomなComponentを自動テストしてみた記事です。

##AtomicDesignとは
Javascriptのコンポーネント指向なフレームワークをどう設計していくかの設計思想です。
コンポーネントを5つの構造に分け、それぞれの役割を明確に決め、再利用や可読性を上げます。

- Atom
- Molecules
- Organisms
- Templates
- Pages

Atomが最小のコンポーネントとなり、下にいくほど規模が大きくなっていくイメージです。
(#AtomicDesignについては、Qiita含めたくさん記事があるので詳しくは省略します)

今回は、その中でAtomを対象にしたいと思います！

##テスト環境

- Vue.js
- vue-test-utils
- Jest

vue-cliのプロジェクト作成時に、Manualを選びTestを有効化し今回はJestを選択しました。

#やってみよう
ということで、ぱぱっと以下のようなComponentをテスト自動してみましょう

```Vue:AtomInput.vue
<template>
    <input 
        type="text" 
        v-model="inputText"
    >
</template>

<script>
export default {
    name:"Atom-input",
    props:{
        value:{
            type:[String, Number]
        }
    },
    computed:{
        inputText:{
            get:function(){
                return this.value
            },
            set:function(value){
                this.$emit("change",value)
            }
        }
    }
}
</script>
```
Atomのルールとして、状態やデータを持ってはならないというのがあるため、`data`の記述がないコンポーネントとなります。
上位から`props`で`value`の値を受け取り、それを`computed`の`setter/getter`を経由しv-modelで`input`に紐づけております。
`props`をそのまま`v-model`で`input`にバインディングしたいところですが、Vueのルールとして単方向データフローがあります。
`props`を子コンポーネントが変更することはそのルールに違反することとなりますので、子から直接`props`の値を変更することはできません。
そこで、`computed`の`setter/getter`を使うことで、v-modelが値を呼び出すときは`getter`で`props`の値を取得、変更は`setter`で親への通知イベントを行っています。

参考にさせていただいた記事

- [Vue公式:フォーム入力バインディング](https://jp.vuejs.org/v2/guide/forms.html)
- [Vue公式:算出プロパティとウォッチャ](https://jp.vuejs.org/v2/guide/computed.html)
- [v-modelにオブジェクトをバインディングする場合のコンポーネント実装を考える](https://qiita.com/clomie/items/7a69ee850a304595142e#%E7%AE%97%E5%87%BA%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AEgettersetter%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B)
- [Vue.jsのv-modelを正しく使う](https://qiita.com/simezi9/items/c27d69f17d2d08722b3a)

##テストを作ってみよう
1つのコンポーネントで行うべきテストケースは色々ありますが、今回は1つに絞ります。
テストケースとしては、
`入力した値が親に返されてくるか`をテストしてみたいと思います。

```Javascript:AtomInput.spec.js
describe('AtomInputText.vue',()=>{
    it('入力した値が親に返されてくるか',()=>{
        const wrapper = mount(Input);
        const value = 'valueだよ';
        const input = wrapper.find('input[type="text"]');
        input.setValue(value)//v-model on change
        expect(wrapper.emitted().change[0][0]).toBe(value);
    });
});
```
内容としてはとてもシンプルです。
対象コンポーネント内にある`input`を見つけて、それに対して`setValue`で値をセットしています。
`setValue`自体が、セットと`input`イベントを同時に行うAPI的な書き方ですので、1行で済ますことができます
[Vue Test Utils : setValue](https://vue-test-utils.vuejs.org/ja/api/wrapper/#setvalue)

`setValue`を使わずに書くとしたら、

```Javascript
   input.setValue(value)//v-model on change
```

これが

```Javascript
   input.element.value = value
   input.trigger('input')
```

こういう風な書き方となります。

`setValue`で`input`が行われるため、`v-model="inputText"`のから算出プロパティの`setter`が呼び出されます。
そして`setter`には`$emit`があるため、引数の値を親にイベントで伝えております。
なのでテストコード側では最後に`emitted`でやってきた値を見ることで、
正しく入力された値がやってくるかのチェックができます。

上の方にも書きましたが、再利用性を高めるためにAtomやMoleculesでは状態を持ってはいけないため、
テストコード側でも入力した値をテストするために、`data`などを確認するのではなく`emitted`で確認しています。

##やってみた感想
書いてみるとすごく短くて記事としてもシンプルなものとなりましたが、知らずにやろうとしたら割と詰まったので記事にしてみました。
テストケースを書くことで、データの流れやイベントなどをより意識しコーディングするようになったので、テスト自動化は早めに着手するのがいいなと感じました。