@tanstack/query-core 4.0.0

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 (85) hide show
  1. package/build/cjs/focusManager.js +101 -0
  2. package/build/cjs/focusManager.js.map +1 -0
  3. package/build/cjs/hydration.js +112 -0
  4. package/build/cjs/hydration.js.map +1 -0
  5. package/build/cjs/index.js +51 -0
  6. package/build/cjs/index.js.map +1 -0
  7. package/build/cjs/infiniteQueryBehavior.js +160 -0
  8. package/build/cjs/infiniteQueryBehavior.js.map +1 -0
  9. package/build/cjs/infiniteQueryObserver.js +92 -0
  10. package/build/cjs/infiniteQueryObserver.js.map +1 -0
  11. package/build/cjs/logger.js +18 -0
  12. package/build/cjs/logger.js.map +1 -0
  13. package/build/cjs/mutation.js +258 -0
  14. package/build/cjs/mutation.js.map +1 -0
  15. package/build/cjs/mutationCache.js +99 -0
  16. package/build/cjs/mutationCache.js.map +1 -0
  17. package/build/cjs/mutationObserver.js +130 -0
  18. package/build/cjs/mutationObserver.js.map +1 -0
  19. package/build/cjs/notifyManager.js +114 -0
  20. package/build/cjs/notifyManager.js.map +1 -0
  21. package/build/cjs/onlineManager.js +100 -0
  22. package/build/cjs/onlineManager.js.map +1 -0
  23. package/build/cjs/queriesObserver.js +170 -0
  24. package/build/cjs/queriesObserver.js.map +1 -0
  25. package/build/cjs/query.js +474 -0
  26. package/build/cjs/query.js.map +1 -0
  27. package/build/cjs/queryCache.js +140 -0
  28. package/build/cjs/queryCache.js.map +1 -0
  29. package/build/cjs/queryClient.js +357 -0
  30. package/build/cjs/queryClient.js.map +1 -0
  31. package/build/cjs/queryObserver.js +521 -0
  32. package/build/cjs/queryObserver.js.map +1 -0
  33. package/build/cjs/removable.js +47 -0
  34. package/build/cjs/removable.js.map +1 -0
  35. package/build/cjs/retryer.js +177 -0
  36. package/build/cjs/retryer.js.map +1 -0
  37. package/build/cjs/subscribable.js +43 -0
  38. package/build/cjs/subscribable.js.map +1 -0
  39. package/build/cjs/utils.js +356 -0
  40. package/build/cjs/utils.js.map +1 -0
  41. package/build/esm/index.js +3077 -0
  42. package/build/esm/index.js.map +1 -0
  43. package/build/stats-html.html +2689 -0
  44. package/build/umd/index.development.js +3106 -0
  45. package/build/umd/index.development.js.map +1 -0
  46. package/build/umd/index.production.js +12 -0
  47. package/build/umd/index.production.js.map +1 -0
  48. package/package.json +25 -0
  49. package/src/focusManager.ts +89 -0
  50. package/src/hydration.ts +164 -0
  51. package/src/index.ts +35 -0
  52. package/src/infiniteQueryBehavior.ts +214 -0
  53. package/src/infiniteQueryObserver.ts +159 -0
  54. package/src/logger.native.ts +11 -0
  55. package/src/logger.ts +9 -0
  56. package/src/mutation.ts +349 -0
  57. package/src/mutationCache.ts +157 -0
  58. package/src/mutationObserver.ts +195 -0
  59. package/src/notifyManager.ts +96 -0
  60. package/src/onlineManager.ts +89 -0
  61. package/src/queriesObserver.ts +211 -0
  62. package/src/query.ts +612 -0
  63. package/src/queryCache.ts +206 -0
  64. package/src/queryClient.ts +716 -0
  65. package/src/queryObserver.ts +748 -0
  66. package/src/removable.ts +37 -0
  67. package/src/retryer.ts +215 -0
  68. package/src/subscribable.ts +33 -0
  69. package/src/tests/focusManager.test.tsx +155 -0
  70. package/src/tests/hydration.test.tsx +429 -0
  71. package/src/tests/infiniteQueryBehavior.test.tsx +124 -0
  72. package/src/tests/infiniteQueryObserver.test.tsx +64 -0
  73. package/src/tests/mutationCache.test.tsx +260 -0
  74. package/src/tests/mutationObserver.test.tsx +75 -0
  75. package/src/tests/mutations.test.tsx +363 -0
  76. package/src/tests/notifyManager.test.tsx +51 -0
  77. package/src/tests/onlineManager.test.tsx +148 -0
  78. package/src/tests/queriesObserver.test.tsx +330 -0
  79. package/src/tests/query.test.tsx +888 -0
  80. package/src/tests/queryCache.test.tsx +236 -0
  81. package/src/tests/queryClient.test.tsx +1435 -0
  82. package/src/tests/queryObserver.test.tsx +802 -0
  83. package/src/tests/utils.test.tsx +360 -0
  84. package/src/types.ts +705 -0
  85. package/src/utils.ts +435 -0
