From d254c3c8137a46748332e2a8467721569094ab26 Mon Sep 17 00:00:00 2001 From: Kirill Date: Wed, 27 May 2026 21:30:42 +0500 Subject: [PATCH] fix: adapt useMutationWithToast to react-query v5 callback signatures --- .../use-mutation-with-toast.test.tsx | 26 ++++++++++--------- .../src/shared/lib/use-mutation-with-toast.ts | 18 ++++++------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/client/src/shared/lib/__tests__/use-mutation-with-toast.test.tsx b/client/src/shared/lib/__tests__/use-mutation-with-toast.test.tsx index 7b07073..7cddc99 100644 --- a/client/src/shared/lib/__tests__/use-mutation-with-toast.test.tsx +++ b/client/src/shared/lib/__tests__/use-mutation-with-toast.test.tsx @@ -21,47 +21,49 @@ describe('useMutationWithToast', () => { }) it('shows success notification on success with successMessage', async () => { - const mutationFn = vi.fn().mockResolvedValue({ ok: true }) + const mutationFn = (): Promise<{ ok: boolean }> => Promise.resolve({ ok: true }) const { result } = renderHook(() => useMutationWithToast({ mutationFn, successMessage: 'Done!' }), { wrapper: createWrapper(), }) - result.current.mutate() + ;(result.current.mutate as () => void)() await waitFor(() => expect(result.current.isSuccess).toBe(true)) expect(addNotification).toHaveBeenCalledWith({ type: 'success', message: 'Done!' }) }) it('does NOT show success notification without successMessage', async () => { - const mutationFn = vi.fn().mockResolvedValue({ ok: true }) + const mutationFn = (): Promise<{ ok: boolean }> => Promise.resolve({ ok: true }) const { result } = renderHook(() => useMutationWithToast({ mutationFn }), { wrapper: createWrapper() }) - result.current.mutate() + ;(result.current.mutate as () => void)() await waitFor(() => expect(result.current.isSuccess).toBe(true)) expect(addNotification).not.toHaveBeenCalled() }) it('shows error notification on mutation error', async () => { - const mutationFn = vi.fn().mockRejectedValue(new Error('Boom')) + const err = new Error('Boom') + const mutationFn = (): Promise => Promise.reject(err) const { result } = renderHook(() => useMutationWithToast({ mutationFn }), { wrapper: createWrapper() }) - result.current.mutate() + ;(result.current.mutate as () => void)() await waitFor(() => expect(result.current.isError).toBe(true)) expect(addNotification).toHaveBeenCalledWith({ type: 'error', message: 'Boom' }) }) it('calls user-provided onSuccess callback', async () => { - const onSuccess = vi.fn() - const mutationFn = vi.fn().mockResolvedValue({ ok: true }) + const onSuccess: (data: { ok: boolean }, variables: void, onMutateResult: unknown, mutationContext: unknown) => void = vi.fn() + const mutationFn = (): Promise<{ ok: boolean }> => Promise.resolve({ ok: true }) const { result } = renderHook(() => useMutationWithToast({ mutationFn, onSuccess, successMessage: 'OK' }), { wrapper: createWrapper(), }) - result.current.mutate() + ;(result.current.mutate as () => void)() await waitFor(() => expect(result.current.isSuccess).toBe(true)) expect(onSuccess).toHaveBeenCalled() }) it('calls user-provided onError callback', async () => { - const onError = vi.fn() - const mutationFn = vi.fn().mockRejectedValue(new Error('fail')) + const onError: (error: Error, variables: void, onMutateResult: unknown, mutationContext: unknown) => void = vi.fn() + const err = new Error('fail') + const mutationFn = (): Promise => Promise.reject(err) const { result } = renderHook(() => useMutationWithToast({ mutationFn, onError }), { wrapper: createWrapper() }) - result.current.mutate() + ;(result.current.mutate as () => void)() await waitFor(() => expect(result.current.isError).toBe(true)) expect(onError).toHaveBeenCalled() }) diff --git a/client/src/shared/lib/use-mutation-with-toast.ts b/client/src/shared/lib/use-mutation-with-toast.ts index e2a3e04..ccb98f9 100644 --- a/client/src/shared/lib/use-mutation-with-toast.ts +++ b/client/src/shared/lib/use-mutation-with-toast.ts @@ -1,32 +1,32 @@ -import { useMutation, type UseMutationOptions } from '@tanstack/react-query' +import { useMutation, type MutationFunctionContext, type UseMutationOptions } from '@tanstack/react-query' import { addNotification } from '../model/notification' import { getApiErrorMessage } from './get-api-error-message' -type MutationWithToastOptions = UseMutationOptions< +type MutationWithToastOptions = UseMutationOptions< TData, TError, TVariables, - TContext + TOnMutateResult > & { successMessage?: string } -export function useMutationWithToast( - options: MutationWithToastOptions, +export function useMutationWithToast( + options: MutationWithToastOptions, ) { const { successMessage, onSuccess, onError, ...mutationOptions } = options return useMutation({ ...mutationOptions, - onSuccess: (data, variables, context) => { + onSuccess: (data: TData, variables: TVariables, onMutateResult: TOnMutateResult, mutationContext: MutationFunctionContext) => { if (successMessage) { addNotification({ type: 'success', message: successMessage }) } - onSuccess?.(data, variables, context) + onSuccess?.(data, variables, onMutateResult, mutationContext) }, - onError: (error, variables, context) => { + onError: (error: TError, variables: TVariables, onMutateResult: TOnMutateResult | undefined, mutationContext: MutationFunctionContext) => { addNotification({ type: 'error', message: getApiErrorMessage(error) }) - onError?.(error, variables, context) + onError?.(error, variables, onMutateResult, mutationContext) }, }) }