@ersbeth/picoflow 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +10 -0
  2. package/SKILL.md +106 -0
  3. package/package.json +5 -1
  4. package/.gitlab-ci.yml +0 -24
  5. package/.vscode/settings.json +0 -5
  6. package/CHANGELOG.md +0 -94
  7. package/biome.json +0 -47
  8. package/docs/.vitepress/config.mts +0 -145
  9. package/docs/api/functions/array.md +0 -35
  10. package/docs/api/functions/constant.md +0 -33
  11. package/docs/api/functions/constantAsync.md +0 -69
  12. package/docs/api/functions/derivation.md +0 -34
  13. package/docs/api/functions/derivationAsync.md +0 -34
  14. package/docs/api/functions/from.md +0 -129
  15. package/docs/api/functions/isDisposable.md +0 -27
  16. package/docs/api/functions/map.md +0 -36
  17. package/docs/api/functions/signal.md +0 -21
  18. package/docs/api/functions/state.md +0 -67
  19. package/docs/api/functions/stateAsync.md +0 -69
  20. package/docs/api/functions/subscribe.md +0 -40
  21. package/docs/api/functions/writableDerivation.md +0 -33
  22. package/docs/api/functions/writableDerivationAsync.md +0 -34
  23. package/docs/api/index.md +0 -61
  24. package/docs/api/interfaces/FlowArray.md +0 -439
  25. package/docs/api/interfaces/FlowConstant.md +0 -220
  26. package/docs/api/interfaces/FlowConstantAsync.md +0 -221
  27. package/docs/api/interfaces/FlowDerivation.md +0 -241
  28. package/docs/api/interfaces/FlowDerivationAsync.md +0 -242
  29. package/docs/api/interfaces/FlowDisposable.md +0 -59
  30. package/docs/api/interfaces/FlowEffect.md +0 -64
  31. package/docs/api/interfaces/FlowMap.md +0 -374
  32. package/docs/api/interfaces/FlowObservable.md +0 -155
  33. package/docs/api/interfaces/FlowSignal.md +0 -156
  34. package/docs/api/interfaces/FlowState.md +0 -269
  35. package/docs/api/interfaces/FlowStateAsync.md +0 -268
  36. package/docs/api/interfaces/FlowSubscribable.md +0 -55
  37. package/docs/api/interfaces/FlowTracker.md +0 -61
  38. package/docs/api/interfaces/FlowValue.md +0 -222
  39. package/docs/api/interfaces/FlowWritableDerivation.md +0 -292
  40. package/docs/api/interfaces/FlowWritableDerivationAsync.md +0 -293
  41. package/docs/api/type-aliases/DerivationFunction.md +0 -28
  42. package/docs/api/type-aliases/DerivationFunctionAsync.md +0 -28
  43. package/docs/api/type-aliases/FlowArrayAction.md +0 -60
  44. package/docs/api/type-aliases/FlowDataTracker.md +0 -33
  45. package/docs/api/type-aliases/FlowMapAction.md +0 -48
  46. package/docs/api/type-aliases/FlowOnDataListener.md +0 -33
  47. package/docs/api/type-aliases/FlowOnErrorListener.md +0 -27
  48. package/docs/api/type-aliases/FlowOnPendingListener.md +0 -21
  49. package/docs/api/type-aliases/FlowReadonly.md +0 -22
  50. package/docs/api/type-aliases/InitFunction.md +0 -21
  51. package/docs/api/type-aliases/InitFunctionAsync.md +0 -21
  52. package/docs/api/type-aliases/NotPromise.md +0 -21
  53. package/docs/api/type-aliases/UpdateFunction.md +0 -27
  54. package/docs/api/type-aliases/UpdateFunctionAsync.md +0 -27
  55. package/docs/api/typedoc-sidebar.json +0 -65
  56. package/docs/examples/examples.md +0 -2311
  57. package/docs/examples/patterns.md +0 -649
  58. package/docs/guide/advanced/architecture.md +0 -1234
  59. package/docs/guide/advanced/disposal.md +0 -426
  60. package/docs/guide/advanced/migration-v1.md +0 -464
  61. package/docs/guide/advanced/migration-v2.md +0 -204
  62. package/docs/guide/advanced/solidjs.md +0 -135
  63. package/docs/guide/introduction/concepts.md +0 -57
  64. package/docs/guide/introduction/conventions.md +0 -30
  65. package/docs/guide/introduction/getting-started.md +0 -139
  66. package/docs/guide/introduction/lifecycle.md +0 -368
  67. package/docs/guide/primitives/array.md +0 -286
  68. package/docs/guide/primitives/constant.md +0 -207
  69. package/docs/guide/primitives/derivations.md +0 -281
  70. package/docs/guide/primitives/effects.md +0 -372
  71. package/docs/guide/primitives/map.md +0 -265
  72. package/docs/guide/primitives/overview.md +0 -92
  73. package/docs/guide/primitives/signal.md +0 -222
  74. package/docs/guide/primitives/state.md +0 -272
  75. package/docs/index.md +0 -47
  76. package/docs/public/logo.svg +0 -1
  77. package/src/api/base/flowDisposable.ts +0 -44
  78. package/src/api/base/flowObservable.ts +0 -28
  79. package/src/api/base/flowSubscribable.ts +0 -87
  80. package/src/api/base/flowTracker.ts +0 -7
  81. package/src/api/base/index.ts +0 -4
  82. package/src/api/index.ts +0 -2
  83. package/src/api/nodes/async/flowConstantAsync.ts +0 -36
  84. package/src/api/nodes/async/flowDerivationAsync.ts +0 -42
  85. package/src/api/nodes/async/flowStateAsync.ts +0 -47
  86. package/src/api/nodes/async/flowWritableDerivationAsync.ts +0 -33
  87. package/src/api/nodes/async/index.ts +0 -4
  88. package/src/api/nodes/collections/flowArray.ts +0 -155
  89. package/src/api/nodes/collections/flowMap.ts +0 -115
  90. package/src/api/nodes/collections/index.ts +0 -2
  91. package/src/api/nodes/flowEffect.ts +0 -42
  92. package/src/api/nodes/flowSignal.ts +0 -28
  93. package/src/api/nodes/flowValue.ts +0 -37
  94. package/src/api/nodes/index.ts +0 -7
  95. package/src/api/nodes/sync/flowConstant.ts +0 -33
  96. package/src/api/nodes/sync/flowDerivation.ts +0 -41
  97. package/src/api/nodes/sync/flowState.ts +0 -45
  98. package/src/api/nodes/sync/flowWritableDerivation.ts +0 -31
  99. package/src/api/nodes/sync/index.ts +0 -4
  100. package/src/api/nodes/utils.ts +0 -24
  101. package/src/base/disposable.ts +0 -18
  102. package/src/base/executionStack.ts +0 -42
  103. package/src/base/index.ts +0 -5
  104. package/src/base/node.ts +0 -98
  105. package/src/base/observable.ts +0 -92
  106. package/src/base/observer.ts +0 -51
  107. package/src/converters/index.ts +0 -1
  108. package/src/converters/solid.ts +0 -109
  109. package/src/index.ts +0 -2
  110. package/src/nodes/arrayNode.ts +0 -180
  111. package/src/nodes/effectNode.ts +0 -58
  112. package/src/nodes/index.ts +0 -7
  113. package/src/nodes/mapNode.ts +0 -125
  114. package/src/nodes/signalNode.ts +0 -19
  115. package/src/nodes/valueAsyncNode.ts +0 -85
  116. package/src/nodes/valueNode.ts +0 -148
  117. package/src/nodes/valueSyncNode.ts +0 -125
  118. package/src/schedulers/asyncResolver.ts +0 -78
  119. package/src/schedulers/asyncScheduler.ts +0 -66
  120. package/src/schedulers/index.ts +0 -4
  121. package/src/schedulers/pendingError.ts +0 -13
  122. package/src/schedulers/scheduler.ts +0 -9
  123. package/src/schedulers/syncResolver.ts +0 -69
  124. package/src/schedulers/syncScheduler.ts +0 -55
  125. package/test/base/pendingError.test.ts +0 -67
  126. package/test/converters/solid.derivation.browser.test.tsx +0 -69
  127. package/test/converters/solid.node.test.ts +0 -654
  128. package/test/converters/solid.state.browser.test.tsx +0 -1592
  129. package/test/reactivity/flowSignal.test.ts +0 -226
  130. package/test/reactivity/nodes/async/asyncScheduler/asyncResolver.test.ts +0 -593
  131. package/test/reactivity/nodes/async/asyncScheduler/asyncScheduler.test.ts +0 -317
  132. package/test/reactivity/nodes/async/flowConstantAsync.test.ts +0 -652
  133. package/test/reactivity/nodes/async/flowDerivation.test.ts +0 -898
  134. package/test/reactivity/nodes/async/flowDerivationAsync.test.ts +0 -1716
  135. package/test/reactivity/nodes/async/flowStateAsync.test.ts +0 -708
  136. package/test/reactivity/nodes/async/flowWritableDerivationAsync.test.ts +0 -614
  137. package/test/reactivity/nodes/collections/flowArray.asyncStates.test.ts +0 -1289
  138. package/test/reactivity/nodes/collections/flowArray.scalars.test.ts +0 -961
  139. package/test/reactivity/nodes/collections/flowArray.states.test.ts +0 -1035
  140. package/test/reactivity/nodes/collections/flowMap.asyncStates.test.ts +0 -960
  141. package/test/reactivity/nodes/collections/flowMap.scalars.test.ts +0 -775
  142. package/test/reactivity/nodes/collections/flowMap.states.test.ts +0 -958
  143. package/test/reactivity/nodes/sync/flowConstant.test.ts +0 -377
  144. package/test/reactivity/nodes/sync/flowDerivation.test.ts +0 -896
  145. package/test/reactivity/nodes/sync/flowState.test.ts +0 -341
  146. package/test/reactivity/nodes/sync/flowWritableDerivation.test.ts +0 -603
  147. package/test/vitest.d.ts +0 -10
  148. package/tsconfig.json +0 -37
  149. package/typedoc.json +0 -37
  150. package/vite.config.ts +0 -31
  151. package/vitest.browser.config.ts +0 -21
  152. package/vitest.config.ts +0 -17
