はじめに
こんにちは。choreiiです。最近自チームで扱っている商材のフロントエンドのテストコードを大量に書く機会がありました。その中で大きくハマった3点について紹介します。
環境
- Vue:2.6.11
- vue-test-utils:1.0.0-beta.29
- Jest:23.6.0
1. ライフサイクルフックをmock化(上書き)したい
以下のようにbeforeMountで初期化処理を書いている場合、beforeMountをまるごとmock化(上書き)したくなる時があります。
<script> export default { beforeMount() { // コンポーネントで必要なデータの取得や初期化の処理 }, methods: { sampleMethods() { // 何らかの処理 } } }; </script>
methodsの内容を上書きする時は以下のようにすれば差し替えることができるので、ライフサイクルフックの場合も上書きできると考えていたのですができませんでした。
test("test", () => { const wrapper = shallowMount(Sample, { beforeMount() { // これで空の内容で上書きできるはず -> できない。。。 } methods: { sampleMethods() {} // 空の内容で上書きできる } }); });
vue-test-utilsのガイドには特に記載がなかったので手元で色々頑張ってみたのですが、下記のissueを発見。
ライフサイクルフックは上書きできないので、処理を上書きしたい場合はbeforeMountの処理をmethodsに切り出して、その切り出した内容を上書きするのが良さそうです。
<script> export default { beforeMount() { this.initData(); // methodsに切り出し }, methods: { initData() { // コンポーネントで必要なデータの取得や初期化の処理 }, sampleMethods() { // 何らかの処理 } } }; </script>
test("test", () => { const wrapper = shallowMount(Sample, { methods: { initData() {}, // methodsの方で上書き sampleMethods() {} } }); });
ちなみに、shallowMount(mount)した後から、setMethods
を使っても上書きできます。
test("test", () => { const wrapper = shallowMount(Sample); wrapper.setMethods({ initData(): {} // 後から上書き }) });
2. テストによってcomputedを差し替えたい
条件が少しだけ異なるテストを書く際に、毎回shallowMount(mount)を行うのはコード記述が増えるのであまりやりたくないです。methodsやcomputedだけを後から差し替える方法があれば完璧です。上記で述べたように、methodsは後から上書きすることができます。
describe("test", () => { const wrapper = shallowMount(Sample); test("test1", () => { wrapper.setMethods({ sampleMethods(): {} // test1用の処理 }) }); test("test2", () => { wrapper.setMethods({ sampleMethods(): {} // test2用の処理 }) }); });
setMethods
があるならsetComputed
もあるだろうと考えていましたが、これまたvue-test-utilsのガイドには記載がありません。
他にもset系のメソッドが用意されていながら、computedだけがありません。。。嫌な予感がしながら情報を探してみると下記のissueを発見(デジャヴ)。
昔は用意されていたものの、バグがテストをすり抜ける可能性があるので廃止されたようです。バグをなくすためと言われては仕方がないのでテストごとにshallowMount(mount)をするようにしています。
describe("test", () => { const render = ((sampleComputedStub), { const wrapper = shallowMount(Sample, { computed: { sampleComputed: sampleComputedStub } }); }); test("test1", () => { const wrapper = render({ // sampleComputedを上書きしたい処理 }): }); test("test2", () => { const wrapper = render({ // sampleComputedを上書きしたい処理 }): }); });
3. localStorageをmock化したい
テストでlocalStorageをそのまま使うわけにはいかないので、mockに差し替える必要があります。
localStorageについては以下を参照
jest.spyOn(localStorage, 'setItem');
spyOnの使い方は間違えていないのに、以下のようなエラーがでてしまいました。
TypeError: object[methodName].mockImplementation is not a function
localStorageの中で、setItemが見つからないみたいです。またまた嫌な予感がしましたが今回は解決方法がありました。
以下のようにproto
を使用するとアクセスできるようです。ただリンク先にも記載がある通り、proto
は非推奨とのことなのであまり多用するのはよろしくなさそう。今回はどうしてもjest.spyOnを使って呼び出し回数や呼び出し引数のテストを書きたかったので使用しています。
jest.spyOn(localStorage.__proto__, 'setItem');
まとめ
Vue/Jestの書き方は公式のガイドが充実しているので、ガイド通りに進めている間はスムーズに進みます。その反面、ガイドに載っていないことをやろうとすると情報がなかなか見つからず痛い目をみることが多かったです。
テストの主目的はプロダクトコードの品質担保なので、あまりテストの書き方を調べるのに時間をかけたくありません。今後は多少記述が増えたり冗長になったとしても、ガイドに従いながらテストを書き、どうしても実現できないことだけ別途調査することにします。
参考
エンジニア中途採用サイト
ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っております!
ご興味ありましたら是非ご確認をお願いします。
https://career-recruit.rakus.co.jp/career_engineer/カジュアル面談お申込みフォーム
どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。
以下フォームよりお申込みください。
rakus.hubspotpagebuilder.comラクスDevelopers登録フォーム
https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/イベント情報
会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください!
◆TECH PLAY
techplay.jp
◆connpass
rakus.connpass.com