@tanstack/angular-query-experimental 5.103.1 → 5.103.3

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 (219) hide show
  1. package/dist/create-base-query.d.mts +169 -0
  2. package/dist/create-base-query.d.mts.map +1 -0
  3. package/dist/create-base-query.mjs +91 -0
  4. package/dist/create-base-query.mjs.map +1 -0
  5. package/dist/devtools/index.d.mts +3 -0
  6. package/dist/devtools/index.mjs +2 -0
  7. package/dist/devtools/production/index.d.mts +4 -0
  8. package/dist/devtools/production/index.mjs +2 -0
  9. package/dist/devtools/stub.d.mts +6 -0
  10. package/dist/devtools/stub.d.mts.map +1 -0
  11. package/dist/devtools/stub.mjs +9 -0
  12. package/dist/devtools/stub.mjs.map +1 -0
  13. package/dist/devtools/types.d.mts +107 -0
  14. package/dist/devtools/types.d.mts.map +1 -0
  15. package/dist/devtools/types.mjs +1 -0
  16. package/{devtools/with-devtools.d.ts → dist/devtools/with-devtools.d.mts} +6 -2
  17. package/dist/devtools/with-devtools.d.mts.map +1 -0
  18. package/dist/devtools/with-devtools.mjs +110 -0
  19. package/dist/devtools/with-devtools.mjs.map +1 -0
  20. package/dist/devtools-panel/index.d.mts +3 -0
  21. package/dist/devtools-panel/index.mjs +2 -0
  22. package/{devtools-panel/inject-devtools-panel.d.ts → dist/devtools-panel/inject-devtools-panel.d.mts} +6 -2
  23. package/dist/devtools-panel/inject-devtools-panel.d.mts.map +1 -0
  24. package/dist/devtools-panel/inject-devtools-panel.mjs +67 -0
  25. package/dist/devtools-panel/inject-devtools-panel.mjs.map +1 -0
  26. package/dist/devtools-panel/production/index.d.mts +4 -0
  27. package/dist/devtools-panel/production/index.mjs +2 -0
  28. package/dist/devtools-panel/stub.d.mts +6 -0
  29. package/dist/devtools-panel/stub.d.mts.map +1 -0
  30. package/dist/devtools-panel/stub.mjs +7 -0
  31. package/dist/devtools-panel/stub.mjs.map +1 -0
  32. package/dist/devtools-panel/types.d.mts +52 -0
  33. package/dist/devtools-panel/types.d.mts.map +1 -0
  34. package/dist/devtools-panel/types.mjs +1 -0
  35. package/dist/index.d.mts +16 -0
  36. package/{index.mjs → dist/index.mjs} +8 -21
  37. package/dist/index.mjs.map +1 -0
  38. package/{infinite-query-options.d.ts → dist/infinite-query-options.d.mts} +35 -31
  39. package/dist/infinite-query-options.d.mts.map +1 -0
  40. package/dist/infinite-query-options.mjs +8 -0
  41. package/dist/infinite-query-options.mjs.map +1 -0
  42. package/{inject-infinite-query.d.ts → dist/inject-infinite-query.d.mts} +18 -14
  43. package/dist/inject-infinite-query.d.mts.map +1 -0
  44. package/dist/inject-infinite-query.mjs +13 -0
  45. package/dist/inject-infinite-query.mjs.map +1 -0
  46. package/{inject-is-fetching.d.ts → dist/inject-is-fetching.d.mts} +14 -10
  47. package/dist/inject-is-fetching.d.mts.map +1 -0
  48. package/dist/inject-is-fetching.mjs +69 -0
  49. package/dist/inject-is-fetching.mjs.map +1 -0
  50. package/{inject-is-mutating.d.ts → dist/inject-is-mutating.d.mts} +14 -10
  51. package/dist/inject-is-mutating.d.mts.map +1 -0
  52. package/dist/inject-is-mutating.mjs +52 -0
  53. package/dist/inject-is-mutating.mjs.map +1 -0
  54. package/{inject-is-restoring.d.ts → dist/inject-is-restoring.d.mts} +13 -10
  55. package/dist/inject-is-restoring.d.mts.map +1 -0
  56. package/dist/inject-is-restoring.mjs +35 -0
  57. package/dist/inject-is-restoring.mjs.map +1 -0
  58. package/{inject-mutation-state.d.ts → dist/inject-mutation-state.d.mts} +16 -13
  59. package/dist/inject-mutation-state.d.mts.map +1 -0
  60. package/dist/inject-mutation-state.mjs +103 -0
  61. package/dist/inject-mutation-state.mjs.map +1 -0
  62. package/{inject-mutation.d.ts → dist/inject-mutation.d.mts} +15 -11
  63. package/dist/inject-mutation.d.mts.map +1 -0
  64. package/dist/inject-mutation.mjs +226 -0
  65. package/dist/inject-mutation.mjs.map +1 -0
  66. package/dist/inject-queries-experimental/index.d.mts +2 -0
  67. package/dist/inject-queries-experimental/index.mjs +2 -0
  68. package/{inject-queries.d.ts → dist/inject-queries.d.mts} +36 -55
  69. package/dist/inject-queries.d.mts.map +1 -0
  70. package/dist/inject-queries.mjs +203 -0
  71. package/dist/inject-queries.mjs.map +1 -0
  72. package/{inject-query-client.d.ts → dist/inject-query-client.d.mts} +8 -4
  73. package/dist/inject-query-client.d.mts.map +1 -0
  74. package/dist/inject-query-client.mjs +23 -0
  75. package/dist/inject-query-client.mjs.map +1 -0
  76. package/{inject-query.d.ts → dist/inject-query.d.mts} +18 -14
  77. package/dist/inject-query.d.mts.map +1 -0
  78. package/dist/inject-query.mjs +12 -0
  79. package/dist/inject-query.mjs.map +1 -0
  80. package/{mutation-options.d.ts → dist/mutation-options.d.mts} +8 -4
  81. package/dist/mutation-options.d.mts.map +1 -0
  82. package/dist/mutation-options.mjs +8 -0
  83. package/dist/mutation-options.mjs.map +1 -0
  84. package/dist/pending-tasks-compat.d.mts +10 -0
  85. package/dist/pending-tasks-compat.d.mts.map +1 -0
  86. package/dist/pending-tasks-compat.mjs +13 -0
  87. package/dist/pending-tasks-compat.mjs.map +1 -0
  88. package/{providers.d.ts → dist/providers.d.mts} +16 -13
  89. package/dist/providers.d.mts.map +1 -0
  90. package/dist/providers.mjs +124 -0
  91. package/dist/providers.mjs.map +1 -0
  92. package/{query-options.d.ts → dist/query-options.d.mts} +41 -37
  93. package/dist/query-options.d.mts.map +1 -0
  94. package/dist/query-options.mjs +8 -0
  95. package/dist/query-options.mjs.map +1 -0
  96. package/dist/signal-proxy.d.mts +13 -0
  97. package/dist/signal-proxy.d.mts.map +1 -0
  98. package/dist/signal-proxy.mjs +35 -0
  99. package/dist/signal-proxy.mjs.map +1 -0
  100. package/{types.d.ts → dist/types.d.mts} +36 -37
  101. package/dist/types.d.mts.map +1 -0
  102. package/dist/types.mjs +6 -0
  103. package/dist/types.mjs.map +1 -0
  104. package/package.json +48 -20
  105. package/src/__tests__/infinite-query-options.test-d.ts +314 -0
  106. package/src/__tests__/infinite-query-options.test.ts +19 -0
  107. package/src/__tests__/inject-devtools-panel.test.ts +196 -0
  108. package/src/__tests__/inject-infinite-query.test-d.ts +66 -0
  109. package/src/__tests__/inject-infinite-query.test.ts +227 -0
  110. package/src/__tests__/inject-is-fetching.test.ts +108 -0
  111. package/src/__tests__/inject-is-mutating.test.ts +113 -0
  112. package/src/__tests__/inject-is-restoring.test.ts +93 -0
  113. package/src/__tests__/inject-mutation-state.test-d.ts +22 -0
  114. package/src/__tests__/inject-mutation-state.test.ts +198 -0
  115. package/src/__tests__/inject-mutation.test-d.ts +158 -0
  116. package/src/__tests__/inject-mutation.test.ts +1161 -0
  117. package/src/__tests__/inject-queries.test-d.ts +196 -0
  118. package/src/__tests__/inject-queries.test.ts +240 -0
  119. package/src/__tests__/inject-query.test-d.ts +357 -0
  120. package/src/__tests__/inject-query.test.ts +700 -0
  121. package/src/__tests__/mutation-options.test-d.ts +234 -0
  122. package/src/__tests__/mutation-options.test.ts +344 -0
  123. package/src/__tests__/pending-tasks.test.ts +644 -0
  124. package/src/__tests__/provide-query-client.test.ts +38 -0
  125. package/src/__tests__/provide-tanstack-query.test.ts +38 -0
  126. package/src/__tests__/query-options.test-d.ts +262 -0
  127. package/src/__tests__/query-options.test.ts +14 -0
  128. package/src/__tests__/signal-proxy.test.ts +27 -0
  129. package/src/__tests__/test-utils.ts +77 -0
  130. package/src/__tests__/with-devtools.test.ts +674 -0
  131. package/src/create-base-query.ts +175 -0
  132. package/src/devtools/index.ts +8 -0
  133. package/src/devtools/production/index.ts +1 -0
  134. package/src/devtools/stub.ts +7 -0
  135. package/src/devtools/types.ts +116 -0
  136. package/src/devtools/with-devtools.ts +182 -0
  137. package/src/devtools-panel/index.ts +8 -0
  138. package/src/devtools-panel/inject-devtools-panel.ts +110 -0
  139. package/src/devtools-panel/production/index.ts +1 -0
  140. package/src/devtools-panel/stub.ts +7 -0
  141. package/src/devtools-panel/types.ts +57 -0
  142. package/src/index.ts +60 -0
  143. package/src/infinite-query-options.ts +354 -0
  144. package/src/inject-infinite-query.ts +296 -0
  145. package/src/inject-is-fetching.ts +97 -0
  146. package/src/inject-is-mutating.ts +80 -0
  147. package/src/inject-is-restoring.ts +53 -0
  148. package/src/inject-mutation-state.ts +167 -0
  149. package/src/inject-mutation.ts +328 -0
  150. package/src/inject-queries-experimental/index.ts +1 -0
  151. package/src/inject-queries.ts +479 -0
  152. package/src/inject-query-client.ts +22 -0
  153. package/src/inject-query.ts +208 -0
  154. package/src/mutation-options.ts +121 -0
  155. package/src/pending-tasks-compat.ts +27 -0
  156. package/src/providers.ts +170 -0
  157. package/src/query-options.ts +292 -0
  158. package/src/signal-proxy.ts +46 -0
  159. package/src/types.ts +429 -0
  160. package/create-base-query.d.ts +0 -164
  161. package/create-base-query.mjs +0 -99
  162. package/create-base-query.mjs.map +0 -1
  163. package/devtools/index.d.ts +0 -2
  164. package/devtools/index.mjs +0 -5
  165. package/devtools/index.mjs.map +0 -1
  166. package/devtools/production/index.d.ts +0 -1
  167. package/devtools/stub.d.ts +0 -2
  168. package/devtools/stub.mjs +0 -8
  169. package/devtools/stub.mjs.map +0 -1
  170. package/devtools/types.d.ts +0 -100
  171. package/devtools/with-devtools.mjs +0 -106
  172. package/devtools/with-devtools.mjs.map +0 -1
  173. package/devtools-panel/index.d.ts +0 -2
  174. package/devtools-panel/index.mjs +0 -5
  175. package/devtools-panel/index.mjs.map +0 -1
  176. package/devtools-panel/inject-devtools-panel.mjs +0 -72
  177. package/devtools-panel/inject-devtools-panel.mjs.map +0 -1
  178. package/devtools-panel/production/index.d.ts +0 -1
  179. package/devtools-panel/stub.d.ts +0 -2
  180. package/devtools-panel/stub.mjs +0 -8
  181. package/devtools-panel/stub.mjs.map +0 -1
  182. package/devtools-panel/types.d.ts +0 -48
  183. package/index.d.ts +0 -25
  184. package/index.mjs.map +0 -1
  185. package/infinite-query-options.mjs +0 -7
  186. package/infinite-query-options.mjs.map +0 -1
  187. package/inject-infinite-query.mjs +0 -18
  188. package/inject-infinite-query.mjs.map +0 -1
  189. package/inject-is-fetching.mjs +0 -31
  190. package/inject-is-fetching.mjs.map +0 -1
  191. package/inject-is-mutating.mjs +0 -31
  192. package/inject-is-mutating.mjs.map +0 -1
  193. package/inject-is-restoring.mjs +0 -21
  194. package/inject-is-restoring.mjs.map +0 -1
  195. package/inject-mutation-state.mjs +0 -51
  196. package/inject-mutation-state.mjs.map +0 -1
  197. package/inject-mutation.mjs +0 -94
  198. package/inject-mutation.mjs.map +0 -1
  199. package/inject-queries-experimental/index.d.ts +0 -1
  200. package/inject-queries-experimental/index.mjs +0 -5
  201. package/inject-queries-experimental/index.mjs.map +0 -1
  202. package/inject-queries.mjs +0 -82
  203. package/inject-queries.mjs.map +0 -1
  204. package/inject-query-client.mjs +0 -9
  205. package/inject-query-client.mjs.map +0 -1
  206. package/inject-query.mjs +0 -14
  207. package/inject-query.mjs.map +0 -1
  208. package/mutation-options.mjs +0 -7
  209. package/mutation-options.mjs.map +0 -1
  210. package/pending-tasks-compat.d.ts +0 -7
  211. package/pending-tasks-compat.mjs +0 -19
  212. package/pending-tasks-compat.mjs.map +0 -1
  213. package/providers.mjs +0 -32
  214. package/providers.mjs.map +0 -1
  215. package/query-options.mjs +0 -7
  216. package/query-options.mjs.map +0 -1
  217. package/signal-proxy.d.ts +0 -11
  218. package/signal-proxy.mjs +0 -29
  219. package/signal-proxy.mjs.map +0 -1
