Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions components/providers/QueryProvider.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { renderHook, waitFor } from "@testing-library/react"
import { useQuery } from "@tanstack/react-query"
import { describe, expect, it, vi } from "vitest"
import { ApiError } from "@/lib/api"
import { QueryProvider } from "./QueryProvider"

vi.mock("@/stores/auth-store", () => ({ useAuthStore: () => () => {} }))

const apiError = (status: number) => new ApiError("실패", "E", "", null, status)

// 실패가 확정될 때까지의 조회 함수 호출 수
const callsUntilError = async (key: string, error: Error) => {
const queryFn = vi.fn(async () => {
throw error
})
const { result } = renderHook(() => useQuery({ queryKey: [key], queryFn }), { wrapper: QueryProvider })
await waitFor(() => expect(result.current.isError).toBe(true), { timeout: 3000 })
return queryFn.mock.calls.length
}

describe("조회 재시도 기본값", () => {
it.each([400, 401, 404])("%i 요청 오류는 다시 보내도 같으므로 재시도하지 않는다", async (status) => {
expect(await callsUntilError(`client-${status}`, apiError(status))).toBe(1)
})

it.each([
["서버 오류(500)", apiError(500)],
["네트워크 오류(상태 0)", apiError(0)],
["ApiError가 아닌 오류", new Error("unknown")],
])("%s는 한 번만 다시 시도한다", async (name, error) => {
expect(await callsUntilError(name, error)).toBe(2)
})
})
9 changes: 9 additions & 0 deletions components/providers/QueryProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useState } from "react";
import { ApiError } from "@/lib/api";
import { AuthInitializer } from "./AuthInitializer";

// 조회 재시도 — 4xx는 다시 보내도 같으므로 바로 실패(401은 lib/api가 이미 재발급·1회 재시도함),
// 네트워크 오류·5xx 등은 한 번만 다시 시도한다. 기본(3회·지수 백오프)이면 실패 화면이 약 7초 늦게 뜬다
const retryQuery = (failureCount: number, error: Error): boolean => {
if (error instanceof ApiError && error.status >= 400 && error.status < 500) return false;
return failureCount < 1;
};

export function QueryProvider({ children }: { children: React.ReactNode }) {
const [queryClient] = useState(
() =>
Expand All @@ -12,6 +20,7 @@ export function QueryProvider({ children }: { children: React.ReactNode }) {
queries: {
staleTime: 60 * 1000, // 1분
refetchOnWindowFocus: false,
retry: retryQuery,
},
},
})
Expand Down
Loading