Closed6
reactでcustom-hook with axiosのテストをしたい
前提
- 最近参画したプロジェクトで、レガシーになるつつある
useRequest.ts
というuseSWRの車輪の再発明にのようなカスタムフックがある。- useRequestはaxiosを使用した
get, post
といった関数を返す(swrでいうfetcher部分です)
- useRequestはaxiosを使用した
- そこにローディングの状態を持つことになり、testの勉強もかねてloadingの状態が正しく切り替わることを担保したい
インストール
この2つは最低限使うことになりそう
一旦これで行けた
import { renderHook, waitFor } from '@testing-library/react'
import MockAdapter from 'axios-mock-adapter'
import { useRequest } from '@/common/hooks/useRequest'
import axios from '../../src/common/libs/axios'
jest.mock('@auth0/auth0-react', () => ({
useAuth0: () => ({
getAccessTokenSilently: jest.fn(() => 'mocked-token'),
}),
}))
const url = 'https://example.com'
const mock = new MockAdapter(axios)
describe('useRequest', () => {
const { result } = renderHook(() => useRequest({ url }))
afterEach(() => {
mock.reset()
})
describe('isLoading', () => {
test('初期値はfalse', () => {
expect(result.current.isLoading).toBe(false)
})
describe('get', () => {
it('リクエスト中はtrue', async () => {
mock.onGet(url).reply(200)
waitFor(async () => {
await result.current.get()
expect(result.current.isLoading).toBe(true)
})
expect(result.current.isLoading).toBe(false)
})
it('リクエスト後はfalse', async () => {
mock.onGet(url).reply(200)
await waitFor(async () => {
await result.current.get()
})
expect(result.current.isLoading).toBe(false)
})
})
describe('update', () => {
it('リクエスト中はtrue', async () => {
mock.onPost(url).reply(200)
waitFor(async () => {
await result.current.update('post', {})
expect(result.current.isLoading).toBe(true)
})
expect(result.current.isLoading).toBe(false)
})
it('リクエスト後はfalse', async () => {
mock.onPost(url).reply(200)
await waitFor(async () => {
await result.current.update('post', {})
})
expect(result.current.isLoading).toBe(false)
})
})
describe('remove', () => {
it('リクエスト中はtrue', async () => {
mock.onDelete(url).reply(200)
waitFor(async () => {
await result.current.remove()
expect(result.current.isLoading).toBe(true)
})
expect(result.current.isLoading).toBe(false)
})
it('リクエスト後はfalse', async () => {
mock.onGet(url).reply(200)
await waitFor(async () => {
await result.current.remove()
})
expect(result.current.isLoading).toBe(false)
})
})
})
})
冗長な処理を削除した
import { renderHook, waitFor } from '@testing-library/react'
import MockAdapter from 'axios-mock-adapter'
import { useRequest } from '@/common/hooks/useRequest'
import axios from '../../src/common/libs/axios'
jest.mock('@auth0/auth0-react', () => ({
useAuth0: () => ({
getAccessTokenSilently: jest.fn(() => 'mocked-token'),
}),
}))
const url = 'https://example.com'
describe('useRequest', () => {
const mock = new MockAdapter(axios)
const {
result: {
current: { isLoading, get, update, remove },
},
} = renderHook(() => useRequest({ url }))
afterEach(() => {
mock.reset()
})
describe('isLoading', () => {
test('初期値はfalse', () => expect(isLoading).toBe(false))
describe('get', () => {
it('リクエスト中はtrue', () => {
waitFor(async () => {
await get()
expect(isLoading).toBe(true)
})
})
it('リクエスト後はfalse', () => {
waitFor(async () => await get())
expect(isLoading).toBe(false)
})
})
describe('update', () => {
it('リクエスト中はtrue', () => {
waitFor(async () => {
await update('post', {})
expect(isLoading).toBe(true)
})
})
it('リクエスト後はfalse', () => {
waitFor(async () => await update('post', {}))
expect(isLoading).toBe(false)
})
})
describe('remove', () => {
it('リクエスト中はtrue', () => {
waitFor(async () => {
await remove()
expect(isLoading).toBe(true)
})
})
it('リクエスト後はfalse', () => {
waitFor(async () => await remove())
expect(isLoading).toBe(false)
})
})
})
})
useRequest.tsでsetIsLoadingの処理を削除してみてテストしてみる。
loadingの状態は変わらないはずなのにテストが通ってしまっている😓
PASS __tests__/hooks/useRequest.test.ts
useRequest
isLoading
✅ 初期値はfalse (2 ms)
get
✅ リクエスト中はtrue (37 ms)
✅ リクエスト後はfalse (1 ms)
update
✅ リクエスト中はtrue (1 ms)
✅ リクエスト後はfalse
remove
✅ リクエスト中はtrue (1 ms)
✅ リクエスト後はfalse
Test Suites: 1 passed, 1 total
Tests: 7 passed, 7 total
Snapshots: 0 total
そもそもwaitFor
は先頭にawaitをつけないと全てパスする様になっていた😢
get methodを呼ぶ前に関数内でtokenを取得しているので、auth0のfunctionに遅延を入れたらフラグが立つのではないか?
import { renderHook, waitFor } from '@testing-library/react'
import MockAdapter from 'axios-mock-adapter'
import { useRequest } from '@/common/hooks/useRequest'
import axios from '../../src/common/libs/axios'
jest.mock('@auth0/auth0-react', () => ({
useAuth0: () => ({
getAccessTokenSilently: jest.fn(
() =>
new Promise((resolve) =>
setTimeout(() => resolve('mocked-token'), 1000),
),
),
}),
}))
const url = 'https://example.com'
describe('useRequest', () => {
const mock = new MockAdapter(axios)
const {
result: {
current: { isLoading, get, update, remove },
},
} = renderHook(() => useRequest({ url }))
afterEach(() => mock.reset())
describe('isLoading', () => {
test('初期値はfalse', () => expect(isLoading).toBe(false))
describe('get', () => {
it('リクエスト中はtrue', () => {
waitFor(async () => {
get()
expect(isLoading).toBe(true)
})
})
it('リクエスト後はfalse', () => {
get()
expect(isLoading).toBe(false)
})
})
describe('update', () => {
it('リクエスト中はtrue', () => {
waitFor(() => {
update('post', {})
expect(isLoading).toBe(true)
})
})
it('リクエスト後はfalse', () => {
update('post', {})
expect(isLoading).toBe(false)
})
})
describe('remove', () => {
it('リクエスト中はtrue', () => {
waitFor(() => {
remove()
expect(isLoading).toBe(true)
})
})
it('リクエスト後はfalse', () => {
remove()
expect(isLoading).toBe(false)
})
})
})
})
→ 無理だった
誰か助けて、、、😶🌫️
このスクラップは2024/01/29にクローズされました