@@ -0,0 +1,674 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { QueryClient } from '@tanstack/query-core'
3
+ import { TestBed } from '@angular/core/testing'
4
+ import {
5
+ ENVIRONMENT_INITIALIZER,
6
+ EnvironmentInjector,
7
+ InjectionToken,
8
+ PLATFORM_ID,
9
+ createEnvironmentInjector,
10
+ isDevMode,
11
+ provideZonelessChangeDetection,
12
+ signal,
13
+ } from '@angular/core'
14
+ import { provideTanStackQuery } from '../providers'
15
+ import { withDevtools } from '../devtools'
16
+ import type {
17
+ DevtoolsButtonPosition,
18
+ DevtoolsErrorType,
19
+ DevtoolsPosition,
20
+ Theme,
21
+ } from '@tanstack/query-devtools'
22
+ import type { DevtoolsOptions } from '../devtools'
23
+
24
+ const mockDevtoolsInstance = {
25
+ mount: vi.fn(),
26
+ unmount: vi.fn(),
27
+ setClient: vi.fn(),
28
+ setPosition: vi.fn(),
29
+ setErrorTypes: vi.fn(),
30
+ setButtonPosition: vi.fn(),
31
+ setInitialIsOpen: vi.fn(),
32
+ setTheme: vi.fn(),
33
+ }
34
+
35
+ function MockTanstackQueryDevtools() {
36
+ return mockDevtoolsInstance
37
+ }
38
+
39
+ const mockTanstackQueryDevtools = vi.fn(MockTanstackQueryDevtools)
40
+
41
+ vi.mock('@tanstack/query-devtools', () => ({
42
+ TanstackQueryDevtools: mockTanstackQueryDevtools,
43
+ }))
44
+
45
+ vi.mock('@angular/core', async () => {
46
+ const actual = await vi.importActual('@angular/core')
47
+ return {
48
+ ...actual,
49
+ isDevMode: vi.fn(),
50
+ }
51
+ })
52
+
53
+ const mockIsDevMode = vi.mocked(isDevMode)
54
+
55
+ describe('withDevtools feature', () => {
56
+ beforeEach(() => {
57
+ vi.clearAllMocks()
58
+ vi.useFakeTimers()
59
+ })
60
+
61
+ afterEach(() => {
62
+ vi.restoreAllMocks()
63
+ TestBed.resetTestingModule()
64
+ vi.useRealTimers()
65
+ })
66
+
67
+ it.each([
68
+ {
69
+ description: 'should load devtools in development mode',
70
+ isDevMode: true,
71
+ expectedCalled: true,
72
+ },
73
+ {
74
+ description: 'should not load devtools in production mode',
75
+ isDevMode: false,
76
+ expectedCalled: false,
77
+ },
78
+ {
79
+ description: `should load devtools in development mode when 'loadDevtools' is set to 'auto'`,
80
+ isDevMode: true,
81
+ loadDevtools: 'auto',
82
+ expectedCalled: true,
83
+ },
84
+ {
85
+ description: `should not load devtools in production mode when 'loadDevtools' is set to 'auto'`,
86
+ isDevMode: false,
87
+ loadDevtools: 'auto',
88
+ expectedCalled: false,
89
+ },
90
+ {
91
+ description:
92
+ "should load devtools in development mode when 'loadDevtools' is set to true",
93
+ isDevMode: true,
94
+ loadDevtools: true,
95
+ expectedCalled: true,
96
+ },
97
+ {
98
+ description:
99
+ "should load devtools in production mode when 'loadDevtools' is set to true",
100
+ isDevMode: false,
101
+ loadDevtools: true,
102
+ expectedCalled: true,
103
+ },
104
+ {
105
+ description:
106
+ "should not load devtools in development mode when 'loadDevtools' is set to false",
107
+ isDevMode: true,
108
+ loadDevtools: false,
109
+ expectedCalled: false,
110
+ },
111
+ {
112
+ description:
113
+ "should not load devtools in production mode when 'loadDevtools' is set to false",
114
+ isDevMode: false,
115
+ loadDevtools: false,
116
+ expectedCalled: false,
117
+ },
118
+ ])(
119
+ '$description',
120
+ async ({ isDevMode: isDevModeValue, loadDevtools, expectedCalled }) => {
121
+ mockIsDevMode.mockReturnValue(isDevModeValue)
122
+
123
+ const providers = [
124
+ provideZonelessChangeDetection(),
125
+ provideTanStackQuery(
126
+ new QueryClient(),
127
+ loadDevtools !== undefined
128
+ ? withDevtools(
129
+ () =>
130
+ ({
131
+ loadDevtools,
132
+ }) as DevtoolsOptions,
133
+ )
134
+ : withDevtools(),
135
+ ),
136
+ ]
137
+
138
+ TestBed.configureTestingModule({
139
+ providers,
140
+ })
141
+
142
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
143
+ await vi.advanceTimersByTimeAsync(0)
144
+ TestBed.tick()
145
+ await vi.dynamicImportSettled()
146
+ TestBed.tick()
147
+ await vi.dynamicImportSettled()
148
+
149
+ expect(mockTanstackQueryDevtools).toHaveBeenCalledTimes(
150
+ expectedCalled ? 1 : 0,
151
+ )
152
+ expect(mockDevtoolsInstance.mount).toHaveBeenCalledTimes(
153
+ expectedCalled ? 1 : 0,
154
+ )
155
+ },
156
+ )
157
+
158
+ it("should throw 'No QueryClient found' when 'loadDevtools' is 'true' and no 'QueryClient' is provided", async () => {
159
+ const consoleErrorMock = vi
160
+ .spyOn(console, 'error')
161
+ .mockImplementation(() => undefined)
162
+
163
+ TestBed.configureTestingModule({
164
+ providers: [
165
+ provideZonelessChangeDetection(),
166
+ withDevtools(() => ({
167
+ loadDevtools: true,
168
+ })).ɵproviders,
169
+ ],
170
+ })
171
+
172
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
173
+ TestBed.tick()
174
+ await vi.dynamicImportSettled()
175
+
176
+ expect(mockTanstackQueryDevtools).not.toHaveBeenCalled()
177
+ expect(consoleErrorMock).toHaveBeenCalledWith(
178
+ 'Install @tanstack/query-devtools or reinstall without --omit=optional.',
179
+ expect.objectContaining({ message: 'No QueryClient found' }),
180
+ )
181
+
182
+ consoleErrorMock.mockRestore()
183
+ })
184
+
185
+ it('should not continue loading devtools after injector is destroyed', async () => {
186
+ TestBed.configureTestingModule({
187
+ providers: [
188
+ provideZonelessChangeDetection(),
189
+ provideTanStackQuery(
190
+ new QueryClient(),
191
+ withDevtools(() => ({
192
+ loadDevtools: true,
193
+ })),
194
+ ),
195
+ ],
196
+ })
197
+
198
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
199
+ // Destroys injector
200
+ TestBed.resetTestingModule()
201
+ await vi.advanceTimersByTimeAsync(0)
202
+ await vi.dynamicImportSettled()
203
+
204
+ expect(mockTanstackQueryDevtools).not.toHaveBeenCalled()
205
+ })
206
+
207
+ it('should not create devtools again when already provided', async () => {
208
+ TestBed.configureTestingModule({
209
+ providers: [
210
+ provideZonelessChangeDetection(),
211
+ provideTanStackQuery(
212
+ new QueryClient(),
213
+ withDevtools(() => ({
214
+ loadDevtools: true,
215
+ })),
216
+ ),
217
+ ],
218
+ })
219
+
220
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
221
+ await vi.advanceTimersByTimeAsync(0)
222
+ await vi.dynamicImportSettled()
223
+
224
+ expect(mockTanstackQueryDevtools).toHaveBeenCalledTimes(1)
225
+
226
+ const injector = TestBed.inject(EnvironmentInjector)
227
+
228
+ createEnvironmentInjector(
229
+ [
230
+ withDevtools(() => ({
231
+ loadDevtools: true,
232
+ })).ɵproviders,
233
+ ],
234
+ injector,
235
+ )
236
+
237
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
238
+ await vi.advanceTimersByTimeAsync(0)
239
+
240
+ expect(mockTanstackQueryDevtools).toHaveBeenCalledTimes(1)
241
+ })
242
+
243
+ it('should not load devtools if platform is not browser', async () => {
244
+ TestBed.configureTestingModule({
245
+ providers: [
246
+ {
247
+ provide: PLATFORM_ID,
248
+ useValue: 'server',
249
+ },
250
+ provideZonelessChangeDetection(),
251
+ provideTanStackQuery(
252
+ new QueryClient(),
253
+ withDevtools(() => ({
254
+ loadDevtools: true,
255
+ })),
256
+ ),
257
+ ],
258
+ })
259
+
260
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
261
+ await vi.runAllTimersAsync()
262
+
263
+ expect(mockTanstackQueryDevtools).not.toHaveBeenCalled()
264
+ })
265
+
266
+ it('should update error types', async () => {
267
+ const errorTypes = signal([] as Array<DevtoolsErrorType>)
268
+
269
+ TestBed.configureTestingModule({
270
+ providers: [
271
+ provideZonelessChangeDetection(),
272
+ provideTanStackQuery(
273
+ new QueryClient(),
274
+ withDevtools(() => ({
275
+ loadDevtools: true,
276
+ errorTypes: errorTypes(),
277
+ })),
278
+ ),
279
+ ],
280
+ })
281
+
282
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
283
+ await vi.advanceTimersByTimeAsync(0)
284
+ await vi.dynamicImportSettled()
285
+
286
+ TestBed.tick()
287
+
288
+ expect(mockDevtoolsInstance.setErrorTypes).toHaveBeenCalledTimes(0)
289
+
290
+ const newErrorTypes = [
291
+ {
292
+ name: '',
293
+ initializer: () => new Error(),
294
+ },
295
+ ]
296
+
297
+ errorTypes.set(newErrorTypes)
298
+
299
+ TestBed.tick()
300
+
301
+ expect(mockDevtoolsInstance.setErrorTypes).toHaveBeenCalledTimes(1)
302
+ expect(mockDevtoolsInstance.setErrorTypes).toHaveBeenCalledWith(
303
+ newErrorTypes,
304
+ )
305
+ })
306
+
307
+ it('should update client', async () => {
308
+ const client = signal(new QueryClient())
309
+
310
+ TestBed.configureTestingModule({
311
+ providers: [
312
+ provideZonelessChangeDetection(),
313
+ provideTanStackQuery(
314
+ new QueryClient(),
315
+ withDevtools(() => ({
316
+ loadDevtools: true,
317
+ client: client(),
318
+ })),
319
+ ),
320
+ ],
321
+ })
322
+
323
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
324
+ await vi.advanceTimersByTimeAsync(0)
325
+ await vi.dynamicImportSettled()
326
+
327
+ TestBed.tick()
328
+
329
+ expect(mockDevtoolsInstance.setClient).toHaveBeenCalledTimes(0)
330
+
331
+ const newClient = new QueryClient()
332
+ client.set(newClient)
333
+
334
+ TestBed.tick()
335
+
336
+ expect(mockDevtoolsInstance.setClient).toHaveBeenCalledTimes(1)
337
+ expect(mockDevtoolsInstance.setClient).toHaveBeenCalledWith(newClient)
338
+ })
339
+
340
+ it('should update position', async () => {
341
+ const position = signal<DevtoolsPosition>('top')
342
+
343
+ TestBed.configureTestingModule({
344
+ providers: [
345
+ provideZonelessChangeDetection(),
346
+ provideTanStackQuery(
347
+ new QueryClient(),
348
+ withDevtools(() => ({
349
+ loadDevtools: true,
350
+ position: position(),
351
+ })),
352
+ ),
353
+ ],
354
+ })
355
+
356
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
357
+ await vi.advanceTimersByTimeAsync(0)
358
+ await vi.dynamicImportSettled()
359
+
360
+ TestBed.tick()
361
+
362
+ expect(mockDevtoolsInstance.setPosition).toHaveBeenCalledTimes(0)
363
+
364
+ position.set('left')
365
+
366
+ TestBed.tick()
367
+
368
+ expect(mockDevtoolsInstance.setPosition).toHaveBeenCalledTimes(1)
369
+ expect(mockDevtoolsInstance.setPosition).toHaveBeenCalledWith('left')
370
+ })
371
+
372
+ it('should update button position', async () => {
373
+ const buttonPosition = signal<DevtoolsButtonPosition>('bottom-left')
374
+
375
+ TestBed.configureTestingModule({
376
+ providers: [
377
+ provideZonelessChangeDetection(),
378
+ provideTanStackQuery(
379
+ new QueryClient(),
380
+ withDevtools(() => ({
381
+ loadDevtools: true,
382
+ buttonPosition: buttonPosition(),
383
+ })),
384
+ ),
385
+ ],
386
+ })
387
+
388
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
389
+ await vi.advanceTimersByTimeAsync(0)
390
+ await vi.dynamicImportSettled()
391
+
392
+ TestBed.tick()
393
+
394
+ expect(mockDevtoolsInstance.setButtonPosition).toHaveBeenCalledTimes(0)
395
+
396
+ buttonPosition.set('bottom-right')
397
+
398
+ TestBed.tick()
399
+
400
+ expect(mockDevtoolsInstance.setButtonPosition).toHaveBeenCalledTimes(1)
401
+ expect(mockDevtoolsInstance.setButtonPosition).toHaveBeenCalledWith(
402
+ 'bottom-right',
403
+ )
404
+ })
405
+
406
+ it('should update initialIsOpen', async () => {
407
+ const initialIsOpen = signal(false)
408
+
409
+ TestBed.configureTestingModule({
410
+ providers: [
411
+ provideZonelessChangeDetection(),
412
+ provideTanStackQuery(
413
+ new QueryClient(),
414
+ withDevtools(() => ({
415
+ loadDevtools: true,
416
+ initialIsOpen: initialIsOpen(),
417
+ })),
418
+ ),
419
+ ],
420
+ })
421
+
422
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
423
+ await vi.advanceTimersByTimeAsync(0)
424
+ await vi.dynamicImportSettled()
425
+
426
+ TestBed.tick()
427
+
428
+ expect(mockDevtoolsInstance.setInitialIsOpen).toHaveBeenCalledTimes(0)
429
+
430
+ initialIsOpen.set(true)
431
+
432
+ TestBed.tick()
433
+
434
+ expect(mockDevtoolsInstance.setInitialIsOpen).toHaveBeenCalledTimes(1)
435
+ expect(mockDevtoolsInstance.setInitialIsOpen).toHaveBeenCalledWith(true)
436
+ })
437
+
438
+ it('should update theme', async () => {
439
+ const theme = signal<Theme>('system')
440
+
441
+ TestBed.configureTestingModule({
442
+ providers: [
443
+ provideZonelessChangeDetection(),
444
+ provideTanStackQuery(
445
+ new QueryClient(),
446
+ withDevtools(() => ({
447
+ loadDevtools: true,
448
+ theme: theme(),
449
+ })),
450
+ ),
451
+ ],
452
+ })
453
+
454
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
455
+ await vi.advanceTimersByTimeAsync(0)
456
+ await vi.dynamicImportSettled()
457
+
458
+ TestBed.tick()
459
+
460
+ expect(mockDevtoolsInstance.setTheme).toHaveBeenCalledTimes(0)
461
+
462
+ theme.set('dark')
463
+
464
+ TestBed.tick()
465
+
466
+ expect(mockDevtoolsInstance.setTheme).toHaveBeenCalledTimes(1)
467
+ expect(mockDevtoolsInstance.setTheme).toHaveBeenCalledWith('dark')
468
+ })
469
+
470
+ it('should destroy devtools', async () => {
471
+ const loadDevtools = signal(true)
472
+
473
+ TestBed.configureTestingModule({
474
+ providers: [
475
+ provideZonelessChangeDetection(),
476
+ provideTanStackQuery(
477
+ new QueryClient(),
478
+ withDevtools(() => ({
479
+ loadDevtools: loadDevtools(),
480
+ })),
481
+ ),
482
+ ],
483
+ })
484
+
485
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
486
+ await vi.advanceTimersByTimeAsync(0)
487
+ await vi.dynamicImportSettled()
488
+
489
+ expect(mockDevtoolsInstance.mount).toHaveBeenCalledTimes(1)
490
+ expect(mockDevtoolsInstance.unmount).toHaveBeenCalledTimes(0)
491
+
492
+ loadDevtools.set(false)
493
+
494
+ TestBed.tick()
495
+
496
+ expect(mockDevtoolsInstance.unmount).toHaveBeenCalledTimes(1)
497
+ })
498
+
499
+ it('should unmount devtools when injector is destroyed', async () => {
500
+ TestBed.configureTestingModule({
501
+ providers: [
502
+ provideZonelessChangeDetection(),
503
+ provideTanStackQuery(
504
+ new QueryClient(),
505
+ withDevtools(() => ({
506
+ loadDevtools: true,
507
+ })),
508
+ ),
509
+ ],
510
+ })
511
+
512
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
513
+ await vi.advanceTimersByTimeAsync(0)
514
+ TestBed.tick()
515
+ await vi.dynamicImportSettled()
516
+
517
+ expect(mockTanstackQueryDevtools).toHaveBeenCalled()
518
+ expect(mockDevtoolsInstance.mount).toHaveBeenCalledTimes(1)
519
+ expect(mockDevtoolsInstance.unmount).toHaveBeenCalledTimes(0)
520
+
521
+ // Destroy the injector
522
+ TestBed.resetTestingModule()
523
+
524
+ expect(mockDevtoolsInstance.unmount).toHaveBeenCalledTimes(1)
525
+ })
526
+
527
+ it('should remount devtools when toggled from false to true', async () => {
528
+ const loadDevtools = signal(false)
529
+
530
+ TestBed.configureTestingModule({
531
+ providers: [
532
+ provideZonelessChangeDetection(),
533
+ provideTanStackQuery(
534
+ new QueryClient(),
535
+ withDevtools(() => ({
536
+ loadDevtools: loadDevtools(),
537
+ })),
538
+ ),
539
+ ],
540
+ })
541
+
542
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
543
+ await vi.advanceTimersByTimeAsync(0)
544
+
545
+ expect(mockTanstackQueryDevtools).not.toHaveBeenCalled()
546
+ expect(mockDevtoolsInstance.mount).not.toHaveBeenCalled()
547
+
548
+ loadDevtools.set(true)
549
+ TestBed.tick()
550
+ await vi.dynamicImportSettled()
551
+
552
+ expect(mockTanstackQueryDevtools).toHaveBeenCalledTimes(1)
553
+ expect(mockDevtoolsInstance.mount).toHaveBeenCalledTimes(1)
554
+ expect(mockDevtoolsInstance.unmount).not.toHaveBeenCalled()
555
+
556
+ loadDevtools.set(false)
557
+ TestBed.tick()
558
+
559
+ expect(mockDevtoolsInstance.unmount).toHaveBeenCalledTimes(1)
560
+ expect(mockDevtoolsInstance.mount).toHaveBeenCalledTimes(1)
561
+
562
+ loadDevtools.set(true)
563
+ TestBed.tick()
564
+ await vi.dynamicImportSettled()
565
+
566
+ // Should remount (mount called twice now)
567
+ expect(mockDevtoolsInstance.mount).toHaveBeenCalledTimes(2)
568
+ expect(mockDevtoolsInstance.unmount).toHaveBeenCalledTimes(1)
569
+ })
570
+
571
+ describe('deps parameter', () => {
572
+ it('should inject dependencies and pass them to withDevtoolsFn in correct order', async () => {
573
+ const mockService1 = { value: 'service1' }
574
+ const mockService2 = { value: 'service2' }
575
+ const mockService1Token = new InjectionToken('MockService1')
576
+ const mockService2Token = new InjectionToken('MockService2')
577
+ const withDevtoolsFn = vi.fn().mockReturnValue({ loadDevtools: true })
578
+
579
+ TestBed.configureTestingModule({
580
+ providers: [
581
+ provideZonelessChangeDetection(),
582
+ {
583
+ provide: mockService1Token,
584
+ useValue: mockService1,
585
+ },
586
+ {
587
+ provide: mockService2Token,
588
+ useValue: mockService2,
589
+ },
590
+ provideTanStackQuery(
591
+ new QueryClient(),
592
+ withDevtools(withDevtoolsFn, {
593
+ deps: [mockService1Token, mockService2Token],
594
+ }),
595
+ ),
596
+ ],
597
+ })
598
+
599
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
600
+ await vi.advanceTimersByTimeAsync(0)
601
+
602
+ expect(withDevtoolsFn).toHaveBeenCalledWith(mockService1, mockService2)
603
+ })
604
+
605
+ it('should work with empty deps array', async () => {
606
+ const withDevtoolsFn = vi.fn().mockReturnValue({ loadDevtools: true })
607
+
608
+ TestBed.configureTestingModule({
609
+ providers: [
610
+ provideZonelessChangeDetection(),
611
+ provideTanStackQuery(
612
+ new QueryClient(),
613
+ withDevtools(withDevtoolsFn, {
614
+ deps: [],
615
+ }),
616
+ ),
617
+ ],
618
+ })
619
+
620
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
621
+ await vi.advanceTimersByTimeAsync(0)
622
+
623
+ expect(withDevtoolsFn).toHaveBeenCalledWith()
624
+ })
625
+
626
+ it('should reactively update when injected services change', async () => {
627
+ class ReactiveService {
628
+ enabled = signal(false)
629
+ position = signal<DevtoolsPosition>('bottom')
630
+ }
631
+
632
+ const withDevtoolsFn = (service: ReactiveService) => ({
633
+ loadDevtools: service.enabled(),
634
+ position: service.position(),
635
+ })
636
+
637
+ TestBed.configureTestingModule({
638
+ providers: [
639
+ provideZonelessChangeDetection(),
640
+ ReactiveService,
641
+ provideTanStackQuery(
642
+ new QueryClient(),
643
+ withDevtools(withDevtoolsFn, {
644
+ deps: [ReactiveService],
645
+ }),
646
+ ),
647
+ ],
648
+ })
649
+
650
+ TestBed.inject(ENVIRONMENT_INITIALIZER)
651
+ await vi.advanceTimersByTimeAsync(0)
652
+
653
+ const service = TestBed.inject(ReactiveService)
654
+
655
+ expect(mockTanstackQueryDevtools).not.toHaveBeenCalled()
656
+
657
+ service.enabled.set(true)
658
+ TestBed.tick()
659
+ await vi.dynamicImportSettled()
660
+
661
+ expect(mockTanstackQueryDevtools).toHaveBeenCalledTimes(1)
662
+ expect(mockTanstackQueryDevtools).toHaveBeenCalledWith(
663
+ expect.objectContaining({
664
+ position: 'bottom',
665
+ }),
666
+ )
667
+
668
+ service.position.set('top')
669
+ TestBed.tick()
670
+
671
+ expect(mockDevtoolsInstance.setPosition).toHaveBeenCalledWith('top')
672
+ })
673
+ })
674
+ })