ripple 0.2.115 → 0.2.118
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/package.json +16 -16
- package/src/compiler/index.js +20 -1
- package/src/compiler/phases/1-parse/index.js +79 -0
- package/src/compiler/phases/3-transform/client/index.js +54 -8
- package/src/compiler/phases/3-transform/segments.js +107 -60
- package/src/compiler/phases/3-transform/server/index.js +21 -11
- package/src/compiler/types/index.d.ts +16 -0
- package/src/runtime/index-client.js +19 -185
- package/src/runtime/index-server.js +24 -0
- package/src/runtime/internal/client/bindings.js +443 -0
- package/src/runtime/internal/client/index.js +4 -0
- package/src/runtime/internal/client/runtime.js +10 -0
- package/src/runtime/internal/client/utils.js +0 -8
- package/src/runtime/map.js +11 -1
- package/src/runtime/set.js +11 -1
- package/tests/client/__snapshots__/for.test.ripple.snap +80 -0
- package/tests/client/_etc.test.ripple +5 -0
- package/tests/client/array/array.copy-within.test.ripple +120 -0
- package/tests/client/array/array.derived.test.ripple +495 -0
- package/tests/client/array/array.iteration.test.ripple +115 -0
- package/tests/client/array/array.mutations.test.ripple +385 -0
- package/tests/client/array/array.static.test.ripple +237 -0
- package/tests/client/array/array.to-methods.test.ripple +93 -0
- package/tests/client/basic/__snapshots__/basic.attributes.test.ripple.snap +60 -0
- package/tests/client/basic/__snapshots__/basic.rendering.test.ripple.snap +106 -0
- package/tests/client/basic/__snapshots__/basic.text.test.ripple.snap +49 -0
- package/tests/client/basic/basic.attributes.test.ripple +474 -0
- package/tests/client/basic/basic.collections.test.ripple +94 -0
- package/tests/client/basic/basic.components.test.ripple +225 -0
- package/tests/client/basic/basic.errors.test.ripple +126 -0
- package/tests/client/basic/basic.events.test.ripple +222 -0
- package/tests/client/basic/basic.reactivity.test.ripple +476 -0
- package/tests/client/basic/basic.rendering.test.ripple +204 -0
- package/tests/client/basic/basic.styling.test.ripple +63 -0
- package/tests/client/basic/basic.utilities.test.ripple +25 -0
- package/tests/client/boundaries.test.ripple +2 -21
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.ripple.snap +12 -0
- package/tests/client/compiler/__snapshots__/compiler.typescript.test.ripple.snap +22 -0
- package/tests/client/compiler/compiler.assignments.test.ripple +112 -0
- package/tests/client/compiler/compiler.attributes.test.ripple +95 -0
- package/tests/client/compiler/compiler.basic.test.ripple +203 -0
- package/tests/client/compiler/compiler.regex.test.ripple +87 -0
- package/tests/client/compiler/compiler.typescript.test.ripple +29 -0
- package/tests/client/{__snapshots__/composite.test.ripple.snap → composite/__snapshots__/composite.render.test.ripple.snap} +2 -2
- package/tests/client/composite/composite.dynamic-components.test.ripple +100 -0
- package/tests/client/composite/composite.generics.test.ripple +211 -0
- package/tests/client/composite/composite.props.test.ripple +106 -0
- package/tests/client/composite/composite.reactivity.test.ripple +184 -0
- package/tests/client/composite/composite.render.test.ripple +84 -0
- package/tests/client/computed-properties.test.ripple +2 -21
- package/tests/client/context.test.ripple +5 -22
- package/tests/client/date.test.ripple +1 -20
- package/tests/client/dynamic-elements.test.ripple +16 -24
- package/tests/client/for.test.ripple +4 -23
- package/tests/client/head.test.ripple +11 -23
- package/tests/client/html.test.ripple +1 -20
- package/tests/client/input-value.test.ripple +11 -31
- package/tests/client/map.test.ripple +82 -20
- package/tests/client/media-query.test.ripple +10 -23
- package/tests/client/object.test.ripple +5 -24
- package/tests/client/portal.test.ripple +2 -19
- package/tests/client/ref.test.ripple +8 -26
- package/tests/client/set.test.ripple +84 -22
- package/tests/client/svg.test.ripple +1 -22
- package/tests/client/switch.test.ripple +6 -25
- package/tests/client/tracked-expression.test.ripple +2 -21
- package/tests/client/typescript-generics.test.ripple +0 -21
- package/tests/client/url/url.derived.test.ripple +83 -0
- package/tests/client/url/url.parsing.test.ripple +165 -0
- package/tests/client/url/url.partial-removal.test.ripple +198 -0
- package/tests/client/url/url.reactivity.test.ripple +449 -0
- package/tests/client/url/url.serialization.test.ripple +50 -0
- package/tests/client/url-search-params/url-search-params.derived.test.ripple +84 -0
- package/tests/client/url-search-params/url-search-params.initialization.test.ripple +61 -0
- package/tests/client/url-search-params/url-search-params.iteration.test.ripple +153 -0
- package/tests/client/url-search-params/url-search-params.mutation.test.ripple +343 -0
- package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +160 -0
- package/tests/client/url-search-params/url-search-params.serialization.test.ripple +53 -0
- package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +55 -0
- package/tests/client.d.ts +12 -0
- package/tests/server/if.test.ripple +66 -0
- package/tests/setup-client.js +28 -0
- package/tsconfig.json +4 -2
- package/types/index.d.ts +92 -46
- package/LICENSE +0 -21
- package/tests/client/__snapshots__/basic.test.ripple.snap +0 -117
- package/tests/client/__snapshots__/compiler.test.ripple.snap +0 -33
- package/tests/client/array.test.ripple +0 -1455
- package/tests/client/basic.test.ripple +0 -1892
- package/tests/client/compiler.test.ripple +0 -541
- package/tests/client/composite.test.ripple +0 -692
- package/tests/client/url-search-params.test.ripple +0 -912
- package/tests/client/url.test.ripple +0 -954
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import { flushSync, track, TrackedArray } from 'ripple';
|
|
2
|
+
|
|
3
|
+
describe('TrackedArray > derived', () => {
|
|
4
|
+
it('handles array methods that return values (map, filter, etc.)', () => {
|
|
5
|
+
component ArrayTest() {
|
|
6
|
+
let items = new TrackedArray(1, 2, 3, 4, 5);
|
|
7
|
+
let doubled = track(() => items.map(x => x * 2));
|
|
8
|
+
let filtered = track(() => items.filter(x => (x % 2) === 0));
|
|
9
|
+
let reduced = track(() => items.reduce((acc, val) => acc + val, 0));
|
|
10
|
+
let includes = track(() => items.includes(3));
|
|
11
|
+
|
|
12
|
+
<button onClick={() => items.push(6)}>{'add item'}</button>
|
|
13
|
+
<pre>{JSON.stringify(@doubled)}</pre>
|
|
14
|
+
<pre>{JSON.stringify(@filtered)}</pre>
|
|
15
|
+
<pre>{@reduced}</pre>
|
|
16
|
+
<pre>{@includes.toString()}</pre>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
render(ArrayTest);
|
|
20
|
+
|
|
21
|
+
const addButton = container.querySelector('button');
|
|
22
|
+
|
|
23
|
+
// Initial state
|
|
24
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[2,4,6,8,10]');
|
|
25
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[2,4]');
|
|
26
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('15');
|
|
27
|
+
expect(container.querySelectorAll('pre')[3].textContent).toBe('true');
|
|
28
|
+
|
|
29
|
+
// Test reactivity with these methods
|
|
30
|
+
addButton.click();
|
|
31
|
+
flushSync();
|
|
32
|
+
|
|
33
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[2,4,6,8,10,12]');
|
|
34
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[2,4,6]');
|
|
35
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('21');
|
|
36
|
+
expect(container.querySelectorAll('pre')[3].textContent).toBe('true');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('handles concat method with reactivity', () => {
|
|
40
|
+
component ArrayTest() {
|
|
41
|
+
let items = new TrackedArray(1, 2, 3);
|
|
42
|
+
let concatenated = track(() => items.concat([4, 5], 6, [7, 8]));
|
|
43
|
+
|
|
44
|
+
<button onClick={() => items.push(3.5)}>{'add to original'}</button>
|
|
45
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
46
|
+
<pre>{JSON.stringify(@concatenated)}</pre>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
render(ArrayTest);
|
|
50
|
+
|
|
51
|
+
const addButton = container.querySelector('button');
|
|
52
|
+
|
|
53
|
+
// Initial state
|
|
54
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3]');
|
|
55
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[1,2,3,4,5,6,7,8]');
|
|
56
|
+
|
|
57
|
+
// Test adding to original array
|
|
58
|
+
addButton.click();
|
|
59
|
+
flushSync();
|
|
60
|
+
|
|
61
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,3.5]');
|
|
62
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[1,2,3,3.5,4,5,6,7,8]');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('handles array slice method with reactivity', () => {
|
|
66
|
+
component ArrayTest() {
|
|
67
|
+
let items = new TrackedArray(1, 2, 3, 4, 5);
|
|
68
|
+
let sliced = track(() => items.slice(1, 4));
|
|
69
|
+
|
|
70
|
+
<button onClick={() => items[2] = 30}>{'change middle'}</button>
|
|
71
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
72
|
+
<pre>{JSON.stringify(@sliced)}</pre>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
render(ArrayTest);
|
|
76
|
+
|
|
77
|
+
const changeButton = container.querySelector('button');
|
|
78
|
+
|
|
79
|
+
// Initial state
|
|
80
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4,5]');
|
|
81
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[2,3,4]');
|
|
82
|
+
|
|
83
|
+
// Test reactivity with slice
|
|
84
|
+
changeButton.click();
|
|
85
|
+
flushSync();
|
|
86
|
+
|
|
87
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,30,4,5]');
|
|
88
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[2,30,4]');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('handles find and findIndex methods with reactivity', () => {
|
|
92
|
+
component ArrayTest() {
|
|
93
|
+
let items = new TrackedArray(5, 10, 15, 20, 25);
|
|
94
|
+
let found = track(() => items.find(x => x > 12));
|
|
95
|
+
let foundIndex = track(() => items.findIndex(x => x > 12));
|
|
96
|
+
|
|
97
|
+
<button onClick={() => {
|
|
98
|
+
items[1] = 13;
|
|
99
|
+
items[0] = 6;
|
|
100
|
+
}}>{'update values'}</button>
|
|
101
|
+
<pre>{@found}</pre>
|
|
102
|
+
<pre>{@foundIndex}</pre>
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
render(ArrayTest);
|
|
106
|
+
|
|
107
|
+
const updateButton = container.querySelector('button');
|
|
108
|
+
|
|
109
|
+
// Initial state
|
|
110
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('15');
|
|
111
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('2');
|
|
112
|
+
|
|
113
|
+
// Test reactivity with find methods
|
|
114
|
+
updateButton.click();
|
|
115
|
+
flushSync();
|
|
116
|
+
|
|
117
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('13');
|
|
118
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('1');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('handles findLast and findLastIndex methods with reactivity', () => {
|
|
122
|
+
component ArrayTest() {
|
|
123
|
+
let items = new TrackedArray(5, 15, 10, 20, 15);
|
|
124
|
+
let foundLast = track(() => items.findLast(x => x === 15));
|
|
125
|
+
let foundLastIndex = track(() => items.findLastIndex(x => x === 15));
|
|
126
|
+
|
|
127
|
+
<button onClick={() => {
|
|
128
|
+
items[1] = 25;
|
|
129
|
+
items[4] = 15;
|
|
130
|
+
}}>{'update values'}</button>
|
|
131
|
+
<pre>{@foundLast}</pre>
|
|
132
|
+
<pre>{@foundLastIndex}</pre>
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
render(ArrayTest);
|
|
136
|
+
|
|
137
|
+
const updateButton = container.querySelector('button');
|
|
138
|
+
|
|
139
|
+
// Initial state
|
|
140
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('15');
|
|
141
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('4');
|
|
142
|
+
|
|
143
|
+
// Test reactivity with findLast methods
|
|
144
|
+
updateButton.click();
|
|
145
|
+
flushSync();
|
|
146
|
+
|
|
147
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('15');
|
|
148
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('4');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('handles every method with reactivity', () => {
|
|
152
|
+
component ArrayTest() {
|
|
153
|
+
let items = new TrackedArray(2, 4, 6, 8);
|
|
154
|
+
let allEven = track(() => items.every(x => x % 2 === 0));
|
|
155
|
+
|
|
156
|
+
<button onClick={() => items.push(3)}>{'add odd'}</button>
|
|
157
|
+
<button onClick={() => {
|
|
158
|
+
items.pop();
|
|
159
|
+
items.push(10);
|
|
160
|
+
}}>{'ensure all even'}</button>
|
|
161
|
+
<pre>{@allEven.toString()}</pre>
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
render(ArrayTest);
|
|
165
|
+
|
|
166
|
+
const addOddButton = container.querySelectorAll('button')[0];
|
|
167
|
+
const makeEvenButton = container.querySelectorAll('button')[1];
|
|
168
|
+
|
|
169
|
+
// Initial state
|
|
170
|
+
expect(container.querySelector('pre').textContent).toBe('true');
|
|
171
|
+
|
|
172
|
+
// Test adding an odd number
|
|
173
|
+
addOddButton.click();
|
|
174
|
+
flushSync();
|
|
175
|
+
expect(container.querySelector('pre').textContent).toBe('false');
|
|
176
|
+
|
|
177
|
+
// Test fixing the array to all even
|
|
178
|
+
makeEvenButton.click();
|
|
179
|
+
flushSync();
|
|
180
|
+
expect(container.querySelector('pre').textContent).toBe('true');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('handles flat method with reactivity', () => {
|
|
184
|
+
component ArrayTest() {
|
|
185
|
+
let items = new TrackedArray([1, 2], [3, 4], 5);
|
|
186
|
+
let flattened = track(() => items.flat());
|
|
187
|
+
|
|
188
|
+
<button onClick={() => items[0] = [6, 7, 8]}>{'change nested'}</button>
|
|
189
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
190
|
+
<pre>{JSON.stringify(@flattened)}</pre>
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
render(ArrayTest);
|
|
194
|
+
|
|
195
|
+
const changeButton = container.querySelector('button');
|
|
196
|
+
|
|
197
|
+
// Initial state
|
|
198
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[[1,2],[3,4],5]');
|
|
199
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[1,2,3,4,5]');
|
|
200
|
+
|
|
201
|
+
// Test changing a nested array
|
|
202
|
+
changeButton.click();
|
|
203
|
+
flushSync();
|
|
204
|
+
|
|
205
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[[6,7,8],[3,4],5]');
|
|
206
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[6,7,8,3,4,5]');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('handles flatMap method with reactivity', () => {
|
|
210
|
+
component ArrayTest() {
|
|
211
|
+
let items = new TrackedArray(1, 2, 3);
|
|
212
|
+
let flatMapped = track(() => items.flatMap(x => [x, x * 2]));
|
|
213
|
+
|
|
214
|
+
<button onClick={() => items.push(4)}>{'add item'}</button>
|
|
215
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
216
|
+
<pre>{JSON.stringify(@flatMapped)}</pre>
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
render(ArrayTest);
|
|
220
|
+
|
|
221
|
+
const addButton = container.querySelector('button');
|
|
222
|
+
|
|
223
|
+
// Initial state
|
|
224
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3]');
|
|
225
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[1,2,2,4,3,6]');
|
|
226
|
+
|
|
227
|
+
// Test adding an item
|
|
228
|
+
addButton.click();
|
|
229
|
+
flushSync();
|
|
230
|
+
|
|
231
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4]');
|
|
232
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[1,2,2,4,3,6,4,8]');
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('handles join method with reactivity', () => {
|
|
236
|
+
component ArrayTest() {
|
|
237
|
+
let items = new TrackedArray('apple', 'banana', 'cherry');
|
|
238
|
+
let joined = track(() => items.join(', '));
|
|
239
|
+
|
|
240
|
+
<button onClick={() => items.push('date')}>{'add item'}</button>
|
|
241
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
242
|
+
<pre>{@joined}</pre>
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
render(ArrayTest);
|
|
246
|
+
|
|
247
|
+
const addButton = container.querySelector('button');
|
|
248
|
+
|
|
249
|
+
// Initial state
|
|
250
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('["apple","banana","cherry"]');
|
|
251
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('apple, banana, cherry');
|
|
252
|
+
|
|
253
|
+
// Test adding an item
|
|
254
|
+
addButton.click();
|
|
255
|
+
flushSync();
|
|
256
|
+
|
|
257
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('["apple","banana","cherry","date"]');
|
|
258
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('apple, banana, cherry, date');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('handles lastIndexOf method with reactivity', () => {
|
|
262
|
+
component ArrayTest() {
|
|
263
|
+
let items = new TrackedArray(1, 2, 3, 2, 1);
|
|
264
|
+
let lastIndex = track(() => items.lastIndexOf(2));
|
|
265
|
+
|
|
266
|
+
<button onClick={() => {
|
|
267
|
+
items.push(2);
|
|
268
|
+
}}>{'add duplicate'}</button>
|
|
269
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
270
|
+
<pre>{@lastIndex}</pre>
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
render(ArrayTest);
|
|
274
|
+
|
|
275
|
+
const addButton = container.querySelector('button');
|
|
276
|
+
|
|
277
|
+
// Initial state
|
|
278
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,2,1]');
|
|
279
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
|
|
280
|
+
|
|
281
|
+
// Test adding a duplicate
|
|
282
|
+
addButton.click();
|
|
283
|
+
flushSync();
|
|
284
|
+
|
|
285
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,2,1,2]');
|
|
286
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('5');
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('handles reduceRight method with reactivity', () => {
|
|
290
|
+
component ArrayTest() {
|
|
291
|
+
let items = new TrackedArray('a', 'b', 'c');
|
|
292
|
+
let reduced = track(() => items.reduceRight((acc, val) => acc + val, ''));
|
|
293
|
+
|
|
294
|
+
<button onClick={() => items.push('d')}>{'add item'}</button>
|
|
295
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
296
|
+
<pre>{@reduced}</pre>
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
render(ArrayTest);
|
|
300
|
+
|
|
301
|
+
const addButton = container.querySelector('button');
|
|
302
|
+
|
|
303
|
+
// Initial state
|
|
304
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('["a","b","c"]');
|
|
305
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('cba');
|
|
306
|
+
|
|
307
|
+
// Test adding an item
|
|
308
|
+
addButton.click();
|
|
309
|
+
flushSync();
|
|
310
|
+
|
|
311
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('["a","b","c","d"]');
|
|
312
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('dcba');
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('handles some method with reactivity', () => {
|
|
316
|
+
component ArrayTest() {
|
|
317
|
+
let items = new TrackedArray(1, 3, 5, 7);
|
|
318
|
+
let hasEven = track(() => items.some(x => x % 2 === 0));
|
|
319
|
+
|
|
320
|
+
<button onClick={() => items.push(2)}>{'add even'}</button>
|
|
321
|
+
<button onClick={() => {
|
|
322
|
+
items.pop();
|
|
323
|
+
items.push(9);
|
|
324
|
+
}}>{'ensure all odd'}</button>
|
|
325
|
+
<pre>{@hasEven.toString()}</pre>
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
render(ArrayTest);
|
|
329
|
+
|
|
330
|
+
const addEvenButton = container.querySelectorAll('button')[0];
|
|
331
|
+
const makeOddButton = container.querySelectorAll('button')[1];
|
|
332
|
+
|
|
333
|
+
// Initial state
|
|
334
|
+
expect(container.querySelector('pre').textContent).toBe('false');
|
|
335
|
+
|
|
336
|
+
// Test adding an even number
|
|
337
|
+
addEvenButton.click();
|
|
338
|
+
flushSync();
|
|
339
|
+
expect(container.querySelector('pre').textContent).toBe('true');
|
|
340
|
+
|
|
341
|
+
// Test fixing the array to all odd
|
|
342
|
+
makeOddButton.click();
|
|
343
|
+
flushSync();
|
|
344
|
+
expect(container.querySelector('pre').textContent).toBe('false');
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it('handles toLocaleString method with reactivity', () => {
|
|
348
|
+
component ArrayTest() {
|
|
349
|
+
let items = new TrackedArray(1000, 2000, 3000);
|
|
350
|
+
let localized = track(() => items.toLocaleString('en-US'));
|
|
351
|
+
|
|
352
|
+
<button onClick={() => {items[2] = 4000}}>{'add item'}</button>
|
|
353
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
354
|
+
<pre>{@localized}</pre>
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
render(ArrayTest);
|
|
358
|
+
|
|
359
|
+
const addButton = container.querySelector('button');
|
|
360
|
+
|
|
361
|
+
// Initial state
|
|
362
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1000,2000,3000]');
|
|
363
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('1,000,2,000,3,000');
|
|
364
|
+
|
|
365
|
+
// Test adding an item
|
|
366
|
+
addButton.click();
|
|
367
|
+
flushSync();
|
|
368
|
+
|
|
369
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1000,2000,4000]');
|
|
370
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('1,000,2,000,4,000');
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
it('handles toString method with reactivity', () => {
|
|
374
|
+
component ArrayTest() {
|
|
375
|
+
let items = new TrackedArray(1, 2, 3);
|
|
376
|
+
let string = track(() => items.toString());
|
|
377
|
+
|
|
378
|
+
<button onClick={() => items.push(4)}>{'add item'}</button>
|
|
379
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
380
|
+
<pre>{@string}</pre>
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
render(ArrayTest);
|
|
384
|
+
|
|
385
|
+
const addButton = container.querySelector('button');
|
|
386
|
+
|
|
387
|
+
// Initial state
|
|
388
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3]');
|
|
389
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('1,2,3');
|
|
390
|
+
|
|
391
|
+
// Test adding an item
|
|
392
|
+
addButton.click();
|
|
393
|
+
flushSync();
|
|
394
|
+
|
|
395
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4]');
|
|
396
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('1,2,3,4');
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it('handles with method with reactivity', (context) => {
|
|
400
|
+
if (!('with' in Array.prototype)) {
|
|
401
|
+
context.skip();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
component ArrayTest() {
|
|
405
|
+
let items = new TrackedArray(1, 2, 3, 4);
|
|
406
|
+
let withReplaced = track(() => items.with(2, 30));
|
|
407
|
+
|
|
408
|
+
<button onClick={() => items[2] = 50}>{'change original'}</button>
|
|
409
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
410
|
+
<pre>{JSON.stringify(@withReplaced)}</pre>
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
render(ArrayTest);
|
|
414
|
+
|
|
415
|
+
const changeButton = container.querySelector('button');
|
|
416
|
+
|
|
417
|
+
// Initial state
|
|
418
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4]');
|
|
419
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[1,2,30,4]');
|
|
420
|
+
|
|
421
|
+
// Test changing the original array
|
|
422
|
+
changeButton.click();
|
|
423
|
+
flushSync();
|
|
424
|
+
|
|
425
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,50,4]');
|
|
426
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[1,2,30,4]');
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('handles toJSON method', () => {
|
|
430
|
+
component ArrayTest() {
|
|
431
|
+
let items = new TrackedArray(1, 2, 3);
|
|
432
|
+
|
|
433
|
+
<button onClick={() => items.push(4)}>{'add'}</button>
|
|
434
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
render(ArrayTest);
|
|
438
|
+
|
|
439
|
+
const addButton = container.querySelector('button');
|
|
440
|
+
|
|
441
|
+
// Initial state - toJSON is implicitly called by JSON.stringify
|
|
442
|
+
expect(container.querySelector('pre').textContent).toBe('[1,2,3]');
|
|
443
|
+
|
|
444
|
+
// Test reactivity with JSON serialization
|
|
445
|
+
addButton.click();
|
|
446
|
+
flushSync();
|
|
447
|
+
|
|
448
|
+
expect(container.querySelector('pre').textContent).toBe('[1,2,3,4]');
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
it('handles at method with reactivity', () => {
|
|
452
|
+
component ArrayTest() {
|
|
453
|
+
let items = new TrackedArray(10, 20, 30, 40, 50);
|
|
454
|
+
let atIndex2 = track(() => items.at(2));
|
|
455
|
+
let atNegative1 = track(() => items.at(-1));
|
|
456
|
+
let atNegative2 = track(() => items.at(-2));
|
|
457
|
+
|
|
458
|
+
<button onClick={() => items[2] = 300}>{'change index 2'}</button>
|
|
459
|
+
<button onClick={() => items[items.length - 1] = 500}>{'change last'}</button>
|
|
460
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
461
|
+
<pre>{@atIndex2}</pre>
|
|
462
|
+
<pre>{@atNegative1}</pre>
|
|
463
|
+
<pre>{@atNegative2}</pre>
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
render(ArrayTest);
|
|
467
|
+
|
|
468
|
+
const changeIndex2Button = container.querySelectorAll('button')[0];
|
|
469
|
+
const changeLastButton = container.querySelectorAll('button')[1];
|
|
470
|
+
|
|
471
|
+
// Initial state
|
|
472
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[10,20,30,40,50]');
|
|
473
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('30');
|
|
474
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('50');
|
|
475
|
+
expect(container.querySelectorAll('pre')[3].textContent).toBe('40');
|
|
476
|
+
|
|
477
|
+
// Test changing index 2
|
|
478
|
+
changeIndex2Button.click();
|
|
479
|
+
flushSync();
|
|
480
|
+
|
|
481
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[10,20,300,40,50]');
|
|
482
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('300');
|
|
483
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('50');
|
|
484
|
+
expect(container.querySelectorAll('pre')[3].textContent).toBe('40');
|
|
485
|
+
|
|
486
|
+
// Test changing last item
|
|
487
|
+
changeLastButton.click();
|
|
488
|
+
flushSync();
|
|
489
|
+
|
|
490
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[10,20,300,40,500]');
|
|
491
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('300');
|
|
492
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('500');
|
|
493
|
+
expect(container.querySelectorAll('pre')[3].textContent).toBe('40');
|
|
494
|
+
});
|
|
495
|
+
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { flushSync, track, effect, untrack, TrackedArray } from 'ripple';
|
|
2
|
+
|
|
3
|
+
describe('TrackedArray > iteration', () => {
|
|
4
|
+
it('handles entries method with reactivity', () => {
|
|
5
|
+
component ArrayTest() {
|
|
6
|
+
let items = new TrackedArray('a', 'b', 'c');
|
|
7
|
+
let entries = track(() => Array.from(items.entries()));
|
|
8
|
+
|
|
9
|
+
<button onClick={() => items.push('d')}>{'add item'}</button>
|
|
10
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
11
|
+
<pre>{JSON.stringify(@entries)}</pre>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
render(ArrayTest);
|
|
15
|
+
|
|
16
|
+
const addButton = container.querySelector('button');
|
|
17
|
+
|
|
18
|
+
// Initial state
|
|
19
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('["a","b","c"]');
|
|
20
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[[0,"a"],[1,"b"],[2,"c"]]');
|
|
21
|
+
|
|
22
|
+
// Test adding an item
|
|
23
|
+
addButton.click();
|
|
24
|
+
flushSync();
|
|
25
|
+
|
|
26
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('["a","b","c","d"]');
|
|
27
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[[0,"a"],[1,"b"],[2,"c"],[3,"d"]]');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('handles keys method with reactivity', () => {
|
|
31
|
+
component ArrayTest() {
|
|
32
|
+
let items = new TrackedArray('a', 'b', 'c');
|
|
33
|
+
let keys = track(() => Array.from(items.keys()));
|
|
34
|
+
|
|
35
|
+
<button onClick={() => items.push('d')}>{'add item'}</button>
|
|
36
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
37
|
+
<pre>{JSON.stringify(@keys)}</pre>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
render(ArrayTest);
|
|
41
|
+
|
|
42
|
+
const addButton = container.querySelector('button');
|
|
43
|
+
|
|
44
|
+
// Initial state
|
|
45
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('["a","b","c"]');
|
|
46
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[0,1,2]');
|
|
47
|
+
|
|
48
|
+
// Test adding an item
|
|
49
|
+
addButton.click();
|
|
50
|
+
flushSync();
|
|
51
|
+
|
|
52
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('["a","b","c","d"]');
|
|
53
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('[0,1,2,3]');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('handles values method with reactivity', () => {
|
|
57
|
+
component ArrayTest() {
|
|
58
|
+
let items = new TrackedArray('a', 'b', 'c');
|
|
59
|
+
let values = track(() => Array.from(items.values()));
|
|
60
|
+
|
|
61
|
+
<button onClick={() => items.push('d')}>{'add item'}</button>
|
|
62
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
63
|
+
<pre>{JSON.stringify(@values)}</pre>
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
render(ArrayTest);
|
|
67
|
+
|
|
68
|
+
const addButton = container.querySelector('button');
|
|
69
|
+
|
|
70
|
+
// Initial state
|
|
71
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('["a","b","c"]');
|
|
72
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('["a","b","c"]');
|
|
73
|
+
|
|
74
|
+
// Test adding an item
|
|
75
|
+
addButton.click();
|
|
76
|
+
flushSync();
|
|
77
|
+
|
|
78
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('["a","b","c","d"]');
|
|
79
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('["a","b","c","d"]');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('handles Symbol.iterator with reactivity', () => {
|
|
83
|
+
component ArrayTest() {
|
|
84
|
+
let items = new TrackedArray(1, 2, 3);
|
|
85
|
+
let sum = track(0);
|
|
86
|
+
|
|
87
|
+
effect(() => {
|
|
88
|
+
@sum = 0;
|
|
89
|
+
for (const item of items) {
|
|
90
|
+
untrack(() => {
|
|
91
|
+
@sum += item;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
<button onClick={() => items.push(4)}>{'add item'}</button>
|
|
97
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
98
|
+
<pre>{@sum}</pre>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
render(ArrayTest);
|
|
102
|
+
flushSync();
|
|
103
|
+
|
|
104
|
+
const addButton = container.querySelectorAll('button')[0];
|
|
105
|
+
|
|
106
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3]');
|
|
107
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('6');
|
|
108
|
+
|
|
109
|
+
addButton.click();
|
|
110
|
+
flushSync();
|
|
111
|
+
|
|
112
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4]');
|
|
113
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('10');
|
|
114
|
+
});
|
|
115
|
+
});
|