ripple 0.2.116 → 0.2.119
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/3-transform/segments.js +99 -57
- package/src/compiler/phases/3-transform/server/index.js +21 -11
- package/src/runtime/index-client.js +1 -1
- package/src/runtime/index-server.js +24 -0
- package/src/runtime/internal/client/runtime.js +10 -0
- package/src/runtime/internal/client/utils.js +0 -8
- 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 +3 -22
- 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 +3 -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 +5 -1
- 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,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
|
+
});
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { flushSync, track, TrackedArray } from 'ripple';
|
|
2
|
+
|
|
3
|
+
describe('TrackedArray > mutations', () => {
|
|
4
|
+
it('handles direct assignment and length tracking', () => {
|
|
5
|
+
component ArrayTest() {
|
|
6
|
+
let items = new TrackedArray(1, 2, 3);
|
|
7
|
+
|
|
8
|
+
<button onClick={() => items[items.length] = items.length + 1}>{'increment'}</button>
|
|
9
|
+
|
|
10
|
+
<Child items={items} />
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
component Child({ items }: { items: TrackedArray<number> }) {
|
|
14
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
15
|
+
<pre>{items.length}</pre>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
render(ArrayTest);
|
|
19
|
+
|
|
20
|
+
const button = container.querySelector('button');
|
|
21
|
+
|
|
22
|
+
button.click();
|
|
23
|
+
flushSync();
|
|
24
|
+
|
|
25
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4]');
|
|
26
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('4');
|
|
27
|
+
|
|
28
|
+
button.click();
|
|
29
|
+
flushSync();
|
|
30
|
+
|
|
31
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4,5]');
|
|
32
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('5');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('handles push and pop operations with reactivity', () => {
|
|
36
|
+
component ArrayTest() {
|
|
37
|
+
let items = new TrackedArray(1, 2, 3);
|
|
38
|
+
let lastItem = track(() => items[items.length - 1]);
|
|
39
|
+
|
|
40
|
+
<button onClick={() => items.push(4)}>{'push'}</button>
|
|
41
|
+
<button onClick={() => items.pop()}>{'pop'}</button>
|
|
42
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
43
|
+
<pre>{items.length}</pre>
|
|
44
|
+
<pre>{@lastItem}</pre>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
render(ArrayTest);
|
|
48
|
+
|
|
49
|
+
const pushButton = container.querySelectorAll('button')[0];
|
|
50
|
+
const popButton = container.querySelectorAll('button')[1];
|
|
51
|
+
|
|
52
|
+
// Initial state
|
|
53
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3]');
|
|
54
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
|
|
55
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('3');
|
|
56
|
+
|
|
57
|
+
// Test push operation
|
|
58
|
+
pushButton.click();
|
|
59
|
+
flushSync();
|
|
60
|
+
|
|
61
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4]');
|
|
62
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('4');
|
|
63
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('4');
|
|
64
|
+
|
|
65
|
+
// Test pop operation
|
|
66
|
+
popButton.click();
|
|
67
|
+
flushSync();
|
|
68
|
+
|
|
69
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3]');
|
|
70
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
|
|
71
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('3');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('handles shift and unshift operations with reactivity', () => {
|
|
75
|
+
component ArrayTest() {
|
|
76
|
+
let items = new TrackedArray(2, 3, 4);
|
|
77
|
+
let firstItem = track(() => items[0]);
|
|
78
|
+
|
|
79
|
+
<button onClick={() => items.unshift(1)}>{'unshift'}</button>
|
|
80
|
+
<button onClick={() => items.shift()}>{'shift'}</button>
|
|
81
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
82
|
+
<pre>{items.length}</pre>
|
|
83
|
+
<pre>{@firstItem}</pre>
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
render(ArrayTest);
|
|
87
|
+
|
|
88
|
+
const unshiftButton = container.querySelectorAll('button')[0];
|
|
89
|
+
const shiftButton = container.querySelectorAll('button')[1];
|
|
90
|
+
|
|
91
|
+
// Initial state
|
|
92
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[2,3,4]');
|
|
93
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
|
|
94
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('2');
|
|
95
|
+
|
|
96
|
+
// Test unshift operation
|
|
97
|
+
unshiftButton.click();
|
|
98
|
+
flushSync();
|
|
99
|
+
|
|
100
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4]');
|
|
101
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('4');
|
|
102
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('1');
|
|
103
|
+
|
|
104
|
+
// Test shift operation
|
|
105
|
+
shiftButton.click();
|
|
106
|
+
flushSync();
|
|
107
|
+
|
|
108
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[2,3,4]');
|
|
109
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
|
|
110
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('2');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('handles splice operation with reactivity', () => {
|
|
114
|
+
component ArrayTest() {
|
|
115
|
+
let items = new TrackedArray<number | string>(1, 2, 3, 4, 5);
|
|
116
|
+
let middleItem = track(() => items[2]);
|
|
117
|
+
|
|
118
|
+
<button onClick={() => items.splice(1, 2, 'a', 'b')}>{'splice'}</button>
|
|
119
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
120
|
+
<pre>{items.length}</pre>
|
|
121
|
+
<pre>{@middleItem}</pre>
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
render(ArrayTest);
|
|
125
|
+
|
|
126
|
+
const spliceButton = container.querySelector('button');
|
|
127
|
+
|
|
128
|
+
// Initial state
|
|
129
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4,5]');
|
|
130
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('5');
|
|
131
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('3');
|
|
132
|
+
|
|
133
|
+
// Test splice operation
|
|
134
|
+
spliceButton.click();
|
|
135
|
+
flushSync();
|
|
136
|
+
|
|
137
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,"a","b",4,5]');
|
|
138
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('5');
|
|
139
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('b');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('handles fill operation with reactivity', () => {
|
|
143
|
+
component ArrayTest() {
|
|
144
|
+
let items = new TrackedArray(1, 2, 3, 4, 5);
|
|
145
|
+
let secondItem = track(() => items[1]);
|
|
146
|
+
|
|
147
|
+
<button onClick={() => items.fill(0, 1, 4)}>{'fill'}</button>
|
|
148
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
149
|
+
<pre>{@secondItem}</pre>
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
render(ArrayTest);
|
|
153
|
+
|
|
154
|
+
const fillButton = container.querySelector('button');
|
|
155
|
+
|
|
156
|
+
// Initial state
|
|
157
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4,5]');
|
|
158
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('2');
|
|
159
|
+
|
|
160
|
+
// Test fill operation
|
|
161
|
+
fillButton.click();
|
|
162
|
+
flushSync();
|
|
163
|
+
|
|
164
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,0,0,0,5]');
|
|
165
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('0');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('handles reverse operation with reactivity', () => {
|
|
169
|
+
component ArrayTest() {
|
|
170
|
+
let items = new TrackedArray(1, 2, 3, 4, 5);
|
|
171
|
+
let firstItem = track(() => items[0]);
|
|
172
|
+
let lastItem = track(() => items[4]);
|
|
173
|
+
|
|
174
|
+
<button onClick={() => items.reverse()}>{'reverse'}</button>
|
|
175
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
176
|
+
<pre>{@firstItem}</pre>
|
|
177
|
+
<pre>{@lastItem}</pre>
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
render(ArrayTest);
|
|
181
|
+
|
|
182
|
+
const reverseButton = container.querySelector('button');
|
|
183
|
+
|
|
184
|
+
// Initial state
|
|
185
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4,5]');
|
|
186
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('1');
|
|
187
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('5');
|
|
188
|
+
|
|
189
|
+
// Test reverse operation
|
|
190
|
+
reverseButton.click();
|
|
191
|
+
flushSync();
|
|
192
|
+
|
|
193
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[5,4,3,2,1]');
|
|
194
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('5');
|
|
195
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('1');
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('handles sort operation with reactivity', () => {
|
|
199
|
+
component ArrayTest() {
|
|
200
|
+
let items = new TrackedArray(5, 3, 1, 4, 2);
|
|
201
|
+
let secondItem = track(() => items[1]);
|
|
202
|
+
|
|
203
|
+
<button onClick={() => items.sort()}>{'sort ascending'}</button>
|
|
204
|
+
<button onClick={() => items.sort((a, b) => b - a)}>{'sort descending'}</button>
|
|
205
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
206
|
+
<pre>{@secondItem}</pre>
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
render(ArrayTest);
|
|
210
|
+
|
|
211
|
+
const sortAscButton = container.querySelectorAll('button')[0];
|
|
212
|
+
const sortDescButton = container.querySelectorAll('button')[1];
|
|
213
|
+
|
|
214
|
+
// Initial state
|
|
215
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[5,3,1,4,2]');
|
|
216
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
|
|
217
|
+
|
|
218
|
+
// Test sort ascending
|
|
219
|
+
sortAscButton.click();
|
|
220
|
+
flushSync();
|
|
221
|
+
|
|
222
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4,5]');
|
|
223
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('2');
|
|
224
|
+
|
|
225
|
+
// Test sort descending
|
|
226
|
+
sortDescButton.click();
|
|
227
|
+
flushSync();
|
|
228
|
+
|
|
229
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[5,4,3,2,1]');
|
|
230
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('4');
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('handles array modification through forEach()', () => {
|
|
234
|
+
component ArrayTest() {
|
|
235
|
+
let items = new TrackedArray(1, 2, 3);
|
|
236
|
+
|
|
237
|
+
<button onClick={() => items.forEach((item, i) => items[i] = item * 2)}>{'double all'}</button>
|
|
238
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
render(ArrayTest);
|
|
242
|
+
|
|
243
|
+
const doubleButton = container.querySelector('button');
|
|
244
|
+
|
|
245
|
+
// Initial state
|
|
246
|
+
expect(container.querySelector('pre').textContent).toBe('[1,2,3]');
|
|
247
|
+
|
|
248
|
+
// Test iteration with side effects
|
|
249
|
+
doubleButton.click();
|
|
250
|
+
flushSync();
|
|
251
|
+
|
|
252
|
+
expect(container.querySelector('pre').textContent).toBe('[2,4,6]');
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('handles array modification through iterator', () => {
|
|
256
|
+
component ArrayTest() {
|
|
257
|
+
let items = new TrackedArray(1, 2, 3);
|
|
258
|
+
|
|
259
|
+
<button onClick={() => items.forEach((item, i) => items[i] = item * 2)}>{'double all'}</button>
|
|
260
|
+
|
|
261
|
+
for (const item of items) {
|
|
262
|
+
<pre>{item}</pre>
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
render(ArrayTest);
|
|
267
|
+
|
|
268
|
+
const doubleButton = container.querySelector('button');
|
|
269
|
+
|
|
270
|
+
// Initial state
|
|
271
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('1');
|
|
272
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('2');
|
|
273
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('3');
|
|
274
|
+
|
|
275
|
+
// Test iteration with side effects
|
|
276
|
+
doubleButton.click();
|
|
277
|
+
flushSync();
|
|
278
|
+
|
|
279
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('2');
|
|
280
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('4');
|
|
281
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('6');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('handles array index access with reactivity', () => {
|
|
285
|
+
component ArrayTest() {
|
|
286
|
+
let items = new TrackedArray(10, 20, 30);
|
|
287
|
+
let firstItem = track(() => items[0]);
|
|
288
|
+
let secondItem = track(() => items[1]);
|
|
289
|
+
|
|
290
|
+
<button onClick={() => items[0] = 100}>{'change first'}</button>
|
|
291
|
+
<pre>{@firstItem}</pre>
|
|
292
|
+
<pre>{@secondItem}</pre>
|
|
293
|
+
<pre>{items[0]}</pre>
|
|
294
|
+
<pre>{items[1]}</pre>
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
render(ArrayTest);
|
|
298
|
+
|
|
299
|
+
const changeButton = container.querySelector('button');
|
|
300
|
+
|
|
301
|
+
// Initial state
|
|
302
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('10');
|
|
303
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('20');
|
|
304
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('10');
|
|
305
|
+
expect(container.querySelectorAll('pre')[3].textContent).toBe('20');
|
|
306
|
+
|
|
307
|
+
// Test changing array element directly
|
|
308
|
+
changeButton.click();
|
|
309
|
+
flushSync();
|
|
310
|
+
|
|
311
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('100');
|
|
312
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('20');
|
|
313
|
+
expect(container.querySelectorAll('pre')[2].textContent).toBe('100');
|
|
314
|
+
expect(container.querySelectorAll('pre')[3].textContent).toBe('20');
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('handles length property for reactivity', () => {
|
|
318
|
+
component ArrayTest() {
|
|
319
|
+
let items = new TrackedArray(1, 2, 3);
|
|
320
|
+
let length = track(() => items.length);
|
|
321
|
+
|
|
322
|
+
<button onClick={() => items.length = 5}>{'expand'}</button>
|
|
323
|
+
<button onClick={() => items.length = 2}>{'shrink'}</button>
|
|
324
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
325
|
+
<pre>{@length}</pre>
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
render(ArrayTest);
|
|
329
|
+
|
|
330
|
+
const expandButton = container.querySelectorAll('button')[0];
|
|
331
|
+
const shrinkButton = container.querySelectorAll('button')[1];
|
|
332
|
+
|
|
333
|
+
// Initial state
|
|
334
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3]');
|
|
335
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
|
|
336
|
+
|
|
337
|
+
// Test expand
|
|
338
|
+
expandButton.click();
|
|
339
|
+
flushSync();
|
|
340
|
+
|
|
341
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,null,null]');
|
|
342
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('5');
|
|
343
|
+
|
|
344
|
+
// Test shrink
|
|
345
|
+
shrinkButton.click();
|
|
346
|
+
flushSync();
|
|
347
|
+
|
|
348
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2]');
|
|
349
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('2');
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('handles setting length property and resizing the array', () => {
|
|
353
|
+
component ArrayTest() {
|
|
354
|
+
let items = new TrackedArray(1, 2, 3, 4, 5);
|
|
355
|
+
|
|
356
|
+
<button onClick={() => items.length = 3}>{'truncate'}</button>
|
|
357
|
+
<button onClick={() => items.length = 7}>{'expand'}</button>
|
|
358
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
359
|
+
<pre>{items.length}</pre>
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
render(ArrayTest);
|
|
363
|
+
|
|
364
|
+
const truncateButton = container.querySelectorAll('button')[0];
|
|
365
|
+
const expandButton = container.querySelectorAll('button')[1];
|
|
366
|
+
|
|
367
|
+
// Initial state
|
|
368
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4,5]');
|
|
369
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('5');
|
|
370
|
+
|
|
371
|
+
// Test truncating
|
|
372
|
+
truncateButton.click();
|
|
373
|
+
flushSync();
|
|
374
|
+
|
|
375
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3]');
|
|
376
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
|
|
377
|
+
|
|
378
|
+
// Test expanding
|
|
379
|
+
expandButton.click();
|
|
380
|
+
flushSync();
|
|
381
|
+
|
|
382
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,null,null,null,null]');
|
|
383
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('7');
|
|
384
|
+
});
|
|
385
|
+
});
|