@esportsplus/reactivity 0.30.2 → 0.30.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/reactive/array.js +24 -22
- package/build/reactive/object.js +3 -2
- package/build/system.js +4 -3
- package/package.json +3 -2
- package/src/reactive/array.ts +27 -26
- package/src/reactive/object.ts +5 -2
- package/src/system.ts +5 -3
- package/tests/array.ts +657 -0
- package/tests/bench/array.ts +162 -0
- package/tests/bench/system.ts +230 -0
- package/tests/effects.ts +211 -0
- package/tests/nested.ts +293 -0
- package/tests/objects.ts +185 -0
- package/tests/primitives.ts +280 -0
- package/tests/reactive.ts +324 -0
- package/tests/system.ts +655 -0
- package/vitest.config.ts +18 -0
- package/test/arrays.ts +0 -146
- package/test/debug.ts +0 -7
- package/test/effects.ts +0 -168
- package/test/index.ts +0 -8
- package/test/nested.ts +0 -201
- package/test/objects.ts +0 -106
- package/test/primitives.ts +0 -87
- package/test/range.ts +0 -45
- package/test/vite.config.ts +0 -41
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { bench, describe } from 'vitest';
|
|
2
|
+
import { ReactiveArray } from '~/reactive/array';
|
|
3
|
+
import { effect } from '~/system';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
describe('ReactiveArray creation', () => {
|
|
7
|
+
bench('create empty', () => {
|
|
8
|
+
new ReactiveArray<number>();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
bench('create with 10 items', () => {
|
|
12
|
+
new ReactiveArray(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
bench('create with 100 items', () => {
|
|
16
|
+
let items = [];
|
|
17
|
+
|
|
18
|
+
for (let i = 0; i < 100; i++) {
|
|
19
|
+
items.push(i);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
new ReactiveArray(...items);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
describe('ReactiveArray push', () => {
|
|
28
|
+
bench('push 1 item', () => {
|
|
29
|
+
let arr = new ReactiveArray<number>();
|
|
30
|
+
|
|
31
|
+
arr.push(1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
bench('push 10 items (single call)', () => {
|
|
35
|
+
let arr = new ReactiveArray<number>();
|
|
36
|
+
|
|
37
|
+
arr.push(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
bench('push 10 items (10 calls)', () => {
|
|
41
|
+
let arr = new ReactiveArray<number>();
|
|
42
|
+
|
|
43
|
+
for (let i = 0; i < 10; i++) {
|
|
44
|
+
arr.push(i);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
bench('push with listener', () => {
|
|
49
|
+
let arr = new ReactiveArray<number>();
|
|
50
|
+
|
|
51
|
+
arr.on('push', () => {});
|
|
52
|
+
arr.push(1);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
describe('ReactiveArray pop', () => {
|
|
58
|
+
bench('pop', () => {
|
|
59
|
+
let arr = new ReactiveArray(1, 2, 3, 4, 5);
|
|
60
|
+
|
|
61
|
+
arr.pop();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
describe('ReactiveArray splice', () => {
|
|
67
|
+
bench('splice remove 1', () => {
|
|
68
|
+
let arr = new ReactiveArray(1, 2, 3, 4, 5);
|
|
69
|
+
|
|
70
|
+
arr.splice(2, 1);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
bench('splice insert 1', () => {
|
|
74
|
+
let arr = new ReactiveArray(1, 2, 3, 4, 5);
|
|
75
|
+
|
|
76
|
+
arr.splice(2, 0, 99);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
bench('splice replace 1', () => {
|
|
80
|
+
let arr = new ReactiveArray(1, 2, 3, 4, 5);
|
|
81
|
+
|
|
82
|
+
arr.splice(2, 1, 99);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
describe('ReactiveArray sort', () => {
|
|
88
|
+
bench('sort 10 items', () => {
|
|
89
|
+
let arr = new ReactiveArray(5, 3, 8, 1, 9, 2, 7, 4, 6, 10);
|
|
90
|
+
|
|
91
|
+
arr.sort((a, b) => a - b);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
bench('sort 100 items', () => {
|
|
95
|
+
let items = [];
|
|
96
|
+
|
|
97
|
+
for (let i = 100; i > 0; i--) {
|
|
98
|
+
items.push(i);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let arr = new ReactiveArray(...items);
|
|
102
|
+
|
|
103
|
+
arr.sort((a, b) => a - b);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
describe('ReactiveArray $set', () => {
|
|
109
|
+
bench('$set', () => {
|
|
110
|
+
let arr = new ReactiveArray(1, 2, 3, 4, 5);
|
|
111
|
+
|
|
112
|
+
arr.$set(2, 99);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
bench('$set same value (no-op)', () => {
|
|
116
|
+
let arr = new ReactiveArray(1, 2, 3, 4, 5);
|
|
117
|
+
|
|
118
|
+
arr.$set(2, 3);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
describe('ReactiveArray events', () => {
|
|
124
|
+
bench('dispatch to 1 listener', () => {
|
|
125
|
+
let arr = new ReactiveArray<number>();
|
|
126
|
+
|
|
127
|
+
arr.on('push', () => {});
|
|
128
|
+
arr.push(1);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
bench('dispatch to 10 listeners', () => {
|
|
132
|
+
let arr = new ReactiveArray<number>();
|
|
133
|
+
|
|
134
|
+
for (let i = 0; i < 10; i++) {
|
|
135
|
+
arr.on('push', () => {});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
arr.push(1);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
bench('on + once interleaved', () => {
|
|
142
|
+
let arr = new ReactiveArray<number>();
|
|
143
|
+
|
|
144
|
+
arr.on('push', () => {});
|
|
145
|
+
arr.once('push', () => {});
|
|
146
|
+
arr.on('push', () => {});
|
|
147
|
+
arr.push(1);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
describe('ReactiveArray reactive length', () => {
|
|
153
|
+
bench('read $length in effect', () => {
|
|
154
|
+
let arr = new ReactiveArray(1, 2, 3);
|
|
155
|
+
|
|
156
|
+
let stop = effect(() => {
|
|
157
|
+
arr.$length;
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
stop();
|
|
161
|
+
});
|
|
162
|
+
});
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { bench, describe } from 'vitest';
|
|
2
|
+
import { computed, dispose, effect, read, root, signal, write } from '~/system';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
describe('signal', () => {
|
|
6
|
+
bench('create signal', () => {
|
|
7
|
+
signal(0);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
bench('read signal (no observer)', () => {
|
|
11
|
+
let s = signal(0);
|
|
12
|
+
|
|
13
|
+
read(s);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
bench('write signal (no subscribers)', () => {
|
|
17
|
+
let s = signal(0);
|
|
18
|
+
|
|
19
|
+
write(s, 1);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
bench('write signal (1 subscriber)', () => {
|
|
23
|
+
let s = signal(0),
|
|
24
|
+
i = 0;
|
|
25
|
+
|
|
26
|
+
effect(() => {
|
|
27
|
+
read(s);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
write(s, ++i);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
bench('write + read cycle', () => {
|
|
34
|
+
let s = signal(0);
|
|
35
|
+
|
|
36
|
+
write(s, 1);
|
|
37
|
+
|
|
38
|
+
read(s);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
describe('computed', () => {
|
|
44
|
+
bench('create computed', () => {
|
|
45
|
+
let s = signal(0);
|
|
46
|
+
|
|
47
|
+
computed(() => read(s));
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
bench('read computed', () => {
|
|
51
|
+
let s = signal(0),
|
|
52
|
+
c = computed(() => read(s));
|
|
53
|
+
|
|
54
|
+
read(c);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
bench('computed chain (depth 5)', () => {
|
|
58
|
+
let s = signal(0),
|
|
59
|
+
c1 = computed(() => read(s) + 1),
|
|
60
|
+
c2 = computed(() => read(c1) + 1),
|
|
61
|
+
c3 = computed(() => read(c2) + 1),
|
|
62
|
+
c4 = computed(() => read(c3) + 1),
|
|
63
|
+
c5 = computed(() => read(c4) + 1);
|
|
64
|
+
|
|
65
|
+
read(c5);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
bench('computed diamond', () => {
|
|
69
|
+
let s = signal(0),
|
|
70
|
+
a = computed(() => read(s) + 1),
|
|
71
|
+
b = computed(() => read(s) * 2),
|
|
72
|
+
c = computed(() => read(a) + read(b));
|
|
73
|
+
|
|
74
|
+
read(c);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
describe('effect', () => {
|
|
80
|
+
bench('create + dispose effect', () => {
|
|
81
|
+
let stop = effect(() => {});
|
|
82
|
+
|
|
83
|
+
stop();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
bench('effect with 1 signal', () => {
|
|
87
|
+
let s = signal(0);
|
|
88
|
+
|
|
89
|
+
let stop = effect(() => {
|
|
90
|
+
read(s);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
stop();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
bench('effect with 10 signals', () => {
|
|
97
|
+
let signals: ReturnType<typeof signal<number>>[] = [];
|
|
98
|
+
|
|
99
|
+
for (let i = 0; i < 10; i++) {
|
|
100
|
+
signals.push(signal(i));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let stop = effect(() => {
|
|
104
|
+
for (let i = 0; i < 10; i++) {
|
|
105
|
+
read(signals[i]);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
stop();
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
describe('propagation', () => {
|
|
115
|
+
bench('1 signal → 1 effect (sync write)', () => {
|
|
116
|
+
let s = signal(0),
|
|
117
|
+
i = 0;
|
|
118
|
+
|
|
119
|
+
effect(() => {
|
|
120
|
+
read(s);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
write(s, ++i);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
bench('1 signal → 10 effects (sync write)', () => {
|
|
127
|
+
let s = signal(0),
|
|
128
|
+
i = 0;
|
|
129
|
+
|
|
130
|
+
for (let j = 0; j < 10; j++) {
|
|
131
|
+
effect(() => {
|
|
132
|
+
read(s);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
write(s, ++i);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
bench('10 signals → 1 computed → 1 effect', () => {
|
|
140
|
+
let signals: ReturnType<typeof signal<number>>[] = [],
|
|
141
|
+
i = 0;
|
|
142
|
+
|
|
143
|
+
for (let j = 0; j < 10; j++) {
|
|
144
|
+
signals.push(signal(j));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let c = computed(() => {
|
|
148
|
+
let sum = 0;
|
|
149
|
+
|
|
150
|
+
for (let j = 0; j < 10; j++) {
|
|
151
|
+
sum += read(signals[j]);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return sum;
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
effect(() => {
|
|
158
|
+
read(c);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
write(signals[0], ++i);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
bench('deep chain (10 computeds)', () => {
|
|
165
|
+
let s = signal(0),
|
|
166
|
+
chain: ReturnType<typeof computed>[] = [],
|
|
167
|
+
i = 0;
|
|
168
|
+
|
|
169
|
+
chain[0] = computed(() => read(s) + 1);
|
|
170
|
+
|
|
171
|
+
for (let j = 1; j < 10; j++) {
|
|
172
|
+
let prev = chain[j - 1];
|
|
173
|
+
|
|
174
|
+
chain[j] = computed(() => read(prev) + 1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
effect(() => {
|
|
178
|
+
read(chain[9]);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
write(s, ++i);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
bench('wide fan-out (1 signal → 100 computeds)', () => {
|
|
185
|
+
let s = signal(0),
|
|
186
|
+
i = 0;
|
|
187
|
+
|
|
188
|
+
for (let j = 0; j < 100; j++) {
|
|
189
|
+
computed(() => read(s) + j);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
write(s, ++i);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
describe('memory', () => {
|
|
198
|
+
bench('create + dispose 100 computeds', () => {
|
|
199
|
+
let computeds: ReturnType<typeof computed<number>>[] = [];
|
|
200
|
+
|
|
201
|
+
for (let i = 0; i < 100; i++) {
|
|
202
|
+
computeds.push(computed(() => i));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
for (let i = 0; i < 100; i++) {
|
|
206
|
+
dispose(computeds[i]);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
bench('link pool (create + dispose cycle)', () => {
|
|
211
|
+
let s = signal(0);
|
|
212
|
+
|
|
213
|
+
for (let i = 0; i < 100; i++) {
|
|
214
|
+
let c = computed(() => read(s));
|
|
215
|
+
|
|
216
|
+
read(c);
|
|
217
|
+
dispose(c);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
bench('root scope create + dispose', () => {
|
|
222
|
+
root((dispose) => {
|
|
223
|
+
let s = signal(0);
|
|
224
|
+
|
|
225
|
+
computed(() => read(s));
|
|
226
|
+
|
|
227
|
+
dispose();
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
});
|
package/tests/effects.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { computed, effect, onCleanup, read, root, signal, write } from '~/system';
|
|
3
|
+
import { ReactiveArray } from '~/reactive/array';
|
|
4
|
+
import { ReactiveObject } from '~/reactive/object';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
// These tests validate effect patterns from the compiler integration tests,
|
|
8
|
+
// including cleanup tracking, root scope, and multi-object dependencies.
|
|
9
|
+
|
|
10
|
+
describe('effect patterns', () => {
|
|
11
|
+
describe('basic effect lifecycle', () => {
|
|
12
|
+
it('effect runs on creation and updates', async () => {
|
|
13
|
+
let s = signal(0),
|
|
14
|
+
runs = 0;
|
|
15
|
+
|
|
16
|
+
let dispose = effect(() => {
|
|
17
|
+
read(s);
|
|
18
|
+
runs++;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
expect(runs).toBe(1);
|
|
22
|
+
|
|
23
|
+
write(s, 1);
|
|
24
|
+
await Promise.resolve();
|
|
25
|
+
|
|
26
|
+
write(s, 2);
|
|
27
|
+
await Promise.resolve();
|
|
28
|
+
|
|
29
|
+
write(s, 3);
|
|
30
|
+
await Promise.resolve();
|
|
31
|
+
|
|
32
|
+
expect(runs).toBe(4);
|
|
33
|
+
|
|
34
|
+
dispose();
|
|
35
|
+
|
|
36
|
+
write(s, 4);
|
|
37
|
+
write(s, 5);
|
|
38
|
+
await Promise.resolve();
|
|
39
|
+
|
|
40
|
+
expect(runs).toBe(4);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
describe('cleanup tracking', () => {
|
|
46
|
+
it('counts cleanup calls across re-runs', async () => {
|
|
47
|
+
let s = signal(0),
|
|
48
|
+
cleanupCalls = 0,
|
|
49
|
+
effectValues: number[] = [];
|
|
50
|
+
|
|
51
|
+
let dispose = effect(() => {
|
|
52
|
+
let current = read(s);
|
|
53
|
+
|
|
54
|
+
effectValues.push(current);
|
|
55
|
+
|
|
56
|
+
onCleanup(() => {
|
|
57
|
+
cleanupCalls++;
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(effectValues).toEqual([0]);
|
|
62
|
+
expect(cleanupCalls).toBe(0);
|
|
63
|
+
|
|
64
|
+
write(s, 1);
|
|
65
|
+
await Promise.resolve();
|
|
66
|
+
|
|
67
|
+
expect(effectValues).toEqual([0, 1]);
|
|
68
|
+
expect(cleanupCalls).toBe(1);
|
|
69
|
+
|
|
70
|
+
write(s, 2);
|
|
71
|
+
await Promise.resolve();
|
|
72
|
+
|
|
73
|
+
expect(effectValues).toEqual([0, 1, 2]);
|
|
74
|
+
expect(cleanupCalls).toBe(2);
|
|
75
|
+
|
|
76
|
+
dispose();
|
|
77
|
+
|
|
78
|
+
expect(cleanupCalls).toBe(3);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
describe('effect with computed', () => {
|
|
84
|
+
it('effect tracks computed property updates', async () => {
|
|
85
|
+
let s = signal(10),
|
|
86
|
+
doubled = computed(() => read(s) * 2),
|
|
87
|
+
reads = 0,
|
|
88
|
+
values: number[] = [];
|
|
89
|
+
|
|
90
|
+
effect(() => {
|
|
91
|
+
reads++;
|
|
92
|
+
values.push(read(doubled));
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
expect(reads).toBe(1);
|
|
96
|
+
expect(values).toEqual([20]);
|
|
97
|
+
|
|
98
|
+
write(s, 20);
|
|
99
|
+
await Promise.resolve();
|
|
100
|
+
|
|
101
|
+
expect(reads).toBe(2);
|
|
102
|
+
expect(values).toEqual([20, 40]);
|
|
103
|
+
|
|
104
|
+
write(s, 30);
|
|
105
|
+
await Promise.resolve();
|
|
106
|
+
|
|
107
|
+
expect(reads).toBe(3);
|
|
108
|
+
expect(values).toEqual([20, 40, 60]);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
describe('root scope', () => {
|
|
114
|
+
it('root with reactive object and effect inside', async () => {
|
|
115
|
+
let rootDisposed = false,
|
|
116
|
+
effectRuns = 0;
|
|
117
|
+
|
|
118
|
+
let result = root((dispose) => {
|
|
119
|
+
let s = signal(1),
|
|
120
|
+
obj = new ReactiveObject({
|
|
121
|
+
doubled: () => read(s) * 2
|
|
122
|
+
}) as any;
|
|
123
|
+
|
|
124
|
+
effect(() => {
|
|
125
|
+
effectRuns++;
|
|
126
|
+
read(s);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
expect(effectRuns).toBe(1);
|
|
130
|
+
expect(obj.doubled).toBe(2);
|
|
131
|
+
|
|
132
|
+
write(s, 5);
|
|
133
|
+
|
|
134
|
+
onCleanup(() => {
|
|
135
|
+
rootDisposed = true;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
dispose();
|
|
139
|
+
|
|
140
|
+
return 'root result';
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expect(result).toBe('root result');
|
|
144
|
+
expect(rootDisposed).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
describe('multiple object dependencies', () => {
|
|
150
|
+
it('effect tracks properties from multiple objects', async () => {
|
|
151
|
+
let obj1 = new ReactiveObject({ x: 1 }) as any,
|
|
152
|
+
obj2 = new ReactiveObject({ y: 2 }) as any,
|
|
153
|
+
obj3 = new ReactiveObject({ z: 3 }) as any,
|
|
154
|
+
runs = 0,
|
|
155
|
+
sums: number[] = [];
|
|
156
|
+
|
|
157
|
+
effect(() => {
|
|
158
|
+
runs++;
|
|
159
|
+
sums.push(obj1.x + obj2.y + obj3.z);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
expect(sums).toEqual([6]);
|
|
163
|
+
|
|
164
|
+
obj1.x = 10;
|
|
165
|
+
await Promise.resolve();
|
|
166
|
+
|
|
167
|
+
expect(sums).toEqual([6, 15]);
|
|
168
|
+
|
|
169
|
+
obj2.y = 20;
|
|
170
|
+
await Promise.resolve();
|
|
171
|
+
|
|
172
|
+
expect(sums).toEqual([6, 15, 33]);
|
|
173
|
+
|
|
174
|
+
obj3.z = 30;
|
|
175
|
+
await Promise.resolve();
|
|
176
|
+
|
|
177
|
+
expect(sums).toEqual([6, 15, 33, 60]);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
describe('effect with reactive array', () => {
|
|
183
|
+
it('effect tracks array length changes', async () => {
|
|
184
|
+
let arr = new ReactiveArray(1, 2, 3),
|
|
185
|
+
runs = 0,
|
|
186
|
+
lengths: number[] = [];
|
|
187
|
+
|
|
188
|
+
effect(() => {
|
|
189
|
+
runs++;
|
|
190
|
+
lengths.push(arr.$length);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(lengths).toEqual([3]);
|
|
194
|
+
|
|
195
|
+
arr.push(4);
|
|
196
|
+
await Promise.resolve();
|
|
197
|
+
|
|
198
|
+
expect(lengths).toEqual([3, 4]);
|
|
199
|
+
|
|
200
|
+
arr.pop();
|
|
201
|
+
await Promise.resolve();
|
|
202
|
+
|
|
203
|
+
expect(lengths).toEqual([3, 4, 3]);
|
|
204
|
+
|
|
205
|
+
arr.splice(0, 1);
|
|
206
|
+
await Promise.resolve();
|
|
207
|
+
|
|
208
|
+
expect(lengths).toEqual([3, 4, 3, 2]);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|