はじめに
めちゃ久しぶりに記事書きます。Pirikaraです。
最近ほぼJavascriptばっかり書いてますが、業務中に解決したやーつを共有したいと思います。
this
thisの挙動の違いについてはこちら。
呼んだ所々で値が変わってしまうthis
。
今まで特に意識せずに使ってましたが、このthis
の参照先が変わることで少々困ったことになりました。
Jestでthisを扱うコードをテストする時に詰んだ
こちらのmixinは、Vue.jsのコンポーネントにmethodsとして読み込まれる関数をまとめたものです。
バックエンド(Ruby on Rails)のコードは自動テストを走らせて品質を担保していますが、フロントのjsファイルに関してはE2Eテストを行なっていました。
E2Eだけでは見落としが発生してしまうので、フロント側にも段階的に自動テストを導入していくことになりました。
そこで、まずはコンポーネントのテストではなくJSファイルのテストを.....と思っていたのですが......
export function A(hoge) {
return this.B(this.$store.hogehoge, hoge)
}
export function B(a, b) {
return a*b
}
import * as mixin from 'path/to/mixin.js';
it('A関数に10を渡すと、50を返す', () => {
expect(mixin.A(10)).toEqual(50);
})
A関数の中ではthis
を取り扱っています。
mixinのコードはコンポーネント内のmethodsとして読み込まれるので、このthis
はコンポーネント自身を指しています。
しかしながら、このテストを実行すると次のエラーが発生します。
TypeError:Cannot read property 'hogehoge' of undefined.
this.$store
でVuexのstoreを参照しようとしていますが、テスト環境で実行したこのthis
はmixin自身を指しており、$store
という値はないためundefinedになります。
当然hogehogeという値も持っていないのでこのエラーになります。
このままではthis
が影響してテストができません。
bindで束縛
Javascriptの関数オブジェクトには、bindという便利なメソッドがありました。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
このメソッドを使うと、関数内のthisを指定の値に固定した新しい関数を返します。
早速使ってみましょう。
import * as mixin from 'path/to/mixin.js';
it('A関数に10を渡すと、50を返す', () => {
const mockTest = mixin.A.bind(5, 10) // 第一引数が関数内のthisの値になる
expect(mockTest()).toEqual(50);
})
これでテストを正しく実行することができました。
ちなみに、下のように直接bindした関数をテストすると、
元の関数がそのまま(thisを固定できないまま)実行されてしまうので注意です。
import * as mixin from 'path/to/mixin.js';
it('A関数に10を渡すと、50を返す', () => {
expect(mixin.A.bind(5, 10)).toEqual(50);
})
おわり
おわります。
またネタがあれば書きます。