😇

jestを既存のNuxtに入れてみた話(テスト編)

2022/11/15に公開

はじめに

前回だした記事で既存のNuxtにjest環境を作成できました。
jestを既存のNuxtに入れてみた話(導入編)を参考
そこで今回は既存のNuxtでテストを実行するまでを一通り自分へのメモ用としてまとめようかなと思っております。

入れた環境

  • Nuxt v2.15
  • node v16

やろうと思っていたテスト

  • 実行する年月日によって挙動が違う部分のテスト
  • pluginで登録していた関数のテスト

テストの設定

  1. testフォルダを作成し、テスト用のindex.spec.jsファイルを作成します。
  2. 今回はNuxt内でのテストなのでテストコードでvue記述を認識(使用?)するために下記コマンドで、vue-test-utlisライブラリをインストール。
// npm
npm install --save-dev @vue/test-utils

// yarn
yarn add --dev @vue/test-utils

※nuxt-test-utilsやvite-test-utlisなどのライブラリがありますが、今回は将来性やしっかりと運用されていそうなvue-test-utlisを使用しました。
3. テストファイルおよび必要なライブラリ関連をindex.spec.jsファイルでimport。

  • 今回は、vuexで状態を管理しているファイルのためvuexをimport
  • vue/test-utilsではvuexを使える環境を作成するためcreateLocalVueとテストするコンポーネントをマウントするためshallowMountそれぞれをimport
  • テスト対象ファイルのimport
    結果、自分は下記import記述になりました。
index.spec.js
import { createLocalVue, shallowMount} from '@vue/test-utils' 
import Vuex from 'vuex';
import Test from 'テストファイルへのパス';

4.vuexを使用できる環境を作成し、storeを前もって入れておきます。
コードしては結果下記です。
beforeAllについては他の方が記事を作成していると思われるので、ここでは説明を割愛します。

index.spec.js

// グローバルVueクラスを汚染しない一時的なVueコンストラクタを作成
const localVue = createLocalVue()
// 一時的なVueコンストラクタでVuexを使用
localVue.use(Vuex);

let store;

// beforeAll(テストファイルの前で一度だけ実行するもの)を使いダミーのstateをセット
beforeAll(() => {
  store = new Vuex.Store({
    state: {
      'store内のstate名': 'ダミーのセットデータ'
    },
  })
})

ここまででそれぞれのテストをするための環境を整いました。
ここからはそれぞれのテストに対しての作成手順を示します。

実行する年月日によって挙動が違う部分のテスト

ここでやりたいテストについて少し補足します。
今回やりたかったことは実行する時期によって初期値で設定される時期が違うものがありそれのテストをしたいです。パターンとしては下記3パターンがあります。

実行されるに時期 初期値で設定される時期
今月の上旬 今月の下旬
今月の中旬 来月の上旬
今月の下旬 来月の中旬

その3パターンのうち今回は、上から二つ目のパターンを例で見せます。
その際に使ったモックがjestのuseFakeTimersモックになります。
これは現在とは別で任意の時間帯をセットできるものになります。それによって上旬、中旬、下旬を操って、テストしようと思います、

下記のように設定しました。

index.spec.js
describe('今月の中旬の場合', () => {
  
  // beforeEachでテスト前に今月の中旬を指定
  beforeEach(() => {
    const date = new Date();
    const year = date.getFullYear();
    const month = date.getMonth();
    jest.useFakeTimers('modern').setSystemTime(new Date(year,month,11))
  })
  test('来月上旬になるかのテスト',() => {
    // 当日の日付を取得(useFakeTimersで設定された任意の日付)
    const now = new Date();
    const year = now.getFullYear();
    const month = now.getMonth() + 1;
    
    // shallowmountによってテストしたコンポーネント or ページを以下設定でマウント
    const wrapper = shallowMount(Test,{
      localVue,
      stubs: ['テストに関係ないコンポーネント',テストに関係ないコンポーネント],
      store,
    })
    
    // テストファイル内で時期を設定する関数が来月の中旬を指しているかをexpectで確認
    expect(wrapper.vm.テストファイル内で時期を設定する関数).toMatchObject({ 
      // 来月の中旬になっているか
      year:year,
      month:month+1,
      day:"上旬"
    })
  })
})

上記コードの中でポイントとなる点が3点ありますので説明していきます。

  1. 任意の時期の指定はbeforeEachのタイミングでuseFakeTimersモックを使い設定しました。
    理由としては、今回は先ほどの時期パターン表の通りテストによって時期が違うためbeforeEachのタイミングで指定しました。
    jest.useFakeTimers('modern').setSystemTime(new Date(year,month,11))

  2. shallowmount時にstubsにテストに関係ないコンポーネントをスタブしております。理由としてはNuxt v2.13以上ではコンポーネントのAuto importすることが可能で今回のテストコードでも使っています。それによりjest側では使用しているコンポーネントがどのファイルなのかを認識できずエラーを吐き出していました。そのため今回のテストとは関係ないためスタブしています。

  3. 最後は上記コードには記載していませんが、テストごとに任意の時期を設定するため、afterEachでuseFakeTimersモックの破棄つまりはuseRealTimersモックを使い、実際の日付をjestに設定し直すことが必要です。(変なバグを起こさないためです。)
    つまりは下記の記述をどこからしらに追記する必要があるかと思います。

index.spec.js
afterEach(() => {
  jest.useRealTimers();
})

一旦は実行する年月日によって挙動が違う部分のテストについては以上かと思われます。

pluginで登録していた関数のテスト

こちらに関しては結論から言いますと作成できませんでした
理由は下記です。

  • pluginはNuxtの記述になるためvue記述のモックを提供するvue-test-utilsでは不適切だった。
  • Blogメモφ(..)さんのJestでNuxt+Vuetifyのテストを書いてみる pluginでinjectしている関数のテストの章で記載がある通りpluginをprotoTypeとして設定すればできるかもですが、そうなるとテストをするためのコードを爆誕させることになり、うーんという感じになりそうであった。
  • plugin側でのstoreはテストファイルmount時に設定できるstoreとは別らしくうまく挙動してくれなかった。

最後に

今回はじめてjestを触ってみて、環境を整えることであったり、今後のことを考えテストに関連するツールを選択したり等テストを作成するのがいかに大変かを学ぶことが出来ました。
そのほかにもテストを作るうえでもパターンがひとつではなく、やり方が違えど同じようなテストが多々あり、その中からどれかしらを参考にし自分なりのテストパターンを作るとなると色々と道筋が多く大変であるなと痛感しました、
この記事もそのような方と手助けになればなと思っております。

Discussion