@tanstack/query-core 5.0.0-alpha.2 → 5.0.0-alpha.23
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.
- package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js +13 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js.map +1 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.js +16 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
- package/build/lib/focusManager.esm.js +31 -15
- package/build/lib/focusManager.esm.js.map +1 -1
- package/build/lib/focusManager.js +31 -15
- package/build/lib/focusManager.js.map +1 -1
- package/build/lib/hydration.d.ts +2 -6
- package/build/lib/hydration.esm.js +9 -20
- package/build/lib/hydration.esm.js.map +1 -1
- package/build/lib/hydration.js +9 -20
- package/build/lib/hydration.js.map +1 -1
- package/build/lib/hydration.mjs +4 -18
- package/build/lib/hydration.mjs.map +1 -1
- package/build/lib/index.d.ts +3 -3
- package/build/lib/infiniteQueryBehavior.d.ts +2 -2
- package/build/lib/infiniteQueryBehavior.esm.js +52 -48
- package/build/lib/infiniteQueryBehavior.esm.js.map +1 -1
- package/build/lib/infiniteQueryBehavior.js +52 -48
- package/build/lib/infiniteQueryBehavior.js.map +1 -1
- package/build/lib/infiniteQueryBehavior.mjs +48 -45
- package/build/lib/infiniteQueryBehavior.mjs.map +1 -1
- package/build/lib/infiniteQueryObserver.d.ts +6 -6
- package/build/lib/infiniteQueryObserver.esm.js +7 -8
- package/build/lib/infiniteQueryObserver.esm.js.map +1 -1
- package/build/lib/infiniteQueryObserver.js +7 -8
- package/build/lib/infiniteQueryObserver.js.map +1 -1
- package/build/lib/infiniteQueryObserver.mjs +4 -6
- package/build/lib/infiniteQueryObserver.mjs.map +1 -1
- package/build/lib/mutation.d.ts +2 -1
- package/build/lib/mutation.esm.js +134 -101
- package/build/lib/mutation.esm.js.map +1 -1
- package/build/lib/mutation.js +134 -101
- package/build/lib/mutation.js.map +1 -1
- package/build/lib/mutation.mjs +10 -2
- package/build/lib/mutation.mjs.map +1 -1
- package/build/lib/mutationCache.d.ts +2 -2
- package/build/lib/mutationCache.esm.js +34 -20
- package/build/lib/mutationCache.esm.js.map +1 -1
- package/build/lib/mutationCache.js +34 -20
- package/build/lib/mutationCache.js.map +1 -1
- package/build/lib/mutationCache.mjs +5 -4
- package/build/lib/mutationCache.mjs.map +1 -1
- package/build/lib/mutationObserver.esm.js +81 -50
- package/build/lib/mutationObserver.esm.js.map +1 -1
- package/build/lib/mutationObserver.js +81 -50
- package/build/lib/mutationObserver.js.map +1 -1
- package/build/lib/mutationObserver.mjs +1 -0
- package/build/lib/mutationObserver.mjs.map +1 -1
- package/build/lib/onlineManager.esm.js +29 -14
- package/build/lib/onlineManager.esm.js.map +1 -1
- package/build/lib/onlineManager.js +29 -14
- package/build/lib/onlineManager.js.map +1 -1
- package/build/lib/queriesObserver.esm.js +95 -65
- package/build/lib/queriesObserver.esm.js.map +1 -1
- package/build/lib/queriesObserver.js +95 -65
- package/build/lib/queriesObserver.js.map +1 -1
- package/build/lib/queriesObserver.mjs +4 -3
- package/build/lib/queriesObserver.mjs.map +1 -1
- package/build/lib/query.d.ts +4 -3
- package/build/lib/query.esm.js +210 -161
- package/build/lib/query.esm.js.map +1 -1
- package/build/lib/query.js +210 -161
- package/build/lib/query.js.map +1 -1
- package/build/lib/query.mjs +1 -1
- package/build/lib/query.mjs.map +1 -1
- package/build/lib/queryCache.d.ts +2 -2
- package/build/lib/queryCache.esm.js +21 -13
- package/build/lib/queryCache.esm.js.map +1 -1
- package/build/lib/queryCache.js +21 -13
- package/build/lib/queryCache.js.map +1 -1
- package/build/lib/queryCache.mjs +5 -4
- package/build/lib/queryCache.mjs.map +1 -1
- package/build/lib/queryClient.esm.js +109 -68
- package/build/lib/queryClient.esm.js.map +1 -1
- package/build/lib/queryClient.js +109 -68
- package/build/lib/queryClient.js.map +1 -1
- package/build/lib/queryClient.mjs +7 -6
- package/build/lib/queryClient.mjs.map +1 -1
- package/build/lib/queryObserver.d.ts +2 -4
- package/build/lib/queryObserver.esm.js +299 -211
- package/build/lib/queryObserver.esm.js.map +1 -1
- package/build/lib/queryObserver.js +297 -209
- package/build/lib/queryObserver.js.map +1 -1
- package/build/lib/queryObserver.mjs +13 -25
- package/build/lib/queryObserver.mjs.map +1 -1
- package/build/lib/removable.esm.js +13 -6
- package/build/lib/removable.esm.js.map +1 -1
- package/build/lib/removable.js +13 -6
- package/build/lib/removable.js.map +1 -1
- package/build/lib/retryer.esm.js +15 -14
- package/build/lib/retryer.esm.js.map +1 -1
- package/build/lib/retryer.js +15 -14
- package/build/lib/retryer.js.map +1 -1
- package/build/lib/tests/utils.d.ts +4 -5
- package/build/lib/types.d.ts +10 -20
- package/build/lib/utils.esm.js +1 -1
- package/build/lib/utils.esm.js.map +1 -1
- package/build/lib/utils.js +1 -1
- package/build/lib/utils.js.map +1 -1
- package/build/umd/index.development.js +101 -113
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/hydration.ts +18 -37
- package/src/index.ts +2 -4
- package/src/infiniteQueryBehavior.ts +52 -60
- package/src/infiniteQueryObserver.ts +15 -10
- package/src/mutation.ts +14 -5
- package/src/mutationCache.ts +6 -6
- package/src/mutationObserver.ts +1 -0
- package/src/queriesObserver.ts +8 -8
- package/src/query.ts +13 -8
- package/src/queryCache.ts +9 -8
- package/src/queryClient.ts +4 -6
- package/src/queryObserver.ts +26 -38
- package/src/tests/focusManager.test.tsx +12 -14
- package/src/tests/hydration.test.tsx +22 -17
- package/src/tests/infiniteQueryBehavior.test.tsx +16 -9
- package/src/tests/infiniteQueryObserver.test.tsx +62 -1
- package/src/tests/mutationCache.test.tsx +11 -10
- package/src/tests/mutationObserver.test.tsx +3 -2
- package/src/tests/mutations.test.tsx +41 -9
- package/src/tests/notifyManager.test.tsx +7 -6
- package/src/tests/onlineManager.test.tsx +12 -17
- package/src/tests/queriesObserver.test.tsx +18 -17
- package/src/tests/query.test.tsx +18 -17
- package/src/tests/queryCache.test.tsx +14 -13
- package/src/tests/queryClient.test.tsx +49 -48
- package/src/tests/queryObserver.test.tsx +65 -9
- package/src/tests/utils.test.tsx +2 -1
- package/src/tests/utils.ts +5 -4
- package/src/types.ts +15 -19
package/src/queryObserver.ts
CHANGED
|
@@ -17,11 +17,11 @@ import type {
|
|
|
17
17
|
QueryOptions,
|
|
18
18
|
RefetchOptions,
|
|
19
19
|
} from './types'
|
|
20
|
-
import type { Query, QueryState,
|
|
20
|
+
import type { Query, QueryState, FetchOptions } from './query'
|
|
21
21
|
import type { QueryClient } from './queryClient'
|
|
22
22
|
import { focusManager } from './focusManager'
|
|
23
23
|
import { Subscribable } from './subscribable'
|
|
24
|
-
import { canFetch
|
|
24
|
+
import { canFetch } from './retryer'
|
|
25
25
|
|
|
26
26
|
type QueryObserverListener<TData, TError> = (
|
|
27
27
|
result: QueryObserverResult<TData, TError>,
|
|
@@ -29,8 +29,6 @@ type QueryObserverListener<TData, TError> = (
|
|
|
29
29
|
|
|
30
30
|
export interface NotifyOptions {
|
|
31
31
|
listeners?: boolean
|
|
32
|
-
onError?: boolean
|
|
33
|
-
onSuccess?: boolean
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
export interface ObserverFetchOptions extends FetchOptions {
|
|
@@ -64,10 +62,12 @@ export class QueryObserver<
|
|
|
64
62
|
TQueryData,
|
|
65
63
|
TQueryKey
|
|
66
64
|
>
|
|
67
|
-
#previousQueryResult?: QueryObserverResult<TData, TError>
|
|
68
65
|
#selectError: TError | null
|
|
69
66
|
#selectFn?: (data: TQueryData) => TData
|
|
70
67
|
#selectResult?: TData
|
|
68
|
+
// This property keeps track of the last defined query data.
|
|
69
|
+
// It will be used to pass the previous data to the placeholder function between renders.
|
|
70
|
+
#lastDefinedQueryData?: TQueryData
|
|
71
71
|
#staleTimeoutId?: ReturnType<typeof setTimeout>
|
|
72
72
|
#refetchIntervalId?: ReturnType<typeof setInterval>
|
|
73
73
|
#currentRefetchInterval?: number | false
|
|
@@ -342,12 +342,14 @@ export class QueryObserver<
|
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
#computeRefetchInterval() {
|
|
345
|
-
return
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
345
|
+
return (
|
|
346
|
+
(typeof this.options.refetchInterval === 'function'
|
|
347
|
+
? this.options.refetchInterval(
|
|
348
|
+
this.#currentResult.data,
|
|
349
|
+
this.#currentQuery,
|
|
350
|
+
)
|
|
351
|
+
: this.options.refetchInterval) ?? false
|
|
352
|
+
)
|
|
351
353
|
}
|
|
352
354
|
|
|
353
355
|
#updateRefetchInterval(nextInterval: number | false): void {
|
|
@@ -414,9 +416,6 @@ export class QueryObserver<
|
|
|
414
416
|
const queryInitialState = queryChange
|
|
415
417
|
? query.state
|
|
416
418
|
: this.#currentQueryInitialState
|
|
417
|
-
const prevQueryResult = queryChange
|
|
418
|
-
? this.#currentResult
|
|
419
|
-
: this.#previousQueryResult
|
|
420
419
|
|
|
421
420
|
const { state } = query
|
|
422
421
|
let { error, errorUpdatedAt, fetchStatus, status } = state
|
|
@@ -490,7 +489,7 @@ export class QueryObserver<
|
|
|
490
489
|
typeof options.placeholderData === 'function'
|
|
491
490
|
? (
|
|
492
491
|
options.placeholderData as unknown as PlaceholderDataFunction<TQueryData>
|
|
493
|
-
)(
|
|
492
|
+
)(this.#lastDefinedQueryData)
|
|
494
493
|
: options.placeholderData
|
|
495
494
|
if (options.select && typeof placeholderData !== 'undefined') {
|
|
496
495
|
try {
|
|
@@ -504,7 +503,11 @@ export class QueryObserver<
|
|
|
504
503
|
|
|
505
504
|
if (typeof placeholderData !== 'undefined') {
|
|
506
505
|
status = 'success'
|
|
507
|
-
data = replaceData(
|
|
506
|
+
data = replaceData(
|
|
507
|
+
prevResult?.data,
|
|
508
|
+
placeholderData as unknown,
|
|
509
|
+
options,
|
|
510
|
+
) as TData
|
|
508
511
|
isPlaceholderData = true
|
|
509
512
|
}
|
|
510
513
|
}
|
|
@@ -568,6 +571,9 @@ export class QueryObserver<
|
|
|
568
571
|
return
|
|
569
572
|
}
|
|
570
573
|
|
|
574
|
+
if (this.#currentResultState.data !== undefined) {
|
|
575
|
+
this.#lastDefinedQueryData = this.#currentResultState.data
|
|
576
|
+
}
|
|
571
577
|
this.#currentResult = nextResult
|
|
572
578
|
|
|
573
579
|
// Determine which callbacks to trigger
|
|
@@ -589,7 +595,7 @@ export class QueryObserver<
|
|
|
589
595
|
|
|
590
596
|
const includedProps = new Set(notifyOnChangeProps ?? this.#trackedProps)
|
|
591
597
|
|
|
592
|
-
if (this.options.
|
|
598
|
+
if (this.options.throwOnError) {
|
|
593
599
|
includedProps.add('error')
|
|
594
600
|
}
|
|
595
601
|
|
|
@@ -619,7 +625,6 @@ export class QueryObserver<
|
|
|
619
625
|
| undefined
|
|
620
626
|
this.#currentQuery = query
|
|
621
627
|
this.#currentQueryInitialState = query.state
|
|
622
|
-
this.#previousQueryResult = this.#currentResult
|
|
623
628
|
|
|
624
629
|
if (this.hasListeners()) {
|
|
625
630
|
prevQuery?.removeObserver(this)
|
|
@@ -627,16 +632,8 @@ export class QueryObserver<
|
|
|
627
632
|
}
|
|
628
633
|
}
|
|
629
634
|
|
|
630
|
-
onQueryUpdate(
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
if (action.type === 'success') {
|
|
634
|
-
notifyOptions.onSuccess = !action.manual
|
|
635
|
-
} else if (action.type === 'error' && !isCancelledError(action.error)) {
|
|
636
|
-
notifyOptions.onError = true
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
this.#updateResult(notifyOptions)
|
|
635
|
+
onQueryUpdate(): void {
|
|
636
|
+
this.#updateResult()
|
|
640
637
|
|
|
641
638
|
if (this.hasListeners()) {
|
|
642
639
|
this.#updateTimers()
|
|
@@ -645,16 +642,7 @@ export class QueryObserver<
|
|
|
645
642
|
|
|
646
643
|
#notify(notifyOptions: NotifyOptions): void {
|
|
647
644
|
notifyManager.batch(() => {
|
|
648
|
-
// First trigger the
|
|
649
|
-
if (notifyOptions.onSuccess) {
|
|
650
|
-
this.options.onSuccess?.(this.#currentResult.data!)
|
|
651
|
-
this.options.onSettled?.(this.#currentResult.data, null)
|
|
652
|
-
} else if (notifyOptions.onError) {
|
|
653
|
-
this.options.onError?.(this.#currentResult.error!)
|
|
654
|
-
this.options.onSettled?.(undefined, this.#currentResult.error)
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
// Then trigger the listeners
|
|
645
|
+
// First, trigger the listeners
|
|
658
646
|
if (notifyOptions.listeners) {
|
|
659
647
|
this.listeners.forEach((listener) => {
|
|
660
648
|
listener(this.#currentResult)
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { sleep } from '../utils'
|
|
2
2
|
import { FocusManager } from '../focusManager'
|
|
3
3
|
import { setIsServer } from './utils'
|
|
4
|
+
import { vi } from 'vitest'
|
|
4
5
|
|
|
5
6
|
describe('focusManager', () => {
|
|
6
7
|
let focusManager: FocusManager
|
|
7
8
|
beforeEach(() => {
|
|
8
|
-
|
|
9
|
+
vi.resetModules()
|
|
9
10
|
focusManager = new FocusManager()
|
|
10
11
|
})
|
|
11
12
|
|
|
12
13
|
it('should call previous remove handler when replacing an event listener', () => {
|
|
13
|
-
const remove1Spy =
|
|
14
|
-
const remove2Spy =
|
|
14
|
+
const remove1Spy = vi.fn()
|
|
15
|
+
const remove2Spy = vi.fn()
|
|
15
16
|
|
|
16
17
|
focusManager.setEventListener(() => remove1Spy)
|
|
17
18
|
focusManager.setEventListener(() => remove2Spy)
|
|
@@ -39,7 +40,7 @@ describe('focusManager', () => {
|
|
|
39
40
|
})
|
|
40
41
|
|
|
41
42
|
it('should not notify listeners on focus if already focused', async () => {
|
|
42
|
-
const subscriptionSpy =
|
|
43
|
+
const subscriptionSpy = vi.fn()
|
|
43
44
|
const unsubscribe = focusManager.subscribe(subscriptionSpy)
|
|
44
45
|
|
|
45
46
|
focusManager.setFocused(true)
|
|
@@ -66,7 +67,7 @@ describe('focusManager', () => {
|
|
|
66
67
|
test('cleanup (removeEventListener) should not be called if window is not defined', async () => {
|
|
67
68
|
const restoreIsServer = setIsServer(true)
|
|
68
69
|
|
|
69
|
-
const removeEventListenerSpy =
|
|
70
|
+
const removeEventListenerSpy = vi.spyOn(globalThis, 'removeEventListener')
|
|
70
71
|
|
|
71
72
|
const unsubscribe = focusManager.subscribe(() => undefined)
|
|
72
73
|
|
|
@@ -83,7 +84,7 @@ describe('focusManager', () => {
|
|
|
83
84
|
// @ts-expect-error
|
|
84
85
|
globalThis.window.addEventListener = undefined
|
|
85
86
|
|
|
86
|
-
const removeEventListenerSpy =
|
|
87
|
+
const removeEventListenerSpy = vi.spyOn(globalThis, 'removeEventListener')
|
|
87
88
|
|
|
88
89
|
const unsubscribe = focusManager.subscribe(() => undefined)
|
|
89
90
|
|
|
@@ -95,8 +96,8 @@ describe('focusManager', () => {
|
|
|
95
96
|
})
|
|
96
97
|
|
|
97
98
|
it('should replace default window listener when a new event listener is set', async () => {
|
|
98
|
-
const unsubscribeSpy =
|
|
99
|
-
const handlerSpy =
|
|
99
|
+
const unsubscribeSpy = vi.fn().mockImplementation(() => undefined)
|
|
100
|
+
const handlerSpy = vi.fn().mockImplementation(() => unsubscribeSpy)
|
|
100
101
|
|
|
101
102
|
focusManager.setEventListener(() => handlerSpy())
|
|
102
103
|
|
|
@@ -115,12 +116,9 @@ describe('focusManager', () => {
|
|
|
115
116
|
})
|
|
116
117
|
|
|
117
118
|
test('should call removeEventListener when last listener unsubscribes', () => {
|
|
118
|
-
const addEventListenerSpy =
|
|
119
|
-
globalThis.window,
|
|
120
|
-
'addEventListener',
|
|
121
|
-
)
|
|
119
|
+
const addEventListenerSpy = vi.spyOn(globalThis.window, 'addEventListener')
|
|
122
120
|
|
|
123
|
-
const removeEventListenerSpy =
|
|
121
|
+
const removeEventListenerSpy = vi.spyOn(
|
|
124
122
|
globalThis.window,
|
|
125
123
|
'removeEventListener',
|
|
126
124
|
)
|
|
@@ -136,7 +134,7 @@ describe('focusManager', () => {
|
|
|
136
134
|
})
|
|
137
135
|
|
|
138
136
|
test('should keep setup function even if last listener unsubscribes', () => {
|
|
139
|
-
const setupSpy =
|
|
137
|
+
const setupSpy = vi.fn().mockImplementation(() => () => undefined)
|
|
140
138
|
|
|
141
139
|
focusManager.setEventListener(setupSpy)
|
|
142
140
|
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from './utils'
|
|
7
7
|
import { QueryCache } from '../queryCache'
|
|
8
8
|
import { dehydrate, hydrate } from '../hydration'
|
|
9
|
+
import { vi } from 'vitest'
|
|
9
10
|
|
|
10
11
|
async function fetchData<TData>(value: TData, ms?: number): Promise<TData> {
|
|
11
12
|
await sleep(ms || 0)
|
|
@@ -67,7 +68,7 @@ describe('dehydration and rehydration', () => {
|
|
|
67
68
|
key: [{ nestedKey: 1 }],
|
|
68
69
|
})
|
|
69
70
|
|
|
70
|
-
const fetchDataAfterHydration =
|
|
71
|
+
const fetchDataAfterHydration = vi.fn<unknown[], unknown>()
|
|
71
72
|
await hydrationClient.prefetchQuery({
|
|
72
73
|
queryKey: ['string'],
|
|
73
74
|
queryFn: fetchDataAfterHydration,
|
|
@@ -112,7 +113,9 @@ describe('dehydration and rehydration', () => {
|
|
|
112
113
|
queryFn: () => fetchData('string'),
|
|
113
114
|
})
|
|
114
115
|
|
|
115
|
-
const dehydrated = dehydrate(queryClient, {
|
|
116
|
+
const dehydrated = dehydrate(queryClient, {
|
|
117
|
+
shouldDehydrateQuery: () => false,
|
|
118
|
+
})
|
|
116
119
|
|
|
117
120
|
expect(dehydrated.queries.length).toBe(0)
|
|
118
121
|
|
|
@@ -192,7 +195,7 @@ describe('dehydration and rehydration', () => {
|
|
|
192
195
|
})?.state.data,
|
|
193
196
|
).toBe('string')
|
|
194
197
|
|
|
195
|
-
const fetchDataAfterHydration =
|
|
198
|
+
const fetchDataAfterHydration = vi.fn<unknown[], unknown>()
|
|
196
199
|
await hydrationClient.prefetchQuery({
|
|
197
200
|
queryKey: ['string', { key: ['string'], key2: 0 }],
|
|
198
201
|
queryFn: fetchDataAfterHydration,
|
|
@@ -205,7 +208,7 @@ describe('dehydration and rehydration', () => {
|
|
|
205
208
|
})
|
|
206
209
|
|
|
207
210
|
test('should only hydrate successful queries by default', async () => {
|
|
208
|
-
const consoleMock =
|
|
211
|
+
const consoleMock = vi.spyOn(console, 'error')
|
|
209
212
|
consoleMock.mockImplementation(() => undefined)
|
|
210
213
|
|
|
211
214
|
const queryCache = new QueryCache()
|
|
@@ -243,7 +246,7 @@ describe('dehydration and rehydration', () => {
|
|
|
243
246
|
consoleMock.mockRestore()
|
|
244
247
|
})
|
|
245
248
|
|
|
246
|
-
test('should filter queries via
|
|
249
|
+
test('should filter queries via dehydrateQuery', async () => {
|
|
247
250
|
const queryCache = new QueryCache()
|
|
248
251
|
const queryClient = createQueryClient({ queryCache })
|
|
249
252
|
await queryClient.prefetchQuery({
|
|
@@ -341,18 +344,18 @@ describe('dehydration and rehydration', () => {
|
|
|
341
344
|
})
|
|
342
345
|
|
|
343
346
|
test('should be able to dehydrate mutations and continue on hydration', async () => {
|
|
344
|
-
const consoleMock =
|
|
347
|
+
const consoleMock = vi.spyOn(console, 'error')
|
|
345
348
|
consoleMock.mockImplementation(() => undefined)
|
|
346
349
|
const onlineMock = mockNavigatorOnLine(false)
|
|
347
350
|
|
|
348
|
-
const serverAddTodo =
|
|
351
|
+
const serverAddTodo = vi
|
|
349
352
|
.fn()
|
|
350
353
|
.mockImplementation(() => Promise.reject(new Error('offline')))
|
|
351
|
-
const serverOnMutate =
|
|
354
|
+
const serverOnMutate = vi.fn().mockImplementation((variables) => {
|
|
352
355
|
const optimisticTodo = { id: 1, text: variables.text }
|
|
353
356
|
return { optimisticTodo }
|
|
354
357
|
})
|
|
355
|
-
const serverOnSuccess =
|
|
358
|
+
const serverOnSuccess = vi.fn()
|
|
356
359
|
|
|
357
360
|
const serverClient = createQueryClient()
|
|
358
361
|
|
|
@@ -386,14 +389,14 @@ describe('dehydration and rehydration', () => {
|
|
|
386
389
|
const parsed = JSON.parse(stringified)
|
|
387
390
|
const client = createQueryClient()
|
|
388
391
|
|
|
389
|
-
const clientAddTodo =
|
|
392
|
+
const clientAddTodo = vi.fn().mockImplementation((variables) => {
|
|
390
393
|
return { id: 2, text: variables.text }
|
|
391
394
|
})
|
|
392
|
-
const clientOnMutate =
|
|
395
|
+
const clientOnMutate = vi.fn().mockImplementation((variables) => {
|
|
393
396
|
const optimisticTodo = { id: 1, text: variables.text }
|
|
394
397
|
return { optimisticTodo }
|
|
395
398
|
})
|
|
396
|
-
const clientOnSuccess =
|
|
399
|
+
const clientOnSuccess = vi.fn()
|
|
397
400
|
|
|
398
401
|
client.setMutationDefaults(['addTodo'], {
|
|
399
402
|
mutationFn: clientAddTodo,
|
|
@@ -422,10 +425,10 @@ describe('dehydration and rehydration', () => {
|
|
|
422
425
|
})
|
|
423
426
|
|
|
424
427
|
test('should not dehydrate mutations if dehydrateMutations is set to false', async () => {
|
|
425
|
-
const consoleMock =
|
|
428
|
+
const consoleMock = vi.spyOn(console, 'error')
|
|
426
429
|
consoleMock.mockImplementation(() => undefined)
|
|
427
430
|
|
|
428
|
-
const serverAddTodo =
|
|
431
|
+
const serverAddTodo = vi
|
|
429
432
|
.fn()
|
|
430
433
|
.mockImplementation(() => Promise.reject(new Error('offline')))
|
|
431
434
|
|
|
@@ -445,7 +448,9 @@ describe('dehydration and rehydration', () => {
|
|
|
445
448
|
).catch(() => undefined)
|
|
446
449
|
|
|
447
450
|
await sleep(1)
|
|
448
|
-
const dehydrated = dehydrate(queryClient, {
|
|
451
|
+
const dehydrated = dehydrate(queryClient, {
|
|
452
|
+
shouldDehydrateMutation: () => false,
|
|
453
|
+
})
|
|
449
454
|
|
|
450
455
|
expect(dehydrated.mutations.length).toBe(0)
|
|
451
456
|
|
|
@@ -454,10 +459,10 @@ describe('dehydration and rehydration', () => {
|
|
|
454
459
|
})
|
|
455
460
|
|
|
456
461
|
test('should not dehydrate mutation if mutation state is set to pause', async () => {
|
|
457
|
-
const consoleMock =
|
|
462
|
+
const consoleMock = vi.spyOn(console, 'error')
|
|
458
463
|
consoleMock.mockImplementation(() => undefined)
|
|
459
464
|
|
|
460
|
-
const serverAddTodo =
|
|
465
|
+
const serverAddTodo = vi
|
|
461
466
|
.fn()
|
|
462
467
|
.mockImplementation(() => Promise.reject(new Error('offline')))
|
|
463
468
|
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { waitFor } from '@testing-library/react'
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
InfiniteQueryObserverResult,
|
|
5
|
-
} from '@tanstack/query-core'
|
|
6
|
-
import { InfiniteQueryObserver, CancelledError } from '@tanstack/query-core'
|
|
2
|
+
import type { QueryClient, InfiniteQueryObserverResult } from '..'
|
|
3
|
+
import { InfiniteQueryObserver, CancelledError } from '..'
|
|
7
4
|
import { createQueryClient, queryKey, sleep } from './utils'
|
|
5
|
+
import { vi } from 'vitest'
|
|
8
6
|
|
|
9
7
|
describe('InfiniteQueryBehavior', () => {
|
|
10
8
|
let queryClient: QueryClient
|
|
@@ -50,7 +48,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
50
48
|
const key = queryKey()
|
|
51
49
|
let abortSignal: AbortSignal | null = null
|
|
52
50
|
|
|
53
|
-
const queryFnSpy =
|
|
51
|
+
const queryFnSpy = vi.fn().mockImplementation(({ pageParam, signal }) => {
|
|
54
52
|
abortSignal = signal
|
|
55
53
|
return pageParam
|
|
56
54
|
})
|
|
@@ -84,6 +82,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
84
82
|
queryKey: key,
|
|
85
83
|
pageParam: 1,
|
|
86
84
|
meta: undefined,
|
|
85
|
+
direction: 'forward',
|
|
87
86
|
signal: abortSignal,
|
|
88
87
|
})
|
|
89
88
|
|
|
@@ -95,6 +94,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
95
94
|
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
96
95
|
queryKey: key,
|
|
97
96
|
pageParam: 2,
|
|
97
|
+
direction: 'forward',
|
|
98
98
|
meta: undefined,
|
|
99
99
|
signal: abortSignal,
|
|
100
100
|
})
|
|
@@ -112,6 +112,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
112
112
|
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
113
113
|
queryKey: key,
|
|
114
114
|
pageParam: 0,
|
|
115
|
+
direction: 'backward',
|
|
115
116
|
meta: undefined,
|
|
116
117
|
signal: abortSignal,
|
|
117
118
|
})
|
|
@@ -131,6 +132,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
131
132
|
queryKey: key,
|
|
132
133
|
pageParam: -1,
|
|
133
134
|
meta: undefined,
|
|
135
|
+
direction: 'backward',
|
|
134
136
|
signal: abortSignal,
|
|
135
137
|
})
|
|
136
138
|
|
|
@@ -148,6 +150,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
148
150
|
queryKey: key,
|
|
149
151
|
pageParam: 1,
|
|
150
152
|
meta: undefined,
|
|
153
|
+
direction: 'forward',
|
|
151
154
|
signal: abortSignal,
|
|
152
155
|
})
|
|
153
156
|
|
|
@@ -168,6 +171,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
168
171
|
queryKey: key,
|
|
169
172
|
pageParam: 0,
|
|
170
173
|
meta: undefined,
|
|
174
|
+
direction: 'forward',
|
|
171
175
|
signal: abortSignal,
|
|
172
176
|
})
|
|
173
177
|
|
|
@@ -175,6 +179,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
175
179
|
queryKey: key,
|
|
176
180
|
pageParam: 1,
|
|
177
181
|
meta: undefined,
|
|
182
|
+
direction: 'forward',
|
|
178
183
|
signal: abortSignal,
|
|
179
184
|
})
|
|
180
185
|
|
|
@@ -185,7 +190,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
185
190
|
const key = queryKey()
|
|
186
191
|
let abortSignal: AbortSignal | null = null
|
|
187
192
|
|
|
188
|
-
const queryFnSpy =
|
|
193
|
+
const queryFnSpy = vi.fn().mockImplementation(({ pageParam, signal }) => {
|
|
189
194
|
abortSignal = signal
|
|
190
195
|
sleep(10)
|
|
191
196
|
return pageParam
|
|
@@ -226,6 +231,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
226
231
|
queryKey: key,
|
|
227
232
|
pageParam: 1,
|
|
228
233
|
meta: undefined,
|
|
234
|
+
direction: 'forward',
|
|
229
235
|
signal: abortSignal,
|
|
230
236
|
})
|
|
231
237
|
|
|
@@ -236,7 +242,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
236
242
|
const key = queryKey()
|
|
237
243
|
let abortSignal: AbortSignal | null = null
|
|
238
244
|
|
|
239
|
-
let queryFnSpy =
|
|
245
|
+
let queryFnSpy = vi.fn().mockImplementation(({ pageParam, signal }) => {
|
|
240
246
|
abortSignal = signal
|
|
241
247
|
return pageParam
|
|
242
248
|
})
|
|
@@ -281,10 +287,11 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
281
287
|
queryKey: key,
|
|
282
288
|
pageParam: 2,
|
|
283
289
|
meta: undefined,
|
|
290
|
+
direction: 'forward',
|
|
284
291
|
signal: abortSignal,
|
|
285
292
|
})
|
|
286
293
|
|
|
287
|
-
queryFnSpy =
|
|
294
|
+
queryFnSpy = vi.fn().mockImplementation(({ pageParam = 1, signal }) => {
|
|
288
295
|
abortSignal = signal
|
|
289
296
|
sleep(10)
|
|
290
297
|
return pageParam
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createQueryClient, queryKey, sleep } from './utils'
|
|
2
2
|
import type { QueryClient } from '..'
|
|
3
3
|
import { InfiniteQueryObserver } from '..'
|
|
4
|
+
import { vi } from 'vitest'
|
|
4
5
|
|
|
5
6
|
describe('InfiniteQueryObserver', () => {
|
|
6
7
|
let queryClient: QueryClient
|
|
@@ -43,7 +44,7 @@ describe('InfiniteQueryObserver', () => {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
const key = queryKey()
|
|
46
|
-
const queryFn =
|
|
47
|
+
const queryFn = vi.fn(() => 1)
|
|
47
48
|
const observer = new InfiniteQueryObserver(queryClient, {
|
|
48
49
|
meta,
|
|
49
50
|
queryKey: key,
|
|
@@ -66,4 +67,64 @@ describe('InfiniteQueryObserver', () => {
|
|
|
66
67
|
})
|
|
67
68
|
expect(queryFn).toBeCalledWith(expect.objectContaining({ meta }))
|
|
68
69
|
})
|
|
70
|
+
|
|
71
|
+
test('getNextPagParam and getPreviousPageParam should receive current pageParams', async () => {
|
|
72
|
+
const key = queryKey()
|
|
73
|
+
let single: string[] = []
|
|
74
|
+
let all: string[] = []
|
|
75
|
+
const observer = new InfiniteQueryObserver(queryClient, {
|
|
76
|
+
queryKey: key,
|
|
77
|
+
queryFn: ({ pageParam }) => String(pageParam),
|
|
78
|
+
defaultPageParam: 1,
|
|
79
|
+
getNextPageParam: (_, __, lastPageParam, allPageParams) => {
|
|
80
|
+
single.push('next' + lastPageParam)
|
|
81
|
+
all.push('next' + allPageParams.join(','))
|
|
82
|
+
return lastPageParam + 1
|
|
83
|
+
},
|
|
84
|
+
getPreviousPageParam: (_, __, firstPageParam, allPageParams) => {
|
|
85
|
+
single.push('prev' + firstPageParam)
|
|
86
|
+
all.push('prev' + allPageParams.join(','))
|
|
87
|
+
return firstPageParam - 1
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
await observer.fetchNextPage()
|
|
92
|
+
await observer.fetchPreviousPage()
|
|
93
|
+
|
|
94
|
+
expect(single).toEqual(['next1', 'prev1', 'prev1', 'next1', 'prev0'])
|
|
95
|
+
expect(all).toEqual(['next1', 'prev1', 'prev1', 'next0,1', 'prev0,1'])
|
|
96
|
+
|
|
97
|
+
single = []
|
|
98
|
+
all = []
|
|
99
|
+
|
|
100
|
+
await observer.refetch()
|
|
101
|
+
|
|
102
|
+
expect(single).toEqual(['next0', 'next1', 'prev0'])
|
|
103
|
+
expect(all).toEqual(['next0', 'next0,1', 'prev0,1'])
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('should stop refetching if undefined is returned from getNextPageParam', async () => {
|
|
107
|
+
const key = queryKey()
|
|
108
|
+
let next: number | undefined = 2
|
|
109
|
+
const queryFn = vi.fn<any, any>(({ pageParam }) => String(pageParam))
|
|
110
|
+
const observer = new InfiniteQueryObserver(queryClient, {
|
|
111
|
+
queryKey: key,
|
|
112
|
+
queryFn,
|
|
113
|
+
defaultPageParam: 1,
|
|
114
|
+
getNextPageParam: () => next,
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
await observer.fetchNextPage()
|
|
118
|
+
await observer.fetchNextPage()
|
|
119
|
+
|
|
120
|
+
expect(observer.getCurrentResult().data?.pages).toEqual(['1', '2'])
|
|
121
|
+
expect(queryFn).toBeCalledTimes(2)
|
|
122
|
+
|
|
123
|
+
next = undefined
|
|
124
|
+
|
|
125
|
+
await observer.refetch()
|
|
126
|
+
|
|
127
|
+
expect(observer.getCurrentResult().data?.pages).toEqual(['1'])
|
|
128
|
+
expect(queryFn).toBeCalledTimes(3)
|
|
129
|
+
})
|
|
69
130
|
})
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { waitFor } from '@testing-library/react'
|
|
2
2
|
import { queryKey, sleep, executeMutation, createQueryClient } from './utils'
|
|
3
3
|
import { MutationCache, MutationObserver } from '..'
|
|
4
|
+
import { vi } from 'vitest'
|
|
4
5
|
|
|
5
6
|
describe('mutationCache', () => {
|
|
6
7
|
describe('MutationCacheConfig error callbacks', () => {
|
|
7
8
|
test('should call onError and onSettled when a mutation errors', async () => {
|
|
8
9
|
const key = queryKey()
|
|
9
|
-
const onError =
|
|
10
|
-
const onSuccess =
|
|
11
|
-
const onSettled =
|
|
10
|
+
const onError = vi.fn()
|
|
11
|
+
const onSuccess = vi.fn()
|
|
12
|
+
const onSettled = vi.fn()
|
|
12
13
|
const testCache = new MutationCache({ onError, onSuccess, onSettled })
|
|
13
14
|
const testClient = createQueryClient({ mutationCache: testCache })
|
|
14
15
|
|
|
@@ -86,9 +87,9 @@ describe('mutationCache', () => {
|
|
|
86
87
|
describe('MutationCacheConfig success callbacks', () => {
|
|
87
88
|
test('should call onSuccess and onSettled when a mutation is successful', async () => {
|
|
88
89
|
const key = queryKey()
|
|
89
|
-
const onError =
|
|
90
|
-
const onSuccess =
|
|
91
|
-
const onSettled =
|
|
90
|
+
const onError = vi.fn()
|
|
91
|
+
const onSuccess = vi.fn()
|
|
92
|
+
const onSettled = vi.fn()
|
|
92
93
|
const testCache = new MutationCache({ onError, onSuccess, onSettled })
|
|
93
94
|
const testClient = createQueryClient({ mutationCache: testCache })
|
|
94
95
|
|
|
@@ -163,7 +164,7 @@ describe('mutationCache', () => {
|
|
|
163
164
|
describe('MutationCacheConfig.onMutate', () => {
|
|
164
165
|
test('should be called before a mutation executes', async () => {
|
|
165
166
|
const key = queryKey()
|
|
166
|
-
const onMutate =
|
|
167
|
+
const onMutate = vi.fn()
|
|
167
168
|
const testCache = new MutationCache({ onMutate })
|
|
168
169
|
const testClient = createQueryClient({ mutationCache: testCache })
|
|
169
170
|
|
|
@@ -286,7 +287,7 @@ describe('mutationCache', () => {
|
|
|
286
287
|
test('should remove unused mutations after gcTime has elapsed', async () => {
|
|
287
288
|
const testCache = new MutationCache()
|
|
288
289
|
const testClient = createQueryClient({ mutationCache: testCache })
|
|
289
|
-
const onSuccess =
|
|
290
|
+
const onSuccess = vi.fn()
|
|
290
291
|
await executeMutation(
|
|
291
292
|
testClient,
|
|
292
293
|
{
|
|
@@ -329,7 +330,7 @@ describe('mutationCache', () => {
|
|
|
329
330
|
|
|
330
331
|
test('should be garbage collected later when unsubscribed and mutation is pending', async () => {
|
|
331
332
|
const queryClient = createQueryClient()
|
|
332
|
-
const onSuccess =
|
|
333
|
+
const onSuccess = vi.fn()
|
|
333
334
|
const observer = new MutationObserver(queryClient, {
|
|
334
335
|
gcTime: 10,
|
|
335
336
|
mutationFn: async () => {
|
|
@@ -355,7 +356,7 @@ describe('mutationCache', () => {
|
|
|
355
356
|
|
|
356
357
|
test('should call callbacks even with gcTime 0 and mutation still pending', async () => {
|
|
357
358
|
const queryClient = createQueryClient()
|
|
358
|
-
const onSuccess =
|
|
359
|
+
const onSuccess = vi.fn()
|
|
359
360
|
const observer = new MutationObserver(queryClient, {
|
|
360
361
|
gcTime: 0,
|
|
361
362
|
mutationFn: async () => {
|
|
@@ -2,6 +2,7 @@ import { waitFor } from '@testing-library/react'
|
|
|
2
2
|
import { createQueryClient, sleep } from './utils'
|
|
3
3
|
import type { QueryClient } from '..'
|
|
4
4
|
import { MutationObserver } from '..'
|
|
5
|
+
import { vi } from 'vitest'
|
|
5
6
|
|
|
6
7
|
describe('mutationObserver', () => {
|
|
7
8
|
let queryClient: QueryClient
|
|
@@ -23,8 +24,8 @@ describe('mutationObserver', () => {
|
|
|
23
24
|
},
|
|
24
25
|
})
|
|
25
26
|
|
|
26
|
-
const subscription1Handler =
|
|
27
|
-
const subscription2Handler =
|
|
27
|
+
const subscription1Handler = vi.fn()
|
|
28
|
+
const subscription2Handler = vi.fn()
|
|
28
29
|
|
|
29
30
|
const unsubscribe1 = mutation.subscribe(subscription1Handler)
|
|
30
31
|
const unsubscribe2 = mutation.subscribe(subscription2Handler)
|