27
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Jestでデフォルト値設定済みのaxiosインスタンスに対するMockテスト

Last updated at Posted at 2019-05-18

TL;DR

axiosそのものではなく、adapterでMockすると良さそう

背景

axiosを使ったコードのテストをJestで書くときにMock化したい。
よくあるサンプルにはaxiosモジュールそのものをMockにしている例がある。
ただし、下記のようにaxios.create()axios.defaultsを使って共通設定している場合、

import axios from 'axios'
const api = axios.create({
  ...
})
export const getFoo = req => api.post('/foo', req)

axiosモジュールそのものをMockにすると、create関数の戻り値でさらにMockを返すなどの実装がテストコード側で必要になりかなり面倒。
さらに、interceptorsやtransformersなんかを設定している場合には、最終的にサーバーにどんなリクエストが飛ぶかをテストしたい場合も出てくる。

解決策

axiosを乗りこなす機能についての知見集 - Qiita を見て知ったのだけど、adapterプロパティを使うとRequest, ResponseがMockできて良い感じだった。

使い方や詳細については下記も参照。
axios/lib/adapters at master · axios/axios

実装サンプル

GitHubにもあります。
clomie/sample-axios-jest-mock-test

プロダクトコード側はMockをインポートしてadapterに渡す実装にしておく。

index.ts
import axios from 'axios'
import { stringify } from 'querystring'
import mockAdapter from './mock'

const api = axios.create({
  baseURL: 'https://api.example.com/v2/',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  adapter: mockAdapter
})

export const createFoo = async (req: any) => {
  const { data } = await api.post('/foo', stringify(req))
  return data
}

プロダクトコード側のMockの中身はundefinedにしておけば良い。

mock/index.ts
import { AxiosAdapter } from 'axios'
export = (undefined as unknown) as AxiosAdapter 

テストコード側でJestのMockに差し替えてテストを書いていく。

index.test.ts
import { AxiosAdapter } from 'axios'

jest.mock('./mock', () => jest.fn())

import mock from './mock'
const axiosMockAdapter = (mock as unknown) as jest.Mock<
  ReturnType<AxiosAdapter>,
  Parameters<AxiosAdapter>
>

import { createFoo } from './index'

describe('createFoo test', () => {
  beforeEach(() => {
    axiosMockAdapter.mockClear()
  })

  it('send form request and receive response', async () => {
    const request = {
      name: 'hogefuga'
    }
    const response = {
      status: 200,
      statusText: 'OK',
      headers: {},
      config: {},
      data: {
        id: 1,
        name: 'hogefuga'
      }
    }

    axiosMockAdapter.mockResolvedValueOnce(response)

    const result = await createFoo(request)
    const callArgs = axiosMockAdapter.mock.calls[0]

    expect(callArgs[0].url).toBe('https://api.example.com/v2/foo')
    expect(callArgs[0].headers).toHaveProperty(
      'Content-Type',
      'application/x-www-form-urlencoded'
    )
    expect(callArgs[0].data).toBe('name=hogefuga')

    expect(result).toStrictEqual({ id: 1, name: 'hogefuga' })
  })
})
27
18
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?