atomirx 0.0.7 → 0.1.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 (138) hide show
  1. package/README.md +198 -2234
  2. package/bin/cli.js +90 -0
  3. package/dist/core/derived.d.ts +2 -2
  4. package/dist/core/effect.d.ts +3 -2
  5. package/dist/core/onCreateHook.d.ts +15 -2
  6. package/dist/core/onErrorHook.d.ts +4 -1
  7. package/dist/core/pool.d.ts +78 -0
  8. package/dist/core/pool.test.d.ts +1 -0
  9. package/dist/core/select-boolean.test.d.ts +1 -0
  10. package/dist/core/select-pool.test.d.ts +1 -0
  11. package/dist/core/select.d.ts +278 -86
  12. package/dist/core/types.d.ts +233 -1
  13. package/dist/core/withAbort.d.ts +95 -0
  14. package/dist/core/withReady.d.ts +3 -3
  15. package/dist/devtools/constants.d.ts +41 -0
  16. package/dist/devtools/index.cjs +1 -0
  17. package/dist/devtools/index.d.ts +29 -0
  18. package/dist/devtools/index.js +429 -0
  19. package/dist/devtools/registry.d.ts +98 -0
  20. package/dist/devtools/registry.test.d.ts +1 -0
  21. package/dist/devtools/setup.d.ts +61 -0
  22. package/dist/devtools/types.d.ts +311 -0
  23. package/dist/index-BZEnfIcB.cjs +1 -0
  24. package/dist/index-BbPZhsDl.js +1653 -0
  25. package/dist/index.cjs +1 -1
  26. package/dist/index.d.ts +4 -3
  27. package/dist/index.js +18 -14
  28. package/dist/onDispatchHook-C8yLzr-o.cjs +1 -0
  29. package/dist/onDispatchHook-SKbiIUaJ.js +5 -0
  30. package/dist/onErrorHook-BGGy3tqK.js +38 -0
  31. package/dist/onErrorHook-DHBASmYw.cjs +1 -0
  32. package/dist/react/index.cjs +1 -30
  33. package/dist/react/index.js +206 -791
  34. package/dist/react/onDispatchHook.d.ts +106 -0
  35. package/dist/react/useAction.d.ts +4 -1
  36. package/dist/react-devtools/DevToolsPanel.d.ts +93 -0
  37. package/dist/react-devtools/EntityDetails.d.ts +10 -0
  38. package/dist/react-devtools/EntityList.d.ts +15 -0
  39. package/dist/react-devtools/LogList.d.ts +12 -0
  40. package/dist/react-devtools/hooks.d.ts +50 -0
  41. package/dist/react-devtools/index.cjs +1 -0
  42. package/dist/react-devtools/index.d.ts +31 -0
  43. package/dist/react-devtools/index.js +1589 -0
  44. package/dist/react-devtools/styles.d.ts +148 -0
  45. package/package.json +26 -2
  46. package/skills/atomirx/SKILL.md +456 -0
  47. package/skills/atomirx/references/async-patterns.md +188 -0
  48. package/skills/atomirx/references/atom-patterns.md +238 -0
  49. package/skills/atomirx/references/deferred-loading.md +191 -0
  50. package/skills/atomirx/references/derived-patterns.md +428 -0
  51. package/skills/atomirx/references/effect-patterns.md +426 -0
  52. package/skills/atomirx/references/error-handling.md +140 -0
  53. package/skills/atomirx/references/hooks.md +322 -0
  54. package/skills/atomirx/references/pool-patterns.md +229 -0
  55. package/skills/atomirx/references/react-integration.md +411 -0
  56. package/skills/atomirx/references/rules.md +407 -0
  57. package/skills/atomirx/references/select-context.md +309 -0
  58. package/skills/atomirx/references/service-template.md +172 -0
  59. package/skills/atomirx/references/store-template.md +205 -0
  60. package/skills/atomirx/references/testing-patterns.md +431 -0
  61. package/coverage/base.css +0 -224
  62. package/coverage/block-navigation.js +0 -87
  63. package/coverage/clover.xml +0 -1440
  64. package/coverage/coverage-final.json +0 -14
  65. package/coverage/favicon.png +0 -0
  66. package/coverage/index.html +0 -131
  67. package/coverage/prettify.css +0 -1
  68. package/coverage/prettify.js +0 -2
  69. package/coverage/sort-arrow-sprite.png +0 -0
  70. package/coverage/sorter.js +0 -210
  71. package/coverage/src/core/atom.ts.html +0 -889
  72. package/coverage/src/core/batch.ts.html +0 -223
  73. package/coverage/src/core/define.ts.html +0 -805
  74. package/coverage/src/core/emitter.ts.html +0 -919
  75. package/coverage/src/core/equality.ts.html +0 -631
  76. package/coverage/src/core/hook.ts.html +0 -460
  77. package/coverage/src/core/index.html +0 -281
  78. package/coverage/src/core/isAtom.ts.html +0 -100
  79. package/coverage/src/core/isPromiseLike.ts.html +0 -133
  80. package/coverage/src/core/onCreateHook.ts.html +0 -138
  81. package/coverage/src/core/scheduleNotifyHook.ts.html +0 -94
  82. package/coverage/src/core/types.ts.html +0 -523
  83. package/coverage/src/core/withUse.ts.html +0 -253
  84. package/coverage/src/index.html +0 -116
  85. package/coverage/src/index.ts.html +0 -106
  86. package/dist/index-CBVj1kSj.js +0 -1350
  87. package/dist/index-Cxk9v0um.cjs +0 -1
  88. package/scripts/publish.js +0 -198
  89. package/src/core/atom.test.ts +0 -633
  90. package/src/core/atom.ts +0 -311
  91. package/src/core/atomState.test.ts +0 -342
  92. package/src/core/atomState.ts +0 -256
  93. package/src/core/batch.test.ts +0 -257
  94. package/src/core/batch.ts +0 -172
  95. package/src/core/define.test.ts +0 -343
  96. package/src/core/define.ts +0 -243
  97. package/src/core/derived.test.ts +0 -1215
  98. package/src/core/derived.ts +0 -450
  99. package/src/core/effect.test.ts +0 -802
  100. package/src/core/effect.ts +0 -188
  101. package/src/core/emitter.test.ts +0 -364
  102. package/src/core/emitter.ts +0 -392
  103. package/src/core/equality.test.ts +0 -392
  104. package/src/core/equality.ts +0 -182
  105. package/src/core/getAtomState.ts +0 -69
  106. package/src/core/hook.test.ts +0 -227
  107. package/src/core/hook.ts +0 -177
  108. package/src/core/isAtom.ts +0 -27
  109. package/src/core/isPromiseLike.test.ts +0 -72
  110. package/src/core/isPromiseLike.ts +0 -16
  111. package/src/core/onCreateHook.ts +0 -107
  112. package/src/core/onErrorHook.test.ts +0 -350
  113. package/src/core/onErrorHook.ts +0 -52
  114. package/src/core/promiseCache.test.ts +0 -241
  115. package/src/core/promiseCache.ts +0 -284
  116. package/src/core/scheduleNotifyHook.ts +0 -53
  117. package/src/core/select.ts +0 -729
  118. package/src/core/selector.test.ts +0 -799
  119. package/src/core/types.ts +0 -389
  120. package/src/core/withReady.test.ts +0 -534
  121. package/src/core/withReady.ts +0 -191
  122. package/src/core/withUse.test.ts +0 -249
  123. package/src/core/withUse.ts +0 -56
  124. package/src/index.test.ts +0 -80
  125. package/src/index.ts +0 -65
  126. package/src/react/index.ts +0 -21
  127. package/src/react/rx.test.tsx +0 -571
  128. package/src/react/rx.tsx +0 -531
  129. package/src/react/strictModeTest.tsx +0 -71
  130. package/src/react/useAction.test.ts +0 -987
  131. package/src/react/useAction.ts +0 -607
  132. package/src/react/useSelector.test.ts +0 -182
  133. package/src/react/useSelector.ts +0 -292
  134. package/src/react/useStable.test.ts +0 -553
  135. package/src/react/useStable.ts +0 -288
  136. package/tsconfig.json +0 -9
  137. package/v2.md +0 -725
  138. package/vite.config.ts +0 -39
