@playfast/reform 1.1.1 → 1.2.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/README.md +85 -55
- package/package.json +17 -17
- package/src/boundary/boundary.test.ts +62 -16
- package/src/boundary/boundary.ts +141 -32
- package/src/calc/asyncCalc.invalidate.test.ts +516 -18
- package/src/calc/asyncCalc.test.ts +207 -175
- package/src/calc/asyncCalc.ts +168 -39
- package/src/calc/calc.test.ts +3 -5
- package/src/calc/calc.ts +44 -18
- package/src/calc/calcFamily.test.ts +80 -22
- package/src/calc/calcFamily.ts +56 -25
- package/src/calc/compose.ts +1 -14
- package/src/channel/channel.ts +128 -11
- package/src/compose/composition.test.ts +19 -0
- package/src/compose/composition.ts +346 -62
- package/src/compose/props.ts +13 -6
- package/src/compose/provide.ts +187 -46
- package/src/compose/slot.ts +156 -19
- package/src/compose/structure.test.ts +6 -3
- package/src/compose/structure.ts +106 -13
- package/src/compose/ui.test.ts +19 -3
- package/src/compose/ui.ts +147 -54
- package/src/compose/ui.typecheck.ts +40 -4
- package/src/definition/definition.ts +22 -9
- package/src/event/event.fromSource.test.ts +172 -0
- package/src/event/event.test.ts +10 -0
- package/src/event/event.ts +102 -18
- package/src/feature/feature.mount.test.ts +123 -56
- package/src/feature/feature.test.ts +67 -63
- package/src/feature/feature.ts +1317 -197
- package/src/feature/feature.typecheck.ts +253 -61
- package/src/graph/closure.ts +403 -0
- package/src/index.ts +171 -245
- package/src/internal/bucketCache.ts +39 -0
- package/src/internal/capture.ts +9 -4
- package/src/internal/env.ts +1 -3
- package/src/internal/errors.ts +21 -10
- package/src/internal/queryDriver.ts +120 -15
- package/src/internal/queryDriverStore.ts +8 -5
- package/src/internal/queryDriverTypes.ts +3 -1
- package/src/internal/reuse.test.ts +10 -3
- package/src/internal/reuse.ts +5 -2
- package/src/internal/scheduler.ts +4 -1
- package/src/internal/sources.ts +25 -11
- package/src/internal/track.ts +3 -2
- package/src/internal.ts +222 -0
- package/src/namespace/namespace.ts +46 -25
- package/src/procedure/procedure.ts +38 -11
- package/src/reducer/reducer.ts +78 -34
- package/src/remote/remoteState.test.ts +515 -339
- package/src/remote/remoteState.ts +572 -107
- package/src/remote/remoteState.typecheck.ts +47 -23
- package/src/runtime/appRuntime.activation.test.ts +100 -0
- package/src/runtime/appRuntime.test.ts +157 -105
- package/src/runtime/appRuntime.ts +394 -33
- package/src/runtime/eventBudget.test.ts +1 -4
- package/src/runtime/eventBudget.ts +9 -8
- package/src/runtime/hardening.test.ts +4 -9
- package/src/runtime/instrumentation.test.ts +174 -192
- package/src/runtime/instrumentation.ts +6 -11
- package/src/runtime/loop.test.ts +36 -0
- package/src/runtime/loop.ts +69 -40
- package/src/scene/featureScene.test.ts +4 -2
- package/src/scene/scene.ts +234 -64
- package/src/scene/seedScene.test.ts +69 -86
- package/src/state/state.nominal.typecheck.ts +68 -0
- package/src/state/state.test.ts +17 -0
- package/src/state/state.ts +79 -26
- package/src/state/stateFamily.test.ts +14 -0
- package/src/state/stateFamily.ts +55 -22
- package/src/state/stateGroup.ts +53 -17
- package/src/state/token.ts +40 -10
- package/src/synced/syncedStore.ts +46 -23
- package/src/testkit/flight.testkit.ts +75 -0
- package/src/wire/tree.test.ts +8 -4
- package/src/wire/triggers.test.ts +6 -2
- package/src/wire/triggers.ts +14 -10
- package/src/calc/asyncCalcDefinitions.ts +0 -48
- package/src/channel/procedureRegistry.ts +0 -90
- package/src/feature/featureBinding.ts +0 -48
- package/src/internal/ctx.ts +0 -9
- package/src/remote/remoteStateDefinition.ts +0 -135
- package/src/remote/remoteStateLayers.ts +0 -118
- package/src/remote/remoteStateLiveTypes.ts +0 -59
- package/src/remote/remoteStateSend.ts +0 -64
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
import { expect, it } from '@effect/vitest'
|
|
2
2
|
import { Data, Duration, Effect, Layer, Schema as S } from 'effect'
|
|
3
3
|
import { AsyncCalc, Engine, Event, State, StateGroup } from '../index'
|
|
4
|
-
|
|
5
|
-
const tick = (ms = 10) => Effect.sleep(Duration.millis(ms))
|
|
6
|
-
|
|
7
|
-
const until = <A>(read: () => A, pred: (a: A) => boolean, rounds = 200): Effect.Effect<A> =>
|
|
8
|
-
Effect.suspend(() => {
|
|
9
|
-
const a = read()
|
|
10
|
-
return pred(a) || rounds <= 0
|
|
11
|
-
? Effect.succeed(a)
|
|
12
|
-
: Effect.flatMap(tick(10), () => until(read, pred, rounds - 1))
|
|
13
|
-
})
|
|
4
|
+
import { makeFlightGate, tick, until } from '../testkit/flight.testkit'
|
|
14
5
|
|
|
15
6
|
class Boom extends Data.TaggedError('Boom')<{ readonly message: string }> {}
|
|
16
7
|
|
|
@@ -216,7 +207,10 @@ it.live('reuse: a refetch returning mostly-equal data keeps unchanged element id
|
|
|
216
207
|
return Effect.gen(function* () {
|
|
217
208
|
const source = yield* StateGroup.select(Inputs, 'page').store
|
|
218
209
|
const store = yield* Rows.store
|
|
219
|
-
const first = yield* until(
|
|
210
|
+
const first = yield* until(
|
|
211
|
+
() => store.get(),
|
|
212
|
+
(v) => v._tag === 'Success',
|
|
213
|
+
)
|
|
220
214
|
if (first._tag !== 'Success') return
|
|
221
215
|
|
|
222
216
|
source.set(2)
|
|
@@ -231,80 +225,99 @@ it.live('reuse: a refetch returning mostly-equal data keeps unchanged element id
|
|
|
231
225
|
}).pipe(Effect.provide(TestLayer))
|
|
232
226
|
})
|
|
233
227
|
|
|
234
|
-
it.live(
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
()
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
228
|
+
it.live(
|
|
229
|
+
'coalesce trailing: a burst during one flight completes it and runs ONE trailing refetch',
|
|
230
|
+
() => {
|
|
231
|
+
class Count extends State.make('count', S.Number) {}
|
|
232
|
+
class Inputs extends StateGroup.make(Count) {}
|
|
233
|
+
const completed: number[] = []
|
|
234
|
+
class Doubled extends AsyncCalc.make('Doubled', {
|
|
235
|
+
inputs: [StateGroup.select(Inputs, 'count')],
|
|
236
|
+
output: S.Number,
|
|
237
|
+
alwaysOn: true,
|
|
238
|
+
}) {}
|
|
239
|
+
const gate = makeFlightGate()
|
|
240
|
+
const DoubledLive = AsyncCalc.live(Doubled, {
|
|
241
|
+
query: ({ count }) =>
|
|
242
|
+
gate.through(
|
|
243
|
+
Effect.sync(() => {
|
|
244
|
+
completed.push(count)
|
|
245
|
+
return count * 2
|
|
246
|
+
}),
|
|
247
|
+
),
|
|
248
|
+
coalesce: 'trailing',
|
|
249
|
+
})
|
|
250
|
+
const TestLayer = DoubledLive.pipe(Layer.provideMerge(StateGroup.live(Inputs, { count: 1 })))
|
|
251
|
+
|
|
252
|
+
return Effect.gen(function* () {
|
|
253
|
+
const source = yield* StateGroup.select(Inputs, 'count').store
|
|
254
|
+
const store = yield* Doubled.store
|
|
255
|
+
yield* until(
|
|
256
|
+
() => store.get(),
|
|
257
|
+
(v) => v._tag === 'Success',
|
|
258
|
+
)
|
|
259
|
+
expect(completed).toEqual([1])
|
|
260
|
+
|
|
261
|
+
// Hold the `2` flight at the gate so 3 and 4 land while it is in flight.
|
|
262
|
+
yield* gate.hold
|
|
263
|
+
source.set(2)
|
|
264
|
+
yield* gate.awaitEntry(2)
|
|
265
|
+
source.set(3)
|
|
266
|
+
yield* tick(5)
|
|
267
|
+
source.set(4)
|
|
268
|
+
yield* tick(5)
|
|
269
|
+
yield* gate.release
|
|
270
|
+
const settled = yield* until(
|
|
271
|
+
() => store.get(),
|
|
272
|
+
(v) => v._tag === 'Success' && v.refetching === false && v.value === 8,
|
|
273
|
+
)
|
|
274
|
+
expect(settled).toMatchObject({ _tag: 'Success', value: 8, refetching: false })
|
|
275
|
+
expect(completed).toEqual([1, 2, 4])
|
|
276
|
+
}).pipe(Effect.provide(TestLayer))
|
|
277
|
+
},
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
it.live(
|
|
281
|
+
'coalesce trailing: the stale settle re-flags refetching until the trailing run lands',
|
|
282
|
+
() => {
|
|
283
|
+
class Count extends State.make('count', S.Number) {}
|
|
284
|
+
class Inputs extends StateGroup.make(Count) {}
|
|
285
|
+
class Doubled extends AsyncCalc.make('Doubled', {
|
|
286
|
+
inputs: [StateGroup.select(Inputs, 'count')],
|
|
287
|
+
output: S.Number,
|
|
288
|
+
alwaysOn: true,
|
|
289
|
+
}) {}
|
|
290
|
+
const DoubledLive = AsyncCalc.live(Doubled, {
|
|
291
|
+
query: ({ count }) => Effect.succeed(count * 2).pipe(Effect.delay(Duration.millis(30))),
|
|
292
|
+
coalesce: 'trailing',
|
|
293
|
+
})
|
|
294
|
+
const TestLayer = DoubledLive.pipe(Layer.provideMerge(StateGroup.live(Inputs, { count: 1 })))
|
|
295
|
+
|
|
296
|
+
return Effect.gen(function* () {
|
|
297
|
+
const source = yield* StateGroup.select(Inputs, 'count').store
|
|
298
|
+
const store = yield* Doubled.store
|
|
299
|
+
yield* until(
|
|
300
|
+
() => store.get(),
|
|
301
|
+
(v) => v._tag === 'Success',
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
source.set(2)
|
|
305
|
+
yield* tick(5)
|
|
306
|
+
source.set(3)
|
|
307
|
+
const midflight = yield* until(
|
|
308
|
+
() => store.get(),
|
|
309
|
+
(v) => v._tag === 'Success' && v.value === 4,
|
|
310
|
+
)
|
|
311
|
+
expect(midflight).toMatchObject({ _tag: 'Success', value: 4, refetching: true })
|
|
312
|
+
|
|
313
|
+
const settled = yield* until(
|
|
314
|
+
() => store.get(),
|
|
315
|
+
(v) => v._tag === 'Success' && v.refetching === false,
|
|
316
|
+
)
|
|
317
|
+
expect(settled).toMatchObject({ _tag: 'Success', value: 6 })
|
|
318
|
+
}).pipe(Effect.provide(TestLayer))
|
|
319
|
+
},
|
|
320
|
+
)
|
|
308
321
|
|
|
309
322
|
it.live('coalesce trailing: a disable while a request waits in the slot skips the run', () => {
|
|
310
323
|
class Count extends State.make('count', S.Number) {}
|
|
@@ -314,12 +327,15 @@ it.live('coalesce trailing: a disable while a request waits in the slot skips th
|
|
|
314
327
|
inputs: [StateGroup.select(Inputs, 'count')],
|
|
315
328
|
output: S.Number,
|
|
316
329
|
}) {}
|
|
330
|
+
const gate = makeFlightGate()
|
|
317
331
|
const QLive = AsyncCalc.live(Q, {
|
|
318
332
|
query: ({ count }) =>
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
333
|
+
gate.through(
|
|
334
|
+
Effect.sync(() => {
|
|
335
|
+
completed.push(count)
|
|
336
|
+
return count * 2
|
|
337
|
+
}),
|
|
338
|
+
),
|
|
323
339
|
disabled: ({ count }) => count < 0,
|
|
324
340
|
coalesce: 'trailing',
|
|
325
341
|
})
|
|
@@ -328,19 +344,32 @@ it.live('coalesce trailing: a disable while a request waits in the slot skips th
|
|
|
328
344
|
return Effect.gen(function* () {
|
|
329
345
|
const source = yield* StateGroup.select(Inputs, 'count').store
|
|
330
346
|
const store = yield* Q.store
|
|
331
|
-
yield* until(
|
|
347
|
+
yield* until(
|
|
348
|
+
() => store.get(),
|
|
349
|
+
(v) => v._tag === 'Success',
|
|
350
|
+
)
|
|
332
351
|
|
|
352
|
+
// 3 queues behind the held `2` flight, then the disable overtakes it: the
|
|
353
|
+
// queued run must be dropped, not executed on release.
|
|
354
|
+
yield* gate.hold
|
|
333
355
|
source.set(2)
|
|
334
|
-
yield*
|
|
356
|
+
yield* gate.awaitEntry(2)
|
|
335
357
|
source.set(3)
|
|
336
|
-
yield* tick(
|
|
358
|
+
yield* tick(5)
|
|
337
359
|
source.set(-1)
|
|
360
|
+
yield* tick(5)
|
|
361
|
+
yield* gate.release
|
|
362
|
+
// Asserting an absence: give the consumer a real window to wake and (wrongly)
|
|
363
|
+
// run the queued key. A slow machine only widens the window, never narrows it.
|
|
338
364
|
yield* tick(60)
|
|
339
365
|
expect(store.get()._tag).toBe('Idle')
|
|
340
366
|
expect(completed).toEqual([1, 2])
|
|
341
367
|
|
|
342
368
|
source.set(5)
|
|
343
|
-
const settled = yield* until(
|
|
369
|
+
const settled = yield* until(
|
|
370
|
+
() => store.get(),
|
|
371
|
+
(v) => v._tag === 'Success',
|
|
372
|
+
)
|
|
344
373
|
expect(settled).toMatchObject({ _tag: 'Success', value: 10 })
|
|
345
374
|
expect(completed).toEqual([1, 2, 5])
|
|
346
375
|
}).pipe(Effect.provide(TestLayer))
|
|
@@ -384,86 +413,92 @@ it.live('invalidateOn: dispatching a listed event re-fetches with refetching: tr
|
|
|
384
413
|
}).pipe(Effect.provide(TestLayer))
|
|
385
414
|
})
|
|
386
415
|
|
|
387
|
-
it.live(
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
const status = yield* StateGroup.select(Inputs, 'status').store
|
|
414
|
-
yield* tick()
|
|
415
|
-
expect(runs.n).toBe(1)
|
|
416
|
-
|
|
417
|
-
status.set('b')
|
|
418
|
-
yield* tick()
|
|
419
|
-
expect(runs.n).toBe(1)
|
|
420
|
-
|
|
421
|
-
yield* Event.dispatch(Poke, {})
|
|
422
|
-
yield* tick()
|
|
423
|
-
expect(runs.n).toBe(2)
|
|
424
|
-
}).pipe(Effect.provide(TestLayer))
|
|
425
|
-
})
|
|
426
|
-
|
|
427
|
-
it.live('invalidateOn: a listed event while disabled stays Idle, and enabling re-fetches once', () => {
|
|
428
|
-
class Count extends State.make('count', S.Number) {}
|
|
429
|
-
class Inputs extends StateGroup.make(Count) {}
|
|
430
|
-
class Poke extends Event.make('Poke', S.Struct({})) {}
|
|
431
|
-
const runs = { n: 0 }
|
|
432
|
-
class Q extends AsyncCalc.make('Q', {
|
|
433
|
-
inputs: [StateGroup.select(Inputs, 'count')],
|
|
434
|
-
output: S.Number,
|
|
435
|
-
}) {}
|
|
436
|
-
const QLive = AsyncCalc.live(Q, {
|
|
437
|
-
query: ({ count }) =>
|
|
438
|
-
Effect.sync(() => {
|
|
439
|
-
runs.n += 1
|
|
440
|
-
return count * 2
|
|
441
|
-
}),
|
|
442
|
-
disabled: ({ count }) => count < 0,
|
|
443
|
-
invalidateOn: [Poke],
|
|
444
|
-
})
|
|
445
|
-
const TestLayer = QLive.pipe(
|
|
446
|
-
Layer.provideMerge(StateGroup.live(Inputs, { count: -1 })),
|
|
447
|
-
Layer.provideMerge(Engine),
|
|
448
|
-
)
|
|
449
|
-
|
|
450
|
-
return Effect.gen(function* () {
|
|
451
|
-
const source = yield* StateGroup.select(Inputs, 'count').store
|
|
452
|
-
const store = yield* Q.store
|
|
453
|
-
yield* tick()
|
|
454
|
-
expect(store.get()._tag).toBe('Idle')
|
|
416
|
+
it.live(
|
|
417
|
+
'invalidateOn: composes with invalidateBy — non-key churn stays inert, the event re-fetches',
|
|
418
|
+
() => {
|
|
419
|
+
class Status extends State.make('status', S.String) {}
|
|
420
|
+
class Page extends State.make('page', S.Number) {}
|
|
421
|
+
class Inputs extends StateGroup.make(Status, Page) {}
|
|
422
|
+
class Poke extends Event.make('Poke', S.Struct({})) {}
|
|
423
|
+
const runs = { n: 0 }
|
|
424
|
+
class Q extends AsyncCalc.make('Q', {
|
|
425
|
+
inputs: [StateGroup.select(Inputs, 'status'), StateGroup.select(Inputs, 'page')],
|
|
426
|
+
output: S.Number,
|
|
427
|
+
alwaysOn: true,
|
|
428
|
+
}) {}
|
|
429
|
+
const QLive = AsyncCalc.live(Q, {
|
|
430
|
+
query: ({ page }) =>
|
|
431
|
+
Effect.sync(() => {
|
|
432
|
+
runs.n += 1
|
|
433
|
+
return page
|
|
434
|
+
}),
|
|
435
|
+
invalidateBy: ({ page }) => [page],
|
|
436
|
+
invalidateOn: [Poke],
|
|
437
|
+
})
|
|
438
|
+
const TestLayer = QLive.pipe(
|
|
439
|
+
Layer.provideMerge(StateGroup.live(Inputs, { status: 'a', page: 1 })),
|
|
440
|
+
Layer.provideMerge(Engine),
|
|
441
|
+
)
|
|
455
442
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
443
|
+
return Effect.gen(function* () {
|
|
444
|
+
const status = yield* StateGroup.select(Inputs, 'status').store
|
|
445
|
+
yield* tick()
|
|
446
|
+
expect(runs.n).toBe(1)
|
|
447
|
+
|
|
448
|
+
status.set('b')
|
|
449
|
+
yield* tick()
|
|
450
|
+
expect(runs.n).toBe(1)
|
|
451
|
+
|
|
452
|
+
yield* Event.dispatch(Poke, {})
|
|
453
|
+
yield* tick()
|
|
454
|
+
expect(runs.n).toBe(2)
|
|
455
|
+
}).pipe(Effect.provide(TestLayer))
|
|
456
|
+
},
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
it.live(
|
|
460
|
+
'invalidateOn: a listed event while disabled stays Idle, and enabling re-fetches once',
|
|
461
|
+
() => {
|
|
462
|
+
class Count extends State.make('count', S.Number) {}
|
|
463
|
+
class Inputs extends StateGroup.make(Count) {}
|
|
464
|
+
class Poke extends Event.make('Poke', S.Struct({})) {}
|
|
465
|
+
const runs = { n: 0 }
|
|
466
|
+
class Q extends AsyncCalc.make('Q', {
|
|
467
|
+
inputs: [StateGroup.select(Inputs, 'count')],
|
|
468
|
+
output: S.Number,
|
|
469
|
+
}) {}
|
|
470
|
+
const QLive = AsyncCalc.live(Q, {
|
|
471
|
+
query: ({ count }) =>
|
|
472
|
+
Effect.sync(() => {
|
|
473
|
+
runs.n += 1
|
|
474
|
+
return count * 2
|
|
475
|
+
}),
|
|
476
|
+
disabled: ({ count }) => count < 0,
|
|
477
|
+
invalidateOn: [Poke],
|
|
478
|
+
})
|
|
479
|
+
const TestLayer = QLive.pipe(
|
|
480
|
+
Layer.provideMerge(StateGroup.live(Inputs, { count: -1 })),
|
|
481
|
+
Layer.provideMerge(Engine),
|
|
482
|
+
)
|
|
460
483
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
484
|
+
return Effect.gen(function* () {
|
|
485
|
+
const source = yield* StateGroup.select(Inputs, 'count').store
|
|
486
|
+
const store = yield* Q.store
|
|
487
|
+
yield* tick()
|
|
488
|
+
expect(store.get()._tag).toBe('Idle')
|
|
489
|
+
|
|
490
|
+
yield* Event.dispatch(Poke, {})
|
|
491
|
+
yield* tick()
|
|
492
|
+
expect(store.get()._tag).toBe('Idle')
|
|
493
|
+
expect(runs.n).toBe(0)
|
|
494
|
+
|
|
495
|
+
source.set(5)
|
|
496
|
+
yield* tick()
|
|
497
|
+
expect(store.get()).toMatchObject({ _tag: 'Success', value: 10 })
|
|
498
|
+
expect(runs.n).toBe(1)
|
|
499
|
+
}).pipe(Effect.provide(TestLayer))
|
|
500
|
+
},
|
|
501
|
+
)
|
|
467
502
|
|
|
468
503
|
it.live('invalidateOn: two async calcs keep independent hidden revisions', () => {
|
|
469
504
|
class Count extends State.make('count', S.Number) {}
|
|
@@ -498,10 +533,7 @@ it.live('invalidateOn: two async calcs keep independent hidden revisions', () =>
|
|
|
498
533
|
}),
|
|
499
534
|
invalidateOn: [PokeB],
|
|
500
535
|
}),
|
|
501
|
-
).pipe(
|
|
502
|
-
Layer.provideMerge(StateGroup.live(Inputs, { count: 1 })),
|
|
503
|
-
Layer.provideMerge(Engine),
|
|
504
|
-
)
|
|
536
|
+
).pipe(Layer.provideMerge(StateGroup.live(Inputs, { count: 1 })), Layer.provideMerge(Engine))
|
|
505
537
|
|
|
506
538
|
return Effect.gen(function* () {
|
|
507
539
|
yield* tick()
|