@esportsplus/reactivity 0.30.2 → 0.31.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.
@@ -0,0 +1,280 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { computed, effect, read, signal, write } from '~/system';
3
+
4
+
5
+ // These tests validate the runtime behavior of compiler-transformed reactive
6
+ // primitives. The compiler rewrites `reactive(0)` to `signal(0)`, property
7
+ // reads to `read()`, and writes to `write()`.
8
+
9
+ describe('reactive primitives (compiler equivalents)', () => {
10
+ describe('creation and access', () => {
11
+ it('creates signals of various types', () => {
12
+ let count = signal(0),
13
+ flag = signal(true),
14
+ name = signal('test'),
15
+ nullable = signal<string | null>(null);
16
+
17
+ expect(read(count)).toBe(0);
18
+ expect(read(flag)).toBe(true);
19
+ expect(read(name)).toBe('test');
20
+ expect(read(nullable)).toBe(null);
21
+ });
22
+
23
+ it('creates computed derivations', () => {
24
+ let s = signal(2),
25
+ doubled = computed(() => read(s) * 2),
26
+ greeting = signal('test'),
27
+ message = computed(() => `Hello ${read(greeting)}!`);
28
+
29
+ expect(read(doubled)).toBe(4);
30
+ expect(read(message)).toBe('Hello test!');
31
+ });
32
+
33
+ it('conditional computed switches dependency', async () => {
34
+ let flag = signal(true),
35
+ x = signal(1),
36
+ y = signal(2),
37
+ conditional = computed(() => read(flag) ? read(x) + read(y) : 0),
38
+ values: number[] = [];
39
+
40
+ effect(() => {
41
+ values.push(read(conditional));
42
+ });
43
+
44
+ expect(values).toEqual([3]);
45
+
46
+ write(flag, false);
47
+ await Promise.resolve();
48
+
49
+ expect(values).toEqual([3, 0]);
50
+ });
51
+ });
52
+
53
+
54
+ describe('compound assignment operators', () => {
55
+ it('+= operator', () => {
56
+ let s = signal(10);
57
+
58
+ write(s, read(s) + 5);
59
+
60
+ expect(read(s)).toBe(15);
61
+ });
62
+
63
+ it('-= operator', () => {
64
+ let s = signal(10);
65
+
66
+ write(s, read(s) - 3);
67
+
68
+ expect(read(s)).toBe(7);
69
+ });
70
+
71
+ it('*= operator', () => {
72
+ let s = signal(4);
73
+
74
+ write(s, read(s) * 3);
75
+
76
+ expect(read(s)).toBe(12);
77
+ });
78
+
79
+ it('/= operator', () => {
80
+ let s = signal(20);
81
+
82
+ write(s, read(s) / 4);
83
+
84
+ expect(read(s)).toBe(5);
85
+ });
86
+
87
+ it('%= operator', () => {
88
+ let s = signal(17);
89
+
90
+ write(s, read(s) % 5);
91
+
92
+ expect(read(s)).toBe(2);
93
+ });
94
+
95
+ it('**= operator', () => {
96
+ let s = signal(3);
97
+
98
+ write(s, read(s) ** 2);
99
+
100
+ expect(read(s)).toBe(9);
101
+ });
102
+
103
+ it('&= operator', () => {
104
+ let s = signal(0xFF);
105
+
106
+ write(s, read(s) & 0x0F);
107
+
108
+ expect(read(s)).toBe(0x0F);
109
+ });
110
+
111
+ it('|= operator', () => {
112
+ let s = signal(0xF0);
113
+
114
+ write(s, read(s) | 0x0F);
115
+
116
+ expect(read(s)).toBe(0xFF);
117
+ });
118
+
119
+ it('^= operator', () => {
120
+ let s = signal(0xFF);
121
+
122
+ write(s, read(s) ^ 0xAA);
123
+
124
+ expect(read(s)).toBe(0x55);
125
+ });
126
+
127
+ it('<<= operator', () => {
128
+ let s = signal(1);
129
+
130
+ write(s, read(s) << 4);
131
+
132
+ expect(read(s)).toBe(16);
133
+ });
134
+
135
+ it('>>= operator', () => {
136
+ let s = signal(16);
137
+
138
+ write(s, read(s) >> 2);
139
+
140
+ expect(read(s)).toBe(4);
141
+ });
142
+
143
+ it('>>>= operator', () => {
144
+ let s = signal(-1);
145
+
146
+ write(s, read(s) >>> 24);
147
+
148
+ expect(read(s)).toBe(255);
149
+ });
150
+
151
+ it('&&= operator', () => {
152
+ let s = signal(1);
153
+
154
+ write(s, read(s) && 42);
155
+
156
+ expect(read(s)).toBe(42);
157
+ });
158
+
159
+ it('||= operator', () => {
160
+ let s = signal(0);
161
+
162
+ write(s, read(s) || 99);
163
+
164
+ expect(read(s)).toBe(99);
165
+ });
166
+
167
+ it('??= operator', () => {
168
+ let s = signal<number | null>(null);
169
+
170
+ write(s, read(s) ?? 42);
171
+
172
+ expect(read(s)).toBe(42);
173
+ });
174
+ });
175
+
176
+
177
+ describe('increment / decrement', () => {
178
+ it('postfix ++ (statement)', () => {
179
+ let s = signal(5);
180
+
181
+ write(s, read(s) + 1);
182
+
183
+ expect(read(s)).toBe(6);
184
+ });
185
+
186
+ it('postfix -- (statement)', () => {
187
+ let s = signal(5);
188
+
189
+ write(s, read(s) - 1);
190
+
191
+ expect(read(s)).toBe(4);
192
+ });
193
+
194
+ it('prefix ++ in expression context returns new value', () => {
195
+ let s = signal(5),
196
+ newValue = (write(s, read(s) + 1), read(s));
197
+
198
+ expect(newValue).toBe(6);
199
+ expect(read(s)).toBe(6);
200
+ });
201
+
202
+ it('prefix -- in expression context returns new value', () => {
203
+ let s = signal(5),
204
+ newValue = (write(s, read(s) - 1), read(s));
205
+
206
+ expect(newValue).toBe(4);
207
+ expect(read(s)).toBe(4);
208
+ });
209
+
210
+ it('postfix ++ in expression context returns old value', () => {
211
+ let s = signal(5),
212
+ oldValue = read(s);
213
+
214
+ write(s, oldValue + 1);
215
+
216
+ expect(oldValue).toBe(5);
217
+ expect(read(s)).toBe(6);
218
+ });
219
+
220
+ it('postfix -- in expression context returns old value', () => {
221
+ let s = signal(5),
222
+ oldValue = read(s);
223
+
224
+ write(s, oldValue - 1);
225
+
226
+ expect(oldValue).toBe(5);
227
+ expect(read(s)).toBe(4);
228
+ });
229
+ });
230
+
231
+
232
+ describe('nested derivations', () => {
233
+ it('multiple computed from same signals', () => {
234
+ let x = signal(3),
235
+ y = signal(4),
236
+ sum = computed(() => read(x) + read(y)),
237
+ product = computed(() => read(x) * read(y)),
238
+ nested = computed(() => read(sum) + read(product));
239
+
240
+ expect(read(sum)).toBe(7);
241
+ expect(read(product)).toBe(12);
242
+ expect(read(nested)).toBe(19);
243
+ });
244
+
245
+ it('computed chain updates propagate', async () => {
246
+ let x = signal(3),
247
+ y = signal(4),
248
+ sum = computed(() => read(x) + read(y)),
249
+ product = computed(() => read(x) * read(y)),
250
+ nested = computed(() => read(sum) + read(product)),
251
+ values: number[] = [];
252
+
253
+ effect(() => {
254
+ values.push(read(nested));
255
+ });
256
+
257
+ expect(values).toEqual([19]);
258
+
259
+ write(x, 10);
260
+ await Promise.resolve();
261
+
262
+ // sum = 14, product = 40, nested = 54
263
+ expect(values).toEqual([19, 54]);
264
+ });
265
+ });
266
+
267
+
268
+ describe('loop accumulation', () => {
269
+ it('accumulates writes in a loop', () => {
270
+ let s = signal(0);
271
+
272
+ for (let i = 0; i < 10; i++) {
273
+ write(s, read(s) + i);
274
+ }
275
+
276
+ // 0+1+2+3+4+5+6+7+8+9 = 45
277
+ expect(read(s)).toBe(45);
278
+ });
279
+ });
280
+ });