@@ -1,534 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { withReady } from "./withReady";
3
- import { atom } from "./atom";
4
- import { select } from "./select";
5
- describe("withReady", () => {
6
- describe("basic functionality", () => {
7
- it("should add ready method to context", () => {
8
- select((context) => {
9
- const enhanced = context.use(withReady());
10
- expect(typeof enhanced.ready).toBe("function");
11
- return null;
12
- });
13
- });
14
-
15
- it("should preserve original context methods", () => {
16
- select((context) => {
17
- const enhanced = context.use(withReady());
18
- expect(typeof enhanced.read).toBe("function");
19
- expect(typeof enhanced.all).toBe("function");
20
- expect(typeof enhanced.any).toBe("function");
21
- expect(typeof enhanced.race).toBe("function");
22
- expect(typeof enhanced.settled).toBe("function");
23
- expect(typeof enhanced.safe).toBe("function");
24
- expect(typeof enhanced.use).toBe("function");
25
- return null;
26
- });
27
- });
28
- });
29
-
30
- describe("ready() with non-null values", () => {
31
- it("should return value when atom has non-null value", () => {
32
- const count$ = atom(42);
33
-
34
- const result = select((context) => {
35
- const ctx = context.use(withReady());
36
- return ctx.ready(count$);
37
- });
38
-
39
- expect(result.value).toBe(42);
40
- expect(result.error).toBeUndefined();
41
- expect(result.promise).toBeUndefined();
42
- });
43
-
44
- it("should return value when atom has zero", () => {
45
- const count$ = atom(0);
46
-
47
- const result = select((context) => {
48
- const ctx = context.use(withReady());
49
- return ctx.ready(count$);
50
- });
51
-
52
- expect(result.value).toBe(0);
53
- });
54
-
55
- it("should return value when atom has empty string", () => {
56
- const str$ = atom("");
57
-
58
- const result = select((context) => {
59
- const ctx = context.use(withReady());
60
- return ctx.ready(str$);
61
- });
62
-
63
- expect(result.value).toBe("");
64
- });
65
-
66
- it("should return value when atom has false", () => {
67
- const bool$ = atom(false);
68
-
69
- const result = select((context) => {
70
- const ctx = context.use(withReady());
71
- return ctx.ready(bool$);
72
- });
73
-
74
- expect(result.value).toBe(false);
75
- });
76
-
77
- it("should return value when atom has object", () => {
78
- const obj$ = atom({ name: "test" });
79
-
80
- const result = select((context) => {
81
- const ctx = context.use(withReady());
82
- return ctx.ready(obj$);
83
- });
84
-
85
- expect(result.value).toEqual({ name: "test" });
86
- });
87
- });
88
-
89
- describe("ready() with null/undefined values", () => {
90
- it("should throw never-resolve promise when atom value is null", () => {
91
- const nullable$ = atom<string | null>(null);
92
-
93
- const result = select((context) => {
94
- const ctx = context.use(withReady());
95
- return ctx.ready(nullable$);
96
- });
97
-
98
- expect(result.value).toBeUndefined();
99
- expect(result.error).toBeUndefined();
100
- expect(result.promise).toBeInstanceOf(Promise);
101
- });
102
-
103
- it("should throw never-resolve promise when atom value is undefined", () => {
104
- const undefinedAtom$ = atom<string | undefined>(undefined);
105
-
106
- const result = select((context) => {
107
- const ctx = context.use(withReady());
108
- return ctx.ready(undefinedAtom$);
109
- });
110
-
111
- expect(result.value).toBeUndefined();
112
- expect(result.error).toBeUndefined();
113
- expect(result.promise).toBeInstanceOf(Promise);
114
- });
115
- });
116
-
117
- describe("ready() with selector", () => {
118
- it("should apply selector and return result when non-null", () => {
119
- const user$ = atom({ id: 1, name: "John" });
120
-
121
- const result = select((context) => {
122
- const ctx = context.use(withReady());
123
- return ctx.ready(user$, (user) => user.name);
124
- });
125
-
126
- expect(result.value).toBe("John");
127
- });
128
-
129
- it("should throw never-resolve promise when selector returns null", () => {
130
- const user$ = atom<{ id: number; email: string | null }>({
131
- id: 1,
132
- email: null,
133
- });
134
-
135
- const result = select((context) => {
136
- const ctx = context.use(withReady());
137
- return ctx.ready(user$, (user) => user.email);
138
- });
139
-
140
- expect(result.value).toBeUndefined();
141
- expect(result.promise).toBeInstanceOf(Promise);
142
- });
143
-
144
- it("should throw never-resolve promise when selector returns undefined", () => {
145
- const data$ = atom<{ value?: string }>({});
146
-
147
- const result = select((context) => {
148
- const ctx = context.use(withReady());
149
- return ctx.ready(data$, (data) => data.value);
150
- });
151
-
152
- expect(result.value).toBeUndefined();
153
- expect(result.promise).toBeInstanceOf(Promise);
154
- });
155
-
156
- it("should return zero from selector", () => {
157
- const data$ = atom({ count: 0 });
158
-
159
- const result = select((context) => {
160
- const ctx = context.use(withReady());
161
- return ctx.ready(data$, (data) => data.count);
162
- });
163
-
164
- expect(result.value).toBe(0);
165
- });
166
-
167
- it("should return empty string from selector", () => {
168
- const data$ = atom({ name: "" });
169
-
170
- const result = select((context) => {
171
- const ctx = context.use(withReady());
172
- return ctx.ready(data$, (data) => data.name);
173
- });
174
-
175
- expect(result.value).toBe("");
176
- });
177
- });
178
-
179
- describe("dependency tracking", () => {
180
- it("should track atom as dependency", () => {
181
- const count$ = atom(42);
182
-
183
- const result = select((context) => {
184
- const ctx = context.use(withReady());
185
- return ctx.ready(count$);
186
- });
187
-
188
- expect(result.dependencies.has(count$)).toBe(true);
189
- });
190
-
191
- it("should track atom as dependency even when throwing promise", () => {
192
- const nullable$ = atom<string | null>(null);
193
-
194
- const result = select((context) => {
195
- const ctx = context.use(withReady());
196
- return ctx.ready(nullable$);
197
- });
198
-
199
- expect(result.dependencies.has(nullable$)).toBe(true);
200
- });
201
- });
202
-
203
- describe("never-resolve promise behavior", () => {
204
- it("should return a promise that never resolves", async () => {
205
- const nullable$ = atom<string | null>(null);
206
-
207
- const result = select((context) => {
208
- const ctx = context.use(withReady());
209
- return ctx.ready(nullable$);
210
- });
211
-
212
- // The promise should never resolve
213
- // We test this by racing with a timeout
214
- const timeoutPromise = new Promise<"timeout">((resolve) =>
215
- setTimeout(() => resolve("timeout"), 50)
216
- );
217
-
218
- const raceResult = await Promise.race([result.promise, timeoutPromise]);
219
- expect(raceResult).toBe("timeout");
220
- });
221
- });
222
-
223
- describe("ready() with function", () => {
224
- it("should return value when function returns non-null value", () => {
225
- const result = select((context) => {
226
- const ctx = context.use(withReady());
227
- return ctx.ready(() => 42);
228
- });
229
-
230
- expect(result.value).toBe(42);
231
- expect(result.error).toBeUndefined();
232
- expect(result.promise).toBeUndefined();
233
- });
234
-
235
- it("should return zero from function", () => {
236
- const result = select((context) => {
237
- const ctx = context.use(withReady());
238
- return ctx.ready(() => 0);
239
- });
240
-
241
- expect(result.value).toBe(0);
242
- });
243
-
244
- it("should return false from function", () => {
245
- const result = select((context) => {
246
- const ctx = context.use(withReady());
247
- return ctx.ready(() => false);
248
- });
249
-
250
- expect(result.value).toBe(false);
251
- });
252
-
253
- it("should return empty string from function", () => {
254
- const result = select((context) => {
255
- const ctx = context.use(withReady());
256
- return ctx.ready(() => "");
257
- });
258
-
259
- expect(result.value).toBe("");
260
- });
261
-
262
- it("should return object from function", () => {
263
- const result = select((context) => {
264
- const ctx = context.use(withReady());
265
- return ctx.ready(() => ({ name: "test" }));
266
- });
267
-
268
- expect(result.value).toEqual({ name: "test" });
269
- });
270
-
271
- it("should throw never-resolve promise when function returns null", () => {
272
- const result = select((context) => {
273
- const ctx = context.use(withReady());
274
- return ctx.ready(() => null);
275
- });
276
-
277
- expect(result.value).toBeUndefined();
278
- expect(result.error).toBeUndefined();
279
- expect(result.promise).toBeInstanceOf(Promise);
280
- });
281
-
282
- it("should throw never-resolve promise when function returns undefined", () => {
283
- const result = select((context) => {
284
- const ctx = context.use(withReady());
285
- return ctx.ready(() => undefined);
286
- });
287
-
288
- expect(result.value).toBeUndefined();
289
- expect(result.error).toBeUndefined();
290
- expect(result.promise).toBeInstanceOf(Promise);
291
- });
292
-
293
- it("should throw error when function returns a pending promise", () => {
294
- const pendingPromise = new Promise<string>(() => {
295
- // Never resolves - stays pending
296
- });
297
-
298
- const result = select((context) => {
299
- const ctx = context.use(withReady());
300
- return ctx.ready(() => pendingPromise);
301
- });
302
-
303
- expect(result.value).toBeUndefined();
304
- expect(result.error).toBeInstanceOf(Error);
305
- expect((result.error as Error).message).toBe(
306
- "ready(callback) overload does not support async callbacks. Use ready(atom, selector?) instead."
307
- );
308
- });
309
-
310
- it("should throw error when function returns a resolved promise", () => {
311
- const resolvedPromise = Promise.resolve("async result");
312
-
313
- const result = select((context) => {
314
- const ctx = context.use(withReady());
315
- return ctx.ready(() => resolvedPromise);
316
- });
317
-
318
- expect(result.value).toBeUndefined();
319
- expect(result.error).toBeInstanceOf(Error);
320
- expect((result.error as Error).message).toBe(
321
- "ready(callback) overload does not support async callbacks. Use ready(atom, selector?) instead."
322
- );
323
- });
324
-
325
- it("should throw error when function returns a rejected promise", () => {
326
- const testError = new Error("async error");
327
- const rejectedPromise = Promise.reject(testError);
328
-
329
- // Prevent unhandled rejection warning
330
- rejectedPromise.catch(() => {});
331
-
332
- const result = select((context) => {
333
- const ctx = context.use(withReady());
334
- return ctx.ready(() => rejectedPromise);
335
- });
336
-
337
- // Should throw the "async not supported" error, not the rejection error
338
- expect(result.value).toBeUndefined();
339
- expect(result.error).toBeInstanceOf(Error);
340
- expect((result.error as Error).message).toBe(
341
- "ready(callback) overload does not support async callbacks. Use ready(atom, selector?) instead."
342
- );
343
- });
344
-
345
- it("should throw error when function returns a promise-like object", () => {
346
- // Custom thenable (promise-like)
347
- const thenable = {
348
- then(resolve: (value: string) => void) {
349
- resolve("thenable result");
350
- },
351
- };
352
-
353
- const result = select((context) => {
354
- const ctx = context.use(withReady());
355
- return ctx.ready(() => thenable);
356
- });
357
-
358
- expect(result.value).toBeUndefined();
359
- expect(result.error).toBeInstanceOf(Error);
360
- expect((result.error as Error).message).toBe(
361
- "ready(callback) overload does not support async callbacks. Use ready(atom, selector?) instead."
362
- );
363
- });
364
-
365
- it("should propagate error when function throws synchronously", () => {
366
- const testError = new Error("sync error");
367
-
368
- const result = select((context) => {
369
- const ctx = context.use(withReady());
370
- return ctx.ready(() => {
371
- throw testError;
372
- });
373
- });
374
-
375
- expect(result.value).toBeUndefined();
376
- expect(result.error).toBe(testError);
377
- expect(result.promise).toBeUndefined();
378
- });
379
-
380
- it("should work with function that reads atoms", () => {
381
- const count$ = atom(10);
382
- const multiplier$ = atom(2);
383
-
384
- const result = select((context) => {
385
- const ctx = context.use(withReady());
386
- return ctx.ready(() => {
387
- const count = ctx.read(count$);
388
- const mult = ctx.read(multiplier$);
389
- return count * mult;
390
- });
391
- });
392
-
393
- expect(result.value).toBe(20);
394
- });
395
- });
396
-
397
- describe("ready() with async selector", () => {
398
- it("should suspend when selector returns a pending promise", () => {
399
- const data$ = atom({ id: 1 });
400
- const pendingPromise = new Promise<string>(() => {
401
- // Never resolves - stays pending
402
- });
403
-
404
- const result = select((context) => {
405
- const ctx = context.use(withReady());
406
- return ctx.ready(data$, () => pendingPromise);
407
- });
408
-
409
- // Should suspend with the tracked promise
410
- expect(result.value).toBeUndefined();
411
- expect(result.error).toBeUndefined();
412
- expect(result.promise).toBeInstanceOf(Promise);
413
- });
414
-
415
- it("should return value when selector returns a resolved promise", async () => {
416
- const data$ = atom({ id: 1 });
417
- const resolvedPromise = Promise.resolve("async result");
418
-
419
- // First call to track the promise and trigger state tracking
420
- select((context) => {
421
- const ctx = context.use(withReady());
422
- return ctx.ready(data$, () => resolvedPromise);
423
- });
424
-
425
- // Wait for the promise .then() handlers to run and update cache
426
- await resolvedPromise;
427
- await new Promise<void>((r) => queueMicrotask(() => r()));
428
-
429
- // Second call - promise should now be fulfilled in cache
430
- const result = select((context) => {
431
- const ctx = context.use(withReady());
432
- return ctx.ready(data$, () => resolvedPromise);
433
- });
434
-
435
- expect(result.value).toBe("async result");
436
- expect(result.error).toBeUndefined();
437
- expect(result.promise).toBeUndefined();
438
- });
439
-
440
- it("should throw error when selector returns a rejected promise", async () => {
441
- const data$ = atom({ id: 1 });
442
- const testError = new Error("async error");
443
- const rejectedPromise = Promise.reject(testError);
444
-
445
- // Prevent unhandled rejection warning
446
- rejectedPromise.catch(() => {});
447
-
448
- // First call to track the promise
449
- select((context) => {
450
- const ctx = context.use(withReady());
451
- return ctx.ready(data$, () => rejectedPromise);
452
- });
453
-
454
- // Wait for the promise rejection handlers to run
455
- await new Promise<void>((r) => queueMicrotask(() => r()));
456
- await new Promise<void>((r) => queueMicrotask(() => r()));
457
-
458
- // Second call - promise should now be rejected in cache
459
- const result = select((context) => {
460
- const ctx = context.use(withReady());
461
- return ctx.ready(data$, () => rejectedPromise);
462
- });
463
-
464
- expect(result.value).toBeUndefined();
465
- expect(result.error).toBe(testError);
466
- expect(result.promise).toBeUndefined();
467
- });
468
-
469
- it("should return null when async selector resolves to null (bypasses null check)", async () => {
470
- const data$ = atom({ id: 1 });
471
- const resolvedToNull = Promise.resolve(null);
472
-
473
- // First call to track the promise
474
- select((context) => {
475
- const ctx = context.use(withReady());
476
- return ctx.ready(data$, () => resolvedToNull);
477
- });
478
-
479
- // Wait for the promise to be tracked as fulfilled
480
- await resolvedToNull;
481
- await new Promise<void>((r) => queueMicrotask(() => r()));
482
-
483
- // Second call - promise should now be fulfilled in cache
484
- const result = select((context) => {
485
- const ctx = context.use(withReady());
486
- return ctx.ready(data$, () => resolvedToNull);
487
- });
488
-
489
- // Async selectors bypass null/undefined checking - value is returned as-is
490
- expect(result.value).toBe(null);
491
- expect(result.error).toBeUndefined();
492
- expect(result.promise).toBeUndefined();
493
- });
494
-
495
- it("should return undefined when async selector resolves to undefined (bypasses undefined check)", async () => {
496
- const data$ = atom({ id: 1 });
497
- const resolvedToUndefined = Promise.resolve(undefined);
498
-
499
- // First call to track the promise
500
- select((context) => {
501
- const ctx = context.use(withReady());
502
- return ctx.ready(data$, () => resolvedToUndefined);
503
- });
504
-
505
- // Wait for the promise to be tracked as fulfilled
506
- await resolvedToUndefined;
507
- await new Promise<void>((r) => queueMicrotask(() => r()));
508
-
509
- // Second call - promise should now be fulfilled in cache
510
- const result = select((context) => {
511
- const ctx = context.use(withReady());
512
- return ctx.ready(data$, () => resolvedToUndefined);
513
- });
514
-
515
- // Async selectors bypass null/undefined checking - value is returned as-is
516
- expect(result.value).toBe(undefined);
517
- expect(result.error).toBeUndefined();
518
- expect(result.promise).toBeUndefined();
519
- });
520
-
521
- it("should track atom as dependency when using async selector", () => {
522
- const data$ = atom({ id: 1 });
523
- const pendingPromise = new Promise<string>(() => {});
524
-
525
- const result = select((context) => {
526
- const ctx = context.use(withReady());
527
- return ctx.ready(data$, () => pendingPromise);
528
- });
529
-
530
- // Dependency is tracked even when suspending
531
- expect(result.dependencies.has(data$)).toBe(true);
532
- });
533
- });
534
- });