@tanstack/angular-query-experimental 5.103.2 → 5.104.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 (218) hide show
  1. package/dist/create-base-query.d.mts +168 -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 +5 -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 +106 -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} +4 -1
  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} +4 -1
  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 +5 -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 +51 -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} +28 -25
  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} +13 -10
  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} +11 -8
  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} +11 -8
  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} +10 -8
  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} +13 -11
  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} +12 -9
  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} +33 -53
  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} +6 -3
  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} +13 -10
  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} +5 -2
  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 +9 -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} +7 -5
  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} +34 -31
  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/{signal-proxy.d.ts → dist/signal-proxy.d.mts} +5 -4
  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} +24 -26
  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 +50 -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 +176 -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 +480 -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 -103
  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.mjs +0 -29
  218. package/signal-proxy.mjs.map +0 -1
@@ -0,0 +1,227 @@
1
+ import { TestBed } from '@angular/core/testing'
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
3
+ import {
4
+ Component,
5
+ Injector,
6
+ provideZonelessChangeDetection,
7
+ signal,
8
+ } from '@angular/core'
9
+ import { render } from '@testing-library/angular'
10
+ import { queryKey, sleep } from '@tanstack/query-test-utils'
11
+ import {
12
+ QueryClient,
13
+ injectInfiniteQuery,
14
+ provideTanStackQuery,
15
+ skipToken,
16
+ } from '..'
17
+
18
+ describe('injectInfiniteQuery', () => {
19
+ let queryClient: QueryClient
20
+
21
+ beforeEach(() => {
22
+ queryClient = new QueryClient()
23
+ vi.useFakeTimers()
24
+ TestBed.configureTestingModule({
25
+ providers: [
26
+ provideZonelessChangeDetection(),
27
+ provideTanStackQuery(queryClient),
28
+ ],
29
+ })
30
+ })
31
+
32
+ afterEach(() => {
33
+ vi.useRealTimers()
34
+ })
35
+
36
+ it('should properly execute infinite query', async () => {
37
+ const key = queryKey()
38
+
39
+ @Component({
40
+ template: `
41
+ <div>status: {{ query.status() }}</div>
42
+ <div>pages: {{ query.data()?.pages?.join(', ') ?? 'none' }}</div>
43
+ `,
44
+ })
45
+ class Page {
46
+ readonly query = injectInfiniteQuery(() => ({
47
+ queryKey: key,
48
+ queryFn: ({ pageParam }) =>
49
+ sleep(10).then(() => 'data on page ' + pageParam),
50
+ initialPageParam: 0,
51
+ getNextPageParam: () => 12,
52
+ }))
53
+ }
54
+
55
+ const rendered = await render(Page)
56
+
57
+ expect(rendered.getByText('status: pending')).toBeInTheDocument()
58
+ expect(rendered.getByText('pages: none')).toBeInTheDocument()
59
+
60
+ await vi.advanceTimersByTimeAsync(11)
61
+ rendered.fixture.detectChanges()
62
+ expect(rendered.getByText('status: success')).toBeInTheDocument()
63
+ expect(rendered.getByText('pages: data on page 0')).toBeInTheDocument()
64
+
65
+ rendered.fixture.componentInstance.query.fetchNextPage()
66
+
67
+ await vi.advanceTimersByTimeAsync(11)
68
+ rendered.fixture.detectChanges()
69
+ expect(rendered.getByText('status: success')).toBeInTheDocument()
70
+ expect(
71
+ rendered.getByText('pages: data on page 0, data on page 12'),
72
+ ).toBeInTheDocument()
73
+ })
74
+
75
+ it('should reject and update signal', async () => {
76
+ const key = queryKey()
77
+
78
+ @Component({
79
+ template: `
80
+ <div>status: {{ query.status() }}</div>
81
+ <div>pages: {{ query.data()?.pages?.join(', ') ?? 'none' }}</div>
82
+ <div>error: {{ query.error()?.message ?? 'none' }}</div>
83
+ <div>isError: {{ query.isError() }}</div>
84
+ <div>failureCount: {{ query.failureCount() }}</div>
85
+ `,
86
+ })
87
+ class Page {
88
+ readonly query = injectInfiniteQuery(() => ({
89
+ retry: false,
90
+ queryKey: key,
91
+ queryFn: () =>
92
+ sleep(10).then(() => Promise.reject(new Error('Some error'))),
93
+ initialPageParam: 0,
94
+ getNextPageParam: () => 12,
95
+ }))
96
+ }
97
+
98
+ const rendered = await render(Page)
99
+
100
+ expect(rendered.getByText('status: pending')).toBeInTheDocument()
101
+ expect(rendered.getByText('pages: none')).toBeInTheDocument()
102
+
103
+ await vi.advanceTimersByTimeAsync(11)
104
+ rendered.fixture.detectChanges()
105
+
106
+ expect(rendered.getByText('status: error')).toBeInTheDocument()
107
+ expect(rendered.getByText('pages: none')).toBeInTheDocument()
108
+ expect(rendered.getByText('error: Some error')).toBeInTheDocument()
109
+ expect(rendered.getByText('isError: true')).toBeInTheDocument()
110
+ expect(rendered.getByText('failureCount: 1')).toBeInTheDocument()
111
+ })
112
+
113
+ it('should keep initialData visible alongside the error when a refetch fails', async () => {
114
+ const key = queryKey()
115
+
116
+ @Component({
117
+ template: `
118
+ <div>pages: {{ query.data().pages.join(', ') }}</div>
119
+ <div>isError: {{ query.isError() }}</div>
120
+ `,
121
+ })
122
+ class Page {
123
+ readonly query = injectInfiniteQuery(() => ({
124
+ queryKey: key,
125
+ queryFn: () =>
126
+ sleep(10).then(() => Promise.reject(new Error('Some error'))),
127
+ initialData: { pages: [1], pageParams: [1] },
128
+ getNextPageParam: (lastPage: number) => lastPage + 1,
129
+ initialPageParam: 0,
130
+ retry: false,
131
+ }))
132
+ }
133
+
134
+ const rendered = await render(Page)
135
+
136
+ expect(rendered.getByText('pages: 1')).toBeInTheDocument()
137
+ expect(rendered.getByText('isError: false')).toBeInTheDocument()
138
+
139
+ await vi.advanceTimersByTimeAsync(11)
140
+ rendered.fixture.detectChanges()
141
+ expect(rendered.getByText('pages: 1')).toBeInTheDocument()
142
+ expect(rendered.getByText('isError: true')).toBeInTheDocument()
143
+ })
144
+
145
+ describe('skipToken', () => {
146
+ it('should not fetch when queryFn is skipToken, and fetch once it is replaced', async () => {
147
+ const key = queryKey()
148
+ const queryFn = vi.fn(({ pageParam }: { pageParam: number }) =>
149
+ sleep(10).then(() => `comments for 1 page ${pageParam}`),
150
+ )
151
+
152
+ @Component({
153
+ template: `
154
+ <div>status: {{ query.status() }}</div>
155
+ <div>isFetching: {{ query.isFetching() }}</div>
156
+ <div>pages: {{ query.data()?.pages?.join(', ') ?? 'none' }}</div>
157
+ `,
158
+ })
159
+ class Page {
160
+ postId = signal<string | undefined>(undefined)
161
+
162
+ readonly query = injectInfiniteQuery(() => ({
163
+ queryKey: key,
164
+ queryFn: this.postId() != null ? queryFn : skipToken,
165
+ initialPageParam: 0,
166
+ getNextPageParam: () => 12,
167
+ }))
168
+ }
169
+
170
+ const rendered = await render(Page)
171
+
172
+ expect(rendered.getByText('status: pending')).toBeInTheDocument()
173
+ expect(rendered.getByText('isFetching: false')).toBeInTheDocument()
174
+
175
+ await vi.advanceTimersByTimeAsync(11)
176
+ rendered.fixture.detectChanges()
177
+ expect(queryFn).not.toHaveBeenCalled()
178
+ expect(rendered.getByText('status: pending')).toBeInTheDocument()
179
+ expect(rendered.getByText('isFetching: false')).toBeInTheDocument()
180
+
181
+ rendered.fixture.componentInstance.postId.set('1')
182
+ rendered.fixture.detectChanges()
183
+ expect(rendered.getByText('isFetching: true')).toBeInTheDocument()
184
+
185
+ await vi.advanceTimersByTimeAsync(11)
186
+ rendered.fixture.detectChanges()
187
+ expect(queryFn).toHaveBeenCalledTimes(1)
188
+ expect(rendered.getByText('status: success')).toBeInTheDocument()
189
+ expect(
190
+ rendered.getByText('pages: comments for 1 page 0'),
191
+ ).toBeInTheDocument()
192
+ })
193
+ })
194
+
195
+ describe('injection context', () => {
196
+ it('should throw NG0203 with descriptive error outside injection context', () => {
197
+ const key = queryKey()
198
+ expect(() => {
199
+ injectInfiniteQuery(() => ({
200
+ queryKey: key,
201
+ queryFn: ({ pageParam }) =>
202
+ sleep(0).then(() => 'data on page ' + pageParam),
203
+ initialPageParam: 0,
204
+ getNextPageParam: () => 12,
205
+ }))
206
+ }).toThrow(/NG0203(.*?)injectInfiniteQuery/)
207
+ })
208
+
209
+ it('should be usable outside injection context when passing an injector', () => {
210
+ const key = queryKey()
211
+ const query = injectInfiniteQuery(
212
+ () => ({
213
+ queryKey: key,
214
+ queryFn: ({ pageParam }) =>
215
+ sleep(0).then(() => 'data on page ' + pageParam),
216
+ initialPageParam: 0,
217
+ getNextPageParam: () => 12,
218
+ }),
219
+ {
220
+ injector: TestBed.inject(Injector),
221
+ },
222
+ )
223
+
224
+ expect(query.status()).toBe('pending')
225
+ })
226
+ })
227
+ })
@@ -0,0 +1,108 @@
1
+ import { TestBed } from '@angular/core/testing'
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
3
+ import {
4
+ Component,
5
+ Injector,
6
+ provideZonelessChangeDetection,
7
+ } from '@angular/core'
8
+ import { render } from '@testing-library/angular'
9
+ import { queryKey, sleep } from '@tanstack/query-test-utils'
10
+ import {
11
+ QueryClient,
12
+ injectIsFetching,
13
+ injectQuery,
14
+ provideTanStackQuery,
15
+ } from '..'
16
+
17
+ describe('injectIsFetching', () => {
18
+ let queryClient: QueryClient
19
+
20
+ beforeEach(() => {
21
+ vi.useFakeTimers()
22
+ queryClient = new QueryClient()
23
+
24
+ TestBed.configureTestingModule({
25
+ providers: [
26
+ provideZonelessChangeDetection(),
27
+ provideTanStackQuery(queryClient),
28
+ ],
29
+ })
30
+ })
31
+
32
+ afterEach(() => {
33
+ vi.useRealTimers()
34
+ })
35
+
36
+ it('should return the number of fetching queries', async () => {
37
+ const key = queryKey()
38
+
39
+ @Component({
40
+ template: `<div>fetching: {{ isFetching() }}</div>`,
41
+ })
42
+ class Page {
43
+ readonly query = injectQuery(() => ({
44
+ queryKey: key,
45
+ queryFn: () => sleep(100).then(() => 'Some data'),
46
+ }))
47
+ readonly isFetching = injectIsFetching()
48
+ }
49
+
50
+ const rendered = await render(Page)
51
+
52
+ expect(rendered.getByText('fetching: 0')).toBeInTheDocument()
53
+
54
+ await vi.advanceTimersByTimeAsync(0)
55
+ rendered.fixture.detectChanges()
56
+ expect(rendered.getByText('fetching: 1')).toBeInTheDocument()
57
+
58
+ await vi.advanceTimersByTimeAsync(101)
59
+ rendered.fixture.detectChanges()
60
+ expect(rendered.getByText('fetching: 0')).toBeInTheDocument()
61
+ })
62
+
63
+ it('should be able to filter by queryKey', async () => {
64
+ const key1 = queryKey()
65
+ const key2 = queryKey()
66
+
67
+ @Component({
68
+ template: `<div>fetching: {{ isFetching() }}</div>`,
69
+ })
70
+ class Page {
71
+ readonly query1 = injectQuery(() => ({
72
+ queryKey: key1,
73
+ queryFn: () => sleep(10).then(() => 'test1'),
74
+ }))
75
+ readonly query2 = injectQuery(() => ({
76
+ queryKey: key2,
77
+ queryFn: () => sleep(100).then(() => 'test2'),
78
+ }))
79
+ readonly isFetching = injectIsFetching({ queryKey: key1 })
80
+ }
81
+
82
+ const rendered = await render(Page)
83
+
84
+ await vi.advanceTimersByTimeAsync(0)
85
+ rendered.fixture.detectChanges()
86
+ expect(rendered.getByText('fetching: 1')).toBeInTheDocument()
87
+
88
+ await vi.advanceTimersByTimeAsync(11)
89
+ rendered.fixture.detectChanges()
90
+ expect(rendered.getByText('fetching: 0')).toBeInTheDocument()
91
+ })
92
+
93
+ describe('injection context', () => {
94
+ it('should throw NG0203 with descriptive error outside injection context', () => {
95
+ expect(() => {
96
+ injectIsFetching()
97
+ }).toThrow(/NG0203(.*?)injectIsFetching/)
98
+ })
99
+
100
+ it('should be usable outside injection context when passing an injector', () => {
101
+ expect(
102
+ injectIsFetching(undefined, {
103
+ injector: TestBed.inject(Injector),
104
+ }),
105
+ ).not.toThrow()
106
+ })
107
+ })
108
+ })
@@ -0,0 +1,113 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { TestBed } from '@angular/core/testing'
3
+ import {
4
+ Component,
5
+ Injector,
6
+ provideZonelessChangeDetection,
7
+ } from '@angular/core'
8
+ import { render } from '@testing-library/angular'
9
+ import { queryKey, sleep } from '@tanstack/query-test-utils'
10
+ import {
11
+ QueryClient,
12
+ injectIsMutating,
13
+ injectMutation,
14
+ provideTanStackQuery,
15
+ } from '..'
16
+
17
+ describe('injectIsMutating', () => {
18
+ let queryClient: QueryClient
19
+
20
+ beforeEach(() => {
21
+ vi.useFakeTimers()
22
+ queryClient = new QueryClient()
23
+
24
+ TestBed.configureTestingModule({
25
+ providers: [
26
+ provideZonelessChangeDetection(),
27
+ provideTanStackQuery(queryClient),
28
+ ],
29
+ })
30
+ })
31
+
32
+ afterEach(() => {
33
+ vi.useRealTimers()
34
+ })
35
+
36
+ it('should properly return isMutating state', async () => {
37
+ const key = queryKey()
38
+
39
+ @Component({
40
+ template: `<div>mutating: {{ isMutating() }}</div>`,
41
+ })
42
+ class Page {
43
+ readonly mutation = injectMutation(() => ({
44
+ mutationKey: key,
45
+ mutationFn: (params: { par1: string }) => sleep(10).then(() => params),
46
+ }))
47
+ readonly isMutating = injectIsMutating()
48
+ }
49
+
50
+ const rendered = await render(Page)
51
+
52
+ expect(rendered.getByText('mutating: 0')).toBeInTheDocument()
53
+
54
+ rendered.fixture.componentInstance.mutation.mutate({ par1: 'par1' })
55
+
56
+ await vi.advanceTimersByTimeAsync(0)
57
+ rendered.fixture.detectChanges()
58
+ expect(rendered.getByText('mutating: 1')).toBeInTheDocument()
59
+
60
+ await vi.advanceTimersByTimeAsync(11)
61
+ rendered.fixture.detectChanges()
62
+ expect(rendered.getByText('mutating: 0')).toBeInTheDocument()
63
+ })
64
+
65
+ it('should be able to filter by mutationKey', async () => {
66
+ const key1 = queryKey()
67
+ const key2 = queryKey()
68
+
69
+ @Component({
70
+ template: `<div>mutating: {{ isMutating() }}</div>`,
71
+ })
72
+ class Page {
73
+ readonly mutation1 = injectMutation(() => ({
74
+ mutationKey: key1,
75
+ mutationFn: () => sleep(10).then(() => 'data1'),
76
+ }))
77
+ readonly mutation2 = injectMutation(() => ({
78
+ mutationKey: key2,
79
+ mutationFn: () => sleep(100).then(() => 'data2'),
80
+ }))
81
+ readonly isMutating = injectIsMutating({ mutationKey: key1 })
82
+ }
83
+
84
+ const rendered = await render(Page)
85
+
86
+ rendered.fixture.componentInstance.mutation1.mutate()
87
+ rendered.fixture.componentInstance.mutation2.mutate()
88
+
89
+ await vi.advanceTimersByTimeAsync(0)
90
+ rendered.fixture.detectChanges()
91
+ expect(rendered.getByText('mutating: 1')).toBeInTheDocument()
92
+
93
+ await vi.advanceTimersByTimeAsync(11)
94
+ rendered.fixture.detectChanges()
95
+ expect(rendered.getByText('mutating: 0')).toBeInTheDocument()
96
+ })
97
+
98
+ describe('injection context', () => {
99
+ it('should throw NG0203 with descriptive error outside injection context', () => {
100
+ expect(() => {
101
+ injectIsMutating()
102
+ }).toThrow(/NG0203(.*?)injectIsMutating/)
103
+ })
104
+
105
+ it('should be usable outside injection context when passing an injector', () => {
106
+ expect(
107
+ injectIsMutating(undefined, {
108
+ injector: TestBed.inject(Injector),
109
+ }),
110
+ ).not.toThrow()
111
+ })
112
+ })
113
+ })
@@ -0,0 +1,93 @@
1
+ import { TestBed } from '@angular/core/testing'
2
+ import { beforeEach, describe, expect, it } from 'vitest'
3
+ import { Injector, provideZonelessChangeDetection, signal } from '@angular/core'
4
+ import {
5
+ QueryClient,
6
+ injectIsRestoring,
7
+ provideIsRestoring,
8
+ provideTanStackQuery,
9
+ } from '..'
10
+
11
+ describe('injectIsRestoring', () => {
12
+ let queryClient: QueryClient
13
+
14
+ beforeEach(() => {
15
+ queryClient = new QueryClient()
16
+ TestBed.configureTestingModule({
17
+ providers: [
18
+ provideZonelessChangeDetection(),
19
+ provideTanStackQuery(queryClient),
20
+ ],
21
+ })
22
+ })
23
+
24
+ it('should return false by default when provideIsRestoring is not used', () => {
25
+ const isRestoring = TestBed.runInInjectionContext(() => {
26
+ return injectIsRestoring()
27
+ })
28
+
29
+ expect(isRestoring()).toBe(false)
30
+ })
31
+
32
+ it('should return the provided signal value when provideIsRestoring is used', () => {
33
+ const restoringSignal = signal(true)
34
+
35
+ TestBed.configureTestingModule({
36
+ providers: [provideIsRestoring(restoringSignal.asReadonly())],
37
+ })
38
+
39
+ const isRestoring = TestBed.runInInjectionContext(() => {
40
+ return injectIsRestoring()
41
+ })
42
+
43
+ expect(isRestoring()).toBe(true)
44
+ })
45
+
46
+ it('should reactively reflect changes to the provided signal', () => {
47
+ const restoringSignal = signal(true)
48
+
49
+ TestBed.configureTestingModule({
50
+ providers: [provideIsRestoring(restoringSignal.asReadonly())],
51
+ })
52
+
53
+ const isRestoring = TestBed.runInInjectionContext(() => {
54
+ return injectIsRestoring()
55
+ })
56
+
57
+ expect(isRestoring()).toBe(true)
58
+
59
+ restoringSignal.set(false)
60
+ expect(isRestoring()).toBe(false)
61
+
62
+ restoringSignal.set(true)
63
+ expect(isRestoring()).toBe(true)
64
+ })
65
+
66
+ it('should be usable outside injection context when passing an injector', () => {
67
+ const isRestoring = injectIsRestoring({
68
+ injector: TestBed.inject(Injector),
69
+ })
70
+
71
+ expect(isRestoring()).toBe(false)
72
+ })
73
+
74
+ it('should return the provided signal value when using injector option', () => {
75
+ const restoringSignal = signal(true)
76
+
77
+ TestBed.configureTestingModule({
78
+ providers: [provideIsRestoring(restoringSignal.asReadonly())],
79
+ })
80
+
81
+ const isRestoring = injectIsRestoring({
82
+ injector: TestBed.inject(Injector),
83
+ })
84
+
85
+ expect(isRestoring()).toBe(true)
86
+ })
87
+
88
+ it('should throw NG0203 with descriptive error outside injection context', () => {
89
+ expect(() => {
90
+ injectIsRestoring()
91
+ }).toThrow(/NG0203(.*?)injectIsRestoring/)
92
+ })
93
+ })
@@ -0,0 +1,22 @@
1
+ import { describe, expectTypeOf, it } from 'vitest'
2
+ import { injectMutationState } from '..'
3
+ import type { MutationState, MutationStatus } from '..'
4
+
5
+ describe('injectMutationState', () => {
6
+ it('should default to QueryState', () => {
7
+ const result = injectMutationState(() => ({
8
+ filters: { status: 'pending' },
9
+ }))
10
+
11
+ expectTypeOf(result()).toEqualTypeOf<Array<MutationState>>()
12
+ })
13
+
14
+ it('should infer with select', () => {
15
+ const result = injectMutationState(() => ({
16
+ filters: { status: 'pending' },
17
+ select: (mutation) => mutation.state.status,
18
+ }))
19
+
20
+ expectTypeOf(result()).toEqualTypeOf<Array<MutationStatus>>()
21
+ })
22
+ })