msw + jestによるテストで、axiosのtimeout設定が動作しない

■開発環境
react(next.js) ver.18.1.0(12.1.6)
axios ver.0.27.2
jest ver.28.1.0
msw ver.0.40.0

■やりたい事
axiosによるAPIアクセスにタイムアウト(ミリ秒)を設定する。
APIアクセスが設定したタイムアウトを経過したら、タイムアウト発生として判定されて、タイムアウト発生エラーの処理に進むことを、jestでテスト化したい。

・テスト対象

import axios, { AxiosRequestConfig } from 'axios'

const client = axios.create({
  headers: { 'Content-Type': 'application/json' },
  responseType: 'Json',
  timeout: 60000 // 60秒タイムアウト
})

// APIアクセス
export async function getSomeData(config?: AxiosRequestConfig, doSuccessAction: () => void, doTimeoutAction: () => void) {
  try {
    await client.get('http://localhost:3000/api/someData', config)
    doSuccessAction()
  } catch (error) {
    if(axios.isAxiosError(error)) {
      if (error.code === 'ECONNABORTED') {
        // タイムアウト処理実施
        doTimeoutAction()
      }
    }
  }
}


・テストコード

import { setupServer } from 'msw/node'
import { getSomeData } from 'テスト対象'

const server = setupServer(
  rest.get('http://localhost:3000/api/someData', async (req, res, ctx) => {
    return res(
      ctx.delay(1500),
      ctx.status(200),
      ctx.json({ id: 1, text: 'テキスト' }),
    )
  })
)
// msw開始
server.listen()

describe('テスト', () => {
  it('api タイムアウトテスト', async () => {
    const doTimeoutAction = jest.fn()
    await getSomeData({ timeout: 1000 }, () => { console.log('success') }, doTimeoutAction )
    // タイムアウト発生となるので、タイムアウトコールバックが実行されるはず
    expect(doTimeoutAction ).toBeCalledTimes(1)
  }
})


■発生する事象
APIアクセスはmswをmockとして利用して、設定したタイムアウト分だけdelayしてレスポンスを返すようにしたが、タイムアウト発生エラー処理に進まない(設定した時間だけdelayした後に、正常系処理としてレスポンス取得できてしまう)。

■原因
どうやら、jest + msw利用の場合、axiosのタイムアウト設定が動作しなくなってしまう様子。

■回避策
jestによるaxiosのタイムアウト発生テストでは、mswのmockへのアクセスとならないようにする。

・テストコード(回避策)

import { setupServer } from 'msw/node'
import { getSomeData } from 'テスト対象'

const server = setupServer(
  rest.get('http://localhost:3000/api/someData', async (req, res, ctx) => {
    return res(
      ctx.delay(1500),
      ctx.status(200),
      ctx.json({ id: 1, text: 'テキスト' }),
    )
  })
)
// msw開始(timeoutテストが終わってからmswを開始する)
// server.listen()

describe('テスト', () => {
  it('api タイムアウトテスト', async () => {
    const doTimeoutAction = jest.fn()
    // タイムアウトは1msで発生させる
    await getSomeData({ timeout: 1}, () => { console.log('success') }, doTimeoutAction )
    // タイムアウト発生となるので、タイムアウトコールバックが実行されるはず
    expect(doTimeoutAction ).toBeCalledTimes(1)
  }
})

// timeoutテストが終わってからmsw開始
server.listen()


この記事が気に入ったらサポートをしてみませんか?