@sylphx/lens-react 1.2.22 → 2.0.2
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/dist/index.d.ts +83 -49
- package/dist/index.js +50 -20
- package/package.json +2 -2
- package/src/hooks.test.tsx +127 -169
- package/src/hooks.ts +182 -88
- package/src/index.ts +2 -1
package/src/hooks.test.tsx
CHANGED
|
@@ -13,7 +13,6 @@ import { test as bunTest, describe, expect } from "bun:test";
|
|
|
13
13
|
const test = hasDom ? bunTest : bunTest.skip;
|
|
14
14
|
|
|
15
15
|
import type { MutationResult, QueryResult } from "@sylphx/lens-client";
|
|
16
|
-
import { signal } from "@sylphx/lens-client";
|
|
17
16
|
import { act, renderHook, waitFor } from "@testing-library/react";
|
|
18
17
|
import { useLazyQuery, useMutation, useQuery } from "./hooks.js";
|
|
19
18
|
|
|
@@ -26,7 +25,6 @@ function createMockQueryResult<T>(initialValue: T | null = null): QueryResult<T>
|
|
|
26
25
|
_setError: (error: Error) => void;
|
|
27
26
|
} {
|
|
28
27
|
let currentValue = initialValue;
|
|
29
|
-
let _currentError: Error | null = null;
|
|
30
28
|
const subscribers: Array<(value: T) => void> = [];
|
|
31
29
|
let resolved = false;
|
|
32
30
|
let resolvePromise: ((value: T) => void) | null = null;
|
|
@@ -45,9 +43,6 @@ function createMockQueryResult<T>(initialValue: T | null = null): QueryResult<T>
|
|
|
45
43
|
get value() {
|
|
46
44
|
return currentValue;
|
|
47
45
|
},
|
|
48
|
-
signal: signal(currentValue),
|
|
49
|
-
loading: signal(initialValue === null),
|
|
50
|
-
error: signal<Error | null>(null),
|
|
51
46
|
subscribe(callback?: (data: T) => void): () => void {
|
|
52
47
|
if (callback) {
|
|
53
48
|
subscribers.push(callback);
|
|
@@ -72,9 +67,6 @@ function createMockQueryResult<T>(initialValue: T | null = null): QueryResult<T>
|
|
|
72
67
|
// Test helpers
|
|
73
68
|
_setValue(value: T) {
|
|
74
69
|
currentValue = value;
|
|
75
|
-
result.signal.value = value;
|
|
76
|
-
result.loading.value = false;
|
|
77
|
-
result.error.value = null;
|
|
78
70
|
for (const cb of subscribers) cb(value);
|
|
79
71
|
if (!resolved && resolvePromise) {
|
|
80
72
|
resolved = true;
|
|
@@ -82,9 +74,6 @@ function createMockQueryResult<T>(initialValue: T | null = null): QueryResult<T>
|
|
|
82
74
|
}
|
|
83
75
|
},
|
|
84
76
|
_setError(error: Error) {
|
|
85
|
-
_currentError = error;
|
|
86
|
-
result.loading.value = false;
|
|
87
|
-
result.error.value = error;
|
|
88
77
|
if (!resolved && rejectPromise) {
|
|
89
78
|
resolved = true;
|
|
90
79
|
rejectPromise(error);
|
|
@@ -99,14 +88,14 @@ function createMockQueryResult<T>(initialValue: T | null = null): QueryResult<T>
|
|
|
99
88
|
}
|
|
100
89
|
|
|
101
90
|
// =============================================================================
|
|
102
|
-
// Tests: useQuery
|
|
91
|
+
// Tests: useQuery (Accessor + Deps pattern)
|
|
103
92
|
// =============================================================================
|
|
104
93
|
|
|
105
94
|
describe("useQuery", () => {
|
|
106
95
|
test("returns loading state initially", () => {
|
|
107
96
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
108
97
|
|
|
109
|
-
const { result } = renderHook(() => useQuery(mockQuery));
|
|
98
|
+
const { result } = renderHook(() => useQuery(() => mockQuery, []));
|
|
110
99
|
|
|
111
100
|
expect(result.current.loading).toBe(true);
|
|
112
101
|
expect(result.current.data).toBe(null);
|
|
@@ -116,7 +105,7 @@ describe("useQuery", () => {
|
|
|
116
105
|
test("returns data when query resolves", async () => {
|
|
117
106
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
118
107
|
|
|
119
|
-
const { result } = renderHook(() => useQuery(mockQuery));
|
|
108
|
+
const { result } = renderHook(() => useQuery(() => mockQuery, []));
|
|
120
109
|
|
|
121
110
|
// Simulate data loading
|
|
122
111
|
act(() => {
|
|
@@ -134,7 +123,7 @@ describe("useQuery", () => {
|
|
|
134
123
|
test("returns error when query fails", async () => {
|
|
135
124
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
136
125
|
|
|
137
|
-
const { result } = renderHook(() => useQuery(mockQuery));
|
|
126
|
+
const { result } = renderHook(() => useQuery(() => mockQuery, []));
|
|
138
127
|
|
|
139
128
|
// Simulate error
|
|
140
129
|
act(() => {
|
|
@@ -158,7 +147,7 @@ describe("useQuery", () => {
|
|
|
158
147
|
},
|
|
159
148
|
} as unknown as QueryResult<{ id: string }>;
|
|
160
149
|
|
|
161
|
-
const { result } = renderHook(() => useQuery(mockQuery));
|
|
150
|
+
const { result } = renderHook(() => useQuery(() => mockQuery, []));
|
|
162
151
|
|
|
163
152
|
await waitFor(() => {
|
|
164
153
|
expect(result.current.error?.message).toBe("String error");
|
|
@@ -168,65 +157,32 @@ describe("useQuery", () => {
|
|
|
168
157
|
test("skips query when skip option is true", () => {
|
|
169
158
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
170
159
|
|
|
171
|
-
const { result } = renderHook(() => useQuery(mockQuery, { skip: true }));
|
|
160
|
+
const { result } = renderHook(() => useQuery(() => mockQuery, [], { skip: true }));
|
|
172
161
|
|
|
173
162
|
expect(result.current.loading).toBe(false);
|
|
174
163
|
expect(result.current.data).toBe(null);
|
|
175
164
|
});
|
|
176
165
|
|
|
177
|
-
test("handles null query", () => {
|
|
178
|
-
const { result } = renderHook(() => useQuery(null));
|
|
166
|
+
test("handles null query from accessor", () => {
|
|
167
|
+
const { result } = renderHook(() => useQuery(() => null, []));
|
|
179
168
|
|
|
180
169
|
expect(result.current.loading).toBe(false);
|
|
181
170
|
expect(result.current.data).toBe(null);
|
|
182
171
|
expect(result.current.error).toBe(null);
|
|
183
172
|
});
|
|
184
173
|
|
|
185
|
-
test("handles undefined query", () => {
|
|
186
|
-
const { result } = renderHook(() => useQuery(undefined));
|
|
174
|
+
test("handles undefined query from accessor", () => {
|
|
175
|
+
const { result } = renderHook(() => useQuery(() => undefined, []));
|
|
187
176
|
|
|
188
177
|
expect(result.current.loading).toBe(false);
|
|
189
178
|
expect(result.current.data).toBe(null);
|
|
190
179
|
expect(result.current.error).toBe(null);
|
|
191
180
|
});
|
|
192
181
|
|
|
193
|
-
test("handles accessor function returning query", async () => {
|
|
194
|
-
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
195
|
-
const accessor = () => mockQuery;
|
|
196
|
-
|
|
197
|
-
const { result } = renderHook(() => useQuery(accessor));
|
|
198
|
-
|
|
199
|
-
act(() => {
|
|
200
|
-
mockQuery._setValue({ id: "123", name: "John" });
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
await waitFor(() => {
|
|
204
|
-
expect(result.current.data).toEqual({ id: "123", name: "John" });
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
test("handles accessor function returning null", () => {
|
|
209
|
-
const accessor = () => null;
|
|
210
|
-
|
|
211
|
-
const { result } = renderHook(() => useQuery(accessor));
|
|
212
|
-
|
|
213
|
-
expect(result.current.loading).toBe(false);
|
|
214
|
-
expect(result.current.data).toBe(null);
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
test("handles accessor function returning undefined", () => {
|
|
218
|
-
const accessor = () => undefined;
|
|
219
|
-
|
|
220
|
-
const { result } = renderHook(() => useQuery(accessor));
|
|
221
|
-
|
|
222
|
-
expect(result.current.loading).toBe(false);
|
|
223
|
-
expect(result.current.data).toBe(null);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
182
|
test("updates when query subscription emits", async () => {
|
|
227
183
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
228
184
|
|
|
229
|
-
const { result } = renderHook(() => useQuery(mockQuery));
|
|
185
|
+
const { result } = renderHook(() => useQuery(() => mockQuery, []));
|
|
230
186
|
|
|
231
187
|
// First value
|
|
232
188
|
act(() => {
|
|
@@ -250,7 +206,7 @@ describe("useQuery", () => {
|
|
|
250
206
|
test("refetch reloads the query", async () => {
|
|
251
207
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
252
208
|
|
|
253
|
-
const { result } = renderHook(() => useQuery(mockQuery));
|
|
209
|
+
const { result } = renderHook(() => useQuery(() => mockQuery, []));
|
|
254
210
|
|
|
255
211
|
// Initial load
|
|
256
212
|
act(() => {
|
|
@@ -278,7 +234,7 @@ describe("useQuery", () => {
|
|
|
278
234
|
test("refetch handles errors", async () => {
|
|
279
235
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
280
236
|
|
|
281
|
-
const { result } = renderHook(() => useQuery(mockQuery));
|
|
237
|
+
const { result } = renderHook(() => useQuery(() => mockQuery, []));
|
|
282
238
|
|
|
283
239
|
// Initial load succeeds
|
|
284
240
|
act(() => {
|
|
@@ -298,7 +254,7 @@ describe("useQuery", () => {
|
|
|
298
254
|
} as unknown as QueryResult<{ id: string; name: string }>;
|
|
299
255
|
|
|
300
256
|
// Update the query to use failing query
|
|
301
|
-
const { result: result2 } = renderHook(() => useQuery(failingQuery));
|
|
257
|
+
const { result: result2 } = renderHook(() => useQuery(() => failingQuery, []));
|
|
302
258
|
|
|
303
259
|
await waitFor(() => {
|
|
304
260
|
expect(result2.current.error?.message).toBe("Refetch failed");
|
|
@@ -306,7 +262,7 @@ describe("useQuery", () => {
|
|
|
306
262
|
});
|
|
307
263
|
|
|
308
264
|
test("refetch does nothing when query is null", () => {
|
|
309
|
-
const { result } = renderHook(() => useQuery(null));
|
|
265
|
+
const { result } = renderHook(() => useQuery(() => null, []));
|
|
310
266
|
|
|
311
267
|
act(() => {
|
|
312
268
|
result.current.refetch();
|
|
@@ -319,7 +275,7 @@ describe("useQuery", () => {
|
|
|
319
275
|
test("refetch does nothing when skip is true", () => {
|
|
320
276
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
321
277
|
|
|
322
|
-
const { result } = renderHook(() => useQuery(mockQuery, { skip: true }));
|
|
278
|
+
const { result } = renderHook(() => useQuery(() => mockQuery, [], { skip: true }));
|
|
323
279
|
|
|
324
280
|
act(() => {
|
|
325
281
|
result.current.refetch();
|
|
@@ -341,7 +297,7 @@ describe("useQuery", () => {
|
|
|
341
297
|
},
|
|
342
298
|
} as unknown as QueryResult<{ id: string; name: string }>;
|
|
343
299
|
|
|
344
|
-
const { result } = renderHook(() => useQuery(mockQuery));
|
|
300
|
+
const { result } = renderHook(() => useQuery(() => mockQuery, []));
|
|
345
301
|
|
|
346
302
|
await waitFor(() => {
|
|
347
303
|
expect(result.current.data).toEqual({ id: "123", name: "John" });
|
|
@@ -373,7 +329,7 @@ describe("useQuery", () => {
|
|
|
373
329
|
};
|
|
374
330
|
};
|
|
375
331
|
|
|
376
|
-
const { unmount } = renderHook(() => useQuery(mockQuery));
|
|
332
|
+
const { unmount } = renderHook(() => useQuery(() => mockQuery, []));
|
|
377
333
|
|
|
378
334
|
unmount();
|
|
379
335
|
|
|
@@ -383,7 +339,7 @@ describe("useQuery", () => {
|
|
|
383
339
|
test("does not update state after unmount", async () => {
|
|
384
340
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
385
341
|
|
|
386
|
-
const { unmount } = renderHook(() => useQuery(mockQuery));
|
|
342
|
+
const { unmount } = renderHook(() => useQuery(() => mockQuery, []));
|
|
387
343
|
|
|
388
344
|
// Unmount before query resolves
|
|
389
345
|
unmount();
|
|
@@ -398,12 +354,12 @@ describe("useQuery", () => {
|
|
|
398
354
|
expect(true).toBe(true);
|
|
399
355
|
});
|
|
400
356
|
|
|
401
|
-
test("handles query change", async () => {
|
|
357
|
+
test("handles query change via deps", async () => {
|
|
402
358
|
const mockQuery1 = createMockQueryResult<{ id: string; name: string }>();
|
|
403
359
|
const mockQuery2 = createMockQueryResult<{ id: string; name: string }>();
|
|
404
360
|
|
|
405
|
-
let
|
|
406
|
-
const { result, rerender } = renderHook(() => useQuery(
|
|
361
|
+
let queryId = 1;
|
|
362
|
+
const { result, rerender } = renderHook(() => useQuery(() => (queryId === 1 ? mockQuery1 : mockQuery2), [queryId]));
|
|
407
363
|
|
|
408
364
|
// Load first query
|
|
409
365
|
act(() => {
|
|
@@ -415,7 +371,7 @@ describe("useQuery", () => {
|
|
|
415
371
|
});
|
|
416
372
|
|
|
417
373
|
// Change to second query
|
|
418
|
-
|
|
374
|
+
queryId = 2;
|
|
419
375
|
rerender();
|
|
420
376
|
|
|
421
377
|
expect(result.current.loading).toBe(true);
|
|
@@ -434,7 +390,7 @@ describe("useQuery", () => {
|
|
|
434
390
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
435
391
|
|
|
436
392
|
let skip = true;
|
|
437
|
-
const { result, rerender } = renderHook(() => useQuery(mockQuery, { skip }));
|
|
393
|
+
const { result, rerender } = renderHook(() => useQuery(() => mockQuery, [], { skip }));
|
|
438
394
|
|
|
439
395
|
expect(result.current.loading).toBe(false);
|
|
440
396
|
|
|
@@ -457,7 +413,7 @@ describe("useQuery", () => {
|
|
|
457
413
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
458
414
|
|
|
459
415
|
let skip = false;
|
|
460
|
-
const { result, rerender } = renderHook(() => useQuery(mockQuery, { skip }));
|
|
416
|
+
const { result, rerender } = renderHook(() => useQuery(() => mockQuery, [], { skip }));
|
|
461
417
|
|
|
462
418
|
act(() => {
|
|
463
419
|
mockQuery._setValue({ id: "123", name: "John" });
|
|
@@ -475,6 +431,46 @@ describe("useQuery", () => {
|
|
|
475
431
|
expect(result.current.data).toBe(null);
|
|
476
432
|
expect(result.current.error).toBe(null);
|
|
477
433
|
});
|
|
434
|
+
|
|
435
|
+
test("select transforms the data", async () => {
|
|
436
|
+
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
437
|
+
|
|
438
|
+
const { result } = renderHook(() =>
|
|
439
|
+
useQuery(() => mockQuery, [], {
|
|
440
|
+
select: (data) => data.name.toUpperCase(),
|
|
441
|
+
}),
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
act(() => {
|
|
445
|
+
mockQuery._setValue({ id: "123", name: "John" });
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
await waitFor(() => {
|
|
449
|
+
expect(result.current.data).toBe("JOHN");
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
test("Route + Params pattern works", async () => {
|
|
454
|
+
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
455
|
+
const route = (_params: { id: string }) => mockQuery;
|
|
456
|
+
|
|
457
|
+
const { result } = renderHook(() => useQuery(route, { id: "123" }));
|
|
458
|
+
|
|
459
|
+
act(() => {
|
|
460
|
+
mockQuery._setValue({ id: "123", name: "John" });
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
await waitFor(() => {
|
|
464
|
+
expect(result.current.data).toEqual({ id: "123", name: "John" });
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
test("Route + Params with null route", () => {
|
|
469
|
+
const { result } = renderHook(() => useQuery(null, { id: "123" }));
|
|
470
|
+
|
|
471
|
+
expect(result.current.loading).toBe(false);
|
|
472
|
+
expect(result.current.data).toBe(null);
|
|
473
|
+
});
|
|
478
474
|
});
|
|
479
475
|
|
|
480
476
|
// =============================================================================
|
|
@@ -665,36 +661,17 @@ describe("useMutation", () => {
|
|
|
665
661
|
// Test passes if no error is thrown (state update after unmount would cause error)
|
|
666
662
|
expect(true).toBe(true);
|
|
667
663
|
});
|
|
668
|
-
|
|
669
|
-
test("mutation result includes rollback function when provided", async () => {
|
|
670
|
-
const rollbackFn = () => console.log("Rollback");
|
|
671
|
-
const mutationFn = async (input: { name: string }): Promise<MutationResult<{ id: string; name: string }>> => {
|
|
672
|
-
return {
|
|
673
|
-
data: { id: "new-id", name: input.name },
|
|
674
|
-
rollback: rollbackFn,
|
|
675
|
-
};
|
|
676
|
-
};
|
|
677
|
-
|
|
678
|
-
const { result } = renderHook(() => useMutation(mutationFn));
|
|
679
|
-
|
|
680
|
-
let mutationResult: MutationResult<{ id: string; name: string }> | undefined;
|
|
681
|
-
await act(async () => {
|
|
682
|
-
mutationResult = await result.current.mutate({ name: "New User" });
|
|
683
|
-
});
|
|
684
|
-
|
|
685
|
-
expect(mutationResult?.rollback).toBe(rollbackFn);
|
|
686
|
-
});
|
|
687
664
|
});
|
|
688
665
|
|
|
689
666
|
// =============================================================================
|
|
690
|
-
// Tests: useLazyQuery
|
|
667
|
+
// Tests: useLazyQuery (Accessor + Deps pattern)
|
|
691
668
|
// =============================================================================
|
|
692
669
|
|
|
693
670
|
describe("useLazyQuery", () => {
|
|
694
671
|
test("does not execute query on mount", () => {
|
|
695
672
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
696
673
|
|
|
697
|
-
const { result } = renderHook(() => useLazyQuery(mockQuery));
|
|
674
|
+
const { result } = renderHook(() => useLazyQuery(() => mockQuery, []));
|
|
698
675
|
|
|
699
676
|
expect(result.current.loading).toBe(false);
|
|
700
677
|
expect(result.current.data).toBe(null);
|
|
@@ -706,7 +683,7 @@ describe("useLazyQuery", () => {
|
|
|
706
683
|
name: "John",
|
|
707
684
|
});
|
|
708
685
|
|
|
709
|
-
const { result } = renderHook(() => useLazyQuery(mockQuery));
|
|
686
|
+
const { result } = renderHook(() => useLazyQuery(() => mockQuery, []));
|
|
710
687
|
|
|
711
688
|
let queryResult: { id: string; name: string } | undefined;
|
|
712
689
|
await act(async () => {
|
|
@@ -721,7 +698,7 @@ describe("useLazyQuery", () => {
|
|
|
721
698
|
// Create a mock query that rejects
|
|
722
699
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
723
700
|
|
|
724
|
-
const { result } = renderHook(() => useLazyQuery(mockQuery));
|
|
701
|
+
const { result } = renderHook(() => useLazyQuery(() => mockQuery, []));
|
|
725
702
|
|
|
726
703
|
// Set error before execute
|
|
727
704
|
act(() => {
|
|
@@ -747,7 +724,7 @@ describe("useLazyQuery", () => {
|
|
|
747
724
|
},
|
|
748
725
|
} as unknown as QueryResult<{ id: string }>;
|
|
749
726
|
|
|
750
|
-
const { result } = renderHook(() => useLazyQuery(mockQuery));
|
|
727
|
+
const { result } = renderHook(() => useLazyQuery(() => mockQuery, []));
|
|
751
728
|
|
|
752
729
|
await act(async () => {
|
|
753
730
|
try {
|
|
@@ -766,7 +743,7 @@ describe("useLazyQuery", () => {
|
|
|
766
743
|
name: "John",
|
|
767
744
|
});
|
|
768
745
|
|
|
769
|
-
const { result } = renderHook(() => useLazyQuery(mockQuery));
|
|
746
|
+
const { result } = renderHook(() => useLazyQuery(() => mockQuery, []));
|
|
770
747
|
|
|
771
748
|
await act(async () => {
|
|
772
749
|
await result.current.execute();
|
|
@@ -783,8 +760,8 @@ describe("useLazyQuery", () => {
|
|
|
783
760
|
expect(result.current.loading).toBe(false);
|
|
784
761
|
});
|
|
785
762
|
|
|
786
|
-
test("handles null query", async () => {
|
|
787
|
-
const { result } = renderHook(() => useLazyQuery(null));
|
|
763
|
+
test("handles null query from accessor", async () => {
|
|
764
|
+
const { result } = renderHook(() => useLazyQuery(() => null, []));
|
|
788
765
|
|
|
789
766
|
let queryResult: any;
|
|
790
767
|
await act(async () => {
|
|
@@ -796,8 +773,8 @@ describe("useLazyQuery", () => {
|
|
|
796
773
|
expect(result.current.loading).toBe(false);
|
|
797
774
|
});
|
|
798
775
|
|
|
799
|
-
test("handles undefined query", async () => {
|
|
800
|
-
const { result } = renderHook(() => useLazyQuery(undefined));
|
|
776
|
+
test("handles undefined query from accessor", async () => {
|
|
777
|
+
const { result } = renderHook(() => useLazyQuery(() => undefined, []));
|
|
801
778
|
|
|
802
779
|
let queryResult: any;
|
|
803
780
|
await act(async () => {
|
|
@@ -809,36 +786,6 @@ describe("useLazyQuery", () => {
|
|
|
809
786
|
expect(result.current.loading).toBe(false);
|
|
810
787
|
});
|
|
811
788
|
|
|
812
|
-
test("handles accessor function returning query", async () => {
|
|
813
|
-
const mockQuery = createMockQueryResult<{ id: string; name: string }>({
|
|
814
|
-
id: "123",
|
|
815
|
-
name: "John",
|
|
816
|
-
});
|
|
817
|
-
const accessor = () => mockQuery;
|
|
818
|
-
|
|
819
|
-
const { result } = renderHook(() => useLazyQuery(accessor));
|
|
820
|
-
|
|
821
|
-
let queryResult: { id: string; name: string } | undefined;
|
|
822
|
-
await act(async () => {
|
|
823
|
-
queryResult = await result.current.execute();
|
|
824
|
-
});
|
|
825
|
-
|
|
826
|
-
expect(queryResult).toEqual({ id: "123", name: "John" });
|
|
827
|
-
});
|
|
828
|
-
|
|
829
|
-
test("handles accessor function returning null", async () => {
|
|
830
|
-
const accessor = () => null;
|
|
831
|
-
|
|
832
|
-
const { result } = renderHook(() => useLazyQuery(accessor));
|
|
833
|
-
|
|
834
|
-
let queryResult: any;
|
|
835
|
-
await act(async () => {
|
|
836
|
-
queryResult = await result.current.execute();
|
|
837
|
-
});
|
|
838
|
-
|
|
839
|
-
expect(queryResult).toBe(null);
|
|
840
|
-
});
|
|
841
|
-
|
|
842
789
|
test("uses latest query value from accessor on execute", async () => {
|
|
843
790
|
let currentValue = "first";
|
|
844
791
|
const mockQuery1 = createMockQueryResult<string>("first");
|
|
@@ -846,7 +793,7 @@ describe("useLazyQuery", () => {
|
|
|
846
793
|
|
|
847
794
|
const accessor = () => (currentValue === "first" ? mockQuery1 : mockQuery2);
|
|
848
795
|
|
|
849
|
-
const { result } = renderHook(() => useLazyQuery(accessor));
|
|
796
|
+
const { result } = renderHook(() => useLazyQuery(accessor, []));
|
|
850
797
|
|
|
851
798
|
// First execute
|
|
852
799
|
let queryResult1: string | undefined;
|
|
@@ -871,7 +818,7 @@ describe("useLazyQuery", () => {
|
|
|
871
818
|
test("shows loading state during execution", async () => {
|
|
872
819
|
const mockQuery = createMockQueryResult<{ id: string }>();
|
|
873
820
|
|
|
874
|
-
const { result } = renderHook(() => useLazyQuery(mockQuery));
|
|
821
|
+
const { result } = renderHook(() => useLazyQuery(() => mockQuery, []));
|
|
875
822
|
|
|
876
823
|
// Execute and set value
|
|
877
824
|
let executePromise: Promise<{ id: string }>;
|
|
@@ -888,7 +835,7 @@ describe("useLazyQuery", () => {
|
|
|
888
835
|
test("does not update state after unmount", async () => {
|
|
889
836
|
const mockQuery = createMockQueryResult<{ id: string; name: string }>();
|
|
890
837
|
|
|
891
|
-
const { result, unmount } = renderHook(() => useLazyQuery(mockQuery));
|
|
838
|
+
const { result, unmount } = renderHook(() => useLazyQuery(() => mockQuery, []));
|
|
892
839
|
|
|
893
840
|
// Start execution, unmount, then resolve
|
|
894
841
|
const executePromise = result.current.execute();
|
|
@@ -897,72 +844,83 @@ describe("useLazyQuery", () => {
|
|
|
897
844
|
// Resolve after unmount
|
|
898
845
|
await act(async () => {
|
|
899
846
|
mockQuery._setValue({ id: "123", name: "John" });
|
|
900
|
-
|
|
847
|
+
try {
|
|
848
|
+
await executePromise;
|
|
849
|
+
} catch {
|
|
850
|
+
// May reject due to unmount
|
|
851
|
+
}
|
|
901
852
|
});
|
|
902
853
|
|
|
903
854
|
// Test passes if no error is thrown (state update after unmount would cause error)
|
|
904
855
|
expect(true).toBe(true);
|
|
905
856
|
});
|
|
906
857
|
|
|
907
|
-
test("
|
|
908
|
-
|
|
909
|
-
const
|
|
858
|
+
test("can execute multiple times", async () => {
|
|
859
|
+
let count = 0;
|
|
860
|
+
const createQuery = () => {
|
|
861
|
+
count++;
|
|
862
|
+
return createMockQueryResult<{ count: number }>({ count });
|
|
863
|
+
};
|
|
910
864
|
|
|
911
|
-
const { result
|
|
912
|
-
initialProps: { query: mockQuery1 },
|
|
913
|
-
});
|
|
865
|
+
const { result } = renderHook(() => useLazyQuery(() => createQuery(), []));
|
|
914
866
|
|
|
915
|
-
// First execution
|
|
867
|
+
// First execution
|
|
916
868
|
await act(async () => {
|
|
917
|
-
|
|
918
|
-
mockQuery1._setError(new Error("Query failed"));
|
|
919
|
-
try {
|
|
920
|
-
await executePromise;
|
|
921
|
-
} catch {
|
|
922
|
-
// Expected error
|
|
923
|
-
}
|
|
869
|
+
await result.current.execute();
|
|
924
870
|
});
|
|
925
871
|
|
|
926
|
-
expect(result.current.
|
|
927
|
-
|
|
928
|
-
// Switch to successful query
|
|
929
|
-
rerender({ query: mockQuery2 });
|
|
872
|
+
expect(result.current.data?.count).toBe(1);
|
|
930
873
|
|
|
931
|
-
// Second execution
|
|
874
|
+
// Second execution
|
|
932
875
|
await act(async () => {
|
|
933
876
|
await result.current.execute();
|
|
934
877
|
});
|
|
935
878
|
|
|
936
|
-
expect(result.current.
|
|
937
|
-
expect(result.current.data).toEqual({ id: "123" });
|
|
879
|
+
expect(result.current.data?.count).toBe(2);
|
|
938
880
|
});
|
|
939
881
|
|
|
940
|
-
test("
|
|
941
|
-
const
|
|
942
|
-
|
|
882
|
+
test("Route + Params pattern works", async () => {
|
|
883
|
+
const mockQuery = createMockQueryResult<{ id: string; name: string }>({
|
|
884
|
+
id: "123",
|
|
885
|
+
name: "John",
|
|
886
|
+
});
|
|
887
|
+
const route = (_params: { id: string }) => mockQuery;
|
|
943
888
|
|
|
944
|
-
const { result
|
|
945
|
-
|
|
889
|
+
const { result } = renderHook(() => useLazyQuery(route, { id: "123" }));
|
|
890
|
+
|
|
891
|
+
await act(async () => {
|
|
892
|
+
await result.current.execute();
|
|
946
893
|
});
|
|
947
894
|
|
|
948
|
-
|
|
895
|
+
expect(result.current.data).toEqual({ id: "123", name: "John" });
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
test("Route + Params with null route", async () => {
|
|
899
|
+
const { result } = renderHook(() => useLazyQuery(null, { id: "123" }));
|
|
900
|
+
|
|
949
901
|
await act(async () => {
|
|
950
|
-
|
|
951
|
-
mockQuery1._setValue({ count: 1 });
|
|
952
|
-
await executePromise;
|
|
902
|
+
await result.current.execute();
|
|
953
903
|
});
|
|
954
904
|
|
|
955
|
-
expect(result.current.data
|
|
905
|
+
expect(result.current.data).toBe(null);
|
|
906
|
+
});
|
|
956
907
|
|
|
957
|
-
|
|
958
|
-
|
|
908
|
+
test("select transforms the data", async () => {
|
|
909
|
+
const mockQuery = createMockQueryResult<{ id: string; name: string }>({
|
|
910
|
+
id: "123",
|
|
911
|
+
name: "John",
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
const { result } = renderHook(() =>
|
|
915
|
+
useLazyQuery(() => mockQuery, [], {
|
|
916
|
+
select: (data) => data.name.toUpperCase(),
|
|
917
|
+
}),
|
|
918
|
+
);
|
|
959
919
|
|
|
960
920
|
await act(async () => {
|
|
961
|
-
|
|
962
|
-
mockQuery2._setValue({ count: 2 });
|
|
963
|
-
await executePromise;
|
|
921
|
+
await result.current.execute();
|
|
964
922
|
});
|
|
965
923
|
|
|
966
|
-
expect(result.current.data
|
|
924
|
+
expect(result.current.data).toBe("JOHN");
|
|
967
925
|
});
|
|
968
926
|
});
|