@tanstack/query-core 5.0.0-alpha.2 → 5.0.0-alpha.21
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 +107 -66
- package/build/lib/queryClient.esm.js.map +1 -1
- package/build/lib/queryClient.js +107 -66
- package/build/lib/queryClient.js.map +1 -1
- package/build/lib/queryClient.mjs +5 -4
- 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 +11 -23
- 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 +5 -15
- 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 +97 -109
- 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 +2 -4
- package/src/queryObserver.ts +17 -31
- 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 +9 -13
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
|
|
@@ -414,9 +414,6 @@ export class QueryObserver<
|
|
|
414
414
|
const queryInitialState = queryChange
|
|
415
415
|
? query.state
|
|
416
416
|
: this.#currentQueryInitialState
|
|
417
|
-
const prevQueryResult = queryChange
|
|
418
|
-
? this.#currentResult
|
|
419
|
-
: this.#previousQueryResult
|
|
420
417
|
|
|
421
418
|
const { state } = query
|
|
422
419
|
let { error, errorUpdatedAt, fetchStatus, status } = state
|
|
@@ -490,7 +487,7 @@ export class QueryObserver<
|
|
|
490
487
|
typeof options.placeholderData === 'function'
|
|
491
488
|
? (
|
|
492
489
|
options.placeholderData as unknown as PlaceholderDataFunction<TQueryData>
|
|
493
|
-
)(
|
|
490
|
+
)(this.#lastDefinedQueryData)
|
|
494
491
|
: options.placeholderData
|
|
495
492
|
if (options.select && typeof placeholderData !== 'undefined') {
|
|
496
493
|
try {
|
|
@@ -504,7 +501,11 @@ export class QueryObserver<
|
|
|
504
501
|
|
|
505
502
|
if (typeof placeholderData !== 'undefined') {
|
|
506
503
|
status = 'success'
|
|
507
|
-
data = replaceData(
|
|
504
|
+
data = replaceData(
|
|
505
|
+
prevResult?.data,
|
|
506
|
+
placeholderData as unknown,
|
|
507
|
+
options,
|
|
508
|
+
) as TData
|
|
508
509
|
isPlaceholderData = true
|
|
509
510
|
}
|
|
510
511
|
}
|
|
@@ -568,6 +569,9 @@ export class QueryObserver<
|
|
|
568
569
|
return
|
|
569
570
|
}
|
|
570
571
|
|
|
572
|
+
if (this.#currentResultState.data !== undefined) {
|
|
573
|
+
this.#lastDefinedQueryData = this.#currentResultState.data
|
|
574
|
+
}
|
|
571
575
|
this.#currentResult = nextResult
|
|
572
576
|
|
|
573
577
|
// Determine which callbacks to trigger
|
|
@@ -619,7 +623,6 @@ export class QueryObserver<
|
|
|
619
623
|
| undefined
|
|
620
624
|
this.#currentQuery = query
|
|
621
625
|
this.#currentQueryInitialState = query.state
|
|
622
|
-
this.#previousQueryResult = this.#currentResult
|
|
623
626
|
|
|
624
627
|
if (this.hasListeners()) {
|
|
625
628
|
prevQuery?.removeObserver(this)
|
|
@@ -627,16 +630,8 @@ export class QueryObserver<
|
|
|
627
630
|
}
|
|
628
631
|
}
|
|
629
632
|
|
|
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)
|
|
633
|
+
onQueryUpdate(): void {
|
|
634
|
+
this.#updateResult()
|
|
640
635
|
|
|
641
636
|
if (this.hasListeners()) {
|
|
642
637
|
this.#updateTimers()
|
|
@@ -645,16 +640,7 @@ export class QueryObserver<
|
|
|
645
640
|
|
|
646
641
|
#notify(notifyOptions: NotifyOptions): void {
|
|
647
642
|
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
|
|
643
|
+
// First, trigger the listeners
|
|
658
644
|
if (notifyOptions.listeners) {
|
|
659
645
|
this.listeners.forEach((listener) => {
|
|
660
646
|
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)
|