@ersbeth/picoflow 1.1.2 → 2.0.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.
- package/.vscode/settings.json +3 -3
- package/CHANGELOG.md +43 -0
- package/README.md +2 -18
- package/biome.json +45 -35
- package/dist/picoflow.js +856 -1530
- package/dist/types/api/base/flowDisposable.d.ts +41 -0
- package/dist/types/api/base/flowDisposable.d.ts.map +1 -0
- package/dist/types/api/base/flowObservable.d.ts +27 -0
- package/dist/types/api/base/flowObservable.d.ts.map +1 -0
- package/dist/types/api/base/flowSubscribable.d.ts +79 -0
- package/dist/types/api/base/flowSubscribable.d.ts.map +1 -0
- package/dist/types/api/base/flowTracker.d.ts +8 -0
- package/dist/types/api/base/flowTracker.d.ts.map +1 -0
- package/dist/types/api/base/index.d.ts +5 -0
- package/dist/types/api/base/index.d.ts.map +1 -0
- package/dist/types/api/index.d.ts +3 -0
- package/dist/types/api/index.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowConstantAsync.d.ts +31 -0
- package/dist/types/api/nodes/async/flowConstantAsync.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowDerivationAsync.d.ts +37 -0
- package/dist/types/api/nodes/async/flowDerivationAsync.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowStateAsync.d.ts +41 -0
- package/dist/types/api/nodes/async/flowStateAsync.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowWritableDerivationAsync.d.ts +30 -0
- package/dist/types/api/nodes/async/flowWritableDerivationAsync.d.ts.map +1 -0
- package/dist/types/{flow → api}/nodes/async/index.d.ts +1 -2
- package/dist/types/api/nodes/async/index.d.ts.map +1 -0
- package/dist/types/api/nodes/collections/flowArray.d.ts +134 -0
- package/dist/types/api/nodes/collections/flowArray.d.ts.map +1 -0
- package/dist/types/api/nodes/collections/flowMap.d.ts +98 -0
- package/dist/types/api/nodes/collections/flowMap.d.ts.map +1 -0
- package/dist/types/api/nodes/collections/index.d.ts.map +1 -0
- package/dist/types/api/nodes/flowEffect.d.ts +28 -0
- package/dist/types/api/nodes/flowEffect.d.ts.map +1 -0
- package/dist/types/api/nodes/flowSignal.d.ts +25 -0
- package/dist/types/api/nodes/flowSignal.d.ts.map +1 -0
- package/dist/types/api/nodes/flowValue.d.ts +35 -0
- package/dist/types/api/nodes/flowValue.d.ts.map +1 -0
- package/dist/types/api/nodes/index.d.ts +8 -0
- package/dist/types/api/nodes/index.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowConstant.d.ts +29 -0
- package/dist/types/api/nodes/sync/flowConstant.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowDerivation.d.ts +36 -0
- package/dist/types/api/nodes/sync/flowDerivation.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowState.d.ts +39 -0
- package/dist/types/api/nodes/sync/flowState.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowWritableDerivation.d.ts +28 -0
- package/dist/types/api/nodes/sync/flowWritableDerivation.d.ts.map +1 -0
- package/dist/types/{flow → api}/nodes/sync/index.d.ts +1 -2
- package/dist/types/api/nodes/sync/index.d.ts.map +1 -0
- package/dist/types/api/nodes/utils.d.ts +22 -0
- package/dist/types/api/nodes/utils.d.ts.map +1 -0
- package/dist/types/base/disposable.d.ts +11 -0
- package/dist/types/base/disposable.d.ts.map +1 -0
- package/dist/types/base/executionStack.d.ts +14 -0
- package/dist/types/base/executionStack.d.ts.map +1 -0
- package/dist/types/base/index.d.ts +6 -0
- package/dist/types/base/index.d.ts.map +1 -0
- package/dist/types/base/node.d.ts +27 -0
- package/dist/types/base/node.d.ts.map +1 -0
- package/dist/types/base/observable.d.ts +37 -0
- package/dist/types/base/observable.d.ts.map +1 -0
- package/dist/types/base/observer.d.ts +25 -0
- package/dist/types/base/observer.d.ts.map +1 -0
- package/dist/types/converters/index.d.ts +2 -0
- package/dist/types/converters/index.d.ts.map +1 -0
- package/dist/types/converters/solid.d.ts +46 -0
- package/dist/types/converters/solid.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -63
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/nodes/arrayNode.d.ts +2 -0
- package/dist/types/nodes/arrayNode.d.ts.map +1 -0
- package/dist/types/nodes/effectNode.d.ts +2 -0
- package/dist/types/nodes/effectNode.d.ts.map +1 -0
- package/dist/types/nodes/index.d.ts +9 -0
- package/dist/types/nodes/index.d.ts.map +1 -0
- package/dist/types/nodes/mapNode.d.ts +2 -0
- package/dist/types/nodes/mapNode.d.ts.map +1 -0
- package/dist/types/nodes/signalNode.d.ts +2 -0
- package/dist/types/nodes/signalNode.d.ts.map +1 -0
- package/dist/types/nodes/valueAsyncNode.d.ts +2 -0
- package/dist/types/nodes/valueAsyncNode.d.ts.map +1 -0
- package/dist/types/nodes/valueNode.d.ts +2 -0
- package/dist/types/nodes/valueNode.d.ts.map +1 -0
- package/dist/types/nodes/valueSyncNode.d.ts +2 -0
- package/dist/types/nodes/valueSyncNode.d.ts.map +1 -0
- package/dist/types/schedulers/asyncResolver.d.ts +2 -0
- package/dist/types/schedulers/asyncResolver.d.ts.map +1 -0
- package/dist/types/schedulers/asyncScheduler.d.ts +2 -0
- package/dist/types/schedulers/asyncScheduler.d.ts.map +1 -0
- package/dist/types/schedulers/index.d.ts +5 -0
- package/dist/types/schedulers/index.d.ts.map +1 -0
- package/dist/types/schedulers/pendingError.d.ts +2 -0
- package/dist/types/schedulers/pendingError.d.ts.map +1 -0
- package/dist/types/schedulers/scheduler.d.ts +2 -0
- package/dist/types/schedulers/scheduler.d.ts.map +1 -0
- package/dist/types/schedulers/syncResolver.d.ts +2 -0
- package/dist/types/schedulers/syncResolver.d.ts.map +1 -0
- package/dist/types/schedulers/syncScheduler.d.ts +2 -0
- package/dist/types/schedulers/syncScheduler.d.ts.map +1 -0
- package/docs/.vitepress/config.mts +128 -93
- package/docs/api/functions/array.md +14 -37
- package/docs/api/functions/constant.md +13 -25
- package/docs/api/functions/constantAsync.md +69 -0
- package/docs/api/functions/derivation.md +14 -33
- package/docs/api/functions/derivationAsync.md +34 -0
- package/docs/api/functions/from.md +62 -153
- package/docs/api/functions/isDisposable.md +8 -30
- package/docs/api/functions/map.md +15 -36
- package/docs/api/functions/signal.md +8 -23
- package/docs/api/functions/state.md +43 -23
- package/docs/api/functions/stateAsync.md +69 -0
- package/docs/api/functions/subscribe.md +40 -0
- package/docs/api/functions/writableDerivation.md +33 -0
- package/docs/api/functions/writableDerivationAsync.md +34 -0
- package/docs/api/index.md +45 -102
- package/docs/api/interfaces/FlowArray.md +439 -0
- package/docs/api/interfaces/FlowConstant.md +220 -0
- package/docs/api/interfaces/FlowConstantAsync.md +221 -0
- package/docs/api/interfaces/FlowDerivation.md +241 -0
- package/docs/api/interfaces/FlowDerivationAsync.md +242 -0
- package/docs/api/interfaces/FlowDisposable.md +32 -38
- package/docs/api/interfaces/FlowEffect.md +64 -0
- package/docs/api/interfaces/FlowMap.md +374 -0
- package/docs/api/interfaces/FlowObservable.md +155 -0
- package/docs/api/interfaces/FlowSignal.md +156 -0
- package/docs/api/interfaces/FlowState.md +269 -0
- package/docs/api/interfaces/FlowStateAsync.md +268 -0
- package/docs/api/interfaces/FlowSubscribable.md +55 -0
- package/docs/api/interfaces/FlowTracker.md +61 -0
- package/docs/api/interfaces/FlowValue.md +222 -0
- package/docs/api/interfaces/FlowWritableDerivation.md +292 -0
- package/docs/api/interfaces/FlowWritableDerivationAsync.md +293 -0
- package/docs/api/type-aliases/DerivationFunction.md +28 -0
- package/docs/api/type-aliases/DerivationFunctionAsync.md +28 -0
- package/docs/api/type-aliases/FlowArrayAction.md +19 -8
- package/docs/api/type-aliases/FlowDataTracker.md +33 -0
- package/docs/api/type-aliases/FlowMapAction.md +48 -0
- package/docs/api/type-aliases/FlowOnDataListener.md +33 -0
- package/docs/api/type-aliases/FlowOnErrorListener.md +27 -0
- package/docs/api/type-aliases/FlowOnPendingListener.md +21 -0
- package/docs/api/type-aliases/FlowReadonly.md +22 -0
- package/docs/api/type-aliases/InitFunction.md +21 -0
- package/docs/api/type-aliases/InitFunctionAsync.md +21 -0
- package/docs/api/type-aliases/NotPromise.md +6 -3
- package/docs/api/type-aliases/UpdateFunction.md +27 -0
- package/docs/api/type-aliases/UpdateFunctionAsync.md +27 -0
- package/docs/api/typedoc-sidebar.json +1 -81
- package/docs/examples/examples.md +0 -2
- package/docs/guide/advanced/architecture.md +1234 -0
- package/docs/guide/advanced/migration-v2.md +204 -0
- package/docs/guide/advanced/solidjs.md +2 -88
- package/docs/guide/introduction/concepts.md +4 -3
- package/docs/guide/introduction/conventions.md +2 -33
- package/docs/guide/introduction/getting-started.md +28 -23
- package/docs/guide/introduction/lifecycle.md +16 -19
- package/docs/guide/primitives/array.md +102 -216
- package/docs/guide/primitives/constant.md +39 -212
- package/docs/guide/primitives/derivations.md +55 -122
- package/docs/guide/primitives/effects.md +155 -241
- package/docs/guide/primitives/map.md +64 -186
- package/docs/guide/primitives/overview.md +45 -128
- package/docs/guide/primitives/signal.md +51 -88
- package/docs/guide/primitives/state.md +34 -130
- package/package.json +56 -60
- package/src/api/base/flowDisposable.ts +44 -0
- package/src/api/base/flowObservable.ts +28 -0
- package/src/api/base/flowSubscribable.ts +87 -0
- package/src/api/base/flowTracker.ts +7 -0
- package/src/api/base/index.ts +4 -0
- package/src/{flow → api}/index.ts +0 -1
- package/src/api/nodes/async/flowConstantAsync.ts +36 -0
- package/src/api/nodes/async/flowDerivationAsync.ts +42 -0
- package/src/api/nodes/async/flowStateAsync.ts +47 -0
- package/src/api/nodes/async/flowWritableDerivationAsync.ts +33 -0
- package/src/{flow → api}/nodes/async/index.ts +1 -2
- package/src/api/nodes/collections/flowArray.ts +155 -0
- package/src/api/nodes/collections/flowMap.ts +115 -0
- package/src/api/nodes/flowEffect.ts +42 -0
- package/src/api/nodes/flowSignal.ts +28 -0
- package/src/api/nodes/flowValue.ts +36 -0
- package/src/api/nodes/index.ts +7 -0
- package/src/api/nodes/sync/flowConstant.ts +33 -0
- package/src/api/nodes/sync/flowDerivation.ts +41 -0
- package/src/api/nodes/sync/flowState.ts +45 -0
- package/src/api/nodes/sync/flowWritableDerivation.ts +31 -0
- package/src/{flow → api}/nodes/sync/index.ts +1 -2
- package/src/api/nodes/utils.ts +22 -0
- package/src/base/disposable.ts +18 -0
- package/src/base/executionStack.ts +42 -0
- package/src/base/index.ts +5 -0
- package/src/base/node.ts +98 -0
- package/src/base/observable.ts +87 -0
- package/src/base/observer.ts +51 -0
- package/src/converters/index.ts +1 -0
- package/src/converters/solid.ts +109 -0
- package/src/index.ts +2 -64
- package/src/nodes/arrayNode.ts +172 -0
- package/src/nodes/effectNode.ts +59 -0
- package/src/nodes/index.ts +8 -0
- package/src/nodes/mapNode.ts +127 -0
- package/src/nodes/signalNode.ts +21 -0
- package/src/nodes/valueAsyncNode.ts +88 -0
- package/src/nodes/valueNode.ts +144 -0
- package/src/nodes/valueSyncNode.ts +128 -0
- package/src/schedulers/asyncResolver.ts +78 -0
- package/src/schedulers/asyncScheduler.ts +66 -0
- package/src/schedulers/index.ts +4 -0
- package/src/schedulers/pendingError.ts +13 -0
- package/src/schedulers/scheduler.ts +9 -0
- package/src/schedulers/syncResolver.ts +69 -0
- package/src/schedulers/syncScheduler.ts +55 -0
- package/test/base/pendingError.test.ts +67 -0
- package/test/converters/solid.derivation.browser.test.tsx +69 -0
- package/test/converters/solid.node.test.ts +654 -0
- package/test/converters/solid.state.browser.test.tsx +1592 -0
- package/test/reactivity/flowSignal.test.ts +226 -0
- package/test/reactivity/nodes/async/asyncScheduler/asyncResolver.test.ts +593 -0
- package/test/reactivity/nodes/async/asyncScheduler/asyncScheduler.test.ts +317 -0
- package/test/reactivity/nodes/async/flowConstantAsync.test.ts +652 -0
- package/test/reactivity/nodes/async/flowDerivation.test.ts +898 -0
- package/test/reactivity/nodes/async/flowDerivationAsync.test.ts +1716 -0
- package/test/reactivity/nodes/async/flowStateAsync.test.ts +708 -0
- package/test/reactivity/nodes/async/flowWritableDerivationAsync.test.ts +614 -0
- package/test/reactivity/nodes/collections/flowArray.asyncStates.test.ts +1289 -0
- package/test/reactivity/nodes/collections/flowArray.scalars.test.ts +961 -0
- package/test/reactivity/nodes/collections/flowArray.states.test.ts +1035 -0
- package/test/reactivity/nodes/collections/flowMap.asyncStates.test.ts +960 -0
- package/test/reactivity/nodes/collections/flowMap.scalars.test.ts +775 -0
- package/test/reactivity/nodes/collections/flowMap.states.test.ts +958 -0
- package/test/reactivity/nodes/sync/flowConstant.test.ts +377 -0
- package/test/reactivity/nodes/sync/flowDerivation.test.ts +896 -0
- package/test/reactivity/nodes/sync/flowState.test.ts +341 -0
- package/test/reactivity/nodes/sync/flowWritableDerivation.test.ts +603 -0
- package/test/vitest.d.ts +10 -0
- package/tsconfig.json +31 -20
- package/typedoc.json +35 -35
- package/vite.config.ts +25 -23
- package/vitest.browser.config.ts +21 -0
- package/vitest.config.ts +12 -12
- package/.cursor/plans/unifier-flowresource-avec-flowderivation-c9506e24.plan.md +0 -372
- package/.cursor/plans/update-js-e795d61b.plan.md +0 -567
- package/dist/types/flow/base/flowDisposable.d.ts +0 -67
- package/dist/types/flow/base/flowDisposable.d.ts.map +0 -1
- package/dist/types/flow/base/flowEffect.d.ts +0 -127
- package/dist/types/flow/base/flowEffect.d.ts.map +0 -1
- package/dist/types/flow/base/flowGraph.d.ts +0 -97
- package/dist/types/flow/base/flowGraph.d.ts.map +0 -1
- package/dist/types/flow/base/flowSignal.d.ts +0 -134
- package/dist/types/flow/base/flowSignal.d.ts.map +0 -1
- package/dist/types/flow/base/flowTracker.d.ts +0 -15
- package/dist/types/flow/base/flowTracker.d.ts.map +0 -1
- package/dist/types/flow/base/index.d.ts +0 -7
- package/dist/types/flow/base/index.d.ts.map +0 -1
- package/dist/types/flow/base/utils.d.ts +0 -20
- package/dist/types/flow/base/utils.d.ts.map +0 -1
- package/dist/types/flow/collections/flowArray.d.ts +0 -148
- package/dist/types/flow/collections/flowArray.d.ts.map +0 -1
- package/dist/types/flow/collections/flowMap.d.ts +0 -224
- package/dist/types/flow/collections/flowMap.d.ts.map +0 -1
- package/dist/types/flow/collections/index.d.ts.map +0 -1
- package/dist/types/flow/index.d.ts +0 -4
- package/dist/types/flow/index.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowConstantAsync.d.ts +0 -137
- package/dist/types/flow/nodes/async/flowConstantAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowDerivationAsync.d.ts +0 -137
- package/dist/types/flow/nodes/async/flowDerivationAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowNodeAsync.d.ts +0 -343
- package/dist/types/flow/nodes/async/flowNodeAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowReadonlyAsync.d.ts +0 -81
- package/dist/types/flow/nodes/async/flowReadonlyAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowStateAsync.d.ts +0 -111
- package/dist/types/flow/nodes/async/flowStateAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/index.d.ts.map +0 -1
- package/dist/types/flow/nodes/index.d.ts +0 -3
- package/dist/types/flow/nodes/index.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowConstant.d.ts +0 -108
- package/dist/types/flow/nodes/sync/flowConstant.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowDerivation.d.ts +0 -100
- package/dist/types/flow/nodes/sync/flowDerivation.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowNode.d.ts +0 -314
- package/dist/types/flow/nodes/sync/flowNode.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowReadonly.d.ts +0 -57
- package/dist/types/flow/nodes/sync/flowReadonly.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowState.d.ts +0 -96
- package/dist/types/flow/nodes/sync/flowState.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/index.d.ts.map +0 -1
- package/dist/types/solid/converters.d.ts +0 -57
- package/dist/types/solid/converters.d.ts.map +0 -1
- package/dist/types/solid/index.d.ts +0 -3
- package/dist/types/solid/index.d.ts.map +0 -1
- package/dist/types/solid/primitives.d.ts +0 -181
- package/dist/types/solid/primitives.d.ts.map +0 -1
- package/docs/api/classes/FlowArray.md +0 -489
- package/docs/api/classes/FlowConstant.md +0 -350
- package/docs/api/classes/FlowDerivation.md +0 -334
- package/docs/api/classes/FlowEffect.md +0 -100
- package/docs/api/classes/FlowMap.md +0 -512
- package/docs/api/classes/FlowObservable.md +0 -306
- package/docs/api/classes/FlowResource.md +0 -380
- package/docs/api/classes/FlowResourceAsync.md +0 -362
- package/docs/api/classes/FlowSignal.md +0 -160
- package/docs/api/classes/FlowState.md +0 -368
- package/docs/api/classes/FlowStream.md +0 -367
- package/docs/api/classes/FlowStreamAsync.md +0 -364
- package/docs/api/classes/SolidDerivation.md +0 -75
- package/docs/api/classes/SolidResource.md +0 -91
- package/docs/api/classes/SolidState.md +0 -71
- package/docs/api/classes/TrackingContext.md +0 -33
- package/docs/api/functions/effect.md +0 -49
- package/docs/api/functions/resource.md +0 -52
- package/docs/api/functions/resourceAsync.md +0 -50
- package/docs/api/functions/stream.md +0 -53
- package/docs/api/functions/streamAsync.md +0 -50
- package/docs/api/interfaces/SolidObservable.md +0 -19
- package/docs/api/type-aliases/FlowStreamDisposer.md +0 -15
- package/docs/api/type-aliases/FlowStreamSetter.md +0 -27
- package/docs/api/type-aliases/FlowStreamUpdater.md +0 -32
- package/docs/api/type-aliases/SolidGetter.md +0 -17
- package/docs/guide/primitives/resources.md +0 -858
- package/docs/guide/primitives/streams.md +0 -931
- package/src/flow/base/flowDisposable.ts +0 -71
- package/src/flow/base/flowEffect.ts +0 -171
- package/src/flow/base/flowGraph.ts +0 -288
- package/src/flow/base/flowSignal.ts +0 -207
- package/src/flow/base/flowTracker.ts +0 -17
- package/src/flow/base/index.ts +0 -6
- package/src/flow/base/utils.ts +0 -19
- package/src/flow/collections/flowArray.ts +0 -409
- package/src/flow/collections/flowMap.ts +0 -398
- package/src/flow/nodes/async/flowConstantAsync.ts +0 -142
- package/src/flow/nodes/async/flowDerivationAsync.ts +0 -143
- package/src/flow/nodes/async/flowNodeAsync.ts +0 -474
- package/src/flow/nodes/async/flowReadonlyAsync.ts +0 -81
- package/src/flow/nodes/async/flowStateAsync.ts +0 -116
- package/src/flow/nodes/await/advanced/index.ts +0 -5
- package/src/flow/nodes/await/advanced/resource.ts +0 -134
- package/src/flow/nodes/await/advanced/resourceAsync.ts +0 -109
- package/src/flow/nodes/await/advanced/stream.ts +0 -188
- package/src/flow/nodes/await/advanced/streamAsync.ts +0 -176
- package/src/flow/nodes/await/flowConstantAwait.ts +0 -154
- package/src/flow/nodes/await/flowDerivationAwait.ts +0 -154
- package/src/flow/nodes/await/flowNodeAwait.ts +0 -508
- package/src/flow/nodes/await/flowReadonlyAwait.ts +0 -89
- package/src/flow/nodes/await/flowStateAwait.ts +0 -130
- package/src/flow/nodes/await/index.ts +0 -5
- package/src/flow/nodes/index.ts +0 -3
- package/src/flow/nodes/sync/flowConstant.ts +0 -111
- package/src/flow/nodes/sync/flowDerivation.ts +0 -105
- package/src/flow/nodes/sync/flowNode.ts +0 -439
- package/src/flow/nodes/sync/flowReadonly.ts +0 -57
- package/src/flow/nodes/sync/flowState.ts +0 -101
- package/src/solid/converters.ts +0 -148
- package/src/solid/index.ts +0 -2
- package/src/solid/primitives.ts +0 -215
- package/test/base/flowEffect.test.ts +0 -108
- package/test/base/flowGraph.test.ts +0 -485
- package/test/base/flowSignal.test.ts +0 -372
- package/test/collections/flowArray.asyncStates.test.ts +0 -1553
- package/test/collections/flowArray.scalars.test.ts +0 -1129
- package/test/collections/flowArray.states.test.ts +0 -1365
- package/test/collections/flowMap.asyncStates.test.ts +0 -1105
- package/test/collections/flowMap.scalars.test.ts +0 -877
- package/test/collections/flowMap.states.test.ts +0 -1097
- package/test/nodes/async/flowConstantAsync.test.ts +0 -860
- package/test/nodes/async/flowDerivationAsync.test.ts +0 -1517
- package/test/nodes/async/flowStateAsync.test.ts +0 -1387
- package/test/nodes/await/advanced/resource.test.ts +0 -129
- package/test/nodes/await/advanced/resourceAsync.test.ts +0 -108
- package/test/nodes/await/advanced/stream.test.ts +0 -198
- package/test/nodes/await/advanced/streamAsync.test.ts +0 -196
- package/test/nodes/await/flowConstantAwait.test.ts +0 -643
- package/test/nodes/await/flowDerivationAwait.test.ts +0 -1583
- package/test/nodes/await/flowStateAwait.test.ts +0 -999
- package/test/nodes/mixed/derivation.test.ts +0 -1527
- package/test/nodes/sync/flowConstant.test.ts +0 -620
- package/test/nodes/sync/flowDerivation.test.ts +0 -1373
- package/test/nodes/sync/flowState.test.ts +0 -945
- package/test/solid/converters.test.ts +0 -721
- package/test/solid/primitives.test.ts +0 -1031
- /package/dist/types/{flow → api/nodes}/collections/index.d.ts +0 -0
- /package/docs/guide/advanced/{upgrading.md → migration-v1.md} +0 -0
- /package/src/{flow → api/nodes}/collections/index.ts +0 -0
|
@@ -0,0 +1,1592 @@
|
|
|
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
|
+
});
|