Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
15
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

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

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' })
  })
})
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
15
Help us understand the problem. What are the problem?