@@ -0,0 +1,51 @@
1
+ import { createNotifyManager } from '../notifyManager'
2
+ import { sleep } from '../../../../tests/utils'
3
+
4
+ describe('notifyManager', () => {
5
+ it('should use default notifyFn', async () => {
6
+ const notifyManagerTest = createNotifyManager()
7
+ const callbackSpy = jest.fn()
8
+ notifyManagerTest.schedule(callbackSpy)
9
+ await sleep(1)
10
+ expect(callbackSpy).toHaveBeenCalled()
11
+ })
12
+
13
+ it('should use default batchNotifyFn', async () => {
14
+ const notifyManagerTest = createNotifyManager()
15
+ const callbackScheduleSpy = jest
16
+ .fn()
17
+ .mockImplementation(async () => await sleep(20))
18
+ const callbackBatchLevel2Spy = jest.fn().mockImplementation(async () => {
19
+ notifyManagerTest.schedule(callbackScheduleSpy)
20
+ })
21
+ const callbackBatchLevel1Spy = jest.fn().mockImplementation(async () => {
22
+ notifyManagerTest.batch(callbackBatchLevel2Spy)
23
+ })
24
+
25
+ notifyManagerTest.batch(callbackBatchLevel1Spy)
26
+
27
+ await sleep(30)
28
+ expect(callbackBatchLevel1Spy).toHaveBeenCalledTimes(1)
29
+ expect(callbackBatchLevel2Spy).toHaveBeenCalledTimes(1)
30
+ expect(callbackScheduleSpy).toHaveBeenCalledTimes(1)
31
+ })
32
+
33
+ it('should notify if error is thrown', async () => {
34
+ const notifyManagerTest = createNotifyManager()
35
+ const notifySpy = jest.fn()
36
+
37
+ notifyManagerTest.setNotifyFunction(notifySpy)
38
+
39
+ try {
40
+ notifyManagerTest.batch(() => {
41
+ notifyManagerTest.schedule(jest.fn)
42
+ throw new Error('Foo')
43
+ })
44
+ } catch {}
45
+
46
+ // needed for scheduleMicroTask to kick in
47
+ await sleep(1)
48
+
49
+ expect(notifySpy).toHaveBeenCalledTimes(1)
50
+ })
51
+ })
@@ -0,0 +1,148 @@
1
+ import { OnlineManager } from '../onlineManager'
2
+ import { setIsServer, sleep } from '../../../../tests/utils'
3
+
4
+ describe('onlineManager', () => {
5
+ let onlineManager: OnlineManager
6
+ beforeEach(() => {
7
+ onlineManager = new OnlineManager()
8
+ })
9
+
10
+ test('isOnline should return true if navigator is undefined', () => {
11
+ const navigatorSpy = jest.spyOn(globalThis, 'navigator', 'get')
12
+
13
+ // Force navigator to be undefined
14
+ //@ts-expect-error
15
+ navigatorSpy.mockImplementation(() => undefined)
16
+ expect(onlineManager.isOnline()).toBeTruthy()
17
+
18
+ navigatorSpy.mockRestore()
19
+ })
20
+
21
+ test('isOnline should return true if navigator.onLine is true', () => {
22
+ const navigatorSpy = jest.spyOn(navigator, 'onLine', 'get')
23
+ navigatorSpy.mockImplementation(() => true)
24
+
25
+ expect(onlineManager.isOnline()).toBeTruthy()
26
+
27
+ navigatorSpy.mockRestore()
28
+ })
29
+
30
+ test('setEventListener should use online boolean arg', async () => {
31
+ let count = 0
32
+
33
+ const setup = (setOnline: (online?: boolean) => void) => {
34
+ setTimeout(() => {
35
+ count++
36
+ setOnline(false)
37
+ }, 20)
38
+ return () => void 0
39
+ }
40
+
41
+ onlineManager.setEventListener(setup)
42
+
43
+ await sleep(30)
44
+ expect(count).toEqual(1)
45
+ expect(onlineManager.isOnline()).toBeFalsy()
46
+ })
47
+
48
+ test('setEventListener should call previous remove handler when replacing an event listener', () => {
49
+ const remove1Spy = jest.fn()
50
+ const remove2Spy = jest.fn()
51
+
52
+ onlineManager.setEventListener(() => remove1Spy)
53
+ onlineManager.setEventListener(() => remove2Spy)
54
+
55
+ expect(remove1Spy).toHaveBeenCalledTimes(1)
56
+ expect(remove2Spy).not.toHaveBeenCalled()
57
+ })
58
+
59
+ test('cleanup should still be undefined if window is not defined', async () => {
60
+ const restoreIsServer = setIsServer(true)
61
+
62
+ const unsubscribe = onlineManager.subscribe(() => undefined)
63
+ expect(onlineManager['cleanup']).toBeUndefined()
64
+
65
+ unsubscribe()
66
+ restoreIsServer()
67
+ })
68
+
69
+ test('cleanup should still be undefined if window.addEventListener is not defined', async () => {
70
+ const { addEventListener } = globalThis.window
71
+
72
+ // @ts-expect-error
73
+ globalThis.window.addEventListener = undefined
74
+
75
+ const unsubscribe = onlineManager.subscribe(() => undefined)
76
+ expect(onlineManager['cleanup']).toBeUndefined()
77
+
78
+ unsubscribe()
79
+ globalThis.window.addEventListener = addEventListener
80
+ })
81
+
82
+ test('it should replace default window listener when a new event listener is set', async () => {
83
+ const addEventListenerSpy = jest.spyOn(
84
+ globalThis.window,
85
+ 'addEventListener',
86
+ )
87
+
88
+ const removeEventListenerSpy = jest.spyOn(
89
+ globalThis.window,
90
+ 'removeEventListener',
91
+ )
92
+
93
+ // Should set the default event listener with window event listeners
94
+ const unsubscribe = onlineManager.subscribe(() => undefined)
95
+ expect(addEventListenerSpy).toHaveBeenCalledTimes(2)
96
+
97
+ // Should replace the window default event listener by a new one
98
+ // and it should call window.removeEventListener twice
99
+ onlineManager.setEventListener(() => {
100
+ return () => void 0
101
+ })
102
+
103
+ expect(removeEventListenerSpy).toHaveBeenCalledTimes(2)
104
+
105
+ unsubscribe()
106
+ addEventListenerSpy.mockRestore()
107
+ removeEventListenerSpy.mockRestore()
108
+ })
109
+
110
+ test('should call removeEventListener when last listener unsubscribes', () => {
111
+ const addEventListenerSpy = jest.spyOn(
112
+ globalThis.window,
113
+ 'addEventListener',
114
+ )
115
+
116
+ const removeEventListenerSpy = jest.spyOn(
117
+ globalThis.window,
118
+ 'removeEventListener',
119
+ )
120
+
121
+ const unsubscribe1 = onlineManager.subscribe(() => undefined)
122
+ const unsubscribe2 = onlineManager.subscribe(() => undefined)
123
+ expect(addEventListenerSpy).toHaveBeenCalledTimes(2) // online + offline
124
+
125
+ unsubscribe1()
126
+ expect(removeEventListenerSpy).toHaveBeenCalledTimes(0)
127
+ unsubscribe2()
128
+ expect(removeEventListenerSpy).toHaveBeenCalledTimes(2) // online + offline
129
+ })
130
+
131
+ test('should keep setup function even if last listener unsubscribes', () => {
132
+ const setupSpy = jest.fn().mockImplementation(() => () => undefined)
133
+
134
+ onlineManager.setEventListener(setupSpy)
135
+
136
+ const unsubscribe1 = onlineManager.subscribe(() => undefined)
137
+
138
+ expect(setupSpy).toHaveBeenCalledTimes(1)
139
+
140
+ unsubscribe1()
141
+
142
+ const unsubscribe2 = onlineManager.subscribe(() => undefined)
143
+
144
+ expect(setupSpy).toHaveBeenCalledTimes(2)
145
+
146
+ unsubscribe2()
147
+ })
148
+ })
@@ -0,0 +1,330 @@
1
+ import { waitFor } from '@testing-library/react'
2
+ import {
3
+ sleep,
4
+ queryKey,
5
+ createQueryClient,
6
+ mockLogger,
7
+ } from '../../../../tests/utils'
8
+ import {
9
+ QueryClient,
10
+ QueriesObserver,
11
+ QueryObserverResult,
12
+ QueryObserver,
13
+ } from '..'
14
+ import { QueryKey } from '..'
15
+
16
+ describe('queriesObserver', () => {
17
+ let queryClient: QueryClient
18
+
19
+ beforeEach(() => {
20
+ queryClient = createQueryClient()
21
+ queryClient.mount()
22
+ })
23
+
24
+ afterEach(() => {
25
+ queryClient.clear()
26
+ })
27
+
28
+ test('should return an array with all query results', async () => {
29
+ const key1 = queryKey()
30
+ const key2 = queryKey()
31
+ const queryFn1 = jest.fn().mockReturnValue(1)
32
+ const queryFn2 = jest.fn().mockReturnValue(2)
33
+ const observer = new QueriesObserver(queryClient, [
34
+ { queryKey: key1, queryFn: queryFn1 },
35
+ { queryKey: key2, queryFn: queryFn2 },
36
+ ])
37
+ let observerResult
38
+ const unsubscribe = observer.subscribe((result) => {
39
+ observerResult = result
40
+ })
41
+ await sleep(1)
42
+ unsubscribe()
43
+ expect(observerResult).toMatchObject([{ data: 1 }, { data: 2 }])
44
+ })
45
+
46
+ test('should still return value for undefined query key', async () => {
47
+ const key1 = queryKey()
48
+ const queryFn1 = jest.fn().mockReturnValue(1)
49
+ const queryFn2 = jest.fn().mockReturnValue(2)
50
+ const observer = new QueriesObserver(queryClient, [
51
+ { queryKey: key1, queryFn: queryFn1 },
52
+ { queryKey: undefined, queryFn: queryFn2 },
53
+ ])
54
+ let observerResult
55
+ const unsubscribe = observer.subscribe((result) => {
56
+ observerResult = result
57
+ })
58
+ await sleep(1)
59
+ unsubscribe()
60
+ expect(observerResult).toMatchObject([{ data: 1 }, { data: 2 }])
61
+
62
+ expect(mockLogger.error).toHaveBeenCalledTimes(1)
63
+ })
64
+
65
+ test('should update when a query updates', async () => {
66
+ const key1 = queryKey()
67
+ const key2 = queryKey()
68
+ const queryFn1 = jest.fn().mockReturnValue(1)
69
+ const queryFn2 = jest.fn().mockReturnValue(2)
70
+ const observer = new QueriesObserver(queryClient, [
71
+ { queryKey: key1, queryFn: queryFn1 },
72
+ { queryKey: key2, queryFn: queryFn2 },
73
+ ])
74
+ const results: QueryObserverResult[][] = []
75
+ results.push(observer.getCurrentResult())
76
+ const unsubscribe = observer.subscribe((result) => {
77
+ results.push(result)
78
+ })
79
+ await sleep(1)
80
+ queryClient.setQueryData(key2, 3)
81
+ await sleep(1)
82
+ unsubscribe()
83
+ expect(results.length).toBe(6)
84
+ expect(results[0]).toMatchObject([
85
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
86
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
87
+ ])
88
+ expect(results[1]).toMatchObject([
89
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
90
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
91
+ ])
92
+ expect(results[2]).toMatchObject([
93
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
94
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
95
+ ])
96
+ expect(results[3]).toMatchObject([
97
+ { status: 'success', data: 1 },
98
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
99
+ ])
100
+ expect(results[4]).toMatchObject([
101
+ { status: 'success', data: 1 },
102
+ { status: 'success', data: 2 },
103
+ ])
104
+ expect(results[5]).toMatchObject([
105
+ { status: 'success', data: 1 },
106
+ { status: 'success', data: 3 },
107
+ ])
108
+ })
109
+
110
+ test('should update when a query is removed', async () => {
111
+ const key1 = queryKey()
112
+ const key2 = queryKey()
113
+ const queryFn1 = jest.fn().mockReturnValue(1)
114
+ const queryFn2 = jest.fn().mockReturnValue(2)
115
+ const observer = new QueriesObserver(queryClient, [
116
+ { queryKey: key1, queryFn: queryFn1 },
117
+ { queryKey: key2, queryFn: queryFn2 },
118
+ ])
119
+ const results: QueryObserverResult[][] = []
120
+ results.push(observer.getCurrentResult())
121
+ const unsubscribe = observer.subscribe((result) => {
122
+ results.push(result)
123
+ })
124
+ await sleep(1)
125
+ observer.setQueries([{ queryKey: key2, queryFn: queryFn2 }])
126
+ await sleep(1)
127
+ const queryCache = queryClient.getQueryCache()
128
+ expect(queryCache.find(key1, { type: 'active' })).toBeUndefined()
129
+ expect(queryCache.find(key2, { type: 'active' })).toBeDefined()
130
+ unsubscribe()
131
+ expect(queryCache.find(key1, { type: 'active' })).toBeUndefined()
132
+ expect(queryCache.find(key2, { type: 'active' })).toBeUndefined()
133
+ expect(results.length).toBe(6)
134
+ expect(results[0]).toMatchObject([
135
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
136
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
137
+ ])
138
+ expect(results[1]).toMatchObject([
139
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
140
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
141
+ ])
142
+ expect(results[2]).toMatchObject([
143
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
144
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
145
+ ])
146
+ expect(results[3]).toMatchObject([
147
+ { status: 'success', data: 1 },
148
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
149
+ ])
150
+ expect(results[4]).toMatchObject([
151
+ { status: 'success', data: 1 },
152
+ { status: 'success', data: 2 },
153
+ ])
154
+ expect(results[5]).toMatchObject([{ status: 'success', data: 2 }])
155
+ })
156
+
157
+ test('should update when a query changed position', async () => {
158
+ const key1 = queryKey()
159
+ const key2 = queryKey()
160
+ const queryFn1 = jest.fn().mockReturnValue(1)
161
+ const queryFn2 = jest.fn().mockReturnValue(2)
162
+ const observer = new QueriesObserver(queryClient, [
163
+ { queryKey: key1, queryFn: queryFn1 },
164
+ { queryKey: key2, queryFn: queryFn2 },
165
+ ])
166
+ const results: QueryObserverResult[][] = []
167
+ results.push(observer.getCurrentResult())
168
+ const unsubscribe = observer.subscribe((result) => {
169
+ results.push(result)
170
+ })
171
+ await sleep(1)
172
+ observer.setQueries([
173
+ { queryKey: key2, queryFn: queryFn2 },
174
+ { queryKey: key1, queryFn: queryFn1 },
175
+ ])
176
+ await sleep(1)
177
+ unsubscribe()
178
+ expect(results.length).toBe(6)
179
+ expect(results[0]).toMatchObject([
180
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
181
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
182
+ ])
183
+ expect(results[1]).toMatchObject([
184
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
185
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
186
+ ])
187
+ expect(results[2]).toMatchObject([
188
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
189
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
190
+ ])
191
+ expect(results[3]).toMatchObject([
192
+ { status: 'success', data: 1 },
193
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
194
+ ])
195
+ expect(results[4]).toMatchObject([
196
+ { status: 'success', data: 1 },
197
+ { status: 'success', data: 2 },
198
+ ])
199
+ expect(results[5]).toMatchObject([
200
+ { status: 'success', data: 2 },
201
+ { status: 'success', data: 1 },
202
+ ])
203
+ })
204
+
205
+ test('should not update when nothing has changed', async () => {
206
+ const key1 = queryKey()
207
+ const key2 = queryKey()
208
+ const queryFn1 = jest.fn().mockReturnValue(1)
209
+ const queryFn2 = jest.fn().mockReturnValue(2)
210
+ const observer = new QueriesObserver(queryClient, [
211
+ { queryKey: key1, queryFn: queryFn1 },
212
+ { queryKey: key2, queryFn: queryFn2 },
213
+ ])
214
+ const results: QueryObserverResult[][] = []
215
+ results.push(observer.getCurrentResult())
216
+ const unsubscribe = observer.subscribe((result) => {
217
+ results.push(result)
218
+ })
219
+ await sleep(1)
220
+ observer.setQueries([
221
+ { queryKey: key1, queryFn: queryFn1 },
222
+ { queryKey: key2, queryFn: queryFn2 },
223
+ ])
224
+ await sleep(1)
225
+ unsubscribe()
226
+ expect(results.length).toBe(5)
227
+ expect(results[0]).toMatchObject([
228
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
229
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
230
+ ])
231
+ expect(results[1]).toMatchObject([
232
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
233
+ { status: 'loading', fetchStatus: 'idle', data: undefined },
234
+ ])
235
+ expect(results[2]).toMatchObject([
236
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
237
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
238
+ ])
239
+ expect(results[3]).toMatchObject([
240
+ { status: 'success', data: 1 },
241
+ { status: 'loading', fetchStatus: 'fetching', data: undefined },
242
+ ])
243
+ expect(results[4]).toMatchObject([
244
+ { status: 'success', data: 1 },
245
+ { status: 'success', data: 2 },
246
+ ])
247
+ })
248
+
249
+ test('should trigger all fetches when subscribed', async () => {
250
+ const key1 = queryKey()
251
+ const key2 = queryKey()
252
+ const queryFn1 = jest.fn().mockReturnValue(1)
253
+ const queryFn2 = jest.fn().mockReturnValue(2)
254
+ const observer = new QueriesObserver(queryClient, [
255
+ { queryKey: key1, queryFn: queryFn1 },
256
+ { queryKey: key2, queryFn: queryFn2 },
257
+ ])
258
+ const unsubscribe = observer.subscribe(() => undefined)
259
+ await sleep(1)
260
+ unsubscribe()
261
+ expect(queryFn1).toHaveBeenCalledTimes(1)
262
+ expect(queryFn2).toHaveBeenCalledTimes(1)
263
+ })
264
+
265
+ test('should not destroy the observer if there is still a subscription', async () => {
266
+ const key1 = queryKey()
267
+ const observer = new QueriesObserver(queryClient, [
268
+ {
269
+ queryKey: key1,
270
+ queryFn: async () => {
271
+ await sleep(20)
272
+ return 1
273
+ },
274
+ },
275
+ ])
276
+
277
+ const subscription1Handler = jest.fn()
278
+ const subscription2Handler = jest.fn()
279
+
280
+ const unsubscribe1 = observer.subscribe(subscription1Handler)
281
+ const unsubscribe2 = observer.subscribe(subscription2Handler)
282
+
283
+ unsubscribe1()
284
+
285
+ await waitFor(() => {
286
+ // 1 call: loading
287
+ expect(subscription1Handler).toBeCalledTimes(1)
288
+ // 1 call: success
289
+ expect(subscription2Handler).toBeCalledTimes(1)
290
+ })
291
+
292
+ // Clean-up
293
+ unsubscribe2()
294
+ })
295
+
296
+ test('onUpdate should not update the result for an unknown observer', async () => {
297
+ const key1 = queryKey()
298
+ const key2 = queryKey()
299
+
300
+ const queriesObserver = new QueriesObserver(queryClient, [
301
+ {
302
+ queryKey: key1,
303
+ queryFn: () => 1,
304
+ },
305
+ ])
306
+
307
+ const newQueryObserver = new QueryObserver<
308
+ unknown,
309
+ unknown,
310
+ unknown,
311
+ unknown,
312
+ QueryKey
313
+ >(queryClient, {
314
+ queryKey: key2,
315
+ queryFn: () => 2,
316
+ })
317
+
318
+ // Force onUpdate with an unknown QueryObserver
319
+ // because no existing use case has been found in the lib
320
+ queriesObserver['onUpdate'](
321
+ newQueryObserver,
322
+ // The current queries observer result is re-used here
323
+ // to use a typescript friendly result
324
+ queriesObserver.getCurrentResult()[0]!,
325
+ )
326
+
327
+ // Should not alter the result
328
+ expect(queriesObserver.getCurrentResult()[-1]).toBeUndefined()
329
+ })
330
+ })