@tanstack/query-core 5.0.0-alpha.0 → 5.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/build/lib/index.d.ts +1 -1
  2. package/build/lib/index.esm.js +1 -1
  3. package/build/lib/index.js +1 -0
  4. package/build/lib/index.js.map +1 -1
  5. package/build/lib/index.mjs +1 -1
  6. package/build/lib/infiniteQueryObserver.d.ts +2 -2
  7. package/build/lib/infiniteQueryObserver.esm.js.map +1 -1
  8. package/build/lib/infiniteQueryObserver.js.map +1 -1
  9. package/build/lib/infiniteQueryObserver.mjs.map +1 -1
  10. package/build/lib/mutation.d.ts +3 -3
  11. package/build/lib/mutation.esm.js +6 -0
  12. package/build/lib/mutation.esm.js.map +1 -1
  13. package/build/lib/mutation.js +6 -0
  14. package/build/lib/mutation.js.map +1 -1
  15. package/build/lib/mutation.mjs +6 -0
  16. package/build/lib/mutation.mjs.map +1 -1
  17. package/build/lib/mutationCache.d.ts +4 -3
  18. package/build/lib/mutationCache.esm.js.map +1 -1
  19. package/build/lib/mutationCache.js.map +1 -1
  20. package/build/lib/mutationCache.mjs.map +1 -1
  21. package/build/lib/mutationObserver.d.ts +2 -2
  22. package/build/lib/mutationObserver.esm.js +1 -3
  23. package/build/lib/mutationObserver.esm.js.map +1 -1
  24. package/build/lib/mutationObserver.js +1 -3
  25. package/build/lib/mutationObserver.js.map +1 -1
  26. package/build/lib/mutationObserver.mjs +1 -3
  27. package/build/lib/mutationObserver.mjs.map +1 -1
  28. package/build/lib/queriesObserver.esm.js +1 -5
  29. package/build/lib/queriesObserver.esm.js.map +1 -1
  30. package/build/lib/queriesObserver.js +1 -5
  31. package/build/lib/queriesObserver.js.map +1 -1
  32. package/build/lib/queriesObserver.mjs +1 -5
  33. package/build/lib/queriesObserver.mjs.map +1 -1
  34. package/build/lib/query.d.ts +4 -4
  35. package/build/lib/query.esm.js +2 -0
  36. package/build/lib/query.esm.js.map +1 -1
  37. package/build/lib/query.js +2 -0
  38. package/build/lib/query.js.map +1 -1
  39. package/build/lib/query.mjs +2 -0
  40. package/build/lib/query.mjs.map +1 -1
  41. package/build/lib/queryCache.d.ts +4 -3
  42. package/build/lib/queryCache.esm.js.map +1 -1
  43. package/build/lib/queryCache.js.map +1 -1
  44. package/build/lib/queryCache.mjs.map +1 -1
  45. package/build/lib/queryClient.d.ts +7 -7
  46. package/build/lib/queryClient.esm.js.map +1 -1
  47. package/build/lib/queryClient.js.map +1 -1
  48. package/build/lib/queryClient.mjs.map +1 -1
  49. package/build/lib/queryObserver.d.ts +2 -2
  50. package/build/lib/queryObserver.esm.js.map +1 -1
  51. package/build/lib/queryObserver.js.map +1 -1
  52. package/build/lib/queryObserver.mjs.map +1 -1
  53. package/build/lib/retryer.d.ts +5 -5
  54. package/build/lib/retryer.esm.js.map +1 -1
  55. package/build/lib/retryer.js.map +1 -1
  56. package/build/lib/retryer.mjs.map +1 -1
  57. package/build/lib/subscribable.esm.js.map +1 -1
  58. package/build/lib/subscribable.js.map +1 -1
  59. package/build/lib/subscribable.mjs.map +1 -1
  60. package/build/lib/types.d.ts +38 -38
  61. package/build/umd/index.development.js +11 -8
  62. package/build/umd/index.development.js.map +1 -1
  63. package/build/umd/index.production.js +1 -1
  64. package/build/umd/index.production.js.map +1 -1
  65. package/package.json +1 -1
  66. package/src/index.ts +7 -1
  67. package/src/infiniteQueryObserver.ts +2 -2
  68. package/src/mutation.ts +22 -4
  69. package/src/mutationCache.ts +10 -3
  70. package/src/mutationObserver.ts +3 -5
  71. package/src/queriesObserver.ts +3 -7
  72. package/src/query.ts +15 -5
  73. package/src/queryCache.ts +8 -3
  74. package/src/queryClient.ts +7 -7
  75. package/src/queryObserver.ts +4 -4
  76. package/src/retryer.ts +5 -5
  77. package/src/subscribable.ts +1 -1
  78. package/src/tests/mutationCache.test.tsx +54 -10
  79. package/src/tests/queryCache.test.tsx +18 -6
  80. package/src/types.ts +44 -36
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/query-core",
3
- "version": "5.0.0-alpha.0",
3
+ "version": "5.0.0-alpha.2",
4
4
  "description": "The framework agnostic core that powers TanStack Query",
