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()