React 入門 (14) ~ TODOアプリを作る(9) ~ sendToApiServer のテスト

今日は sendToApiServer のテスト。fetch が絡むので mock ライブラリを導入する。

$ npm i --save fetch-mock
$ npm i --save @types/fetch-mock

fetchMock は import * as fetchMock from 'fetch-mock' でインポート可能。

一旦以下のように作ってnpm test を実行してみる。

import sendToApiServer from './sendToApiServer'

describe('sendToApiServer', () => {
  it('ADD_TODO', () => {
    const action = {
      type: 'ADD_TODO',
      text: "test",
    }
    sendToApiServer({}, action)
  })
})

すると、以下のようなエラーが表示された。

 FAIL  src/utils/sendToApiServer.test.tsx
  ● Test suite failed to run

    TypeScript diagnostics (customize using `[jest-config].globals.ts-jest.diagnostics` option):
    src/utils/sendToApiServer.test.tsx:9:21 - error TS2345: Argument of type '{}' is not assignable to parameter of type 'Dispatch<any>'.
      Type '{}' provides no match for the signature '<T extends any>(action: T): T'.

    9     sendToApiServer({}, action)
                          ~~

どうも型が一致していないようだ。ここはいったん sendToApiServer.tsx 側の型を any にして無理やり通すことにした。


続いて、fetchMock を足してテストを通す。

import * as fetchMock from 'fetch-mock'
import sendToApiServer from './sendToApiServer'

describe('sendToApiServer', () => {
  it('ADD_TODO', async () => {
    const action = {
      type: 'ADD_TODO',
      text: "test",
    }

    fetchMock.post('/api/add_todo', {body: {'type':'ADD_TODO', 'text':'test'}, status: 200});

    const mockDispatch = jest.fn()

    await sendToApiServer(mockDispatch, action)

    expect(mockDispatch.mock.calls.length).toBe(1)
    expect(mockDispatch.mock.calls[0][0]).toEqual(action)
  })
})

sendToApiServer() 自体は非同期で動作するので、await をつける。つけないと mockDispatch が呼ばれる前にexpect() の評価がされてしまう。あと、await をつけるなら テスト関数自体を async にしないと怒られるのでつけておくこと。

fetchMock は post 関数を呼ぶことで post がきたときのみ動作するようになる。body には返り値を指定する。

私の設計では、渡したアクションをそのまま返すので、はじめはactionのオブジェクトをbodyに設定していたが、元のアクションが間違っていた場合にテストが通ってしまうな。と思ったので、めんどくさいが分けて書くことにした。


COMPLETE_TODODELETE_TODO に関しても同様にテストを記載した。ADD_TODO と変わるところはないので、省略


FETCH_TODO もテストを追加する。FETCH_TODO は返り値がDBの状況によって変化するため、いくつかテストパターンを書いたほうがいいと思い、describe でネストしてその下にテストを追加した。そうした場合に fetchMock がエラーを出力するようになった。原因はテストケースをまたいでfetchMock が使用されてしまい、関数が再定義されてしまうためのようだ。各テストケースの終わりに fetchMock.restore() で解放してやることで問題なく動作するようになった。


成果物は以下。

GitHub - bamchoh/react-study at c711a96976f8f9df82f0b17bacd334535c339cb0


次回は サーバーサイドのテストを書く予定。