@tanstack/angular-query-experimental 5.34.2 → 5.35.1
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/rollup.d.ts +591 -0
- package/package.json +10 -6
- package/build/create-base-query.d.ts +0 -6
- package/build/index.d.ts +0 -14
- package/build/infinite-query-options.d.ts +0 -34
- package/build/inject-infinite-query.d.ts +0 -31
- package/build/inject-is-fetching.d.ts +0 -13
- package/build/inject-is-mutating.d.ts +0 -12
- package/build/inject-mutation-state.d.ts +0 -21
- package/build/inject-mutation.d.ts +0 -13
- package/build/inject-queries.d.ts +0 -76
- package/build/inject-query-client.d.ts +0 -30
- package/build/inject-query.d.ts +0 -106
- package/build/providers.d.ts +0 -42
- package/build/query-options.d.ts +0 -66
- package/build/signal-proxy.d.ts +0 -11
- package/build/types.d.ts +0 -95
- package/build/util/assert-injector/assert-injector.d.ts +0 -54
- package/build/util/create-injection-token/create-injection-token.d.ts +0 -52
- package/build/util/index.d.ts +0 -2
- package/build/util/lazy-init/lazy-init.d.ts +0 -1
- package/build/util/lazy-signal-initializer/lazy-signal-initializer.d.ts +0 -4
- package/src/__tests__/inject-infinite-query.test.ts +0 -64
- package/src/__tests__/inject-is-fetching.test.ts +0 -35
- package/src/__tests__/inject-is-mutating.test.ts +0 -39
- package/src/__tests__/inject-mutation-state.test-d.ts +0 -22
- package/src/__tests__/inject-mutation-state.test.ts +0 -175
- package/src/__tests__/inject-mutation.test-d.ts +0 -71
- package/src/__tests__/inject-mutation.test.ts +0 -458
- package/src/__tests__/inject-query.test-d.ts +0 -59
- package/src/__tests__/inject-query.test.ts +0 -349
- package/src/__tests__/query-options.test-d.ts +0 -127
- package/src/__tests__/signal-proxy.test.ts +0 -27
- package/src/__tests__/test-utils.ts +0 -131
- package/src/__tests__/util/lazy-init/lazy-init.test.ts +0 -126
- package/src/__tests__/util/lazy-signal-initializer/lazy-signal-initializer.test.ts +0 -130
- package/src/create-base-query.ts +0 -116
- package/src/index.ts +0 -24
- package/src/infinite-query-options.ts +0 -118
- package/src/inject-infinite-query.ts +0 -125
- package/src/inject-is-fetching.ts +0 -49
- package/src/inject-is-mutating.ts +0 -48
- package/src/inject-mutation-state.ts +0 -107
- package/src/inject-mutation.ts +0 -118
- package/src/inject-queries.ts +0 -265
- package/src/inject-query-client.ts +0 -25
- package/src/inject-query.ts +0 -200
- package/src/providers.ts +0 -65
- package/src/query-options.ts +0 -122
- package/src/signal-proxy.ts +0 -46
- package/src/test-setup.ts +0 -12
- package/src/types.ts +0 -311
- package/src/util/assert-injector/assert-injector.test.ts +0 -74
- package/src/util/assert-injector/assert-injector.ts +0 -81
- package/src/util/create-injection-token/create-injection-token.test.ts +0 -32
- package/src/util/create-injection-token/create-injection-token.ts +0 -185
- package/src/util/index.ts +0 -13
- package/src/util/lazy-init/lazy-init.ts +0 -34
- package/src/util/lazy-signal-initializer/lazy-signal-initializer.ts +0 -28
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Component,
|
|
3
|
-
Injectable,
|
|
4
|
-
computed,
|
|
5
|
-
inject,
|
|
6
|
-
input,
|
|
7
|
-
signal,
|
|
8
|
-
} from '@angular/core'
|
|
9
|
-
import { TestBed, fakeAsync, flush, tick } from '@angular/core/testing'
|
|
10
|
-
import { QueryClient } from '@tanstack/query-core'
|
|
11
|
-
import { describe, expect, vi } from 'vitest'
|
|
12
|
-
import { injectQuery } from '../inject-query'
|
|
13
|
-
import { provideAngularQuery } from '../providers'
|
|
14
|
-
import {
|
|
15
|
-
delayedFetcher,
|
|
16
|
-
getSimpleFetcherWithReturnData,
|
|
17
|
-
rejectFetcher,
|
|
18
|
-
setSignalInputs,
|
|
19
|
-
simpleFetcher,
|
|
20
|
-
} from './test-utils'
|
|
21
|
-
|
|
22
|
-
describe('injectQuery', () => {
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
TestBed.configureTestingModule({
|
|
25
|
-
providers: [provideAngularQuery(new QueryClient())],
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test('should return pending status initially', fakeAsync(() => {
|
|
30
|
-
const query = TestBed.runInInjectionContext(() => {
|
|
31
|
-
return injectQuery(() => ({
|
|
32
|
-
queryKey: ['key1'],
|
|
33
|
-
queryFn: simpleFetcher,
|
|
34
|
-
}))
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
expect(query.status()).toBe('pending')
|
|
38
|
-
expect(query.isPending()).toBe(true)
|
|
39
|
-
expect(query.isFetching()).toBe(true)
|
|
40
|
-
expect(query.isStale()).toBe(true)
|
|
41
|
-
expect(query.isFetched()).toBe(false)
|
|
42
|
-
|
|
43
|
-
flush()
|
|
44
|
-
}))
|
|
45
|
-
|
|
46
|
-
test('should resolve to success and update signal: injectQuery()', fakeAsync(() => {
|
|
47
|
-
const query = TestBed.runInInjectionContext(() => {
|
|
48
|
-
return injectQuery(() => ({
|
|
49
|
-
queryKey: ['key2'],
|
|
50
|
-
queryFn: getSimpleFetcherWithReturnData('result2'),
|
|
51
|
-
}))
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
flush()
|
|
55
|
-
|
|
56
|
-
expect(query.status()).toBe('success')
|
|
57
|
-
expect(query.data()).toBe('result2')
|
|
58
|
-
expect(query.isPending()).toBe(false)
|
|
59
|
-
expect(query.isFetching()).toBe(false)
|
|
60
|
-
expect(query.isFetched()).toBe(true)
|
|
61
|
-
expect(query.isSuccess()).toBe(true)
|
|
62
|
-
}))
|
|
63
|
-
|
|
64
|
-
test('should reject and update signal', fakeAsync(() => {
|
|
65
|
-
const query = TestBed.runInInjectionContext(() => {
|
|
66
|
-
return injectQuery(() => ({
|
|
67
|
-
retry: false,
|
|
68
|
-
queryKey: ['key3'],
|
|
69
|
-
queryFn: rejectFetcher,
|
|
70
|
-
}))
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
flush()
|
|
74
|
-
|
|
75
|
-
expect(query.status()).toBe('error')
|
|
76
|
-
expect(query.data()).toBe(undefined)
|
|
77
|
-
expect(query.error()).toMatchObject({ message: 'Some error' })
|
|
78
|
-
expect(query.isPending()).toBe(false)
|
|
79
|
-
expect(query.isFetching()).toBe(false)
|
|
80
|
-
expect(query.isError()).toBe(true)
|
|
81
|
-
expect(query.failureCount()).toBe(1)
|
|
82
|
-
expect(query.failureReason()).toMatchObject({ message: 'Some error' })
|
|
83
|
-
}))
|
|
84
|
-
|
|
85
|
-
test('should update query on options contained signal change', fakeAsync(() => {
|
|
86
|
-
const key = signal(['key6', 'key7'])
|
|
87
|
-
const spy = vi.fn(simpleFetcher)
|
|
88
|
-
|
|
89
|
-
const query = TestBed.runInInjectionContext(() => {
|
|
90
|
-
return injectQuery(() => ({
|
|
91
|
-
queryKey: key(),
|
|
92
|
-
queryFn: spy,
|
|
93
|
-
}))
|
|
94
|
-
})
|
|
95
|
-
flush()
|
|
96
|
-
expect(spy).toHaveBeenCalledTimes(1)
|
|
97
|
-
|
|
98
|
-
expect(query.status()).toBe('success')
|
|
99
|
-
|
|
100
|
-
key.set(['key8'])
|
|
101
|
-
TestBed.flushEffects()
|
|
102
|
-
|
|
103
|
-
expect(spy).toHaveBeenCalledTimes(2)
|
|
104
|
-
|
|
105
|
-
flush()
|
|
106
|
-
}))
|
|
107
|
-
|
|
108
|
-
test('should only run query once enabled signal is set to true', fakeAsync(() => {
|
|
109
|
-
const spy = vi.fn(simpleFetcher)
|
|
110
|
-
const enabled = signal(false)
|
|
111
|
-
|
|
112
|
-
const query = TestBed.runInInjectionContext(() => {
|
|
113
|
-
return injectQuery(() => ({
|
|
114
|
-
queryKey: ['key9'],
|
|
115
|
-
queryFn: spy,
|
|
116
|
-
enabled: enabled(),
|
|
117
|
-
}))
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
expect(spy).not.toHaveBeenCalled()
|
|
121
|
-
expect(query.status()).toBe('pending')
|
|
122
|
-
|
|
123
|
-
enabled.set(true)
|
|
124
|
-
TestBed.flushEffects()
|
|
125
|
-
flush()
|
|
126
|
-
expect(spy).toHaveBeenCalledTimes(1)
|
|
127
|
-
expect(query.status()).toBe('success')
|
|
128
|
-
}))
|
|
129
|
-
|
|
130
|
-
test('should properly execute dependant queries', fakeAsync(() => {
|
|
131
|
-
const query1 = TestBed.runInInjectionContext(() => {
|
|
132
|
-
return injectQuery(() => ({
|
|
133
|
-
queryKey: ['dependant1'],
|
|
134
|
-
queryFn: simpleFetcher,
|
|
135
|
-
}))
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
const dependentQueryFn = vi.fn().mockImplementation(delayedFetcher(1000))
|
|
139
|
-
|
|
140
|
-
const query2 = TestBed.runInInjectionContext(() => {
|
|
141
|
-
return injectQuery(
|
|
142
|
-
computed(() => ({
|
|
143
|
-
queryKey: ['dependant2'],
|
|
144
|
-
queryFn: dependentQueryFn,
|
|
145
|
-
enabled: !!query1.data(),
|
|
146
|
-
})),
|
|
147
|
-
)
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
expect(query1.data()).toStrictEqual(undefined)
|
|
151
|
-
expect(query2.fetchStatus()).toStrictEqual('idle')
|
|
152
|
-
expect(dependentQueryFn).not.toHaveBeenCalled()
|
|
153
|
-
|
|
154
|
-
tick()
|
|
155
|
-
TestBed.flushEffects()
|
|
156
|
-
|
|
157
|
-
expect(query1.data()).toStrictEqual('Some data')
|
|
158
|
-
expect(query2.fetchStatus()).toStrictEqual('fetching')
|
|
159
|
-
|
|
160
|
-
flush()
|
|
161
|
-
|
|
162
|
-
expect(query2.fetchStatus()).toStrictEqual('idle')
|
|
163
|
-
expect(query2.status()).toStrictEqual('success')
|
|
164
|
-
expect(dependentQueryFn).toHaveBeenCalledTimes(1)
|
|
165
|
-
expect(dependentQueryFn).toHaveBeenCalledWith(
|
|
166
|
-
expect.objectContaining({ queryKey: ['dependant2'] }),
|
|
167
|
-
)
|
|
168
|
-
}))
|
|
169
|
-
|
|
170
|
-
test('should use the current value for the queryKey when refetch is called', fakeAsync(() => {
|
|
171
|
-
const fetchFn = vi.fn(simpleFetcher)
|
|
172
|
-
const keySignal = signal('key11')
|
|
173
|
-
|
|
174
|
-
const query = TestBed.runInInjectionContext(() => {
|
|
175
|
-
return injectQuery(() => ({
|
|
176
|
-
queryKey: ['key10', keySignal()],
|
|
177
|
-
queryFn: fetchFn,
|
|
178
|
-
enabled: false,
|
|
179
|
-
}))
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
expect(fetchFn).not.toHaveBeenCalled()
|
|
183
|
-
|
|
184
|
-
query.refetch().then(() => {
|
|
185
|
-
expect(fetchFn).toHaveBeenCalledTimes(1)
|
|
186
|
-
expect(fetchFn).toHaveBeenCalledWith(
|
|
187
|
-
expect.objectContaining({
|
|
188
|
-
queryKey: ['key10', 'key11'],
|
|
189
|
-
}),
|
|
190
|
-
)
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
flush()
|
|
194
|
-
|
|
195
|
-
keySignal.set('key12')
|
|
196
|
-
|
|
197
|
-
TestBed.flushEffects()
|
|
198
|
-
|
|
199
|
-
query.refetch().then(() => {
|
|
200
|
-
expect(fetchFn).toHaveBeenCalledTimes(2)
|
|
201
|
-
expect(fetchFn).toHaveBeenCalledWith(
|
|
202
|
-
expect.objectContaining({
|
|
203
|
-
queryKey: ['key10', 'key12'],
|
|
204
|
-
}),
|
|
205
|
-
)
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
flush()
|
|
209
|
-
}))
|
|
210
|
-
|
|
211
|
-
describe('throwOnError', () => {
|
|
212
|
-
test('should evaluate throwOnError when query is expected to throw', fakeAsync(() => {
|
|
213
|
-
const boundaryFn = vi.fn()
|
|
214
|
-
TestBed.runInInjectionContext(() => {
|
|
215
|
-
return injectQuery(() => ({
|
|
216
|
-
queryKey: ['key12'],
|
|
217
|
-
queryFn: rejectFetcher,
|
|
218
|
-
throwOnError: boundaryFn,
|
|
219
|
-
}))
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
flush()
|
|
223
|
-
|
|
224
|
-
expect(boundaryFn).toHaveBeenCalledTimes(1)
|
|
225
|
-
expect(boundaryFn).toHaveBeenCalledWith(
|
|
226
|
-
Error('Some error'),
|
|
227
|
-
expect.objectContaining({
|
|
228
|
-
state: expect.objectContaining({ status: 'error' }),
|
|
229
|
-
}),
|
|
230
|
-
)
|
|
231
|
-
}))
|
|
232
|
-
|
|
233
|
-
test('should throw when throwOnError is true', fakeAsync(() => {
|
|
234
|
-
TestBed.runInInjectionContext(() => {
|
|
235
|
-
return injectQuery(() => ({
|
|
236
|
-
queryKey: ['key13'],
|
|
237
|
-
queryFn: rejectFetcher,
|
|
238
|
-
throwOnError: true,
|
|
239
|
-
}))
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
expect(() => {
|
|
243
|
-
flush()
|
|
244
|
-
}).toThrowError('Some error')
|
|
245
|
-
flush()
|
|
246
|
-
}))
|
|
247
|
-
|
|
248
|
-
test('should throw when throwOnError function returns true', fakeAsync(() => {
|
|
249
|
-
TestBed.runInInjectionContext(() => {
|
|
250
|
-
return injectQuery(() => ({
|
|
251
|
-
queryKey: ['key14'],
|
|
252
|
-
queryFn: rejectFetcher,
|
|
253
|
-
throwOnError: () => true,
|
|
254
|
-
}))
|
|
255
|
-
})
|
|
256
|
-
|
|
257
|
-
expect(() => {
|
|
258
|
-
flush()
|
|
259
|
-
}).toThrowError('Some error')
|
|
260
|
-
flush()
|
|
261
|
-
}))
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
test('should set state to error when queryFn returns reject promise', fakeAsync(() => {
|
|
265
|
-
const query = TestBed.runInInjectionContext(() => {
|
|
266
|
-
return injectQuery(() => ({
|
|
267
|
-
retry: false,
|
|
268
|
-
queryKey: ['key15'],
|
|
269
|
-
queryFn: rejectFetcher,
|
|
270
|
-
}))
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
expect(query.status()).toBe('pending')
|
|
274
|
-
|
|
275
|
-
flush()
|
|
276
|
-
|
|
277
|
-
expect(query.status()).toBe('error')
|
|
278
|
-
}))
|
|
279
|
-
|
|
280
|
-
test('should render with required signal inputs', fakeAsync(async () => {
|
|
281
|
-
@Component({
|
|
282
|
-
selector: 'app-fake',
|
|
283
|
-
template: `{{ query.data() }}`,
|
|
284
|
-
standalone: true,
|
|
285
|
-
})
|
|
286
|
-
class FakeComponent {
|
|
287
|
-
name = input.required<string>()
|
|
288
|
-
|
|
289
|
-
query = injectQuery(() => ({
|
|
290
|
-
queryKey: ['fake', this.name()],
|
|
291
|
-
queryFn: () => Promise.resolve(this.name()),
|
|
292
|
-
}))
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const fixture = TestBed.createComponent(FakeComponent)
|
|
296
|
-
setSignalInputs(fixture.componentInstance, {
|
|
297
|
-
name: 'signal-input-required-test',
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
flush()
|
|
301
|
-
fixture.detectChanges()
|
|
302
|
-
|
|
303
|
-
expect(fixture.debugElement.nativeElement.textContent).toEqual(
|
|
304
|
-
'signal-input-required-test',
|
|
305
|
-
)
|
|
306
|
-
}))
|
|
307
|
-
|
|
308
|
-
test('should run options in injection context', fakeAsync(async () => {
|
|
309
|
-
@Injectable()
|
|
310
|
-
class FakeService {
|
|
311
|
-
getData(name: string) {
|
|
312
|
-
return Promise.resolve(name)
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
@Component({
|
|
317
|
-
selector: 'app-fake',
|
|
318
|
-
template: `{{ query.data() }}`,
|
|
319
|
-
standalone: true,
|
|
320
|
-
providers: [FakeService],
|
|
321
|
-
})
|
|
322
|
-
class FakeComponent {
|
|
323
|
-
name = signal<string>('test name')
|
|
324
|
-
|
|
325
|
-
query = injectQuery(() => {
|
|
326
|
-
const service = inject(FakeService)
|
|
327
|
-
|
|
328
|
-
return {
|
|
329
|
-
queryKey: ['fake', this.name()],
|
|
330
|
-
queryFn: () => {
|
|
331
|
-
return service.getData(this.name())
|
|
332
|
-
},
|
|
333
|
-
}
|
|
334
|
-
})
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
const fixture = TestBed.createComponent(FakeComponent)
|
|
338
|
-
flush()
|
|
339
|
-
fixture.detectChanges()
|
|
340
|
-
|
|
341
|
-
expect(fixture.componentInstance.query.data()).toEqual('test name')
|
|
342
|
-
|
|
343
|
-
fixture.componentInstance.name.set('test name 2')
|
|
344
|
-
fixture.detectChanges()
|
|
345
|
-
flush()
|
|
346
|
-
|
|
347
|
-
expect(fixture.componentInstance.query.data()).toEqual('test name 2')
|
|
348
|
-
}))
|
|
349
|
-
})
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { assertType, describe, expectTypeOf } from 'vitest'
|
|
2
|
-
import { QueryClient } from '@tanstack/query-core'
|
|
3
|
-
import { dataTagSymbol } from '@tanstack/query-core'
|
|
4
|
-
import { queryOptions } from '../query-options'
|
|
5
|
-
import { injectQuery } from '../inject-query'
|
|
6
|
-
import type { Signal } from '@angular/core'
|
|
7
|
-
|
|
8
|
-
describe('queryOptions', () => {
|
|
9
|
-
test('should not allow excess properties', () => {
|
|
10
|
-
return queryOptions({
|
|
11
|
-
queryKey: ['key'],
|
|
12
|
-
queryFn: () => Promise.resolve(5),
|
|
13
|
-
// @ts-expect-error this is a good error, because stallTime does not exist!
|
|
14
|
-
stallTime: 1000,
|
|
15
|
-
})
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
test('should infer types for callbacks', () => {
|
|
19
|
-
return queryOptions({
|
|
20
|
-
queryKey: ['key'],
|
|
21
|
-
queryFn: () => Promise.resolve(5),
|
|
22
|
-
staleTime: 1000,
|
|
23
|
-
select: (data) => {
|
|
24
|
-
expectTypeOf(data).toEqualTypeOf<number>()
|
|
25
|
-
},
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('should work when passed to injectQuery', () => {
|
|
31
|
-
const options = queryOptions({
|
|
32
|
-
queryKey: ['key'],
|
|
33
|
-
queryFn: () => Promise.resolve(5),
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
const { data } = injectQuery(() => options)
|
|
37
|
-
expectTypeOf(data).toEqualTypeOf<Signal<number | undefined>>()
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test('should work when passed to fetchQuery', () => {
|
|
41
|
-
const options = queryOptions({
|
|
42
|
-
queryKey: ['key'],
|
|
43
|
-
queryFn: () => Promise.resolve(5),
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
const data = new QueryClient().fetchQuery(options)
|
|
47
|
-
assertType<Promise<number>>(data)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
test('should tag the queryKey with the result type of the QueryFn', () => {
|
|
51
|
-
const { queryKey } = queryOptions({
|
|
52
|
-
queryKey: ['key'],
|
|
53
|
-
queryFn: () => Promise.resolve(5),
|
|
54
|
-
})
|
|
55
|
-
assertType<number>(queryKey[dataTagSymbol])
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('should tag the queryKey even if no promise is returned', () => {
|
|
59
|
-
const { queryKey } = queryOptions({
|
|
60
|
-
queryKey: ['key'],
|
|
61
|
-
queryFn: () => 5,
|
|
62
|
-
})
|
|
63
|
-
assertType<number>(queryKey[dataTagSymbol])
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
test('should tag the queryKey with unknown if there is no queryFn', () => {
|
|
67
|
-
const { queryKey } = queryOptions({
|
|
68
|
-
queryKey: ['key'],
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
assertType<unknown>(queryKey[dataTagSymbol])
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
test('should tag the queryKey with the result type of the QueryFn if select is used', () => {
|
|
75
|
-
const { queryKey } = queryOptions({
|
|
76
|
-
queryKey: ['key'],
|
|
77
|
-
queryFn: () => Promise.resolve(5),
|
|
78
|
-
select: (data) => data.toString(),
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
assertType<number>(queryKey[dataTagSymbol])
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
test('should return the proper type when passed to getQueryData', () => {
|
|
85
|
-
const { queryKey } = queryOptions({
|
|
86
|
-
queryKey: ['key'],
|
|
87
|
-
queryFn: () => Promise.resolve(5),
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
const queryClient = new QueryClient()
|
|
91
|
-
const data = queryClient.getQueryData(queryKey)
|
|
92
|
-
|
|
93
|
-
expectTypeOf(data).toEqualTypeOf<number | undefined>()
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
test('should properly type updaterFn when passed to setQueryData', () => {
|
|
97
|
-
const { queryKey } = queryOptions({
|
|
98
|
-
queryKey: ['key'],
|
|
99
|
-
queryFn: () => Promise.resolve(5),
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
const queryClient = new QueryClient()
|
|
103
|
-
const data = queryClient.setQueryData(queryKey, (prev) => {
|
|
104
|
-
expectTypeOf(prev).toEqualTypeOf<number | undefined>()
|
|
105
|
-
return prev
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
expectTypeOf(data).toEqualTypeOf<number | undefined>()
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
test('should properly type value when passed to setQueryData', () => {
|
|
112
|
-
const { queryKey } = queryOptions({
|
|
113
|
-
queryKey: ['key'],
|
|
114
|
-
queryFn: () => Promise.resolve(5),
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
const queryClient = new QueryClient()
|
|
118
|
-
|
|
119
|
-
// @ts-expect-error value should be a number
|
|
120
|
-
queryClient.setQueryData(queryKey, '5')
|
|
121
|
-
// @ts-expect-error value should be a number
|
|
122
|
-
queryClient.setQueryData(queryKey, () => '5')
|
|
123
|
-
|
|
124
|
-
const data = queryClient.setQueryData(queryKey, 5)
|
|
125
|
-
|
|
126
|
-
expectTypeOf(data).toEqualTypeOf<number | undefined>()
|
|
127
|
-
})
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { isSignal, signal } from '@angular/core'
|
|
2
|
-
import { describe } from 'vitest'
|
|
3
|
-
import { signalProxy } from '../signal-proxy'
|
|
4
|
-
|
|
5
|
-
describe('signalProxy', () => {
|
|
6
|
-
const inputSignal = signal({ fn: () => 'bar', baz: 'qux' })
|
|
7
|
-
const proxy = signalProxy(inputSignal)
|
|
8
|
-
|
|
9
|
-
test('should have computed fields', () => {
|
|
10
|
-
expect(proxy.baz()).toEqual('qux')
|
|
11
|
-
expect(isSignal(proxy.baz)).toBe(true)
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
test('should pass through functions as-is', () => {
|
|
15
|
-
expect(proxy.fn()).toEqual('bar')
|
|
16
|
-
expect(isSignal(proxy.fn)).toBe(false)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test('supports "in" operator', () => {
|
|
20
|
-
expect('baz' in proxy).toBe(true)
|
|
21
|
-
expect('foo' in proxy).toBe(false)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('supports "Object.keys"', () => {
|
|
25
|
-
expect(Object.keys(proxy)).toEqual(['fn', 'baz'])
|
|
26
|
-
})
|
|
27
|
-
})
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { type InputSignal, isSignal, untracked } from '@angular/core'
|
|
2
|
-
import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals'
|
|
3
|
-
import type { ComponentFixture } from '@angular/core/testing'
|
|
4
|
-
|
|
5
|
-
export function simpleFetcher(): Promise<string> {
|
|
6
|
-
return new Promise((resolve) => {
|
|
7
|
-
setTimeout(() => {
|
|
8
|
-
return resolve('Some data')
|
|
9
|
-
}, 0)
|
|
10
|
-
})
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function delayedFetcher(timeout = 0): () => Promise<string> {
|
|
14
|
-
return () =>
|
|
15
|
-
new Promise((resolve) => {
|
|
16
|
-
setTimeout(() => {
|
|
17
|
-
return resolve('Some data')
|
|
18
|
-
}, timeout)
|
|
19
|
-
})
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function getSimpleFetcherWithReturnData(returnData: unknown) {
|
|
23
|
-
return () =>
|
|
24
|
-
new Promise((resolve) => setTimeout(() => resolve(returnData), 0))
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function rejectFetcher(): Promise<Error> {
|
|
28
|
-
return new Promise((_, reject) => {
|
|
29
|
-
setTimeout(() => {
|
|
30
|
-
return reject(new Error('Some error'))
|
|
31
|
-
}, 0)
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function infiniteFetcher({
|
|
36
|
-
pageParam,
|
|
37
|
-
}: {
|
|
38
|
-
pageParam?: number
|
|
39
|
-
}): Promise<string> {
|
|
40
|
-
return new Promise((resolve) => {
|
|
41
|
-
setTimeout(() => {
|
|
42
|
-
return resolve('data on page ' + pageParam)
|
|
43
|
-
}, 0)
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function successMutator<T>(param: T): Promise<T> {
|
|
48
|
-
return new Promise((resolve) => {
|
|
49
|
-
setTimeout(() => {
|
|
50
|
-
return resolve(param)
|
|
51
|
-
}, 0)
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function errorMutator(_parameter?: unknown): Promise<Error> {
|
|
56
|
-
return rejectFetcher()
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Evaluate all signals on an object and return the result
|
|
60
|
-
function evaluateSignals<T extends Record<string, any>>(
|
|
61
|
-
obj: T,
|
|
62
|
-
): { [K in keyof T]: ReturnType<T[K]> } {
|
|
63
|
-
const result: Partial<{ [K in keyof T]: ReturnType<T[K]> }> = {}
|
|
64
|
-
|
|
65
|
-
untracked(() => {
|
|
66
|
-
for (const key in obj) {
|
|
67
|
-
if (
|
|
68
|
-
Object.prototype.hasOwnProperty.call(obj, key) &&
|
|
69
|
-
// Only evaluate signals, not normal functions
|
|
70
|
-
isSignal(obj[key])
|
|
71
|
-
) {
|
|
72
|
-
const func = obj[key]
|
|
73
|
-
result[key] = func()
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
return result as { [K in keyof T]: ReturnType<T[K]> }
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export const expectSignals = <T extends Record<string, any>>(
|
|
82
|
-
obj: T,
|
|
83
|
-
expected: Partial<{ [K in keyof T]: ReturnType<T[K]> }>,
|
|
84
|
-
): void => {
|
|
85
|
-
expect(evaluateSignals(obj)).toMatchObject(expected)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
type ToSignalInputUpdatableMap<T> = {
|
|
89
|
-
[K in keyof T as T[K] extends InputSignal<any>
|
|
90
|
-
? K
|
|
91
|
-
: never]: T[K] extends InputSignal<infer Value> ? Value : never
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function componentHasSignalInputProperty<TProperty extends string>(
|
|
95
|
-
component: object,
|
|
96
|
-
property: TProperty,
|
|
97
|
-
): component is { [key in TProperty]: InputSignal<unknown> } {
|
|
98
|
-
return (
|
|
99
|
-
component.hasOwnProperty(property) && (component as any)[property][SIGNAL]
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Set required signal input value to component fixture
|
|
105
|
-
* @see https://github.com/angular/angular/issues/54013
|
|
106
|
-
*/
|
|
107
|
-
export function setSignalInputs<T extends NonNullable<unknown>>(
|
|
108
|
-
component: T,
|
|
109
|
-
inputs: ToSignalInputUpdatableMap<T>,
|
|
110
|
-
) {
|
|
111
|
-
for (const inputKey in inputs) {
|
|
112
|
-
if (componentHasSignalInputProperty(component, inputKey)) {
|
|
113
|
-
signalSetFn(component[inputKey][SIGNAL], inputs[inputKey])
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function setFixtureSignalInputs<T extends NonNullable<unknown>>(
|
|
119
|
-
componentFixture: ComponentFixture<T>,
|
|
120
|
-
inputs: ToSignalInputUpdatableMap<T>,
|
|
121
|
-
options: { detectChanges: boolean } = { detectChanges: true },
|
|
122
|
-
) {
|
|
123
|
-
setSignalInputs(componentFixture.componentInstance, inputs)
|
|
124
|
-
if (options.detectChanges) {
|
|
125
|
-
componentFixture.detectChanges()
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export async function flushQueue() {
|
|
130
|
-
await new Promise(setImmediate)
|
|
131
|
-
}
|