diff --git a/packages/svelte-query/tests/createMutation/InvalidateFromContext.svelte b/packages/svelte-query/tests/createMutation/InvalidateFromContext.svelte
new file mode 100644
index 0000000000..400c153d78
--- /dev/null
+++ b/packages/svelte-query/tests/createMutation/InvalidateFromContext.svelte
@@ -0,0 +1,23 @@
+
+
+
diff --git a/packages/svelte-query/tests/createMutation/MutationFnContext.svelte b/packages/svelte-query/tests/createMutation/MutationFnContext.svelte
new file mode 100644
index 0000000000..1e831a0331
--- /dev/null
+++ b/packages/svelte-query/tests/createMutation/MutationFnContext.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
data: {mutation.data}
diff --git a/packages/svelte-query/tests/createMutation/PerCallSuccess.svelte b/packages/svelte-query/tests/createMutation/PerCallSuccess.svelte
new file mode 100644
index 0000000000..f50fa88595
--- /dev/null
+++ b/packages/svelte-query/tests/createMutation/PerCallSuccess.svelte
@@ -0,0 +1,24 @@
+
+
+
diff --git a/packages/svelte-query/tests/createMutation/SuccessContext.svelte b/packages/svelte-query/tests/createMutation/SuccessContext.svelte
new file mode 100644
index 0000000000..a132cb2c7d
--- /dev/null
+++ b/packages/svelte-query/tests/createMutation/SuccessContext.svelte
@@ -0,0 +1,24 @@
+
+
+
diff --git a/packages/svelte-query/tests/createMutation/createMutation.svelte.test.ts b/packages/svelte-query/tests/createMutation/createMutation.svelte.test.ts
index 2c44298cda..7195054194 100644
--- a/packages/svelte-query/tests/createMutation/createMutation.svelte.test.ts
+++ b/packages/svelte-query/tests/createMutation/createMutation.svelte.test.ts
@@ -9,6 +9,10 @@ import Reset from './Reset.svelte'
import Success from './Success.svelte'
import Failure from './Failure.svelte'
import OptimisticUpdate from './OptimisticUpdate.svelte'
+import SuccessContext from './SuccessContext.svelte'
+import InvalidateFromContext from './InvalidateFromContext.svelte'
+import PerCallSuccess from './PerCallSuccess.svelte'
+import MutationFnContext from './MutationFnContext.svelte'
describe('createMutation', () => {
let queryClient: QueryClient
@@ -171,4 +175,86 @@ describe('createMutation', () => {
expect(queryClient.getQueryData(key)).toEqual(['Todo 1', 'Todo 2'])
})
+
+ it('should pass a non-undefined onMutateResult alongside context to onSuccess', async () => {
+ const onSuccessMock = vi.fn()
+
+ const rendered = render(SuccessContext, {
+ props: { queryClient, onSuccessMock },
+ })
+
+ fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
+ await vi.advanceTimersByTimeAsync(10)
+
+ expect(onSuccessMock).toHaveBeenCalledTimes(1)
+ const [data, variables, onMutateResult, context] =
+ onSuccessMock.mock.calls[0]!
+ expect(data).toBe('TODO')
+ expect(variables).toBe('todo')
+ expect(onMutateResult).toEqual({ startedWith: 'todo' })
+ expect(context.client).toBe(queryClient)
+ expect(context.meta).toBeUndefined()
+ expect(context.mutationKey).toBeUndefined()
+ })
+
+ it('should include mutationKey in the context passed to hook-level callbacks', async () => {
+ const onSuccessMock = vi.fn()
+
+ const rendered = render(SuccessContext, {
+ props: { queryClient, mutationKey: ['todos', 'add'], onSuccessMock },
+ })
+
+ fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
+ await vi.advanceTimersByTimeAsync(10)
+
+ expect(onSuccessMock).toHaveBeenCalledTimes(1)
+ expect(onSuccessMock.mock.calls[0]?.[3].mutationKey).toEqual([
+ 'todos',
+ 'add',
+ ])
+ })
+
+ it('should give mutationFn the same QueryClient instance via context', async () => {
+ const key = queryKey()
+ queryClient.setQueryData(key, 'tag-from-this-client')
+
+ const rendered = render(MutationFnContext, {
+ props: { queryClient, queryKey: key },
+ })
+
+ fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
+ await vi.advanceTimersByTimeAsync(11)
+
+ expect(rendered.getByText('data: tag-from-this-client')).toBeInTheDocument()
+ })
+
+ it('should let onSuccess invalidate queries via context.client without a useQueryClient() closure', async () => {
+ const key = queryKey()
+ queryClient.setQueryData(key, 'data')
+
+ const rendered = render(InvalidateFromContext, {
+ props: { queryClient, queryKey: key },
+ })
+
+ expect(queryClient.getQueryState(key)?.isInvalidated).toBe(false)
+
+ fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
+ await vi.advanceTimersByTimeAsync(10)
+
+ expect(queryClient.getQueryState(key)?.isInvalidated).toBe(true)
+ })
+
+ it('should give a per-call onSuccess the same QueryClient instance via context', async () => {
+ const perCallOnSuccess = vi.fn()
+
+ const rendered = render(PerCallSuccess, {
+ props: { queryClient, perCallOnSuccess },
+ })
+
+ fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
+ await vi.advanceTimersByTimeAsync(10)
+
+ expect(perCallOnSuccess).toHaveBeenCalledTimes(1)
+ expect(perCallOnSuccess.mock.calls[0]?.[3].client).toBe(queryClient)
+ })
})
diff --git a/packages/svelte-query/tests/createMutation/createMutation.test-d.ts b/packages/svelte-query/tests/createMutation/createMutation.test-d.ts
index a5a4bd8419..cc1cfa6c1a 100644
--- a/packages/svelte-query/tests/createMutation/createMutation.test-d.ts
+++ b/packages/svelte-query/tests/createMutation/createMutation.test-d.ts
@@ -1,7 +1,11 @@
import { describe, expectTypeOf, it } from 'vitest'
import { QueryClient } from '@tanstack/query-core'
import { createMutation } from '../../src/index.js'
-import type { DefaultError } from '@tanstack/query-core'
+import type {
+ DefaultError,
+ MutationFunctionContext,
+ MutationKey,
+} from '@tanstack/query-core'
import type { CreateMutationResult } from '../../src/types.js'
describe('createMutation', () => {
@@ -144,4 +148,56 @@ describe('createMutation', () => {
expectTypeOf(mutation.data).toEqualTypeOf()
})
+
+ it('should type context as the last argument for mutationFn and every hook-level callback', () => {
+ createMutation(() => ({
+ mutationFn: (_vars: string, context) => {
+ expectTypeOf(context).toEqualTypeOf()
+ expectTypeOf(context.client).toEqualTypeOf()
+ return Promise.resolve('data')
+ },
+ onMutate: (_variables, context) => {
+ expectTypeOf(context).toEqualTypeOf()
+ },
+ onSuccess: (_data, _variables, _onMutateResult, context) => {
+ expectTypeOf(context).toEqualTypeOf()
+ },
+ onError: (_error, _variables, _onMutateResult, context) => {
+ expectTypeOf(context).toEqualTypeOf()
+ },
+ onSettled: (_data, _error, _variables, _onMutateResult, context) => {
+ expectTypeOf(context).toEqualTypeOf()
+ },
+ }))
+ })
+
+ it('should type context as the last argument for every per-call mutate option', () => {
+ const mutation = createMutation(() => ({
+ mutationFn: () => Promise.resolve('data'),
+ }))
+
+ mutation.mutate(undefined, {
+ onSuccess: (_data, _variables, _onMutateResult, context) => {
+ expectTypeOf(context).toEqualTypeOf()
+ },
+ onError: (_error, _variables, _onMutateResult, context) => {
+ expectTypeOf(context).toEqualTypeOf()
+ },
+ onSettled: (_data, _error, _variables, _onMutateResult, context) => {
+ expectTypeOf(context).toEqualTypeOf()
+ },
+ })
+ })
+
+ it('should type context.mutationKey as MutationKey', () => {
+ createMutation(() => ({
+ mutationKey: ['todos', 'add'] as const,
+ mutationFn: () => Promise.resolve('data'),
+ onSuccess: (_data, _variables, _onMutateResult, context) => {
+ expectTypeOf(context.mutationKey).toEqualTypeOf<
+ MutationKey | undefined
+ >()
+ },
+ }))
+ })
})