@zeix/cause-effect 0.14.1 → 0.15.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 +256 -27
- package/biome.json +35 -0
- package/index.d.ts +32 -7
- package/index.dev.js +629 -0
- package/index.js +1 -1
- package/index.ts +41 -21
- package/package.json +6 -7
- package/src/computed.ts +30 -21
- package/src/diff.ts +136 -0
- package/src/effect.ts +59 -49
- package/src/match.ts +57 -0
- package/src/resolve.ts +58 -0
- package/src/scheduler.ts +3 -3
- package/src/signal.ts +48 -15
- package/src/state.ts +4 -3
- package/src/store.ts +325 -0
- package/src/util.ts +57 -5
- package/test/batch.test.ts +29 -25
- package/test/benchmark.test.ts +81 -45
- package/test/computed.test.ts +43 -39
- package/test/diff.test.ts +638 -0
- package/test/effect.test.ts +657 -49
- package/test/match.test.ts +378 -0
- package/test/resolve.test.ts +156 -0
- package/test/state.test.ts +33 -33
- package/test/store.test.ts +719 -0
- package/test/util/framework-types.ts +2 -2
- package/test/util/perf-tests.ts +2 -2
- package/test/util/reactive-framework.ts +1 -1
- package/tsconfig.json +9 -10
- package/types/index.d.ts +15 -0
- package/{src → types/src}/computed.d.ts +2 -2
- package/types/src/diff.d.ts +27 -0
- package/types/src/effect.d.ts +16 -0
- package/types/src/match.d.ts +21 -0
- package/types/src/resolve.d.ts +29 -0
- package/{src → types/src}/scheduler.d.ts +2 -2
- package/types/src/signal.d.ts +40 -0
- package/{src → types/src}/state.d.ts +1 -1
- package/types/src/store.d.ts +57 -0
- package/types/src/util.d.ts +15 -0
- package/types/test-new-effect.d.ts +1 -0
- package/src/effect.d.ts +0 -17
- package/src/signal.d.ts +0 -26
- package/src/util.d.ts +0 -7
package/test/benchmark.test.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import { describe,
|
|
2
|
-
import {
|
|
3
|
-
import { makeGraph, runGraph
|
|
4
|
-
import {
|
|
5
|
-
type ReactiveFramework,
|
|
6
|
-
type Computed,
|
|
7
|
-
} from './util/reactive-framework'
|
|
1
|
+
import { describe, expect, mock, test } from 'bun:test'
|
|
2
|
+
import { batch, computed, effect, state } from '../'
|
|
3
|
+
import { Counter, makeGraph, runGraph } from './util/dependency-graph'
|
|
4
|
+
import type { Computed, ReactiveFramework } from './util/reactive-framework'
|
|
8
5
|
|
|
9
6
|
/* === Utility Functions === */
|
|
10
7
|
|
|
@@ -30,8 +27,8 @@ const framework = {
|
|
|
30
27
|
read: () => c.get(),
|
|
31
28
|
}
|
|
32
29
|
},
|
|
33
|
-
effect: (fn: () =>
|
|
34
|
-
withBatch: (fn: () =>
|
|
30
|
+
effect: (fn: () => undefined) => effect(fn),
|
|
31
|
+
withBatch: (fn: () => undefined) => batch(fn),
|
|
35
32
|
withBuild: <T>(fn: () => T) => fn(),
|
|
36
33
|
}
|
|
37
34
|
const testPullCounts = true
|
|
@@ -53,7 +50,7 @@ function makeConfig() {
|
|
|
53
50
|
/** some basic tests to validate the reactive framework
|
|
54
51
|
* wrapper works and can run performance tests.
|
|
55
52
|
*/
|
|
56
|
-
describe('Basic test',
|
|
53
|
+
describe('Basic test', () => {
|
|
57
54
|
const name = framework.name
|
|
58
55
|
test(`${name} | simple dependency executes`, () => {
|
|
59
56
|
framework.withBuild(() => {
|
|
@@ -145,11 +142,11 @@ describe('Basic test', function () {
|
|
|
145
142
|
})
|
|
146
143
|
|
|
147
144
|
test(`${name} | effect`, () => {
|
|
148
|
-
const spy = _v => {}
|
|
145
|
+
const spy = (_v: number) => {}
|
|
149
146
|
const spyMock = mock(spy)
|
|
150
147
|
|
|
151
148
|
const s = framework.signal(2)
|
|
152
|
-
let c:
|
|
149
|
+
let c: { read: () => number } = { read: () => 0 }
|
|
153
150
|
|
|
154
151
|
framework.withBuild(() => {
|
|
155
152
|
c = framework.computed(() => s.read() * 2)
|
|
@@ -169,18 +166,22 @@ describe('Basic test', function () {
|
|
|
169
166
|
})
|
|
170
167
|
})
|
|
171
168
|
|
|
172
|
-
describe('Kairo tests',
|
|
169
|
+
describe('Kairo tests', () => {
|
|
173
170
|
const name = framework.name
|
|
174
171
|
|
|
175
|
-
test(`${name} | avoidable propagation`, () => {
|
|
172
|
+
test(`${name} | avoidable propagation`, async () => {
|
|
176
173
|
const head = framework.signal(0)
|
|
177
174
|
const computed1 = framework.computed(() => head.read())
|
|
178
|
-
const computed2 = framework.computed(() =>
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
)
|
|
182
|
-
const
|
|
183
|
-
|
|
175
|
+
const computed2 = framework.computed(() => {
|
|
176
|
+
computed1.read()
|
|
177
|
+
return 0
|
|
178
|
+
})
|
|
179
|
+
const computed3 = framework.computed(() => {
|
|
180
|
+
busy()
|
|
181
|
+
return computed2.read() + 1
|
|
182
|
+
}) // heavy computation
|
|
183
|
+
const computed4 = framework.computed(() => computed3.read() + 2)
|
|
184
|
+
const computed5 = framework.computed(() => computed4.read() + 3)
|
|
184
185
|
framework.effect(() => {
|
|
185
186
|
computed5.read()
|
|
186
187
|
busy() // heavy side effect
|
|
@@ -200,16 +201,16 @@ describe('Kairo tests', function () {
|
|
|
200
201
|
}
|
|
201
202
|
})
|
|
202
203
|
|
|
203
|
-
test(`${name} | broad propagation`, () => {
|
|
204
|
+
test(`${name} | broad propagation`, async () => {
|
|
204
205
|
const head = framework.signal(0)
|
|
205
206
|
let last = head as { read: () => number }
|
|
206
207
|
const callCounter = new Counter()
|
|
207
208
|
for (let i = 0; i < 50; i++) {
|
|
208
209
|
const current = framework.computed(() => {
|
|
209
|
-
return head.read()
|
|
210
|
+
return head.read() + i
|
|
210
211
|
})
|
|
211
212
|
const current2 = framework.computed(() => {
|
|
212
|
-
return current.read()
|
|
213
|
+
return current.read() + 1
|
|
213
214
|
})
|
|
214
215
|
framework.effect(() => {
|
|
215
216
|
current2.read()
|
|
@@ -234,7 +235,7 @@ describe('Kairo tests', function () {
|
|
|
234
235
|
}
|
|
235
236
|
})
|
|
236
237
|
|
|
237
|
-
test(`${name} | deep propagation`, () => {
|
|
238
|
+
test(`${name} | deep propagation`, async () => {
|
|
238
239
|
const len = 50
|
|
239
240
|
const head = framework.signal(0)
|
|
240
241
|
let current = head as { read: () => number }
|
|
@@ -267,7 +268,7 @@ describe('Kairo tests', function () {
|
|
|
267
268
|
}
|
|
268
269
|
})
|
|
269
270
|
|
|
270
|
-
test(`${name} | diamond`,
|
|
271
|
+
test(`${name} | diamond`, async () => {
|
|
271
272
|
const width = 5
|
|
272
273
|
const head = framework.signal(0)
|
|
273
274
|
const current: { read(): number }[] = []
|
|
@@ -300,7 +301,7 @@ describe('Kairo tests', function () {
|
|
|
300
301
|
}
|
|
301
302
|
})
|
|
302
303
|
|
|
303
|
-
test(`${name} | mux`,
|
|
304
|
+
test(`${name} | mux`, async () => {
|
|
304
305
|
const heads = new Array(100).fill(null).map(_ => framework.signal(0))
|
|
305
306
|
const mux = framework.computed(() => {
|
|
306
307
|
return Object.fromEntries(heads.map(h => h.read()).entries())
|
|
@@ -310,7 +311,9 @@ describe('Kairo tests', function () {
|
|
|
310
311
|
.map(x => framework.computed(() => x.read() + 1))
|
|
311
312
|
|
|
312
313
|
splited.forEach(x => {
|
|
313
|
-
framework.effect(() =>
|
|
314
|
+
framework.effect(() => {
|
|
315
|
+
x.read()
|
|
316
|
+
})
|
|
314
317
|
})
|
|
315
318
|
|
|
316
319
|
return () => {
|
|
@@ -329,7 +332,7 @@ describe('Kairo tests', function () {
|
|
|
329
332
|
}
|
|
330
333
|
})
|
|
331
334
|
|
|
332
|
-
test(`${name} | repeated observers`,
|
|
335
|
+
test(`${name} | repeated observers`, async () => {
|
|
333
336
|
const size = 30
|
|
334
337
|
const head = framework.signal(0)
|
|
335
338
|
const current = framework.computed(() => {
|
|
@@ -362,7 +365,7 @@ describe('Kairo tests', function () {
|
|
|
362
365
|
}
|
|
363
366
|
})
|
|
364
367
|
|
|
365
|
-
test(`${name} | triangle`,
|
|
368
|
+
test(`${name} | triangle`, async () => {
|
|
366
369
|
const width = 10
|
|
367
370
|
const head = framework.signal(0)
|
|
368
371
|
let current = head as { read: () => number }
|
|
@@ -407,7 +410,7 @@ describe('Kairo tests', function () {
|
|
|
407
410
|
}
|
|
408
411
|
})
|
|
409
412
|
|
|
410
|
-
test(`${name} | unstable`,
|
|
413
|
+
test(`${name} | unstable`, async () => {
|
|
411
414
|
const head = framework.signal(0)
|
|
412
415
|
const double = framework.computed(() => head.read() * 2)
|
|
413
416
|
const inverse = framework.computed(() => -head.read())
|
|
@@ -442,10 +445,10 @@ describe('Kairo tests', function () {
|
|
|
442
445
|
})
|
|
443
446
|
})
|
|
444
447
|
|
|
445
|
-
describe('$mol_wire tests',
|
|
448
|
+
describe('$mol_wire tests', () => {
|
|
446
449
|
const name = framework.name
|
|
447
450
|
|
|
448
|
-
test(`${name} | $mol_wire benchmark`,
|
|
451
|
+
test(`${name} | $mol_wire benchmark`, () => {
|
|
449
452
|
const fib = (n: number) => {
|
|
450
453
|
if (n < 2) return 1
|
|
451
454
|
return fib(n - 1) + fib(n - 2)
|
|
@@ -454,7 +457,7 @@ describe('$mol_wire tests', function () {
|
|
|
454
457
|
return n + fib(16)
|
|
455
458
|
}
|
|
456
459
|
const numbers = Array.from({ length: 5 }, (_, i) => i)
|
|
457
|
-
const res: (() =>
|
|
460
|
+
const res: (() => unknown)[] = []
|
|
458
461
|
framework.withBuild(() => {
|
|
459
462
|
const A = framework.signal(0)
|
|
460
463
|
const B = framework.signal(0)
|
|
@@ -475,12 +478,24 @@ describe('$mol_wire tests', function () {
|
|
|
475
478
|
D.read()[4].x +
|
|
476
479
|
F.read(),
|
|
477
480
|
)
|
|
478
|
-
framework.effect(() =>
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
framework.effect(() =>
|
|
482
|
-
|
|
483
|
-
|
|
481
|
+
framework.effect(() => {
|
|
482
|
+
res.push(hard(G.read(), 'H'))
|
|
483
|
+
})
|
|
484
|
+
framework.effect(() => {
|
|
485
|
+
res.push(G.read())
|
|
486
|
+
}) // I
|
|
487
|
+
framework.effect(() => {
|
|
488
|
+
res.push(hard(F.read(), 'J'))
|
|
489
|
+
})
|
|
490
|
+
framework.effect(() => {
|
|
491
|
+
res[0] = hard(G.read(), 'H')
|
|
492
|
+
})
|
|
493
|
+
framework.effect(() => {
|
|
494
|
+
res[1] = G.read()
|
|
495
|
+
}) // I
|
|
496
|
+
framework.effect(() => {
|
|
497
|
+
res[2] = hard(F.read(), 'J')
|
|
498
|
+
})
|
|
484
499
|
|
|
485
500
|
return (i: number) => {
|
|
486
501
|
res.length = 0
|
|
@@ -499,10 +514,10 @@ describe('$mol_wire tests', function () {
|
|
|
499
514
|
})
|
|
500
515
|
})
|
|
501
516
|
|
|
502
|
-
describe('CellX tests',
|
|
517
|
+
describe('CellX tests', () => {
|
|
503
518
|
const name = framework.name
|
|
504
519
|
|
|
505
|
-
test(`${name} | CellX benchmark`,
|
|
520
|
+
test(`${name} | CellX benchmark`, () => {
|
|
506
521
|
const expected = {
|
|
507
522
|
10: [
|
|
508
523
|
[3, 6, 2, -2],
|
|
@@ -540,10 +555,31 @@ describe('CellX tests', function () {
|
|
|
540
555
|
prop4: framework.computed(() => m.prop3.read()),
|
|
541
556
|
}
|
|
542
557
|
|
|
543
|
-
framework.effect(() =>
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
framework.effect(() =>
|
|
558
|
+
framework.effect(() => {
|
|
559
|
+
s.prop1.read()
|
|
560
|
+
})
|
|
561
|
+
framework.effect(() => {
|
|
562
|
+
s.prop2.read()
|
|
563
|
+
})
|
|
564
|
+
framework.effect(() => {
|
|
565
|
+
s.prop3.read()
|
|
566
|
+
})
|
|
567
|
+
framework.effect(() => {
|
|
568
|
+
s.prop4.read()
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
framework.effect(() => {
|
|
572
|
+
s.prop1.read()
|
|
573
|
+
})
|
|
574
|
+
framework.effect(() => {
|
|
575
|
+
s.prop2.read()
|
|
576
|
+
})
|
|
577
|
+
framework.effect(() => {
|
|
578
|
+
s.prop3.read()
|
|
579
|
+
})
|
|
580
|
+
framework.effect(() => {
|
|
581
|
+
s.prop4.read()
|
|
582
|
+
})
|
|
547
583
|
|
|
548
584
|
s.prop1.read()
|
|
549
585
|
s.prop2.read()
|
package/test/computed.test.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { describe,
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
2
|
import {
|
|
3
|
-
state,
|
|
4
3
|
computed,
|
|
5
|
-
|
|
4
|
+
effect,
|
|
6
5
|
isComputed,
|
|
7
6
|
isState,
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
match,
|
|
8
|
+
resolve,
|
|
9
|
+
state,
|
|
10
|
+
UNSET,
|
|
11
|
+
} from '../'
|
|
10
12
|
|
|
11
13
|
/* === Utility Functions === */
|
|
12
14
|
|
|
@@ -15,7 +17,7 @@ const increment = (n: number) => (Number.isFinite(n) ? n + 1 : UNSET)
|
|
|
15
17
|
|
|
16
18
|
/* === Tests === */
|
|
17
19
|
|
|
18
|
-
describe('Computed',
|
|
20
|
+
describe('Computed', () => {
|
|
19
21
|
test('should identify computed signals with isComputed()', () => {
|
|
20
22
|
const count = state(42)
|
|
21
23
|
const doubled = computed(() => count.get() * 2)
|
|
@@ -23,25 +25,25 @@ describe('Computed', function () {
|
|
|
23
25
|
expect(isState(doubled)).toBe(false)
|
|
24
26
|
})
|
|
25
27
|
|
|
26
|
-
test('should compute a function',
|
|
28
|
+
test('should compute a function', () => {
|
|
27
29
|
const derived = computed(() => 1 + 2)
|
|
28
30
|
expect(derived.get()).toBe(3)
|
|
29
31
|
})
|
|
30
32
|
|
|
31
|
-
test('should compute function dependent on a signal',
|
|
33
|
+
test('should compute function dependent on a signal', () => {
|
|
32
34
|
const cause = state(42)
|
|
33
35
|
const derived = computed(() => cause.get() + 1)
|
|
34
36
|
expect(derived.get()).toBe(43)
|
|
35
37
|
})
|
|
36
38
|
|
|
37
|
-
test('should compute function dependent on an updated signal',
|
|
39
|
+
test('should compute function dependent on an updated signal', () => {
|
|
38
40
|
const cause = state(42)
|
|
39
41
|
const derived = computed(() => cause.get() + 1)
|
|
40
42
|
cause.set(24)
|
|
41
43
|
expect(derived.get()).toBe(25)
|
|
42
44
|
})
|
|
43
45
|
|
|
44
|
-
test('should compute function dependent on an async signal', async
|
|
46
|
+
test('should compute function dependent on an async signal', async () => {
|
|
45
47
|
const status = state('pending')
|
|
46
48
|
const promised = computed(async () => {
|
|
47
49
|
await wait(100)
|
|
@@ -56,7 +58,7 @@ describe('Computed', function () {
|
|
|
56
58
|
expect(status.get()).toBe('success')
|
|
57
59
|
})
|
|
58
60
|
|
|
59
|
-
test('should handle errors from an async signal gracefully', async
|
|
61
|
+
test('should handle errors from an async signal gracefully', async () => {
|
|
60
62
|
const status = state('pending')
|
|
61
63
|
const error = state('')
|
|
62
64
|
const promised = computed(async () => {
|
|
@@ -73,7 +75,7 @@ describe('Computed', function () {
|
|
|
73
75
|
expect(status.get()).toBe('error')
|
|
74
76
|
})
|
|
75
77
|
|
|
76
|
-
test('should compute task signals in parallel without waterfalls', async
|
|
78
|
+
test('should compute task signals in parallel without waterfalls', async () => {
|
|
77
79
|
const a = computed(async () => {
|
|
78
80
|
await wait(100)
|
|
79
81
|
return 10
|
|
@@ -94,7 +96,7 @@ describe('Computed', function () {
|
|
|
94
96
|
expect(c.get()).toBe(30)
|
|
95
97
|
})
|
|
96
98
|
|
|
97
|
-
test('should compute function dependent on a chain of computed states dependent on a signal',
|
|
99
|
+
test('should compute function dependent on a chain of computed states dependent on a signal', () => {
|
|
98
100
|
const x = state(42)
|
|
99
101
|
const a = computed(() => x.get() + 1)
|
|
100
102
|
const b = computed(() => a.get() * 2)
|
|
@@ -102,7 +104,7 @@ describe('Computed', function () {
|
|
|
102
104
|
expect(c.get()).toBe(87)
|
|
103
105
|
})
|
|
104
106
|
|
|
105
|
-
test('should compute function dependent on a chain of computed states dependent on an updated signal',
|
|
107
|
+
test('should compute function dependent on a chain of computed states dependent on an updated signal', () => {
|
|
106
108
|
const x = state(42)
|
|
107
109
|
const a = computed(() => x.get() + 1)
|
|
108
110
|
const b = computed(() => a.get() * 2)
|
|
@@ -111,14 +113,14 @@ describe('Computed', function () {
|
|
|
111
113
|
expect(c.get()).toBe(51)
|
|
112
114
|
})
|
|
113
115
|
|
|
114
|
-
test('should drop X->B->X updates',
|
|
116
|
+
test('should drop X->B->X updates', () => {
|
|
115
117
|
let count = 0
|
|
116
118
|
const x = state(2)
|
|
117
119
|
const a = computed(() => x.get() - 1)
|
|
118
120
|
const b = computed(() => x.get() + a.get())
|
|
119
121
|
const c = computed(() => {
|
|
120
122
|
count++
|
|
121
|
-
return
|
|
123
|
+
return `c: ${b.get()}`
|
|
122
124
|
})
|
|
123
125
|
expect(c.get()).toBe('c: 3')
|
|
124
126
|
expect(count).toBe(1)
|
|
@@ -127,14 +129,14 @@ describe('Computed', function () {
|
|
|
127
129
|
expect(count).toBe(2)
|
|
128
130
|
})
|
|
129
131
|
|
|
130
|
-
test('should only update every signal once (diamond graph)',
|
|
132
|
+
test('should only update every signal once (diamond graph)', () => {
|
|
131
133
|
let count = 0
|
|
132
134
|
const x = state('a')
|
|
133
135
|
const a = computed(() => x.get())
|
|
134
136
|
const b = computed(() => x.get())
|
|
135
137
|
const c = computed(() => {
|
|
136
138
|
count++
|
|
137
|
-
return a.get()
|
|
139
|
+
return `${a.get()} ${b.get()}`
|
|
138
140
|
})
|
|
139
141
|
expect(c.get()).toBe('a a')
|
|
140
142
|
expect(count).toBe(1)
|
|
@@ -144,12 +146,12 @@ describe('Computed', function () {
|
|
|
144
146
|
expect(count).toBe(2)
|
|
145
147
|
})
|
|
146
148
|
|
|
147
|
-
test('should only update every signal once (diamond graph + tail)',
|
|
149
|
+
test('should only update every signal once (diamond graph + tail)', () => {
|
|
148
150
|
let count = 0
|
|
149
151
|
const x = state('a')
|
|
150
152
|
const a = computed(() => x.get())
|
|
151
153
|
const b = computed(() => x.get())
|
|
152
|
-
const c = computed(() => a.get()
|
|
154
|
+
const c = computed(() => `${a.get()} ${b.get()}`)
|
|
153
155
|
const d = computed(() => {
|
|
154
156
|
count++
|
|
155
157
|
return c.get()
|
|
@@ -161,7 +163,7 @@ describe('Computed', function () {
|
|
|
161
163
|
expect(count).toBe(2)
|
|
162
164
|
})
|
|
163
165
|
|
|
164
|
-
test('should update multiple times after multiple state changes',
|
|
166
|
+
test('should update multiple times after multiple state changes', () => {
|
|
165
167
|
const a = state(3)
|
|
166
168
|
const b = state(4)
|
|
167
169
|
let count = 0
|
|
@@ -185,7 +187,7 @@ describe('Computed', function () {
|
|
|
185
187
|
* one-time performance cost that allows for efficient memoization and
|
|
186
188
|
* error handling in most cases.
|
|
187
189
|
*/
|
|
188
|
-
test('should bail out if result is the same',
|
|
190
|
+
test('should bail out if result is the same', () => {
|
|
189
191
|
let count = 0
|
|
190
192
|
const x = state('a')
|
|
191
193
|
const a = computed(() => {
|
|
@@ -205,7 +207,7 @@ describe('Computed', function () {
|
|
|
205
207
|
expect(count).toBe(2)
|
|
206
208
|
})
|
|
207
209
|
|
|
208
|
-
test('should block if result remains unchanged',
|
|
210
|
+
test('should block if result remains unchanged', () => {
|
|
209
211
|
let count = 0
|
|
210
212
|
const x = state(42)
|
|
211
213
|
const a = computed(() => x.get() % 2)
|
|
@@ -223,7 +225,7 @@ describe('Computed', function () {
|
|
|
223
225
|
expect(count).toBe(2)
|
|
224
226
|
})
|
|
225
227
|
|
|
226
|
-
test('should detect and throw error for circular dependencies',
|
|
228
|
+
test('should detect and throw error for circular dependencies', () => {
|
|
227
229
|
const a = state(1)
|
|
228
230
|
const b = computed(() => c.get() + 1)
|
|
229
231
|
const c = computed(() => b.get() + a.get())
|
|
@@ -233,7 +235,7 @@ describe('Computed', function () {
|
|
|
233
235
|
expect(a.get()).toBe(1)
|
|
234
236
|
})
|
|
235
237
|
|
|
236
|
-
test('should propagate error if an error occurred',
|
|
238
|
+
test('should propagate error if an error occurred', () => {
|
|
237
239
|
let okCount = 0
|
|
238
240
|
let errCount = 0
|
|
239
241
|
const x = state(0)
|
|
@@ -273,7 +275,7 @@ describe('Computed', function () {
|
|
|
273
275
|
}
|
|
274
276
|
})
|
|
275
277
|
|
|
276
|
-
test('should create an effect that reacts on async computed changes', async
|
|
278
|
+
test('should create an effect that reacts on async computed changes', async () => {
|
|
277
279
|
const cause = state(42)
|
|
278
280
|
const derived = computed(async () => {
|
|
279
281
|
await wait(100)
|
|
@@ -282,15 +284,17 @@ describe('Computed', function () {
|
|
|
282
284
|
let okCount = 0
|
|
283
285
|
let nilCount = 0
|
|
284
286
|
let result: number = 0
|
|
285
|
-
effect({
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
287
|
+
effect(() => {
|
|
288
|
+
const resolved = resolve({ derived })
|
|
289
|
+
match(resolved, {
|
|
290
|
+
ok: ({ derived: v }) => {
|
|
291
|
+
result = v
|
|
292
|
+
okCount++
|
|
293
|
+
},
|
|
294
|
+
nil: () => {
|
|
295
|
+
nilCount++
|
|
296
|
+
},
|
|
297
|
+
})
|
|
294
298
|
})
|
|
295
299
|
cause.set(43)
|
|
296
300
|
expect(okCount).toBe(0)
|
|
@@ -303,7 +307,7 @@ describe('Computed', function () {
|
|
|
303
307
|
expect(result).toBe(44)
|
|
304
308
|
})
|
|
305
309
|
|
|
306
|
-
test('should handle complex computed signal with error and async dependencies', async
|
|
310
|
+
test('should handle complex computed signal with error and async dependencies', async () => {
|
|
307
311
|
const toggleState = state(true)
|
|
308
312
|
const errorProne = computed(() => {
|
|
309
313
|
if (toggleState.get()) throw new Error('Intentional error')
|
|
@@ -350,7 +354,7 @@ describe('Computed', function () {
|
|
|
350
354
|
expect(errCount).toBeGreaterThan(0)
|
|
351
355
|
})
|
|
352
356
|
|
|
353
|
-
test('should handle signal changes during async computation', async
|
|
357
|
+
test('should handle signal changes during async computation', async () => {
|
|
354
358
|
const source = state(1)
|
|
355
359
|
let computationCount = 0
|
|
356
360
|
const derived = computed(async abort => {
|
|
@@ -371,7 +375,7 @@ describe('Computed', function () {
|
|
|
371
375
|
expect(computationCount).toBe(1)
|
|
372
376
|
})
|
|
373
377
|
|
|
374
|
-
test('should handle multiple rapid changes during async computation', async
|
|
378
|
+
test('should handle multiple rapid changes during async computation', async () => {
|
|
375
379
|
const source = state(1)
|
|
376
380
|
let computationCount = 0
|
|
377
381
|
const derived = computed(async abort => {
|
|
@@ -396,7 +400,7 @@ describe('Computed', function () {
|
|
|
396
400
|
expect(computationCount).toBe(1)
|
|
397
401
|
})
|
|
398
402
|
|
|
399
|
-
test('should handle errors in aborted computations', async
|
|
403
|
+
test('should handle errors in aborted computations', async () => {
|
|
400
404
|
const source = state(1)
|
|
401
405
|
const derived = computed(async () => {
|
|
402
406
|
await wait(100)
|