snapshot of https://github.com/TanStack/query.git (main, 2026-09-16; blobs > 131072B omitted)
This commit is contained in:
60
packages/svelte-query/tests/mutationOptions/Base.svelte
Normal file
60
packages/svelte-query/tests/mutationOptions/Base.svelte
Normal file
@@ -0,0 +1,60 @@
|
||||
<script lang="ts">
|
||||
import type { QueryClient } from '@tanstack/query-core'
|
||||
import {
|
||||
createMutation,
|
||||
setQueryClientContext,
|
||||
useIsMutating,
|
||||
useMutationState,
|
||||
} from '../../src/index.js'
|
||||
import type {
|
||||
Accessor,
|
||||
CreateMutationOptions,
|
||||
MutationStateOptions,
|
||||
} from '../../src/index.js'
|
||||
import type { MutationFilters } from '@tanstack/query-core'
|
||||
|
||||
type Props = {
|
||||
queryClient: QueryClient
|
||||
mutationOpts: Accessor<CreateMutationOptions<string>>
|
||||
isMutatingFilters?: MutationFilters
|
||||
mutationStateOpts?: MutationStateOptions
|
||||
}
|
||||
|
||||
let {
|
||||
queryClient,
|
||||
mutationOpts,
|
||||
isMutatingFilters,
|
||||
mutationStateOpts,
|
||||
}: Props = $props()
|
||||
|
||||
setQueryClientContext(queryClient)
|
||||
|
||||
const mutation = createMutation(mutationOpts)
|
||||
const isMutating = useIsMutating(isMutatingFilters)
|
||||
const mutationState = useMutationState(mutationStateOpts)
|
||||
|
||||
let clientIsMutating = $state(0)
|
||||
|
||||
$effect(() => {
|
||||
const mutationCache = queryClient.getMutationCache()
|
||||
clientIsMutating = isMutatingFilters
|
||||
? queryClient.isMutating(isMutatingFilters)
|
||||
: queryClient.isMutating()
|
||||
|
||||
const unsubscribe = mutationCache.subscribe(() => {
|
||||
clientIsMutating = isMutatingFilters
|
||||
? queryClient.isMutating(isMutatingFilters)
|
||||
: queryClient.isMutating()
|
||||
})
|
||||
|
||||
return unsubscribe
|
||||
})
|
||||
</script>
|
||||
|
||||
<button onclick={() => mutation.mutate()}>mutate</button>
|
||||
|
||||
<div>isMutating: {isMutating.current}</div>
|
||||
<div>clientIsMutating: {clientIsMutating}</div>
|
||||
<div>
|
||||
mutationState: {JSON.stringify(mutationState.map((state) => state.data))}
|
||||
</div>
|
||||
64
packages/svelte-query/tests/mutationOptions/Multi.svelte
Normal file
64
packages/svelte-query/tests/mutationOptions/Multi.svelte
Normal file
@@ -0,0 +1,64 @@
|
||||
<script lang="ts">
|
||||
import type { QueryClient } from '@tanstack/query-core'
|
||||
import {
|
||||
createMutation,
|
||||
setQueryClientContext,
|
||||
useIsMutating,
|
||||
useMutationState,
|
||||
} from '../../src/index.js'
|
||||
import type {
|
||||
Accessor,
|
||||
CreateMutationOptions,
|
||||
MutationStateOptions,
|
||||
} from '../../src/index.js'
|
||||
import type { MutationFilters } from '@tanstack/query-core'
|
||||
|
||||
type Props = {
|
||||
queryClient: QueryClient
|
||||
mutationOpts1: Accessor<CreateMutationOptions<string>>
|
||||
mutationOpts2: Accessor<CreateMutationOptions<string>>
|
||||
isMutatingFilters?: MutationFilters
|
||||
mutationStateOpts?: MutationStateOptions
|
||||
}
|
||||
|
||||
let {
|
||||
queryClient,
|
||||
mutationOpts1,
|
||||
mutationOpts2,
|
||||
isMutatingFilters,
|
||||
mutationStateOpts,
|
||||
}: Props = $props()
|
||||
|
||||
setQueryClientContext(queryClient)
|
||||
|
||||
const mutation1 = createMutation(mutationOpts1)
|
||||
const mutation2 = createMutation(mutationOpts2)
|
||||
const isMutating = useIsMutating(isMutatingFilters)
|
||||
const mutationState = useMutationState(mutationStateOpts)
|
||||
|
||||
let clientIsMutating = $state(0)
|
||||
|
||||
$effect(() => {
|
||||
const mutationCache = queryClient.getMutationCache()
|
||||
clientIsMutating = isMutatingFilters
|
||||
? queryClient.isMutating(isMutatingFilters)
|
||||
: queryClient.isMutating()
|
||||
|
||||
const unsubscribe = mutationCache.subscribe(() => {
|
||||
clientIsMutating = isMutatingFilters
|
||||
? queryClient.isMutating(isMutatingFilters)
|
||||
: queryClient.isMutating()
|
||||
})
|
||||
|
||||
return unsubscribe
|
||||
})
|
||||
</script>
|
||||
|
||||
<button onclick={() => mutation1.mutate()}>mutate1</button>
|
||||
<button onclick={() => mutation2.mutate()}>mutate2</button>
|
||||
|
||||
<div>isMutating: {isMutating.current}</div>
|
||||
<div>clientIsMutating: {clientIsMutating}</div>
|
||||
<div>
|
||||
mutationState: {JSON.stringify(mutationState.map((state) => state.data))}
|
||||
</div>
|
||||
@@ -0,0 +1,344 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { fireEvent, render } from '@testing-library/svelte'
|
||||
import { QueryClient } from '@tanstack/query-core'
|
||||
import { queryKey, sleep } from '@tanstack/query-test-utils'
|
||||
import { mutationOptions } from '../../src/index.js'
|
||||
import Base from './Base.svelte'
|
||||
import Multi from './Multi.svelte'
|
||||
|
||||
describe('mutationOptions', () => {
|
||||
let queryClient: QueryClient
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
queryClient = new QueryClient()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
queryClient.clear()
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('should return the object received as a parameter without any modification (with mutationKey in mutationOptions)', () => {
|
||||
const object = {
|
||||
mutationKey: ['key'],
|
||||
mutationFn: () => sleep(10).then(() => 5),
|
||||
} as const
|
||||
|
||||
expect(mutationOptions(object)).toBe(object)
|
||||
})
|
||||
|
||||
it('should return the object received as a parameter without any modification (without mutationKey in mutationOptions)', () => {
|
||||
const object = {
|
||||
mutationFn: () => sleep(10).then(() => 5),
|
||||
} as const
|
||||
|
||||
expect(mutationOptions(object)).toBe(object)
|
||||
})
|
||||
|
||||
it('should return the number of fetching mutations when used with useIsMutating (with mutationKey in mutationOptions)', async () => {
|
||||
const key = queryKey()
|
||||
const mutationOpts = mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => sleep(50).then(() => 'data'),
|
||||
})
|
||||
|
||||
const rendered = render(Base, {
|
||||
props: { queryClient, mutationOpts: () => mutationOpts },
|
||||
})
|
||||
|
||||
expect(rendered.getByText('isMutating: 0')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
expect(rendered.getByText('isMutating: 1')).toBeInTheDocument()
|
||||
await vi.advanceTimersByTimeAsync(50)
|
||||
expect(rendered.getByText('isMutating: 0')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return the number of fetching mutations when used with useIsMutating (without mutationKey in mutationOptions)', async () => {
|
||||
const mutationOpts = mutationOptions({
|
||||
mutationFn: () => sleep(50).then(() => 'data'),
|
||||
})
|
||||
|
||||
const rendered = render(Base, {
|
||||
props: { queryClient, mutationOpts: () => mutationOpts },
|
||||
})
|
||||
|
||||
expect(rendered.getByText('isMutating: 0')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
expect(rendered.getByText('isMutating: 1')).toBeInTheDocument()
|
||||
await vi.advanceTimersByTimeAsync(50)
|
||||
expect(rendered.getByText('isMutating: 0')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return the number of fetching mutations when used with useIsMutating', async () => {
|
||||
const key = queryKey()
|
||||
const mutationOpts1 = mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => sleep(50).then(() => 'data1'),
|
||||
})
|
||||
const mutationOpts2 = mutationOptions({
|
||||
mutationFn: () => sleep(50).then(() => 'data2'),
|
||||
})
|
||||
|
||||
const rendered = render(Multi, {
|
||||
props: {
|
||||
queryClient,
|
||||
mutationOpts1: () => mutationOpts1,
|
||||
mutationOpts2: () => mutationOpts2,
|
||||
},
|
||||
})
|
||||
|
||||
expect(rendered.getByText('isMutating: 0')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate1/i }))
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate2/i }))
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
expect(rendered.getByText('isMutating: 2')).toBeInTheDocument()
|
||||
await vi.advanceTimersByTimeAsync(50)
|
||||
expect(rendered.getByText('isMutating: 0')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return the number of fetching mutations when used with useIsMutating (filter mutationOpts1.mutationKey)', async () => {
|
||||
const key = queryKey()
|
||||
const mutationOpts1 = mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => sleep(50).then(() => 'data1'),
|
||||
})
|
||||
const mutationOpts2 = mutationOptions({
|
||||
mutationFn: () => sleep(50).then(() => 'data2'),
|
||||
})
|
||||
|
||||
const rendered = render(Multi, {
|
||||
props: {
|
||||
queryClient,
|
||||
mutationOpts1: () => mutationOpts1,
|
||||
mutationOpts2: () => mutationOpts2,
|
||||
isMutatingFilters: { mutationKey: mutationOpts1.mutationKey },
|
||||
},
|
||||
})
|
||||
|
||||
expect(rendered.getByText('isMutating: 0')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate1/i }))
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate2/i }))
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
expect(rendered.getByText('isMutating: 1')).toBeInTheDocument()
|
||||
await vi.advanceTimersByTimeAsync(50)
|
||||
expect(rendered.getByText('isMutating: 0')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return the number of fetching mutations when used with queryClient.isMutating (with mutationKey in mutationOptions)', async () => {
|
||||
const key = queryKey()
|
||||
const mutationOpts = mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => sleep(500).then(() => 'data'),
|
||||
})
|
||||
|
||||
const rendered = render(Base, {
|
||||
props: {
|
||||
queryClient,
|
||||
mutationOpts: () => mutationOpts,
|
||||
isMutatingFilters: { mutationKey: mutationOpts.mutationKey },
|
||||
},
|
||||
})
|
||||
|
||||
expect(rendered.getByText('clientIsMutating: 0')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
expect(rendered.getByText('clientIsMutating: 1')).toBeInTheDocument()
|
||||
await vi.advanceTimersByTimeAsync(500)
|
||||
expect(rendered.getByText('clientIsMutating: 0')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return the number of fetching mutations when used with queryClient.isMutating (without mutationKey in mutationOptions)', async () => {
|
||||
const mutationOpts = mutationOptions({
|
||||
mutationFn: () => sleep(500).then(() => 'data'),
|
||||
})
|
||||
|
||||
const rendered = render(Base, {
|
||||
props: { queryClient, mutationOpts: () => mutationOpts },
|
||||
})
|
||||
|
||||
expect(rendered.getByText('clientIsMutating: 0')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
expect(rendered.getByText('clientIsMutating: 1')).toBeInTheDocument()
|
||||
await vi.advanceTimersByTimeAsync(500)
|
||||
expect(rendered.getByText('clientIsMutating: 0')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return the number of fetching mutations when used with queryClient.isMutating', async () => {
|
||||
const key = queryKey()
|
||||
const mutationOpts1 = mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => sleep(500).then(() => 'data1'),
|
||||
})
|
||||
const mutationOpts2 = mutationOptions({
|
||||
mutationFn: () => sleep(500).then(() => 'data2'),
|
||||
})
|
||||
|
||||
const rendered = render(Multi, {
|
||||
props: {
|
||||
queryClient,
|
||||
mutationOpts1: () => mutationOpts1,
|
||||
mutationOpts2: () => mutationOpts2,
|
||||
},
|
||||
})
|
||||
|
||||
expect(rendered.getByText('clientIsMutating: 0')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate1/i }))
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate2/i }))
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
expect(rendered.getByText('clientIsMutating: 2')).toBeInTheDocument()
|
||||
await vi.advanceTimersByTimeAsync(500)
|
||||
expect(rendered.getByText('clientIsMutating: 0')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return the number of fetching mutations when used with queryClient.isMutating (filter mutationOpts1.mutationKey)', async () => {
|
||||
const key = queryKey()
|
||||
const mutationOpts1 = mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => sleep(500).then(() => 'data1'),
|
||||
})
|
||||
const mutationOpts2 = mutationOptions({
|
||||
mutationFn: () => sleep(500).then(() => 'data2'),
|
||||
})
|
||||
|
||||
const rendered = render(Multi, {
|
||||
props: {
|
||||
queryClient,
|
||||
mutationOpts1: () => mutationOpts1,
|
||||
mutationOpts2: () => mutationOpts2,
|
||||
isMutatingFilters: { mutationKey: mutationOpts1.mutationKey },
|
||||
},
|
||||
})
|
||||
|
||||
expect(rendered.getByText('clientIsMutating: 0')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate1/i }))
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate2/i }))
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
expect(rendered.getByText('clientIsMutating: 1')).toBeInTheDocument()
|
||||
await vi.advanceTimersByTimeAsync(500)
|
||||
expect(rendered.getByText('clientIsMutating: 0')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return mutation states when used with useMutationState (with mutationKey in mutationOptions)', async () => {
|
||||
const key = queryKey()
|
||||
const mutationOpts = mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => sleep(10).then(() => 'data'),
|
||||
})
|
||||
|
||||
const rendered = render(Base, {
|
||||
props: {
|
||||
queryClient,
|
||||
mutationOpts: () => mutationOpts,
|
||||
mutationStateOpts: {
|
||||
filters: {
|
||||
mutationKey: mutationOpts.mutationKey,
|
||||
status: 'success',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(rendered.getByText('mutationState: []')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
expect(rendered.getByText('mutationState: ["data"]')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return mutation states when used with useMutationState (without mutationKey in mutationOptions)', async () => {
|
||||
const mutationOpts = mutationOptions({
|
||||
mutationFn: () => sleep(10).then(() => 'data'),
|
||||
})
|
||||
|
||||
const rendered = render(Base, {
|
||||
props: {
|
||||
queryClient,
|
||||
mutationOpts: () => mutationOpts,
|
||||
mutationStateOpts: {
|
||||
filters: { status: 'success' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(rendered.getByText('mutationState: []')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
expect(rendered.getByText('mutationState: ["data"]')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return mutation states when used with useMutationState', async () => {
|
||||
const key = queryKey()
|
||||
const mutationOpts1 = mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => sleep(10).then(() => 'data1'),
|
||||
})
|
||||
const mutationOpts2 = mutationOptions({
|
||||
mutationFn: () => sleep(10).then(() => 'data2'),
|
||||
})
|
||||
|
||||
const rendered = render(Multi, {
|
||||
props: {
|
||||
queryClient,
|
||||
mutationOpts1: () => mutationOpts1,
|
||||
mutationOpts2: () => mutationOpts2,
|
||||
mutationStateOpts: {
|
||||
filters: { status: 'success' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(rendered.getByText('mutationState: []')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate1/i }))
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate2/i }))
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
expect(
|
||||
rendered.getByText('mutationState: ["data1","data2"]'),
|
||||
).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should return mutation states when used with useMutationState (filter mutationOpts1.mutationKey)', async () => {
|
||||
const key = queryKey()
|
||||
const mutationOpts1 = mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => sleep(10).then(() => 'data1'),
|
||||
})
|
||||
const mutationOpts2 = mutationOptions({
|
||||
mutationFn: () => sleep(10).then(() => 'data2'),
|
||||
})
|
||||
|
||||
const rendered = render(Multi, {
|
||||
props: {
|
||||
queryClient,
|
||||
mutationOpts1: () => mutationOpts1,
|
||||
mutationOpts2: () => mutationOpts2,
|
||||
mutationStateOpts: {
|
||||
filters: {
|
||||
mutationKey: mutationOpts1.mutationKey,
|
||||
status: 'success',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(rendered.getByText('mutationState: []')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate1/i }))
|
||||
fireEvent.click(rendered.getByRole('button', { name: /mutate2/i }))
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
expect(rendered.getByText('mutationState: ["data1"]')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,246 @@
|
||||
import { assertType, describe, expectTypeOf, it } from 'vitest'
|
||||
import { QueryClient } from '@tanstack/query-core'
|
||||
import { queryKey } from '@tanstack/query-test-utils'
|
||||
import {
|
||||
createMutation,
|
||||
mutationOptions,
|
||||
useIsMutating,
|
||||
useMutationState,
|
||||
} from '../../src/index.js'
|
||||
import type {
|
||||
DefaultError,
|
||||
MutationFunctionContext,
|
||||
MutationState,
|
||||
WithRequired,
|
||||
} from '@tanstack/query-core'
|
||||
import type {
|
||||
CreateMutationOptions,
|
||||
CreateMutationResult,
|
||||
} from '../../src/types.js'
|
||||
|
||||
describe('mutationOptions', () => {
|
||||
it('should not allow excess properties', () => {
|
||||
const key = queryKey()
|
||||
|
||||
// @ts-expect-error this is a good error, because onMutates does not exist!
|
||||
mutationOptions({
|
||||
mutationFn: () => Promise.resolve(5),
|
||||
mutationKey: key,
|
||||
onMutates: 1000,
|
||||
onSuccess: (data) => {
|
||||
expectTypeOf(data).toEqualTypeOf<number>()
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should infer types for callbacks', () => {
|
||||
const key = queryKey()
|
||||
|
||||
mutationOptions({
|
||||
mutationFn: () => Promise.resolve(5),
|
||||
mutationKey: key,
|
||||
onSuccess: (data) => {
|
||||
expectTypeOf(data).toEqualTypeOf<number>()
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should infer types for onError callback', () => {
|
||||
const key = queryKey()
|
||||
|
||||
mutationOptions({
|
||||
mutationFn: () => {
|
||||
throw new Error('fail')
|
||||
},
|
||||
mutationKey: key,
|
||||
onError: (error) => {
|
||||
expectTypeOf(error).toEqualTypeOf<DefaultError>()
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should infer types for variables', () => {
|
||||
const key = queryKey()
|
||||
|
||||
mutationOptions<number, DefaultError, { id: string }>({
|
||||
mutationFn: (vars) => {
|
||||
expectTypeOf(vars).toEqualTypeOf<{ id: string }>()
|
||||
return Promise.resolve(5)
|
||||
},
|
||||
mutationKey: key,
|
||||
})
|
||||
})
|
||||
|
||||
it('should infer result type correctly', () => {
|
||||
const key = queryKey()
|
||||
|
||||
mutationOptions<number, DefaultError, void, { name: string }>({
|
||||
mutationFn: () => Promise.resolve(5),
|
||||
mutationKey: key,
|
||||
onMutate: () => {
|
||||
return { name: 'onMutateResult' }
|
||||
},
|
||||
onSuccess: (_data, _variables, onMutateResult) => {
|
||||
expectTypeOf(onMutateResult).toEqualTypeOf<{ name: string }>()
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should infer context type correctly', () => {
|
||||
const key = queryKey()
|
||||
|
||||
mutationOptions<number>({
|
||||
mutationFn: (_variables, context) => {
|
||||
expectTypeOf(context).toEqualTypeOf<MutationFunctionContext>()
|
||||
return Promise.resolve(5)
|
||||
},
|
||||
mutationKey: key,
|
||||
onMutate: (_variables, context) => {
|
||||
expectTypeOf(context).toEqualTypeOf<MutationFunctionContext>()
|
||||
},
|
||||
onSuccess: (_data, _variables, _onMutateResult, context) => {
|
||||
expectTypeOf(context).toEqualTypeOf<MutationFunctionContext>()
|
||||
},
|
||||
onError: (_error, _variables, _onMutateResult, context) => {
|
||||
expectTypeOf(context).toEqualTypeOf<MutationFunctionContext>()
|
||||
},
|
||||
onSettled: (_data, _error, _variables, _onMutateResult, context) => {
|
||||
expectTypeOf(context).toEqualTypeOf<MutationFunctionContext>()
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should error if mutationFn return type mismatches TData', () => {
|
||||
assertType(
|
||||
mutationOptions<number>({
|
||||
// @ts-expect-error this is a good error, because return type is string, not number
|
||||
mutationFn: async () => Promise.resolve('wrong return'),
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('should allow mutationKey to be omitted', () => {
|
||||
return mutationOptions({
|
||||
mutationFn: () => Promise.resolve(123),
|
||||
onSuccess: (data) => {
|
||||
expectTypeOf(data).toEqualTypeOf<number>()
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should infer all types when not explicitly provided', () => {
|
||||
const key = queryKey()
|
||||
|
||||
expectTypeOf(
|
||||
mutationOptions({
|
||||
mutationFn: (id: string) => Promise.resolve(id.length),
|
||||
mutationKey: key,
|
||||
onSuccess: (data) => {
|
||||
expectTypeOf(data).toEqualTypeOf<number>()
|
||||
},
|
||||
}),
|
||||
).toEqualTypeOf<
|
||||
WithRequired<
|
||||
CreateMutationOptions<number, DefaultError, string>,
|
||||
'mutationKey'
|
||||
>
|
||||
>()
|
||||
expectTypeOf(
|
||||
mutationOptions({
|
||||
mutationFn: (id: string) => Promise.resolve(id.length),
|
||||
onSuccess: (data) => {
|
||||
expectTypeOf(data).toEqualTypeOf<number>()
|
||||
},
|
||||
}),
|
||||
).toEqualTypeOf<
|
||||
Omit<CreateMutationOptions<number, DefaultError, string>, 'mutationKey'>
|
||||
>()
|
||||
})
|
||||
|
||||
it('should work when used with createMutation', () => {
|
||||
const key = queryKey()
|
||||
|
||||
const mutation = createMutation(() =>
|
||||
mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => Promise.resolve('data'),
|
||||
onSuccess: (data) => {
|
||||
expectTypeOf(data).toEqualTypeOf<string>()
|
||||
},
|
||||
}),
|
||||
)
|
||||
expectTypeOf(mutation).toEqualTypeOf<
|
||||
CreateMutationResult<string, DefaultError, void, unknown>
|
||||
>()
|
||||
|
||||
createMutation(() =>
|
||||
// should allow when used with createMutation without mutationKey
|
||||
mutationOptions({
|
||||
mutationFn: () => Promise.resolve('data'),
|
||||
onSuccess: (data) => {
|
||||
expectTypeOf(data).toEqualTypeOf<string>()
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('should work when used with useIsMutating', () => {
|
||||
const key = queryKey()
|
||||
|
||||
const isMutating = useIsMutating(
|
||||
mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => Promise.resolve(5),
|
||||
}),
|
||||
)
|
||||
expectTypeOf(isMutating.current).toEqualTypeOf<number>()
|
||||
|
||||
useIsMutating(
|
||||
// @ts-expect-error filters should have mutationKey
|
||||
mutationOptions({
|
||||
mutationFn: () => Promise.resolve(5),
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('should work when used with queryClient.isMutating', () => {
|
||||
const key = queryKey()
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
const isMutating = queryClient.isMutating(
|
||||
mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => Promise.resolve(5),
|
||||
}),
|
||||
)
|
||||
expectTypeOf(isMutating).toEqualTypeOf<number>()
|
||||
|
||||
queryClient.isMutating(
|
||||
// @ts-expect-error filters should have mutationKey
|
||||
mutationOptions({
|
||||
mutationFn: () => Promise.resolve(5),
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('should work when used with useMutationState', () => {
|
||||
const key = queryKey()
|
||||
|
||||
const mutationState = useMutationState({
|
||||
filters: mutationOptions({
|
||||
mutationKey: key,
|
||||
mutationFn: () => Promise.resolve(5),
|
||||
}),
|
||||
})
|
||||
expectTypeOf(mutationState).toEqualTypeOf<
|
||||
Array<MutationState<unknown, Error, unknown, unknown>>
|
||||
>()
|
||||
|
||||
useMutationState({
|
||||
// @ts-expect-error filters should have mutationKey
|
||||
filters: mutationOptions({
|
||||
mutationFn: () => Promise.resolve(5),
|
||||
}),
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user