5
5
  "author": "tannerlinsley",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -11,7 +11,13 @@ export { MutationObserver } from './mutationObserver'
11
11
  export { notifyManager } from './notifyManager'
12
12
  export { focusManager } from './focusManager'
13
13
  export { onlineManager } from './onlineManager'
14
- export { hashKey, replaceEqualDeep, isServer, keepPreviousData } from './utils'
14
+ export {
15
+ hashKey,
16
+ replaceEqualDeep,
17
+ isServer,
18
+ matchQuery,
19
+ keepPreviousData,
20
+ } from './utils'
15
21
  export type { MutationFilters, QueryFilters, Updater } from './utils'
16
22
  export { isCancelledError } from './retryer'
17
23
  export {
@@ -6,7 +6,7 @@ import type {
6
6
  InfiniteQueryObserverOptions,
7
7
  InfiniteQueryObserverResult,
8
8
  QueryKey,
9
- RegisteredError,
9
+ DefaultError,
10
10
  } from './types'
11
11
  import type { QueryClient } from './queryClient'
12
12
  import type { NotifyOptions, ObserverFetchOptions } from './queryObserver'
@@ -24,7 +24,7 @@ type InfiniteQueryObserverListener<TData, TError> = (
24
24
 
25
25
  export class InfiniteQueryObserver<
26
26
  TQueryFnData = unknown,
27
- TError = RegisteredError,
27
+ TError = DefaultError,
28
28
  TData = InfiniteData<TQueryFnData>,
29
29
  TQueryData = TQueryFnData,
30
30
  TQueryKey extends QueryKey = QueryKey,
package/src/mutation.ts CHANGED
@@ -2,7 +2,7 @@ import type {
2
2
  MutationOptions,
3
3
  MutationStatus,
4
4
  MutationMeta,
5
- RegisteredError,
5
+ DefaultError,
6
6
  } from './types'
7
7
  import type { MutationCache } from './mutationCache'
8
8
  import type { MutationObserver } from './mutationObserver'
@@ -23,7 +23,7 @@ interface MutationConfig<TData, TError, TVariables, TContext> {
23
23
 
24
24
  export interface MutationState<
25
25
  TData = unknown,
26
- TError = RegisteredError,
26
+ TError = DefaultError,
27
27
  TVariables = void,
28
28
  TContext = unknown,
29
29
  > {
@@ -80,7 +80,7 @@ export type Action<TData, TError, TVariables, TContext> =
80
80
 
81
81
  export class Mutation<
82
82
  TData = unknown,
83
- TError = RegisteredError,
83
+ TError = DefaultError,
84
84
  TVariables = void,
85
85
  TContext = unknown,
86
86
  > extends Removable {
@@ -209,7 +209,16 @@ export class Mutation<
209
209
  this as Mutation<unknown, unknown, unknown, unknown>,
210
210
  )
211
211
 
212
- await this.options.onSuccess?.(data, variables, this.state.context!)
212
+ await this.options.onSuccess?.(data, variables, this.state.context)
213
+
214
+ // Notify cache callback
215
+ await this.#mutationCache.config.onSettled?.(
216
+ data,
217
+ null,
218
+ this.state.variables,
219
+ this.state.context,
220
+ this as Mutation<unknown, unknown, unknown, unknown>,
221
+ )
213
222
 
214
223
  await this.options.onSettled?.(data, null, variables, this.state.context)
215
224
 
@@ -231,6 +240,15 @@ export class Mutation<
231
240
  this.state.context,
232
241
  )
233
242
 
243
+ // Notify cache callback
244
+ await this.#mutationCache.config.onSettled?.(
245
+ undefined,
246
+ error,
247
+ this.state.variables,
248
+ this.state.context,
249
+ this as Mutation<unknown, unknown, unknown, unknown>,
250
+ )
251
+
234
252
  await this.options.onSettled?.(
235
253
  undefined,
236
254
  error as TError,
@@ -1,5 +1,5 @@
1
1
  import type { MutationObserver } from './mutationObserver'
2
- import type { NotifyEvent, MutationOptions, RegisteredError } from './types'
2
+ import type { NotifyEvent, MutationOptions, DefaultError } from './types'
3
3
  import type { QueryClient } from './queryClient'
4
4
  import { notifyManager } from './notifyManager'
5
5
  import type { Action, MutationState } from './mutation'
@@ -25,7 +25,14 @@ interface MutationCacheConfig {
25
25
  ) => Promise<unknown> | unknown
26
26
  onMutate?: (
27
27
  variables: unknown,
28
- mutation: Mutation<unknown, unknown, unknown, unknown>,
28
+ mutation: Mutation<unknown, unknown, unknown>,
29
+ ) => Promise<unknown> | unknown
30
+ onSettled?: (
31
+ data: unknown | undefined,
32
+ error: unknown | null,
33
+ variables: unknown,
34
+ context: unknown,
35
+ mutation: Mutation<unknown, unknown, unknown>,
29
36
  ) => Promise<unknown> | unknown
30
37
  }
31
38
 
@@ -126,7 +133,7 @@ export class MutationCache extends Subscribable<MutationCacheListener> {
126
133
 
127
134
  find<
128
135
  TData = unknown,
129
- TError = RegisteredError,
136
+ TError = DefaultError,
130
137
  TVariables = any,
131
138
  TContext = unknown,
132
139
  >(
@@ -7,7 +7,7 @@ import type {
7
7
  MutateOptions,
8
8
  MutationObserverResult,
9
9
  MutationObserverOptions,
10
- RegisteredError,
10
+ DefaultError,
11
11
  } from './types'
12
12
  import { shallowEqualObjects } from './utils'
13
13
 
@@ -21,7 +21,7 @@ type MutationObserverListener<TData, TError, TVariables, TContext> = (
21
21
 
22
22
  export class MutationObserver<
23
23
  TData = unknown,
24
- TError = RegisteredError,
24
+ TError = DefaultError,
25
25
  TVariables = void,
26
26
  TContext = unknown,
27
27
  > extends Subscribable<
@@ -103,9 +103,7 @@ export class MutationObserver<
103
103
 
104
104
  this.#currentMutation = this.#client
105
105
  .getMutationCache()
106
- .build(this.#client, {
107
- ...this.options,
108
- })
106
+ .build(this.#client, this.options)
109
107
 
110
108
  this.#currentMutation.addObserver(this)
111
109
 
@@ -26,7 +26,6 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
26
26
  #result: QueryObserverResult[]
27
27
  #queries: QueryObserverOptions[]
28
28
  #observers: QueryObserver[]
29
- #observersMap: Record<string, QueryObserver>
30
29
 
31
30
  constructor(client: QueryClient, queries?: QueryObserverOptions[]) {
32
31
  super()
@@ -35,7 +34,6 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
35
34
  this.#queries = []
36
35
  this.#result = []
37
36
  this.#observers = []
38
- this.#observersMap = {}
39
37
 
40
38
  if (queries) {
41
39
  this.setQueries(queries)
@@ -82,9 +80,6 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
82
80
  )
83
81
 
84
82
  const newObservers = newObserverMatches.map((match) => match.observer)
85
- const newObserversMap = Object.fromEntries(
86
- newObservers.map((observer) => [observer.options.queryHash, observer]),
87
- )
88
83
  const newResult = newObservers.map((observer) =>
89
84
  observer.getCurrentResult(),
90
85
  )
@@ -97,7 +92,6 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
97
92
  }
98
93
 
99
94
  this.#observers = newObservers
100
- this.#observersMap = newObserversMap
101
95
  this.#result = newResult
102
96
 
103
97
  if (!this.hasListeners()) {
@@ -166,7 +160,9 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
166
160
 
167
161
  const getObserver = (options: QueryObserverOptions): QueryObserver => {
168
162
  const defaultedOptions = this.#client.defaultQueryOptions(options)
169
- const currentObserver = this.#observersMap[defaultedOptions.queryHash!]
163
+ const currentObserver = this.#observers.find(
164
+ (o) => o.options.queryHash === defaultedOptions.queryHash,
165
+ )
170
166
  return (
171
167
  currentObserver ?? new QueryObserver(this.#client, defaultedOptions)
172
168
  )
package/src/query.ts CHANGED
@@ -9,7 +9,7 @@ import type {
9
9
  CancelOptions,
10
10
  SetDataOptions,
11
11
  FetchStatus,
12
- RegisteredError,
12
+ DefaultError,
13
13
  } from './types'
14
14
  import type { QueryCache } from './queryCache'
15
15
  import type { QueryObserver } from './queryObserver'
@@ -34,7 +34,7 @@ interface QueryConfig<
34
34
  state?: QueryState<TData, TError>
35
35
  }
36
36
 
37
- export interface QueryState<TData = unknown, TError = RegisteredError> {
37
+ export interface QueryState<TData = unknown, TError = DefaultError> {
38
38
  data: TData | undefined
39
39
  dataUpdateCount: number
40
40
  dataUpdatedAt: number
@@ -65,7 +65,7 @@ export interface FetchContext<
65
65
 
66
66
  export interface QueryBehavior<
67
67
  TQueryFnData = unknown,
68
- TError = RegisteredError,
68
+ TError = DefaultError,
69
69
  TData = TQueryFnData,
70
70
  TQueryKey extends QueryKey = QueryKey,
71
71
  > {
@@ -142,7 +142,7 @@ export interface SetStateOptions {
142
142
 
143
143
  export class Query<
144
144
  TQueryFnData = unknown,
145
- TError = RegisteredError,
145
+ TError = DefaultError,
146
146
  TData = TQueryFnData,
147
147
  TQueryKey extends QueryKey = QueryKey,
148
148
  > extends Removable {
@@ -434,6 +434,11 @@ export class Query<
434
434
  if (!isCancelledError(error)) {
435
435
  // Notify cache callback
436
436
  this.#cache.config.onError?.(error, this as Query<any, any, any, any>)
437
+ this.#cache.config.onSettled?.(
438
+ this.state.data,
439
+ error,
440
+ this as Query<any, any, any, any>,
441
+ )
437
442
  }
438
443
 
439
444
  if (!this.isFetchingOptimistic) {
@@ -458,10 +463,15 @@ export class Query<
458
463
  return
459
464
  }
460
465
 
461
- this.setData(data as TData)
466
+ this.setData(data)
462
467
 
463
468
  // Notify cache callback
464
469
  this.#cache.config.onSuccess?.(data, this as Query<any, any, any, any>)
470
+ this.#cache.config.onSettled?.(
471
+ data,
472
+ this.state.error,
473
+ this as Query<any, any, any, any>,
474
+ )
465
475
 
466
476
  if (!this.isFetchingOptimistic) {
467
477
  // Schedule query gc after fetching
package/src/queryCache.ts CHANGED
@@ -6,7 +6,7 @@ import type {
6
6
  NotifyEvent,
7
7
  QueryKey,
8
8
  QueryOptions,
9
- RegisteredError,
9
+ DefaultError,
10
10
  WithRequired,
11
11
  } from './types'
12
12
  import { notifyManager } from './notifyManager'
@@ -19,6 +19,11 @@ import type { QueryObserver } from './queryObserver'
19
19
  interface QueryCacheConfig {
20
20
  onError?: (error: unknown, query: Query<unknown, unknown, unknown>) => void
21
21
  onSuccess?: (data: unknown, query: Query<unknown, unknown, unknown>) => void
22
+ onSettled?: (
23
+ data: unknown | undefined,
24
+ error: unknown | null,
25
+ query: Query<unknown, unknown, unknown>,
26
+ ) => void
22
27
  createStore?: () => QueryStore
23
28
  }
24
29
 
@@ -150,7 +155,7 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
150
155
 
151
156
  get<
152
157
  TQueryFnData = unknown,
153
- TError = RegisteredError,
158
+ TError = DefaultError,
154
159
  TData = TQueryFnData,
155
160
  TQueryKey extends QueryKey = QueryKey,
156
161
  >(
@@ -165,7 +170,7 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
165
170
  return [...this.#queries.values()]
166
171
  }
167
172
 
168
- find<TQueryFnData = unknown, TError = RegisteredError, TData = TQueryFnData>(
173
+ find<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData>(
169
174
  filters: WithRequired<QueryFilters, 'queryKey'>,
170
175
  ): Query<TQueryFnData, TError, TData> | undefined {
171
176
  if (typeof filters.exact === 'undefined') {
@@ -24,7 +24,7 @@ import type {
24
24
  RefetchQueryFilters,
25
25
  ResetOptions,
26
26
  SetDataOptions,
27
- RegisteredError,
27
+ DefaultError,
28
28
  } from './types'
29
29
  import type { QueryState } from './query'
30
30
  import { QueryCache } from './queryCache'
@@ -177,7 +177,7 @@ export class QueryClient {
177
177
  )
178
178
  }
179
179
 
180
- getQueryState<TQueryFnData = unknown, TError = RegisteredError>(
180
+ getQueryState<TQueryFnData = unknown, TError = DefaultError>(
181
181
  queryKey: QueryKey,
182
182
  ): QueryState<TQueryFnData, TError> | undefined {
183
183
  return this.#queryCache.find<TQueryFnData, TError>({ queryKey })?.state
@@ -272,7 +272,7 @@ export class QueryClient {
272
272
 
273
273
  fetchQuery<
274
274
  TQueryFnData,
275
- TError = RegisteredError,
275
+ TError = DefaultError,
276
276
  TData = TQueryFnData,
277
277
  TQueryKey extends QueryKey = QueryKey,
278
278
  TPageParam = never,
@@ -301,7 +301,7 @@ export class QueryClient {
301
301
 
302
302
  prefetchQuery<
303
303
  TQueryFnData = unknown,
304
- TError = RegisteredError,
304
+ TError = DefaultError,
305
305
  TData = TQueryFnData,
306
306
  TQueryKey extends QueryKey = QueryKey,
307
307
  >(
@@ -312,7 +312,7 @@ export class QueryClient {
312
312
 
313
313
  fetchInfiniteQuery<
314
314
  TQueryFnData,
315
- TError = RegisteredError,
315
+ TError = DefaultError,
316
316
  TData = TQueryFnData,
317
317
  TQueryKey extends QueryKey = QueryKey,
318
318
  TPageParam = unknown,
@@ -331,7 +331,7 @@ export class QueryClient {
331
331
 
332
332
  prefetchInfiniteQuery<
333
333
  TQueryFnData,
334
- TError = RegisteredError,
334
+ TError = DefaultError,
335
335
  TData = TQueryFnData,
336
336
  TQueryKey extends QueryKey = QueryKey,
337
337
  TPageParam = unknown,
@@ -422,7 +422,7 @@ export class QueryClient {
422
422
 
423
423
  defaultQueryOptions<
424
424
  TQueryFnData = unknown,
425
- TError = RegisteredError,
425
+ TError = DefaultError,
426
426
  TData = TQueryFnData,
427
427
  TQueryData = TQueryFnData,
428
428
  TQueryKey extends QueryKey = QueryKey,
@@ -1,4 +1,4 @@
1
- import type { DefaultedQueryObserverOptions, RegisteredError } from './types'
1
+ import type { DefaultedQueryObserverOptions, DefaultError } from './types'
2
2
  import {
3
3
  isServer,
4
4
  isValidTimeout,
@@ -39,7 +39,7 @@ export interface ObserverFetchOptions extends FetchOptions {
39
39
 
40
40
  export class QueryObserver<
41
41
  TQueryFnData = unknown,
42
- TError = RegisteredError,
42
+ TError = DefaultError,
43
43
  TData = TQueryFnData,
44
44
  TQueryData = TQueryFnData,
45
45
  TQueryKey extends QueryKey = QueryKey,
@@ -648,10 +648,10 @@ export class QueryObserver<
648
648
  // First trigger the configuration callbacks
649
649
  if (notifyOptions.onSuccess) {
650
650
  this.options.onSuccess?.(this.#currentResult.data!)
651
- this.options.onSettled?.(this.#currentResult.data!, null)
651
+ this.options.onSettled?.(this.#currentResult.data, null)
652
652
  } else if (notifyOptions.onError) {
653
653
  this.options.onError?.(this.#currentResult.error!)
654
- this.options.onSettled?.(undefined, this.#currentResult.error!)
654
+ this.options.onSettled?.(undefined, this.#currentResult.error)
655
655
  }
656
656
 
657
657
  // Then trigger the listeners
package/src/retryer.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { focusManager } from './focusManager'
2
2
  import { onlineManager } from './onlineManager'
3
3
  import { sleep } from './utils'
4
- import type { CancelOptions, NetworkMode, RegisteredError } from './types'
4
+ import type { CancelOptions, NetworkMode, DefaultError } from './types'
5
5
 
6
6
  // TYPES
7
7
 
8
- interface RetryerConfig<TData = unknown, TError = RegisteredError> {
8
+ interface RetryerConfig<TData = unknown, TError = DefaultError> {
9
9
  fn: () => TData | Promise<TData>
10
10
  abort?: () => void
11
11
  onError?: (error: TError) => void
@@ -28,14 +28,14 @@ export interface Retryer<TData = unknown> {
28
28
 
29
29
  export type RetryValue<TError> = boolean | number | ShouldRetryFunction<TError>
30
30
 
31
- type ShouldRetryFunction<TError = RegisteredError> = (
31
+ type ShouldRetryFunction<TError = DefaultError> = (
32
32
  failureCount: number,
33
33
  error: TError,
34
34
  ) => boolean
35
35
 
36
36
  export type RetryDelayValue<TError> = number | RetryDelayFunction<TError>
37
37
 
38
- type RetryDelayFunction<TError = RegisteredError> = (
38
+ type RetryDelayFunction<TError = DefaultError> = (
39
39
  failureCount: number,
40
40
  error: TError,
41
41
  ) => number
@@ -63,7 +63,7 @@ export function isCancelledError(value: any): value is CancelledError {
63
63
  return value instanceof CancelledError
64
64
  }
65
65
 
66
- export function createRetryer<TData = unknown, TError = RegisteredError>(
66
+ export function createRetryer<TData = unknown, TError = DefaultError>(
67
67
  config: RetryerConfig<TData, TError>,
68
68
  ): Retryer<TData> {
69
69
  let isRetryCancelled = false
@@ -9,7 +9,7 @@ export class Subscribable<TListener extends Function = Listener> {
9
9
  }
10
10
 
11
11
  subscribe(listener: TListener): () => void {
12
- this.listeners.push(listener as TListener)
12
+ this.listeners.push(listener)
13
13
 
14
14
  this.onSubscribe()
15
15
 
@@ -3,11 +3,13 @@ import { queryKey, sleep, executeMutation, createQueryClient } from './utils'
3
3
  import { MutationCache, MutationObserver } from '..'
4
4
 
5
5
  describe('mutationCache', () => {
6
- describe('MutationCacheConfig.onError', () => {
7
- test('should be called when a mutation errors', async () => {
6
+ describe('MutationCacheConfig error callbacks', () => {
7
+ test('should call onError and onSettled when a mutation errors', async () => {
8
8
  const key = queryKey()
9
9
  const onError = jest.fn()
10
- const testCache = new MutationCache({ onError })
10
+ const onSuccess = jest.fn()
11
+ const onSettled = jest.fn()
12
+ const testCache = new MutationCache({ onError, onSuccess, onSettled })
11
13
  const testClient = createQueryClient({ mutationCache: testCache })
12
14
 
13
15
  try {
@@ -23,12 +25,22 @@ describe('mutationCache', () => {
23
25
  } catch {}
24
26
 
25
27
  const mutation = testCache.getAll()[0]
28
+ expect(onError).toHaveBeenCalledTimes(1)
26
29
  expect(onError).toHaveBeenCalledWith(
27
30
  new Error('error'),
28
31
  'vars',
29
32
  'context',
30
33
  mutation,
31
34
  )
35
+ expect(onSuccess).not.toHaveBeenCalled()
36
+ expect(onSettled).toHaveBeenCalledTimes(1)
37
+ expect(onSettled).toHaveBeenCalledWith(
38
+ undefined,
39
+ new Error('error'),
40
+ 'vars',
41
+ 'context',
42
+ mutation,
43
+ )
32
44
  })
33
45
 
34
46
  test('should be awaited', async () => {
@@ -39,7 +51,12 @@ describe('mutationCache', () => {
39
51
  await sleep(1)
40
52
  states.push(2)
41
53
  }
42
- const testCache = new MutationCache({ onError })
54
+ const onSettled = async () => {
55
+ states.push(5)
56
+ await sleep(1)
57
+ states.push(6)
58
+ }
59
+ const testCache = new MutationCache({ onError, onSettled })
43
60
  const testClient = createQueryClient({ mutationCache: testCache })
44
61
 
45
62
  try {
@@ -53,19 +70,26 @@ describe('mutationCache', () => {
53
70
  await sleep(1)
54
71
  states.push(4)
55
72
  },
73
+ onSettled: async () => {
74
+ states.push(7)
75
+ await sleep(1)
76
+ states.push(8)
77
+ },
56
78
  },
57
79
  'vars',
58
80
  )
59
81
  } catch {}
60
82
 
61
- expect(states).toEqual([1, 2, 3, 4])
83
+ expect(states).toEqual([1, 2, 3, 4, 5, 6, 7, 8])
62
84
  })
63
85
  })
64
- describe('MutationCacheConfig.onSuccess', () => {
65
- test('should be called when a mutation is successful', async () => {
86
+ describe('MutationCacheConfig success callbacks', () => {
87
+ test('should call onSuccess and onSettled when a mutation is successful', async () => {
66
88
  const key = queryKey()
89
+ const onError = jest.fn()
67
90
  const onSuccess = jest.fn()
68
- const testCache = new MutationCache({ onSuccess })
91
+ const onSettled = jest.fn()
92
+ const testCache = new MutationCache({ onError, onSuccess, onSettled })
69
93
  const testClient = createQueryClient({ mutationCache: testCache })
70
94
 
71
95
  try {
@@ -81,12 +105,22 @@ describe('mutationCache', () => {
81
105
  } catch {}
82
106
 
83
107
  const mutation = testCache.getAll()[0]
108
+ expect(onSuccess).toHaveBeenCalledTimes(1)
84
109
  expect(onSuccess).toHaveBeenCalledWith(
85
110
  { data: 5 },
86
111
  'vars',
87
112
  'context',
88
113
  mutation,
89
114
  )
115
+ expect(onError).not.toHaveBeenCalled()
116
+ expect(onSettled).toHaveBeenCalledTimes(1)
117
+ expect(onSettled).toHaveBeenCalledWith(
118
+ { data: 5 },
119
+ null,
120
+ 'vars',
121
+ 'context',
122
+ mutation,
123
+ )
90
124
  })
91
125
  test('should be awaited', async () => {
92
126
  const key = queryKey()
@@ -96,7 +130,12 @@ describe('mutationCache', () => {
96
130
  await sleep(1)
97
131
  states.push(2)
98
132
  }
99
- const testCache = new MutationCache({ onSuccess })
133
+ const onSettled = async () => {
134
+ states.push(5)
135
+ await sleep(1)
136
+ states.push(6)
137
+ }
138
+ const testCache = new MutationCache({ onSuccess, onSettled })
100
139
  const testClient = createQueryClient({ mutationCache: testCache })
101
140
 
102
141
  await executeMutation(
@@ -109,11 +148,16 @@ describe('mutationCache', () => {
109
148
  await sleep(1)
110
149
  states.push(4)
111
150
  },
151
+ onSettled: async () => {
152
+ states.push(7)
153
+ await sleep(1)
154
+ states.push(8)
155
+ },
112
156
  },
113
157
  'vars',
114
158
  )
115
159
 
116
- expect(states).toEqual([1, 2, 3, 4])
160
+ expect(states).toEqual([1, 2, 3, 4, 5, 6, 7, 8])
117
161
  })
118
162
  })
119
163
  describe('MutationCacheConfig.onMutate', () => {
@@ -286,11 +286,13 @@ describe('queryCache', () => {
286
286
  })
287
287
  })
288
288
 
289
- describe('QueryCacheConfig.onError', () => {
290
- test('should be called when a query errors', async () => {
289
+ describe('QueryCacheConfig error callbacks', () => {
290
+ test('should call onError and onSettled when a query errors', async () => {
291
291
  const key = queryKey()
292
+ const onSuccess = jest.fn()
293
+ const onSettled = jest.fn()
292
294
  const onError = jest.fn()
293
- const testCache = new QueryCache({ onError })
295
+ const testCache = new QueryCache({ onSuccess, onError, onSettled })
294
296
  const testClient = createQueryClient({ queryCache: testCache })
295
297
  await testClient.prefetchQuery({
296
298
  queryKey: key,
@@ -298,14 +300,20 @@ describe('queryCache', () => {
298
300
  })
299
301
  const query = testCache.find({ queryKey: key })
300
302
  expect(onError).toHaveBeenCalledWith('error', query)
303
+ expect(onError).toHaveBeenCalledTimes(1)
304
+ expect(onSuccess).not.toHaveBeenCalled()
305
+ expect(onSettled).toHaveBeenCalledTimes(1)
306
+ expect(onSettled).toHaveBeenCalledWith(undefined, 'error', query)
301
307
  })
302
308
  })
303
309
 
304
- describe('QueryCacheConfig.onSuccess', () => {
305
- test('should be called when a query is successful', async () => {
310
+ describe('QueryCacheConfig success callbacks', () => {
311
+ test('should call onSuccess and onSettled when a query is successful', async () => {
306
312
  const key = queryKey()
307
313
  const onSuccess = jest.fn()
308
- const testCache = new QueryCache({ onSuccess })
314
+ const onSettled = jest.fn()
315
+ const onError = jest.fn()
316
+ const testCache = new QueryCache({ onSuccess, onError, onSettled })
309
317
  const testClient = createQueryClient({ queryCache: testCache })
310
318
  await testClient.prefetchQuery({
311
319
  queryKey: key,
@@ -313,6 +321,10 @@ describe('queryCache', () => {
313
321
  })
314
322
  const query = testCache.find({ queryKey: key })
315
323
  expect(onSuccess).toHaveBeenCalledWith({ data: 5 }, query)
324
+ expect(onSuccess).toHaveBeenCalledTimes(1)
325
+ expect(onError).not.toHaveBeenCalled()
326
+ expect(onSettled).toHaveBeenCalledTimes(1)
327
+ expect(onSettled).toHaveBeenCalledWith({ data: 5 }, null, query)
316
328
  })
317
329
  })
318
330