@@ -1,1592 +0,0 @@
1
- import { cleanup, render } from "@solidjs/testing-library";
2
- import { type Component, createResource, ErrorBoundary, Match, Suspense, Switch } from "solid-js";
3
- import { beforeEach, describe, expect, it, vi } from "vitest";
4
- import { userEvent } from "vitest/browser";
5
- import { type FlowState, from, state, stateAsync } from "~";
6
-
7
- describe("solid converter", () => {
8
- beforeEach(() => {
9
- cleanup();
10
- });
11
-
12
- describe("initialization", () => {
13
- describe("happy path", () => {
14
- it("init-happy-path: should convert FlowState to SolidResource", async () => {
15
- const Comp: Component = () => {
16
- const $state = state(42);
17
- const $$state = from($state);
18
-
19
- return <div>{$$state()}</div>;
20
- };
21
-
22
- const { getByText } = render(() => <Comp />);
23
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
24
- });
25
-
26
- it("init-happy-path: should convert AsyncFlowState to SolidResource", async () => {
27
- const Comp: Component = () => {
28
- const $stateAsync = stateAsync(Promise.resolve(42));
29
- const $$stateAsync = from($stateAsync);
30
-
31
- return <div>{$$stateAsync()}</div>;
32
- };
33
-
34
- const { getByText } = render(() => <Comp />);
35
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
36
- });
37
-
38
- it("init-happy-path: should convert getter function to SolidResource", async () => {
39
- const Comp: Component = () => {
40
- const $a = state(10);
41
- const $b = state(20);
42
-
43
- const $$result = from((t) => $a.get(t) + $b.get(t));
44
-
45
- return <div>{$$result()}</div>;
46
- };
47
-
48
- const { getByText } = render(() => <Comp />);
49
-
50
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
51
- });
52
-
53
- it("init-happy-path: should convert async getter function to SolidResource", async () => {
54
- const Comp: Component = () => {
55
- const $a = stateAsync<number>(Promise.resolve(10));
56
- const $b = state(20);
57
-
58
- const $$result = from((t) => $a.get(t) + $b.get(t));
59
-
60
- return <div>{$$result()}</div>;
61
- };
62
-
63
- const { getByText } = render(() => <Comp />);
64
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
65
- });
66
- });
67
-
68
- describe("suspense", () => {
69
- describe("flag", () => {
70
- it("init-suspense-flag: should handle suspense in FlowStateAsync", async () => {
71
- const Comp: Component = () => {
72
- const $stateAsync = stateAsync<number>(Promise.resolve(42));
73
- const $$stateAsync = from($stateAsync);
74
-
75
- return (
76
- <Switch>
77
- <Match when={$$stateAsync.loading}>
78
- <div>Loading</div>
79
- </Match>
80
- <Match when={$$stateAsync()}>
81
- <div>{$$stateAsync()}</div>
82
- </Match>
83
- </Switch>
84
- );
85
- };
86
-
87
- const { getByText } = render(() => <Comp />);
88
-
89
- await expect.element(getByText("Loading")).toBeInTheDocument();
90
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
91
- });
92
-
93
- it("init-suspense-flag: should handle suspense in async getter function", async () => {
94
- const Comp: Component = () => {
95
- const $a = stateAsync<number>(Promise.resolve(10));
96
- const $b = state(20);
97
-
98
- const $$result = from((t) => $a.get(t) + $b.get(t));
99
-
100
- return (
101
- <Switch>
102
- <Match when={$$result.loading}>
103
- <div>Loading</div>
104
- </Match>
105
- <Match when={$$result()}>
106
- <div>{$$result()}</div>
107
- </Match>
108
- </Switch>
109
- );
110
- };
111
-
112
- const { getByText } = render(() => <Comp />);
113
-
114
- await expect.element(getByText("Loading")).toBeInTheDocument();
115
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
116
- });
117
- });
118
-
119
- describe("component", () => {
120
- it("init-suspense-component: should handle suspense in FlowState", async () => {
121
- const Comp: Component = () => {
122
- const $state = state<number>(42);
123
- const $$state = from($state);
124
-
125
- return (
126
- <Suspense fallback="Loading">
127
- <div>{$$state()}</div>
128
- </Suspense>
129
- );
130
- };
131
-
132
- const { getByText } = render(() => <Comp />);
133
-
134
- await expect.element(getByText("Loading")).toBeInTheDocument();
135
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
136
- });
137
-
138
- it("init-suspense-component: should handle suspense in AsyncFlowState", async () => {
139
- const Comp: Component = () => {
140
- const $stateAsync = stateAsync<number>(Promise.resolve(42));
141
- const $$stateAsync = from($stateAsync);
142
-
143
- return (
144
- <Suspense fallback="Loading">
145
- <div>{$$stateAsync()}</div>
146
- </Suspense>
147
- );
148
- };
149
-
150
- const { getByText } = render(() => <Comp />);
151
-
152
- await expect.element(getByText("Loading")).toBeInTheDocument();
153
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
154
- });
155
-
156
- it("init-suspense-component: should handle suspense in getter function", async () => {
157
- const Comp: Component = () => {
158
- const $a = state<number>(10);
159
- const $b = state(20);
160
-
161
- const $$result = from((t) => $a.get(t) + $b.get(t));
162
- return (
163
- <Suspense fallback="Loading">
164
- <div>{$$result()}</div>
165
- </Suspense>
166
- );
167
- };
168
-
169
- const { getByText } = render(() => <Comp />);
170
-
171
- await expect.element(getByText("Loading")).toBeInTheDocument();
172
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
173
- });
174
-
175
- it("init-suspense-component: should handle suspense in async getter function", async () => {
176
- const Comp: Component = () => {
177
- const $a = stateAsync<number>(Promise.resolve(10));
178
- const $b = state(20);
179
-
180
- const $$result = from((t) => $a.get(t) + $b.get(t));
181
- return (
182
- <Suspense fallback="Loading">
183
- <div>{$$result()}</div>
184
- </Suspense>
185
- );
186
- };
187
-
188
- const { getByText } = render(() => <Comp />);
189
-
190
- await expect.element(getByText("Loading")).toBeInTheDocument();
191
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
192
- });
193
- });
194
- });
195
-
196
- describe("error", () => {
197
- describe("flag", () => {
198
- it("init-error-flag: should handle error in FlowState", async () => {
199
- const Comp: Component = () => {
200
- const $state = state<number>(() => {
201
- throw new Error("Test error");
202
- });
203
- const $$state = from($state);
204
- return (
205
- <Switch>
206
- <Match when={$$state.error}>
207
- <div>Error</div>
208
- </Match>
209
- <Match when={$$state()}>
210
- <div>{$$state()}</div>
211
- </Match>
212
- </Switch>
213
- );
214
- };
215
-
216
- const { getByText } = render(() => <Comp />);
217
-
218
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
219
- });
220
-
221
- it("init-error-flag: should handle error in AsyncFlowState", async () => {
222
- const Comp: Component = () => {
223
- const $stateAsync = stateAsync<number>(Promise.reject(new Error("Test error")));
224
- const $$stateAsync = from($stateAsync);
225
-
226
- return (
227
- <Switch>
228
- <Match when={$$stateAsync.error}>
229
- <div>Error</div>
230
- </Match>
231
- <Match when={$$stateAsync()}>
232
- <div>{$$stateAsync()}</div>
233
- </Match>
234
- </Switch>
235
- );
236
- };
237
-
238
- const { getByText } = render(() => <Comp />);
239
-
240
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
241
- });
242
-
243
- it("init-error-flag: should handle error in getter function", async () => {
244
- const Comp: Component = () => {
245
- const $a = state<number>(() => {
246
- throw new Error("Test error");
247
- });
248
- const $b = state(20);
249
-
250
- const $$result = from((t) => $a.get(t) + $b.get(t));
251
-
252
- return (
253
- <Switch>
254
- <Match when={$$result.error}>
255
- <div>Error</div>
256
- </Match>
257
- <Match when={$$result()}>
258
- <div>{$$result()}</div>
259
- </Match>
260
- </Switch>
261
- );
262
- };
263
-
264
- const { getByText } = render(() => <Comp />);
265
-
266
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
267
- });
268
-
269
- it("init-error-flag: should handle error in async getter function", async () => {
270
- const Comp: Component = () => {
271
- const $a = stateAsync<number>(Promise.reject(new Error("Test error")));
272
- const $b = state(20);
273
-
274
- const $$result = from((t) => $a.get(t) + $b.get(t));
275
-
276
- return (
277
- <Switch>
278
- <Match when={$$result.error}>
279
- <div>Error</div>
280
- </Match>
281
- <Match when={$$result()}>
282
- <div>{$$result()}</div>
283
- </Match>
284
- </Switch>
285
- );
286
- };
287
-
288
- const { getByText } = render(() => <Comp />);
289
-
290
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
291
- });
292
- });
293
-
294
- describe("component", () => {
295
- it("init-error-component: should handle error in FlowState", async () => {
296
- const Comp: Component = () => {
297
- const $state = state<number>(() => {
298
- throw new Error("Test error");
299
- });
300
- const $$state = from($state);
301
-
302
- return (
303
- <ErrorBoundary fallback="Error">
304
- <div>{$$state()}</div>
305
- </ErrorBoundary>
306
- );
307
- };
308
-
309
- const { getByText } = render(() => <Comp />);
310
-
311
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
312
- });
313
-
314
- it("init-error-component: should handle error in AsyncFlowState", async () => {
315
- const Comp: Component = () => {
316
- const $stateAsync = stateAsync<number>(Promise.reject(new Error("Test error")));
317
- const $$stateAsync = from($stateAsync);
318
-
319
- return (
320
- <ErrorBoundary fallback="Error">
321
- <div>{$$stateAsync()}</div>
322
- </ErrorBoundary>
323
- );
324
- };
325
-
326
- const { getByText } = render(() => <Comp />);
327
-
328
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
329
- });
330
-
331
- it("init-error-component: should handle error in getter function", async () => {
332
- const Comp: Component = () => {
333
- const $a = state<number>(() => {
334
- throw new Error("Test error");
335
- });
336
- const $b = state(20);
337
-
338
- const $$result = from((t) => $a.get(t) + $b.get(t));
339
-
340
- return (
341
- <ErrorBoundary fallback="Error">
342
- <div>{$$result()}</div>
343
- </ErrorBoundary>
344
- );
345
- };
346
-
347
- const { getByText } = render(() => <Comp />);
348
-
349
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
350
- });
351
-
352
- it("init-error-component: should handle error in async getter function", async () => {
353
- const Comp: Component = () => {
354
- const $a = stateAsync<number>(Promise.reject(new Error("Test error")));
355
- const $b = state(20);
356
-
357
- const $$result = from((t) => $a.get(t) + $b.get(t));
358
-
359
- return (
360
- <ErrorBoundary fallback="Error">
361
- <div>{$$result()}</div>
362
- </ErrorBoundary>
363
- );
364
- };
365
-
366
- const { getByText } = render(() => <Comp />);
367
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
368
- });
369
- });
370
- });
371
-
372
- describe("suspense-error", () => {
373
- describe("flag", () => {
374
- it("init-suspense-error-flag: should handle suspense and error in AsyncFlowState", async () => {
375
- const Comp: Component = () => {
376
- const $stateAsync = stateAsync<number>(Promise.reject(new Error("Test error")));
377
- const $$stateAsync = from($stateAsync);
378
-
379
- return (
380
- <Switch>
381
- <Match when={$$stateAsync.error}>
382
- <div>Error</div>
383
- </Match>
384
- <Match when={$$stateAsync.loading}>
385
- <div>Loading</div>
386
- </Match>
387
- <Match when={$$stateAsync()}>
388
- <div>{$$stateAsync()}</div>
389
- </Match>
390
- </Switch>
391
- );
392
- };
393
-
394
- const { getByText } = render(() => <Comp />);
395
-
396
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
397
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
398
- });
399
-
400
- it("init-suspense-error-flag: should handle suspense and error in async getter function", async () => {
401
- const Comp: Component = () => {
402
- const $a = stateAsync<number>(Promise.reject(new Error("Test error")));
403
- const $b = state(20);
404
-
405
- const $$result = from((t) => $a.get(t) + $b.get(t));
406
-
407
- return (
408
- <Switch>
409
- <Match when={$$result.error}>
410
- <div>Error</div>
411
- </Match>
412
- <Match when={$$result.loading}>
413
- <div>Loading</div>
414
- </Match>
415
- <Match when={$$result()}>
416
- <div>{$$result()}</div>
417
- </Match>
418
- </Switch>
419
- );
420
- };
421
-
422
- const { getByText } = render(() => <Comp />);
423
-
424
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
425
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
426
- });
427
- });
428
-
429
- describe("component", () => {
430
- it("init-suspense-error-component: should handle suspense and error in FlowState", async () => {
431
- const Comp: Component = () => {
432
- const $state = state<number>(() => {
433
- throw new Error("Test error");
434
- });
435
- const $$state = from($state);
436
-
437
- return (
438
- <Suspense fallback="Loading">
439
- <ErrorBoundary fallback="Error">
440
- <div>{$$state()}</div>
441
- </ErrorBoundary>
442
- </Suspense>
443
- );
444
- };
445
-
446
- const { getByText } = render(() => <Comp />);
447
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
448
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
449
- });
450
-
451
- it("init-suspense-error-component: should handle suspense and error in AsyncFlowState", async () => {
452
- const Comp: Component = () => {
453
- const $stateAsync = stateAsync<number>(Promise.reject(new Error("Test error")));
454
- const $$stateAsync = from($stateAsync);
455
-
456
- return (
457
- <Suspense fallback="Loading">
458
- <ErrorBoundary fallback="Error">
459
- <div>{$$stateAsync()}</div>
460
- </ErrorBoundary>
461
- </Suspense>
462
- );
463
- };
464
-
465
- const { getByText } = render(() => <Comp />);
466
-
467
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
468
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
469
- });
470
-
471
- it("init-suspense-error-component: should handle suspense and error in getter function", async () => {
472
- const Comp: Component = () => {
473
- const $a = state<number>(() => {
474
- throw new Error("Test error");
475
- });
476
- const $b = state(20);
477
-
478
- const $$result = from((t) => $a.get(t) + $b.get(t));
479
-
480
- return (
481
- <Suspense fallback="Loading">
482
- <ErrorBoundary fallback="Error">
483
- <div>{$$result()}</div>
484
- </ErrorBoundary>
485
- </Suspense>
486
- );
487
- };
488
-
489
- const { getByText } = render(() => <Comp />);
490
-
491
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
492
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
493
- });
494
-
495
- it("init-suspense-error-component: should handle suspense and error in async getter function", async () => {
496
- const Comp: Component = () => {
497
- const $a = stateAsync<number>(Promise.reject(new Error("Test error")));
498
- const $b = state(20);
499
-
500
- const $$result = from((t) => $a.get(t) + $b.get(t));
501
-
502
- return (
503
- <Suspense fallback="Loading">
504
- <ErrorBoundary fallback="Error">
505
- <div>{$$result()}</div>
506
- </ErrorBoundary>
507
- </Suspense>
508
- );
509
- };
510
-
511
- const { getByText } = render(() => <Comp />);
512
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
513
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
514
- });
515
- });
516
- });
517
- });
518
-
519
- describe("updates", () => {
520
- describe("happy path", () => {
521
- it("update-happy-path: should update FlowState", async () => {
522
- const Comp: Component = () => {
523
- const $state = state<number>(42);
524
- const $$state = from($state);
525
-
526
- return (
527
- <div>
528
- <div>{$$state()}</div>
529
- <button type="button" onClick={() => $state.set(43)}>
530
- Update
531
- </button>
532
- </div>
533
- );
534
- };
535
-
536
- const { getByText } = render(() => <Comp />);
537
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
538
- await userEvent.click(getByText("Update"));
539
- await vi.waitFor(() => expect.element(getByText("43")).toBeInTheDocument());
540
- });
541
-
542
- it("update-happy-path: should update AsyncFlowState", async () => {
543
- const Comp: Component = () => {
544
- const $stateAsync = stateAsync<number>(Promise.resolve(42));
545
- const $$stateAsync = from($stateAsync);
546
-
547
- return (
548
- <div>
549
- <div>{$$stateAsync()}</div>
550
- <button type="button" onClick={() => $stateAsync.set(Promise.resolve(43))}>
551
- Update
552
- </button>
553
- </div>
554
- );
555
- };
556
-
557
- const { getByText } = render(() => <Comp />);
558
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
559
- await userEvent.click(getByText("Update"));
560
- await vi.waitFor(() => expect.element(getByText("43")).toBeInTheDocument());
561
- });
562
-
563
- it("update-happy-path: should update getter function", async () => {
564
- const Comp: Component = () => {
565
- const $a = state<number>(10);
566
- const $b = state(20);
567
-
568
- const $$result = from((t) => $a.get(t) + $b.get(t));
569
-
570
- return (
571
- <div>
572
- <div>{$$result()}</div>
573
- <button type="button" onClick={() => $a.set(11)}>
574
- Update
575
- </button>
576
- </div>
577
- );
578
- };
579
-
580
- const { getByText } = render(() => <Comp />);
581
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
582
- await userEvent.click(getByText("Update"));
583
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
584
- });
585
-
586
- it("update-happy-path: should update async getter function", async () => {
587
- const Comp: Component = () => {
588
- const $a = stateAsync<number>(Promise.resolve(10));
589
- const $b = state(20);
590
-
591
- const $$result = from((t) => $a.get(t) + $b.get(t));
592
- return (
593
- <div>
594
- <div>{$$result()}</div>
595
- <button type="button" onClick={() => $a.set(Promise.resolve(11))}>
596
- Update
597
- </button>
598
- </div>
599
- );
600
- };
601
-
602
- const { getByText } = render(() => <Comp />);
603
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
604
- await userEvent.click(getByText("Update"));
605
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
606
- });
607
- });
608
-
609
- describe("suspense", () => {
610
- describe("flag", () => {
611
- it("update-suspense-flag: should handle suspense in AsyncFlowState", async () => {
612
- const Comp: Component = () => {
613
- const $stateAsync = stateAsync<number>(Promise.resolve(42));
614
- const $$stateAsync = from($stateAsync);
615
-
616
- return (
617
- <Switch>
618
- <Match when={$$stateAsync.loading}>
619
- <div>Loading</div>
620
- </Match>
621
- <Match when={$$stateAsync()}>
622
- <div>{$$stateAsync()}</div>
623
- <button
624
- type="button"
625
- onClick={() =>
626
- $stateAsync.set(
627
- new Promise((resolve) => setTimeout(() => resolve(43), 100)),
628
- )
629
- }
630
- >
631
- Update
632
- </button>
633
- </Match>
634
- </Switch>
635
- );
636
- };
637
-
638
- const { getByText } = render(() => <Comp />);
639
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
640
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
641
- await userEvent.click(getByText("Update"));
642
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
643
- await vi.waitFor(() => expect.element(getByText("43")).toBeInTheDocument());
644
- });
645
-
646
- it("update-suspense-flag: should handle suspense in async getter function", async () => {
647
- const Comp: Component = () => {
648
- const $a = stateAsync<number>(Promise.resolve(10));
649
- const $b = state(20);
650
-
651
- const $$result = from((t) => $a.get(t) + $b.get(t));
652
-
653
- return (
654
- <Switch>
655
- <Match when={$$result.loading}>
656
- <div>Loading</div>
657
- </Match>
658
- <Match when={$$result()}>
659
- <div>{$$result()}</div>
660
- <button
661
- type="button"
662
- onClick={() =>
663
- $a.set(new Promise((resolve) => setTimeout(() => resolve(11), 100)))
664
- }
665
- >
666
- Update
667
- </button>
668
- </Match>
669
- </Switch>
670
- );
671
- };
672
-
673
- const { getByText } = render(() => <Comp />);
674
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
675
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
676
- await userEvent.click(getByText("Update"));
677
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
678
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
679
- });
680
- });
681
-
682
- describe("component", () => {
683
- it("update-suspense-component: should handle suspense in FlowState", async () => {
684
- const Comp: Component = () => {
685
- const $state = state<number>(42);
686
- const $$state = from($state);
687
-
688
- return (
689
- <Suspense fallback="Loading">
690
- <div>{$$state()}</div>
691
- <button type="button" onClick={() => $state.set(43)}>
692
- Update
693
- </button>
694
- </Suspense>
695
- );
696
- };
697
-
698
- const { getByText } = render(() => <Comp />);
699
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
700
-
701
- await userEvent.click(getByText("Update"));
702
- await vi.waitFor(() => expect.element(getByText("43")).toBeInTheDocument());
703
- });
704
-
705
- it.skip("temp", async () => {
706
- const Comp: Component = () => {
707
- let value = 42;
708
-
709
- const [resource, { refetch }] = createResource<number>(() => {
710
- return new Promise((resolve) => setTimeout(() => resolve(value), 500));
711
- });
712
-
713
- return (
714
- <Suspense fallback="Loading">
715
- <div>{resource()}</div>
716
- <button
717
- type="button"
718
- onClick={() => {
719
- value = 43;
720
- refetch();
721
- }}
722
- >
723
- Update
724
- </button>
725
- </Suspense>
726
- );
727
- };
728
-
729
- const { getByText } = render(() => <Comp />);
730
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
731
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
732
-
733
- await userEvent.click(getByText("Update"));
734
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
735
- await vi.waitFor(() => expect.element(getByText("43")).toBeInTheDocument());
736
- });
737
-
738
- it("update-suspense-component: should handle suspense in AsyncFlowState", async () => {
739
- const Comp: Component = () => {
740
- const $stateAsync = stateAsync<number>(
741
- new Promise((resolve) => setTimeout(() => resolve(42), 500)),
742
- );
743
- const $$stateAsync = from($stateAsync);
744
-
745
- return (
746
- <Suspense fallback="Loading">
747
- <div>{$$stateAsync()}</div>
748
- <button
749
- type="button"
750
- onClick={() =>
751
- $stateAsync.set(new Promise((resolve) => setTimeout(() => resolve(43), 500)))
752
- }
753
- >
754
- Update
755
- </button>
756
- </Suspense>
757
- );
758
- };
759
-
760
- const { getByText } = render(() => <Comp />);
761
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
762
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
763
-
764
- await userEvent.click(getByText("Update"));
765
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
766
- await vi.waitFor(() => expect.element(getByText("43")).toBeInTheDocument());
767
- });
768
-
769
- it("update-suspense-component: should handle suspense in getter function", async () => {
770
- const Comp: Component = () => {
771
- const $a = state<number>(10);
772
- const $b = state(20);
773
-
774
- const $$result = from((t) => $a.get(t) + $b.get(t));
775
- return (
776
- <Suspense fallback="Loading">
777
- <div>{$$result()}</div>
778
- <button type="button" onClick={() => $a.set(11)}>
779
- Update
780
- </button>
781
- </Suspense>
782
- );
783
- };
784
-
785
- const { getByText } = render(() => <Comp />);
786
- await expect.element(getByText("Loading")).toBeInTheDocument();
787
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
788
- await userEvent.click(getByText("Update"));
789
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
790
- });
791
-
792
- it("update-suspense-component: should handle suspense in async getter function", async () => {
793
- const Comp: Component = () => {
794
- const $a = stateAsync<number>(Promise.resolve(10));
795
- const $b = state(20);
796
-
797
- const $$result = from((t) => $a.get(t) + $b.get(t));
798
- return (
799
- <div>
800
- <Suspense fallback="Loading">
801
- <div>{$$result()}</div>
802
- </Suspense>
803
- <button
804
- type="button"
805
- onClick={() => $a.set(new Promise((resolve) => setTimeout(() => resolve(11), 100)))}
806
- >
807
- Update
808
- </button>
809
- </div>
810
- );
811
- };
812
-
813
- const { getByText } = render(() => <Comp />);
814
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
815
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
816
-
817
- await userEvent.click(getByText("Update"));
818
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
819
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
820
- });
821
- });
822
- });
823
-
824
- describe("error", () => {
825
- describe("flag", () => {
826
- it("update-error-flag: should recover from initial error in FlowState", async () => {
827
- const Comp: Component = () => {
828
- const $state = state<number>(() => {
829
- throw new Error("Test error");
830
- });
831
- const $$state = from($state);
832
- return (
833
- <div>
834
- <Switch>
835
- <Match when={$$state.error}>
836
- <div>Error</div>
837
- </Match>
838
- <Match when={$$state()}>
839
- <div>{$$state()}</div>
840
- </Match>
841
- </Switch>
842
- <button type="button" onClick={() => $state.set(42)}>
843
- Update Value
844
- </button>
845
- </div>
846
- );
847
- };
848
-
849
- const { getByText } = render(() => <Comp />);
850
-
851
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
852
- await userEvent.click(getByText("Update Value"));
853
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
854
- });
855
-
856
- it("update-error-flag: should recover from initial error in AsyncFlowState", async () => {
857
- const Comp: Component = () => {
858
- const $stateAsync = stateAsync<number>(Promise.reject(new Error("Test error")));
859
- const $$stateAsync = from($stateAsync);
860
-
861
- return (
862
- <div>
863
- <Switch>
864
- <Match when={$$stateAsync.error}>
865
- <div>Error</div>
866
- </Match>
867
- <Match when={$$stateAsync()}>
868
- <div>{$$stateAsync()}</div>
869
- </Match>
870
- </Switch>
871
- <button type="button" onClick={() => $stateAsync.set(Promise.resolve(42))}>
872
- Update Value
873
- </button>
874
- </div>
875
- );
876
- };
877
-
878
- const { getByText } = render(() => <Comp />);
879
-
880
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
881
- await userEvent.click(getByText("Update Value"));
882
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
883
- });
884
-
885
- it("update-error-flag: should recover from initial error in getter function", async () => {
886
- const Comp: Component = () => {
887
- const $a = state<number>(() => {
888
- throw new Error("Test error");
889
- });
890
- const $b = state(20);
891
-
892
- const $$result = from((t) => $a.get(t) + $b.get(t));
893
-
894
- return (
895
- <div>
896
- <Switch>
897
- <Match when={$$result.error}>
898
- <div>Error</div>
899
- </Match>
900
- <Match when={$$result()}>
901
- <div>{$$result()}</div>
902
- </Match>
903
- </Switch>
904
- <button type="button" onClick={() => $a.set(11)}>
905
- Update Value
906
- </button>
907
- </div>
908
- );
909
- };
910
-
911
- const { getByText } = render(() => <Comp />);
912
-
913
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
914
- await userEvent.click(getByText("Update Value"));
915
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
916
- });
917
-
918
- it("update-error-flag: should recover from initial error in async getter function", async () => {
919
- const Comp: Component = () => {
920
- const $a = stateAsync<number>(Promise.reject(new Error("Test error")));
921
- const $b = state(20);
922
-
923
- const $$result = from((t) => $a.get(t) + $b.get(t));
924
-
925
- return (
926
- <div>
927
- <Switch>
928
- <Match when={$$result.error}>
929
- <div>Error</div>
930
- </Match>
931
- <Match when={$$result()}>
932
- <div>{$$result()}</div>
933
- </Match>
934
- </Switch>
935
- <button type="button" onClick={() => $a.set(Promise.resolve(11))}>
936
- Update Value
937
- </button>
938
- </div>
939
- );
940
- };
941
-
942
- const { getByText } = render(() => <Comp />);
943
-
944
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
945
- await userEvent.click(getByText("Update Value"));
946
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
947
- });
948
-
949
- it("update-error-flag: should handle error in getter function", async () => {
950
- const Comp: Component = () => {
951
- const $a = state<number>(10);
952
- const $b = state(20);
953
-
954
- const $$result = from((t) => {
955
- if ($a.get(t) > 10) {
956
- throw new Error("Test error");
957
- } else {
958
- return $a.get(t) + $b.get(t);
959
- }
960
- });
961
-
962
- return (
963
- <div>
964
- <Switch>
965
- <Match when={$$result.error}>
966
- <div>Error</div>
967
- </Match>
968
- <Match when={$$result()}>
969
- <div>{$$result()}</div>
970
- </Match>
971
- </Switch>
972
- <button type="button" onClick={() => $a.set((v) => (v ? v + 1 : 0))}>
973
- Increment Value
974
- </button>
975
- <button type="button" onClick={() => $a.set((v) => (v ? v - 1 : 0))}>
976
- Decrement Value
977
- </button>
978
- </div>
979
- );
980
- };
981
-
982
- const { getByText } = render(() => <Comp />);
983
-
984
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
985
- await userEvent.click(getByText("Increment Value"));
986
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
987
- await userEvent.click(getByText("Decrement Value"));
988
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
989
- });
990
-
991
- it("update-error-flag: should handle error in async getter function", async () => {
992
- const Comp: Component = () => {
993
- const $a = stateAsync<number>(Promise.resolve(10));
994
- const $b = state(20);
995
-
996
- const $$result = from((t) => {
997
- if ($a.get(t) > 10) {
998
- throw new Error("Test error");
999
- } else {
1000
- return $a.get(t) + $b.get(t);
1001
- }
1002
- });
1003
-
1004
- return (
1005
- <div>
1006
- <Switch>
1007
- <Match when={$$result.error}>
1008
- <div>Error</div>
1009
- </Match>
1010
- <Match when={$$result()}>
1011
- <div>{$$result()}</div>
1012
- </Match>
1013
- </Switch>
1014
- <button type="button" onClick={() => $a.set(async (v) => (v ? v + 1 : 0))}>
1015
- Increment Value
1016
- </button>
1017
- <button type="button" onClick={() => $a.set(async (v) => (v ? v - 1 : 0))}>
1018
- Decrement Value
1019
- </button>
1020
- </div>
1021
- );
1022
- };
1023
-
1024
- const { getByText } = render(() => <Comp />);
1025
-
1026
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1027
- await userEvent.click(getByText("Increment Value"));
1028
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1029
- await userEvent.click(getByText("Decrement Value"));
1030
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1031
- });
1032
- });
1033
-
1034
- describe("component", () => {
1035
- it("update-error-component: should recover from initial error in FlowState", async () => {
1036
- const Comp: Component = () => {
1037
- const $state = state<number>(() => {
1038
- throw new Error("Test error");
1039
- });
1040
- const $$state = from($state);
1041
- return (
1042
- <div>
1043
- <ErrorBoundary fallback="Error">
1044
- <div>{$$state()}</div>
1045
- </ErrorBoundary>
1046
- <button type="button" onClick={() => $state.set(42)}>
1047
- Update Value
1048
- </button>
1049
- </div>
1050
- );
1051
- };
1052
-
1053
- const { getByText } = render(() => <Comp />);
1054
-
1055
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1056
- await userEvent.click(getByText("Update Value"));
1057
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
1058
- });
1059
-
1060
- it("update-error-component: should recover from initial error in AsyncFlowState", async () => {
1061
- const Comp: Component = () => {
1062
- const $stateAsync = stateAsync<number>(Promise.reject(new Error("Test error")));
1063
- const $$stateAsync = from($stateAsync);
1064
-
1065
- return (
1066
- <div>
1067
- <ErrorBoundary fallback="Error">
1068
- <div>{$$stateAsync()}</div>
1069
- </ErrorBoundary>
1070
- <button type="button" onClick={() => $stateAsync.set(Promise.resolve(42))}>
1071
- Update Value
1072
- </button>
1073
- </div>
1074
- );
1075
- };
1076
-
1077
- const { getByText } = render(() => <Comp />);
1078
-
1079
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1080
- await userEvent.click(getByText("Update Value"));
1081
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
1082
- });
1083
-
1084
- it("update-error-component: should recover from initial error in getter function", async () => {
1085
- const Comp: Component = () => {
1086
- const $a = state<number>(() => {
1087
- throw new Error("Test error");
1088
- });
1089
- const $b = state(20);
1090
-
1091
- const $$result = from((t) => $a.get(t) + $b.get(t));
1092
-
1093
- return (
1094
- <div>
1095
- <ErrorBoundary fallback="Error">
1096
- <div>{$$result()}</div>
1097
- </ErrorBoundary>
1098
- <button type="button" onClick={() => $a.set(11)}>
1099
- Update Value
1100
- </button>
1101
- </div>
1102
- );
1103
- };
1104
-
1105
- const { getByText } = render(() => <Comp />);
1106
-
1107
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1108
- await userEvent.click(getByText("Update Value"));
1109
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
1110
- });
1111
-
1112
- it("update-error-component: should recover from initial error in async getter function", async () => {
1113
- const Comp: Component = () => {
1114
- const $a = stateAsync<number>(Promise.reject(new Error("Test error")));
1115
- const $b = state(20);
1116
-
1117
- const $$result = from((t) => $a.get(t) + $b.get(t));
1118
-
1119
- return (
1120
- <div>
1121
- <ErrorBoundary fallback="Error">
1122
- <div>{$$result()}</div>
1123
- </ErrorBoundary>
1124
- <button type="button" onClick={() => $a.set(Promise.resolve(11))}>
1125
- Update Value
1126
- </button>
1127
- </div>
1128
- );
1129
- };
1130
-
1131
- const { getByText } = render(() => <Comp />);
1132
-
1133
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1134
- await userEvent.click(getByText("Update Value"));
1135
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
1136
- });
1137
-
1138
- it("update-error-component: should handle error in getter function", async () => {
1139
- const Comp: Component = () => {
1140
- const $a = state<number>(10);
1141
- const $b = state(20);
1142
-
1143
- const $$result = from((t) => {
1144
- if ($a.get(t) > 10) {
1145
- throw new Error("Test error");
1146
- } else {
1147
- return $a.get(t) + $b.get(t);
1148
- }
1149
- });
1150
-
1151
- return (
1152
- <div>
1153
- <ErrorBoundary fallback="Error">
1154
- <div>{$$result()}</div>
1155
- </ErrorBoundary>
1156
- <button type="button" onClick={() => $a.set((v) => (v ? v + 1 : 0))}>
1157
- Increment Value
1158
- </button>
1159
- <button type="button" onClick={() => $a.set((v) => (v ? v - 1 : 0))}>
1160
- Decrement Value
1161
- </button>
1162
- </div>
1163
- );
1164
- };
1165
-
1166
- const { getByText } = render(() => <Comp />);
1167
-
1168
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1169
- await userEvent.click(getByText("Increment Value"));
1170
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1171
- await userEvent.click(getByText("Decrement Value"));
1172
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1173
- });
1174
-
1175
- it("update-error-component: should handle error in async getter function", async () => {
1176
- const Comp: Component = () => {
1177
- const $a = stateAsync<number>(Promise.resolve(10));
1178
- const $b = state(20);
1179
-
1180
- const $$result = from((t) => {
1181
- if ($a.get(t) > 10) {
1182
- throw new Error("Test error");
1183
- } else {
1184
- return $a.get(t) + $b.get(t);
1185
- }
1186
- });
1187
-
1188
- return (
1189
- <div>
1190
- <ErrorBoundary fallback="Error">
1191
- <div>{$$result()}</div>
1192
- </ErrorBoundary>
1193
- <button type="button" onClick={() => $a.set(async (v) => (v ? v + 1 : 0))}>
1194
- Increment Value
1195
- </button>
1196
- <button type="button" onClick={() => $a.set(async (v) => (v ? v - 1 : 0))}>
1197
- Decrement Value
1198
- </button>
1199
- </div>
1200
- );
1201
- };
1202
-
1203
- const { getByText } = render(() => <Comp />);
1204
-
1205
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1206
- await userEvent.click(getByText("Increment Value"));
1207
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1208
- await userEvent.click(getByText("Decrement Value"));
1209
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1210
- });
1211
- });
1212
- });
1213
-
1214
- describe("suspense-error", () => {
1215
- describe("flag", () => {
1216
- it("update-suspense-error-flag: should recover from initial error in AsyncFlowState", async () => {
1217
- const Comp: Component = () => {
1218
- const $stateAsync = stateAsync<number>(Promise.reject(new Error("Test error")));
1219
- const $$stateAsync = from($stateAsync);
1220
-
1221
- return (
1222
- <div>
1223
- <Switch>
1224
- <Match when={$$stateAsync.error}>
1225
- <div>Error</div>
1226
- </Match>
1227
- <Match when={$$stateAsync.loading}>
1228
- <div>Loading</div>
1229
- </Match>
1230
- <Match when={$$stateAsync()}>
1231
- <div>{$$stateAsync()}</div>
1232
- </Match>
1233
- </Switch>
1234
- <button type="button" onClick={() => $stateAsync.set(Promise.resolve(42))}>
1235
- Update Value
1236
- </button>
1237
- </div>
1238
- );
1239
- };
1240
-
1241
- const { getByText } = render(() => <Comp />);
1242
-
1243
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
1244
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1245
- await userEvent.click(getByText("Update Value"));
1246
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
1247
- });
1248
-
1249
- it("update-suspense-error-flag: should recover from initial error in async getter function", async () => {
1250
- const Comp: Component = () => {
1251
- const $a = stateAsync<number>(Promise.reject(new Error("Test error")));
1252
- const $b = state(20);
1253
-
1254
- const $$result = from((t) => $a.get(t) + $b.get(t));
1255
-
1256
- return (
1257
- <div>
1258
- <Switch>
1259
- <Match when={$$result.error}>
1260
- <div>Error</div>
1261
- </Match>
1262
- <Match when={$$result.loading}>
1263
- <div>Loading</div>
1264
- </Match>
1265
- <Match when={$$result()}>
1266
- <div>{$$result()}</div>
1267
- </Match>
1268
- </Switch>
1269
- <button type="button" onClick={() => $a.set(Promise.resolve(11))}>
1270
- Update Value
1271
- </button>
1272
- </div>
1273
- );
1274
- };
1275
-
1276
- const { getByText } = render(() => <Comp />);
1277
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
1278
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1279
- await userEvent.click(getByText("Update Value"));
1280
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
1281
- });
1282
-
1283
- it("update-suspense-error-flag: should handle error in async getter function", async () => {
1284
- const Comp: Component = () => {
1285
- const $a = stateAsync<number>(Promise.resolve(10));
1286
- const $b = state(20);
1287
-
1288
- const $$result = from((t) => {
1289
- if ($a.get(t) > 10) {
1290
- throw new Error("Test error");
1291
- } else {
1292
- return $a.get(t) + $b.get(t);
1293
- }
1294
- });
1295
-
1296
- return (
1297
- <div>
1298
- <Switch>
1299
- <Match when={$$result.error}>
1300
- <div>Error</div>
1301
- </Match>
1302
- <Match when={$$result.loading}>
1303
- <div>Loading</div>
1304
- </Match>
1305
- <Match when={$$result()}>
1306
- <div>{$$result()}</div>
1307
- </Match>
1308
- </Switch>
1309
- <button type="button" onClick={() => $a.set(async (v) => (v ? v + 1 : 0))}>
1310
- Increment Value
1311
- </button>
1312
- <button type="button" onClick={() => $a.set(async (v) => (v ? v - 1 : 0))}>
1313
- Decrement Value
1314
- </button>
1315
- </div>
1316
- );
1317
- };
1318
-
1319
- const { getByText } = render(() => <Comp />);
1320
-
1321
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1322
- await userEvent.click(getByText("Increment Value"));
1323
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1324
- await userEvent.click(getByText("Decrement Value"));
1325
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1326
- });
1327
- });
1328
-
1329
- describe("component", () => {
1330
- it("update-suspense-error-component: should recover from initial error in AsyncFlowState", async () => {
1331
- const Comp: Component = () => {
1332
- const $stateAsync = stateAsync<number>(Promise.reject(new Error("Test error")));
1333
- const $$stateAsync = from($stateAsync);
1334
-
1335
- return (
1336
- <div>
1337
- <Suspense fallback="Loading">
1338
- <ErrorBoundary fallback="Error">
1339
- <div>{$$stateAsync()}</div>
1340
- </ErrorBoundary>
1341
- </Suspense>
1342
- <button type="button" onClick={() => $stateAsync.set(Promise.resolve(42))}>
1343
- Update Value
1344
- </button>
1345
- </div>
1346
- );
1347
- };
1348
-
1349
- const { getByText } = render(() => <Comp />);
1350
-
1351
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
1352
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1353
- await userEvent.click(getByText("Update Value"));
1354
- await vi.waitFor(() => expect.element(getByText("42")).toBeInTheDocument());
1355
- });
1356
-
1357
- it("update-suspense-error-component: should recover from initial error in async getter function", async () => {
1358
- const Comp: Component = () => {
1359
- const $a = stateAsync<number>(Promise.reject(new Error("Test error")));
1360
- const $b = state(20);
1361
-
1362
- const $$result = from((t) => $a.get(t) + $b.get(t));
1363
-
1364
- return (
1365
- <div>
1366
- <Suspense fallback="Loading">
1367
- <ErrorBoundary fallback="Error">
1368
- <div>{$$result()}</div>
1369
- </ErrorBoundary>
1370
- </Suspense>
1371
- <button type="button" onClick={() => $a.set(Promise.resolve(11))}>
1372
- Update Value
1373
- </button>
1374
- </div>
1375
- );
1376
- };
1377
-
1378
- const { getByText } = render(() => <Comp />);
1379
-
1380
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
1381
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1382
- await userEvent.click(getByText("Update Value"));
1383
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
1384
- });
1385
-
1386
- it("update-suspense-error-component: should handle error in async getter function", async () => {
1387
- const Comp: Component = () => {
1388
- const $a = stateAsync<number>(Promise.resolve(10));
1389
- const $b = state(20);
1390
-
1391
- const $$result = from((t) => {
1392
- if ($a.get(t) > 10) {
1393
- throw new Error("Test error");
1394
- } else {
1395
- return $a.get(t) + $b.get(t);
1396
- }
1397
- });
1398
-
1399
- return (
1400
- <div>
1401
- <Suspense fallback="Loading">
1402
- <ErrorBoundary fallback="Error">
1403
- <div>{$$result()}</div>
1404
- </ErrorBoundary>
1405
- </Suspense>
1406
- <button type="button" onClick={() => $a.set(async (v) => (v ? v + 1 : 0))}>
1407
- Increment Value
1408
- </button>
1409
- <button type="button" onClick={() => $a.set(async (v) => (v ? v - 1 : 0))}>
1410
- Decrement Value
1411
- </button>
1412
- </div>
1413
- );
1414
- };
1415
-
1416
- const { getByText } = render(() => <Comp />);
1417
-
1418
- await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
1419
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1420
- await userEvent.click(getByText("Increment Value"));
1421
- await vi.waitFor(() => expect.element(getByText("Error")).toBeInTheDocument());
1422
- await userEvent.click(getByText("Decrement Value"));
1423
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1424
- });
1425
- });
1426
- });
1427
- });
1428
-
1429
- describe("replacement", () => {
1430
- describe("happy path", () => {
1431
- it("replacement-happy-path: should update FlowState via Switch", async () => {
1432
- const CompInner: Component<{ $state: FlowState<number> }> = ({ $state }) => {
1433
- const $$state = from($state);
1434
-
1435
- return (
1436
- <div>
1437
- <div>{$$state()}</div>
1438
- <button type="button" onClick={() => $state.set((v) => (v ? v + 1 : 0))}>
1439
- Increment
1440
- </button>
1441
- </div>
1442
- );
1443
- };
1444
-
1445
- const CompOuter: Component = () => {
1446
- const $stateA = state<number>(20);
1447
- const $stateB = state<number>(30);
1448
- const $selected = state<FlowState<number>>($stateA);
1449
-
1450
- const $$selected = from($selected);
1451
-
1452
- return (
1453
- <div>
1454
- <Switch>
1455
- <Match when={$$selected.loading}>
1456
- <div>Loading</div>
1457
- </Match>
1458
- <Match when={$$selected()}>{(selected) => <CompInner $state={selected()} />}</Match>
1459
- </Switch>
1460
- <button type="button" onClick={() => $selected.set($stateA)}>
1461
- Use A
1462
- </button>
1463
- <button type="button" onClick={() => $selected.set($stateB)}>
1464
- Use B
1465
- </button>
1466
- </div>
1467
- );
1468
- };
1469
-
1470
- const { getByText } = render(() => <CompOuter />);
1471
- await vi.waitFor(() => expect.element(getByText("20")).toBeInTheDocument());
1472
- await userEvent.click(getByText("Increment"));
1473
- await vi.waitFor(() => expect.element(getByText("21")).toBeInTheDocument());
1474
- await userEvent.click(getByText("Use B"));
1475
- await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1476
- await userEvent.click(getByText("Increment"));
1477
- await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
1478
- await userEvent.click(getByText("Use A"));
1479
- await vi.waitFor(() => expect.element(getByText("21")).toBeInTheDocument());
1480
- });
1481
-
1482
- // it("replacement-happy-path: should update FlowState via Show", async () => {
1483
-
1484
- // const FlowBoundary: Component<{ resource: Resource<FlowState<unknown>>, children: Component<{ $state: FlowState<unknown> }> }> = (props) => {
1485
- // return (
1486
- // <div>
1487
- // <Switch>
1488
- // <Match when={props.resource.loading}>
1489
- // <div>Loading</div>
1490
- // </Match>
1491
- // <Match when={props.resource.error}>
1492
- // <div>Error</div>
1493
- // </Match>
1494
- // <Match when={props.resource()}>
1495
- // {(resource) => props.children({ $state: resource() })}
1496
- // </Match>
1497
- // </Switch>
1498
- // </div >
1499
- // )
1500
- // }
1501
-
1502
- // const CompInner: Component<{ $state: FlowState<number> }> = ({ $state }) => {
1503
-
1504
- // const $$state = from($state);
1505
-
1506
- // return (
1507
- // <div>
1508
- // <div>{$$state()}</div>
1509
- // <button type="button" onClick={() => $state.set((v) => v ? v + 1 : 0)}>Increment</button>
1510
- // </div>
1511
- // )
1512
- // }
1513
-
1514
- // const CompOuter: Component = () => {
1515
- // const $stateA = state<number>(20);
1516
- // const $stateB = state<number>(30);
1517
- // const $selected = state<FlowState<number>>($stateA);
1518
-
1519
- // const $$selected = from($selected);
1520
-
1521
- // return (
1522
- // <div>
1523
- // <FlowBoundary resource={$$selected}>
1524
- // <CompInner/>
1525
- // </FlowBoundary>
1526
- // <button type="button" onClick={() => $selected.set($stateA)}>Use A</button>
1527
- // <button type="button" onClick={() => $selected.set($stateB)}>Use B</button>
1528
- // </div >
1529
- // )
1530
- // }
1531
-
1532
- // const { getByText } = render(() => <CompOuter />);
1533
- // await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
1534
- // await vi.waitFor(() => expect.element(getByText("20")).toBeInTheDocument());
1535
- // await userEvent.click(getByText("Increment"));
1536
- // await vi.waitFor(() => expect.element(getByText("21")).toBeInTheDocument());
1537
- // await userEvent.click(getByText("Use B"));
1538
- // await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1539
- // await userEvent.click(getByText("Increment"));
1540
- // await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
1541
- // await userEvent.click(getByText("Use A"));
1542
- // await vi.waitFor(() => expect.element(getByText("21")).toBeInTheDocument());
1543
- // });
1544
-
1545
- // it("replacement-happy-path: should update FlowState via FlowBoundary", async () => {
1546
-
1547
- // const CompInner: Component<{ $state: FlowState<number> }> = ({ $state }) => {
1548
- // // if (!props.$state) { return undefined }
1549
-
1550
- // const $$state = from($state);
1551
-
1552
- // return (
1553
- // <div>
1554
- // <div>{$$state()}</div>
1555
- // <button type="button" onClick={() => $state.set((v) => v ? v + 1 : 0)}>Increment</button>
1556
- // </div>
1557
- // )
1558
- // }
1559
-
1560
- // const CompOuter: Component = () => {
1561
- // const $stateA = state<number>(20);
1562
- // const $stateB = state<number>(30);
1563
- // const $selected = state<FlowState<number>>($stateA);
1564
-
1565
- // const $$selected = from($selected);
1566
-
1567
- // return (
1568
- // <div>
1569
- // <Suspense fallback="Loading Outer">
1570
- // <CompInner $state={$$selected()} />
1571
- // </Suspense>
1572
- // <button type="button" onClick={() => $selected.set($stateA)}>Use A</button>
1573
- // <button type="button" onClick={() => $selected.set($stateB)}>Use B</button>
1574
- // </div >
1575
- // )
1576
- // }
1577
-
1578
- // const { getByText } = render(() => <CompOuter />);
1579
- // await vi.waitFor(() => expect.element(getByText("Loading")).toBeInTheDocument());
1580
- // await vi.waitFor(() => expect.element(getByText("20")).toBeInTheDocument());
1581
- // await userEvent.click(getByText("Increment"));
1582
- // await vi.waitFor(() => expect.element(getByText("21")).toBeInTheDocument());
1583
- // await userEvent.click(getByText("Use B"));
1584
- // await vi.waitFor(() => expect.element(getByText("30")).toBeInTheDocument());
1585
- // await userEvent.click(getByText("Increment"));
1586
- // await vi.waitFor(() => expect.element(getByText("31")).toBeInTheDocument());
1587
- // await userEvent.click(getByText("Use A"));
1588
- // await vi.waitFor(() => expect.element(getByText("21")).toBeInTheDocument());
1589
- // });
1590
- });
1591
- });
1592
- });