@thyn/core 0.0.343 → 0.0.346
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/.github/workflows/static.yml +48 -0
- package/.github/workflows/test.yml +39 -0
- package/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/{element.js → core/element.js} +14 -36
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -2
- package/dist/plugin/html-parser.d.ts +31 -0
- package/dist/plugin/html-parser.js +275 -0
- package/dist/plugin/index.d.ts +24 -0
- package/dist/plugin/index.js +1009 -0
- package/dist/plugin/utils.d.ts +12 -0
- package/dist/plugin/utils.js +194 -0
- package/docs/CNAME +1 -0
- package/docs/index.html +18 -0
- package/docs/package-lock.json +980 -0
- package/docs/package.json +15 -0
- package/docs/public/thyn.png +0 -0
- package/docs/public/thyn.svg +1 -0
- package/docs/src/App.thyn +10 -0
- package/docs/src/components/Button.thyn +3 -0
- package/docs/src/docs/GettingStarted.thyn +8 -0
- package/docs/src/main.css +17 -0
- package/docs/src/main.js +5 -0
- package/docs/src/pages/Home.thyn +147 -0
- package/docs/vite.config.js +7 -0
- package/package.json +18 -10
- package/src/{element.ts → core/element.ts} +14 -34
- package/src/core/index.ts +1 -0
- package/src/{signals.ts → core/signals.ts} +1 -1
- package/src/index.ts +5 -15
- package/src/plugin/html-parser.ts +332 -0
- package/src/plugin/index.ts +1127 -0
- package/src/plugin/utils.ts +213 -0
- package/tests/Bind.test.ts +14 -0
- package/tests/Bind.thyn +7 -0
- package/tests/ConsecInterps.test.ts +9 -0
- package/tests/ConsecInterps.thyn +9 -0
- package/tests/Counter.test.ts +12 -0
- package/tests/Counter.thyn +7 -0
- package/tests/DoubleQuotes.test.ts +9 -0
- package/tests/DoubleQuotes.thyn +3 -0
- package/tests/Escape.test.ts +9 -0
- package/tests/Escape.thyn +3 -0
- package/tests/EscapeDollar.test.ts +9 -0
- package/tests/EscapeDollar.thyn +5 -0
- package/tests/EventPipes.test.ts +13 -0
- package/tests/EventPipes.thyn +11 -0
- package/tests/List.test.ts +21 -0
- package/tests/List.thyn +15 -0
- package/tests/ListV2.test.ts +20 -0
- package/tests/ListV2.thyn +16 -0
- package/tests/MixElemAndText.test.ts +9 -0
- package/tests/MixElemAndText.thyn +12 -0
- package/tests/Show.test.ts +13 -0
- package/tests/Show.thyn +8 -0
- package/tests/Template.test.ts +9 -0
- package/tests/Template.thyn +8 -0
- package/tests/list/comprehensive.test.ts +659 -0
- package/tests/list/operations/ChildrenAppend.thyn +11 -0
- package/tests/list/operations/ChildrenFilter.thyn +11 -0
- package/tests/list/operations/ChildrenInsert.thyn +11 -0
- package/tests/list/operations/ChildrenNoneToSome.thyn +11 -0
- package/tests/list/operations/ChildrenPrepend.thyn +11 -0
- package/tests/list/operations/ChildrenRemove.thyn +11 -0
- package/tests/list/operations/ChildrenReplaceAll.thyn +11 -0
- package/tests/list/operations/ChildrenSomeToNone.thyn +11 -0
- package/tests/list/operations/ChildrenSort.thyn +11 -0
- package/tests/list/operations/IsolatedAppend.thyn +10 -0
- package/tests/list/operations/IsolatedFilter.thyn +16 -0
- package/tests/list/operations/IsolatedInsert.thyn +10 -0
- package/tests/list/operations/IsolatedMove.thyn +16 -0
- package/tests/list/operations/IsolatedNoneToSome.thyn +16 -0
- package/tests/list/operations/IsolatedPrepend.thyn +10 -0
- package/tests/list/operations/IsolatedRemove.thyn +17 -0
- package/tests/list/operations/IsolatedReplaceAll.thyn +10 -0
- package/tests/list/operations/IsolatedSomeToNone.thyn +10 -0
- package/tests/list/operations/IsolatedSort.thyn +16 -0
- package/tests/list/operations/TerminalAppend.thyn +12 -0
- package/tests/list/operations/TerminalFilter.thyn +12 -0
- package/tests/list/operations/TerminalInsert.thyn +12 -0
- package/tests/list/operations/TerminalNoneToSome.thyn +12 -0
- package/tests/list/operations/TerminalPrepend.thyn +12 -0
- package/tests/list/operations/TerminalRemove.thyn +12 -0
- package/tests/list/operations/TerminalReplaceAll.thyn +12 -0
- package/tests/list/operations/TerminalSomeToNone.thyn +12 -0
- package/tests/list/operations/TerminalSort.thyn +12 -0
- package/tests/tsconfig.json +14 -0
- package/tsconfig.json +11 -6
- package/types/thyn.d.ts +4 -0
- package/vitest.config.ts +7 -2
- package/tests/fx.test.ts +0 -31
- package/tests/lists.test.ts +0 -184
- package/tests/router.test.ts +0 -69
- package/tests/show.test.ts +0 -66
- package/tests/utils.ts +0 -3
- package/tsconfig.tsbuildinfo +0 -1
- /package/dist/{element.d.ts → core/element.d.ts} +0 -0
- /package/dist/{router.d.ts → core/router.d.ts} +0 -0
- /package/dist/{router.js → core/router.js} +0 -0
- /package/dist/{signals.d.ts → core/signals.d.ts} +0 -0
- /package/dist/{signals.js → core/signals.js} +0 -0
- /package/src/{router.ts → core/router.ts} +0 -0
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
// isolatedTerminalList tests (no siblings)
|
|
4
|
+
import IsolatedAppend from "./operations/IsolatedAppend.thyn";
|
|
5
|
+
import IsolatedFilter from "./operations/IsolatedFilter.thyn";
|
|
6
|
+
import IsolatedInsert from "./operations/IsolatedInsert.thyn";
|
|
7
|
+
import IsolatedMove from "./operations/IsolatedMove.thyn";
|
|
8
|
+
import IsolatedNoneToSome from "./operations/IsolatedNoneToSome.thyn";
|
|
9
|
+
import IsolatedPrepend from "./operations/IsolatedPrepend.thyn";
|
|
10
|
+
import IsolatedRemove from "./operations/IsolatedRemove.thyn";
|
|
11
|
+
import IsolatedReplaceAll from "./operations/IsolatedReplaceAll.thyn";
|
|
12
|
+
import IsolatedSomeToNone from "./operations/IsolatedSomeToNone.thyn";
|
|
13
|
+
import IsolatedSort from "./operations/IsolatedSort.thyn";
|
|
14
|
+
|
|
15
|
+
// terminalList tests (with siblings)
|
|
16
|
+
import TerminalAppend from "./operations/TerminalAppend.thyn";
|
|
17
|
+
import TerminalFilter from "./operations/TerminalFilter.thyn";
|
|
18
|
+
import TerminalInsert from "./operations/TerminalInsert.thyn";
|
|
19
|
+
import TerminalNoneToSome from "./operations/TerminalNoneToSome.thyn";
|
|
20
|
+
import TerminalPrepend from "./operations/TerminalPrepend.thyn";
|
|
21
|
+
import TerminalRemove from "./operations/TerminalRemove.thyn";
|
|
22
|
+
import TerminalReplaceAll from "./operations/TerminalReplaceAll.thyn";
|
|
23
|
+
import TerminalSomeToNone from "./operations/TerminalSomeToNone.thyn";
|
|
24
|
+
import TerminalSort from "./operations/TerminalSort.thyn";
|
|
25
|
+
|
|
26
|
+
// list with component children tests (full teardown)
|
|
27
|
+
import ChildrenAppend from "./operations/ChildrenAppend.thyn";
|
|
28
|
+
import ChildrenFilter from "./operations/ChildrenFilter.thyn";
|
|
29
|
+
import ChildrenInsert from "./operations/ChildrenInsert.thyn";
|
|
30
|
+
import ChildrenNoneToSome from "./operations/ChildrenNoneToSome.thyn";
|
|
31
|
+
import ChildrenPrepend from "./operations/ChildrenPrepend.thyn";
|
|
32
|
+
import ChildrenRemove from "./operations/ChildrenRemove.thyn";
|
|
33
|
+
import ChildrenReplaceAll from "./operations/ChildrenReplaceAll.thyn";
|
|
34
|
+
import ChildrenSomeToNone from "./operations/ChildrenSomeToNone.thyn";
|
|
35
|
+
import ChildrenSort from "./operations/ChildrenSort.thyn";
|
|
36
|
+
|
|
37
|
+
const wait = () => Promise.resolve();
|
|
38
|
+
|
|
39
|
+
describe("List Operations - Comprehensive", () => {
|
|
40
|
+
|
|
41
|
+
// ============================================================
|
|
42
|
+
// ISOLATED TERMINAL LIST (isolatedTerminalList)
|
|
43
|
+
// Triggered when #for loop has NO siblings
|
|
44
|
+
// ============================================================
|
|
45
|
+
describe("isolatedTerminalList (no siblings)", () => {
|
|
46
|
+
|
|
47
|
+
describe("none → some", () => {
|
|
48
|
+
it("adds single item to empty list", async () => {
|
|
49
|
+
const root = IsolatedNoneToSome();
|
|
50
|
+
await wait();
|
|
51
|
+
|
|
52
|
+
expect(root.textContent).toBe("");
|
|
53
|
+
|
|
54
|
+
root.click();
|
|
55
|
+
await wait();
|
|
56
|
+
await wait();
|
|
57
|
+
|
|
58
|
+
expect(root.textContent).toBe("1");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("adds multiple items to empty list", async () => {
|
|
62
|
+
const root = IsolatedNoneToSome();
|
|
63
|
+
await wait();
|
|
64
|
+
|
|
65
|
+
root.click();
|
|
66
|
+
await wait();
|
|
67
|
+
root.click();
|
|
68
|
+
await wait();
|
|
69
|
+
|
|
70
|
+
expect(root.textContent).toBe("123");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("some → none", () => {
|
|
75
|
+
it("clears all items from list", async () => {
|
|
76
|
+
const root = IsolatedSomeToNone();
|
|
77
|
+
await wait();
|
|
78
|
+
|
|
79
|
+
expect(root.textContent).toBe("123");
|
|
80
|
+
|
|
81
|
+
root.click();
|
|
82
|
+
await wait();
|
|
83
|
+
await wait();
|
|
84
|
+
|
|
85
|
+
expect(root.textContent).toBe("");
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe("append", () => {
|
|
90
|
+
it("adds items to end of existing list", async () => {
|
|
91
|
+
const root = IsolatedAppend();
|
|
92
|
+
await wait();
|
|
93
|
+
|
|
94
|
+
expect(root.textContent).toBe("12");
|
|
95
|
+
|
|
96
|
+
root.click();
|
|
97
|
+
await wait();
|
|
98
|
+
await wait();
|
|
99
|
+
|
|
100
|
+
expect(root.textContent).toBe("1234");
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe("prepend", () => {
|
|
105
|
+
it("adds items to beginning of existing list", async () => {
|
|
106
|
+
const root = IsolatedPrepend();
|
|
107
|
+
await wait();
|
|
108
|
+
|
|
109
|
+
expect(root.textContent).toBe("34");
|
|
110
|
+
|
|
111
|
+
root.click();
|
|
112
|
+
await wait();
|
|
113
|
+
await wait();
|
|
114
|
+
|
|
115
|
+
expect(root.textContent).toBe("1234");
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("insert", () => {
|
|
120
|
+
it("inserts items in middle of list", async () => {
|
|
121
|
+
const root = IsolatedInsert();
|
|
122
|
+
await wait();
|
|
123
|
+
|
|
124
|
+
expect(root.textContent).toBe("14");
|
|
125
|
+
|
|
126
|
+
root.click();
|
|
127
|
+
await wait();
|
|
128
|
+
await wait();
|
|
129
|
+
|
|
130
|
+
expect(root.textContent).toBe("1234");
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe("remove", () => {
|
|
135
|
+
it("removes items from end", async () => {
|
|
136
|
+
const root = IsolatedRemove();
|
|
137
|
+
await wait();
|
|
138
|
+
|
|
139
|
+
expect(root.textContent).toBe("1234");
|
|
140
|
+
|
|
141
|
+
root.click();
|
|
142
|
+
await wait();
|
|
143
|
+
await wait();
|
|
144
|
+
|
|
145
|
+
expect(root.textContent).toBe("12");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("removes items from beginning on second click", async () => {
|
|
149
|
+
const root = IsolatedRemove();
|
|
150
|
+
await wait();
|
|
151
|
+
|
|
152
|
+
expect(root.textContent).toBe("1234");
|
|
153
|
+
|
|
154
|
+
root.click();
|
|
155
|
+
await wait();
|
|
156
|
+
root.click();
|
|
157
|
+
await wait();
|
|
158
|
+
await wait();
|
|
159
|
+
|
|
160
|
+
expect(root.textContent).toBe("34");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("removes items from middle on third click", async () => {
|
|
164
|
+
const root = IsolatedRemove();
|
|
165
|
+
await wait();
|
|
166
|
+
|
|
167
|
+
root.click();
|
|
168
|
+
await wait();
|
|
169
|
+
root.click();
|
|
170
|
+
await wait();
|
|
171
|
+
root.click();
|
|
172
|
+
await wait();
|
|
173
|
+
await wait();
|
|
174
|
+
|
|
175
|
+
expect(root.textContent).toBe("14");
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe("replace all", () => {
|
|
180
|
+
it("replaces entire list with new items", async () => {
|
|
181
|
+
const root = IsolatedReplaceAll();
|
|
182
|
+
await wait();
|
|
183
|
+
|
|
184
|
+
expect(root.textContent).toBe("123");
|
|
185
|
+
|
|
186
|
+
root.click();
|
|
187
|
+
await wait();
|
|
188
|
+
await wait();
|
|
189
|
+
|
|
190
|
+
expect(root.textContent).toBe("456");
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe("sort", () => {
|
|
195
|
+
it("sorts items ascending", async () => {
|
|
196
|
+
const root = IsolatedSort();
|
|
197
|
+
await wait();
|
|
198
|
+
|
|
199
|
+
expect(root.textContent).toBe("3145");
|
|
200
|
+
|
|
201
|
+
root.click();
|
|
202
|
+
await wait();
|
|
203
|
+
await wait();
|
|
204
|
+
|
|
205
|
+
expect(root.textContent).toBe("1345");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("sorts items descending on second click", async () => {
|
|
209
|
+
const root = IsolatedSort();
|
|
210
|
+
await wait();
|
|
211
|
+
|
|
212
|
+
root.click();
|
|
213
|
+
await wait();
|
|
214
|
+
root.click();
|
|
215
|
+
await wait();
|
|
216
|
+
await wait();
|
|
217
|
+
|
|
218
|
+
expect(root.textContent).toBe("5431");
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("reverses list on third click", async () => {
|
|
222
|
+
const root = IsolatedSort();
|
|
223
|
+
await wait();
|
|
224
|
+
|
|
225
|
+
root.click();
|
|
226
|
+
await wait();
|
|
227
|
+
root.click();
|
|
228
|
+
await wait();
|
|
229
|
+
root.click();
|
|
230
|
+
await wait();
|
|
231
|
+
await wait();
|
|
232
|
+
|
|
233
|
+
expect(root.textContent).toBe("54321");
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
describe("filter", () => {
|
|
238
|
+
it("filters to even numbers only", async () => {
|
|
239
|
+
const root = IsolatedFilter();
|
|
240
|
+
await wait();
|
|
241
|
+
|
|
242
|
+
expect(root.textContent).toBe("123456");
|
|
243
|
+
|
|
244
|
+
root.click();
|
|
245
|
+
await wait();
|
|
246
|
+
await wait();
|
|
247
|
+
|
|
248
|
+
expect(root.textContent).toBe("246");
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("filters to odd numbers only on second click", async () => {
|
|
252
|
+
const root = IsolatedFilter();
|
|
253
|
+
await wait();
|
|
254
|
+
|
|
255
|
+
root.click();
|
|
256
|
+
await wait();
|
|
257
|
+
root.click();
|
|
258
|
+
await wait();
|
|
259
|
+
await wait();
|
|
260
|
+
|
|
261
|
+
expect(root.textContent).toBe("135");
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it("filters to items greater than threshold on third click", async () => {
|
|
265
|
+
const root = IsolatedFilter();
|
|
266
|
+
await wait();
|
|
267
|
+
|
|
268
|
+
root.click();
|
|
269
|
+
await wait();
|
|
270
|
+
root.click();
|
|
271
|
+
await wait();
|
|
272
|
+
root.click();
|
|
273
|
+
await wait();
|
|
274
|
+
await wait();
|
|
275
|
+
|
|
276
|
+
expect(root.textContent).toBe("101520");
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
describe("move/reorder", () => {
|
|
281
|
+
it("moves item to front", async () => {
|
|
282
|
+
const root = IsolatedMove();
|
|
283
|
+
await wait();
|
|
284
|
+
|
|
285
|
+
expect(root.textContent).toBe("1234");
|
|
286
|
+
|
|
287
|
+
root.click();
|
|
288
|
+
await wait();
|
|
289
|
+
await wait();
|
|
290
|
+
|
|
291
|
+
expect(root.textContent).toBe("4123");
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it("swaps adjacent items on second click", async () => {
|
|
295
|
+
const root = IsolatedMove();
|
|
296
|
+
await wait();
|
|
297
|
+
|
|
298
|
+
root.click();
|
|
299
|
+
await wait();
|
|
300
|
+
root.click();
|
|
301
|
+
await wait();
|
|
302
|
+
await wait();
|
|
303
|
+
|
|
304
|
+
expect(root.textContent).toBe("1324");
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it("reverses list on third click", async () => {
|
|
308
|
+
const root = IsolatedMove();
|
|
309
|
+
await wait();
|
|
310
|
+
|
|
311
|
+
root.click();
|
|
312
|
+
await wait();
|
|
313
|
+
root.click();
|
|
314
|
+
await wait();
|
|
315
|
+
root.click();
|
|
316
|
+
await wait();
|
|
317
|
+
await wait();
|
|
318
|
+
|
|
319
|
+
expect(root.textContent).toBe("4321");
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// ============================================================
|
|
325
|
+
// TERMINAL LIST WITH SIBLINGS
|
|
326
|
+
// Triggered when #for loop HAS siblings
|
|
327
|
+
// ============================================================
|
|
328
|
+
describe("terminalList (with siblings)", () => {
|
|
329
|
+
|
|
330
|
+
describe("none → some", () => {
|
|
331
|
+
it("adds items between siblings", async () => {
|
|
332
|
+
const root = TerminalNoneToSome();
|
|
333
|
+
await wait();
|
|
334
|
+
|
|
335
|
+
expect(root.textContent).toBe("startend");
|
|
336
|
+
|
|
337
|
+
// Click on the list area to add items
|
|
338
|
+
const listItem = root.querySelector('[data-id]');
|
|
339
|
+
if (listItem) {
|
|
340
|
+
(listItem as HTMLElement).click();
|
|
341
|
+
await wait();
|
|
342
|
+
await wait();
|
|
343
|
+
expect(root.textContent).toBe("start123end");
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
describe("some → none", () => {
|
|
349
|
+
it("removes items leaving only siblings", async () => {
|
|
350
|
+
const root = TerminalSomeToNone();
|
|
351
|
+
await wait();
|
|
352
|
+
|
|
353
|
+
expect(root.textContent).toBe("start123end");
|
|
354
|
+
|
|
355
|
+
root.click();
|
|
356
|
+
await wait();
|
|
357
|
+
await wait();
|
|
358
|
+
|
|
359
|
+
expect(root.textContent).toBe("startend");
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
describe("append", () => {
|
|
364
|
+
it("appends items between siblings", async () => {
|
|
365
|
+
const root = TerminalAppend();
|
|
366
|
+
await wait();
|
|
367
|
+
|
|
368
|
+
expect(root.textContent).toBe("start12end");
|
|
369
|
+
|
|
370
|
+
root.click();
|
|
371
|
+
await wait();
|
|
372
|
+
await wait();
|
|
373
|
+
|
|
374
|
+
expect(root.textContent).toBe("start1234end");
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
describe("prepend", () => {
|
|
379
|
+
it("prepends items between siblings", async () => {
|
|
380
|
+
const root = TerminalPrepend();
|
|
381
|
+
await wait();
|
|
382
|
+
|
|
383
|
+
expect(root.textContent).toBe("start34end");
|
|
384
|
+
|
|
385
|
+
root.click();
|
|
386
|
+
await wait();
|
|
387
|
+
await wait();
|
|
388
|
+
|
|
389
|
+
expect(root.textContent).toBe("start1234end");
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
describe("insert", () => {
|
|
394
|
+
it("inserts items in middle between siblings", async () => {
|
|
395
|
+
const root = TerminalInsert();
|
|
396
|
+
await wait();
|
|
397
|
+
|
|
398
|
+
expect(root.textContent).toBe("start14end");
|
|
399
|
+
|
|
400
|
+
root.click();
|
|
401
|
+
await wait();
|
|
402
|
+
await wait();
|
|
403
|
+
|
|
404
|
+
expect(root.textContent).toBe("start1234end");
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
describe("remove", () => {
|
|
409
|
+
it("removes items maintaining sibling positions", async () => {
|
|
410
|
+
const root = TerminalRemove();
|
|
411
|
+
await wait();
|
|
412
|
+
|
|
413
|
+
expect(root.textContent).toBe("start1234end");
|
|
414
|
+
|
|
415
|
+
root.click();
|
|
416
|
+
await wait();
|
|
417
|
+
await wait();
|
|
418
|
+
|
|
419
|
+
expect(root.textContent).toBe("start12end");
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
describe("replace all", () => {
|
|
424
|
+
it("replaces all items while keeping siblings", async () => {
|
|
425
|
+
const root = TerminalReplaceAll();
|
|
426
|
+
await wait();
|
|
427
|
+
|
|
428
|
+
expect(root.textContent).toBe("start12end");
|
|
429
|
+
|
|
430
|
+
root.click();
|
|
431
|
+
await wait();
|
|
432
|
+
await wait();
|
|
433
|
+
|
|
434
|
+
expect(root.textContent).toBe("start789end");
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
describe("sort", () => {
|
|
439
|
+
it("sorts items between siblings", async () => {
|
|
440
|
+
const root = TerminalSort();
|
|
441
|
+
await wait();
|
|
442
|
+
|
|
443
|
+
expect(root.textContent).toBe("start312end");
|
|
444
|
+
|
|
445
|
+
root.click();
|
|
446
|
+
await wait();
|
|
447
|
+
await wait();
|
|
448
|
+
|
|
449
|
+
expect(root.textContent).toBe("start123end");
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
describe("filter", () => {
|
|
454
|
+
it("filters items between siblings", async () => {
|
|
455
|
+
const root = TerminalFilter();
|
|
456
|
+
await wait();
|
|
457
|
+
|
|
458
|
+
expect(root.textContent).toBe("start123456end");
|
|
459
|
+
|
|
460
|
+
root.click();
|
|
461
|
+
await wait();
|
|
462
|
+
await wait();
|
|
463
|
+
|
|
464
|
+
expect(root.textContent).toBe("start246end");
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
// ============================================================
|
|
470
|
+
// LIST WITH COMPONENT CHILDREN (full teardown)
|
|
471
|
+
// Triggered when #for items contain components (#if, etc)
|
|
472
|
+
// ============================================================
|
|
473
|
+
describe("list with component children (full teardown)", () => {
|
|
474
|
+
|
|
475
|
+
describe("none → some", () => {
|
|
476
|
+
it("renders children components for new items", async () => {
|
|
477
|
+
const root = ChildrenNoneToSome();
|
|
478
|
+
await wait();
|
|
479
|
+
|
|
480
|
+
const items = root.querySelectorAll('[data-id]');
|
|
481
|
+
expect(items.length).toBe(0);
|
|
482
|
+
|
|
483
|
+
root.click();
|
|
484
|
+
await wait();
|
|
485
|
+
await wait();
|
|
486
|
+
|
|
487
|
+
const text = root.textContent || '';
|
|
488
|
+
expect(text).toContain("odd: 1");
|
|
489
|
+
expect(text).toContain("even: 2");
|
|
490
|
+
expect(text).toContain("odd: 3");
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
describe("some → none", () => {
|
|
495
|
+
it("removes all child components", async () => {
|
|
496
|
+
const root = ChildrenSomeToNone();
|
|
497
|
+
await wait();
|
|
498
|
+
|
|
499
|
+
let items = root.querySelectorAll('[data-id]');
|
|
500
|
+
expect(items.length).toBe(3);
|
|
501
|
+
|
|
502
|
+
root.click();
|
|
503
|
+
await wait();
|
|
504
|
+
await wait();
|
|
505
|
+
|
|
506
|
+
items = root.querySelectorAll('[data-id]');
|
|
507
|
+
expect(items.length).toBe(0);
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
describe("append", () => {
|
|
512
|
+
it("appends items with child components", async () => {
|
|
513
|
+
const root = ChildrenAppend();
|
|
514
|
+
await wait();
|
|
515
|
+
|
|
516
|
+
const text = root.textContent || '';
|
|
517
|
+
expect(text).toContain("odd: 1");
|
|
518
|
+
|
|
519
|
+
root.click();
|
|
520
|
+
await wait();
|
|
521
|
+
await wait();
|
|
522
|
+
|
|
523
|
+
const newText = root.textContent || '';
|
|
524
|
+
expect(newText).toContain("odd: 1");
|
|
525
|
+
expect(newText).toContain("even: 2");
|
|
526
|
+
expect(newText).toContain("odd: 3");
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
describe("prepend", () => {
|
|
531
|
+
it("prepends items with child components", async () => {
|
|
532
|
+
const root = ChildrenPrepend();
|
|
533
|
+
await wait();
|
|
534
|
+
|
|
535
|
+
const text = root.textContent || '';
|
|
536
|
+
expect(text).toContain("odd: 3");
|
|
537
|
+
|
|
538
|
+
root.click();
|
|
539
|
+
await wait();
|
|
540
|
+
await wait();
|
|
541
|
+
|
|
542
|
+
const newText = root.textContent || '';
|
|
543
|
+
expect(newText).toContain("odd: 1");
|
|
544
|
+
expect(newText).toContain("even: 2");
|
|
545
|
+
expect(newText).toContain("odd: 3");
|
|
546
|
+
});
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
describe("insert", () => {
|
|
550
|
+
it("inserts items with child components in middle", async () => {
|
|
551
|
+
const root = ChildrenInsert();
|
|
552
|
+
await wait();
|
|
553
|
+
|
|
554
|
+
let items = root.querySelectorAll('[data-id]');
|
|
555
|
+
expect(items.length).toBe(2);
|
|
556
|
+
|
|
557
|
+
root.click();
|
|
558
|
+
await wait();
|
|
559
|
+
await wait();
|
|
560
|
+
|
|
561
|
+
items = root.querySelectorAll('[data-id]');
|
|
562
|
+
expect(items.length).toBe(4);
|
|
563
|
+
|
|
564
|
+
const text = root.textContent || '';
|
|
565
|
+
expect(text).toContain("odd: 1");
|
|
566
|
+
expect(text).toContain("even: 2");
|
|
567
|
+
expect(text).toContain("odd: 3");
|
|
568
|
+
expect(text).toContain("even: 4");
|
|
569
|
+
});
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
describe("remove", () => {
|
|
573
|
+
it("removes items with their child components", async () => {
|
|
574
|
+
const root = ChildrenRemove();
|
|
575
|
+
await wait();
|
|
576
|
+
|
|
577
|
+
let items = root.querySelectorAll('[data-id]');
|
|
578
|
+
expect(items.length).toBe(4);
|
|
579
|
+
|
|
580
|
+
root.click();
|
|
581
|
+
await wait();
|
|
582
|
+
await wait();
|
|
583
|
+
|
|
584
|
+
items = root.querySelectorAll('[data-id]');
|
|
585
|
+
expect(items.length).toBe(2);
|
|
586
|
+
|
|
587
|
+
const text = root.textContent || '';
|
|
588
|
+
expect(text).toContain("odd: 1");
|
|
589
|
+
expect(text).toContain("odd: 3");
|
|
590
|
+
expect(text).not.toContain("even: 2");
|
|
591
|
+
expect(text).not.toContain("even: 4");
|
|
592
|
+
});
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
describe("replace all", () => {
|
|
596
|
+
it("replaces all items with new child components", async () => {
|
|
597
|
+
const root = ChildrenReplaceAll();
|
|
598
|
+
await wait();
|
|
599
|
+
|
|
600
|
+
let text = root.textContent || '';
|
|
601
|
+
expect(text).toContain("odd: 1");
|
|
602
|
+
expect(text).toContain("even: 2");
|
|
603
|
+
|
|
604
|
+
root.click();
|
|
605
|
+
await wait();
|
|
606
|
+
await wait();
|
|
607
|
+
|
|
608
|
+
text = root.textContent || '';
|
|
609
|
+
expect(text).toContain("odd: 5");
|
|
610
|
+
expect(text).toContain("even: 6");
|
|
611
|
+
expect(text).toContain("odd: 7");
|
|
612
|
+
expect(text).not.toContain("1");
|
|
613
|
+
expect(text).not.toContain("2");
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
describe("sort", () => {
|
|
618
|
+
it("sorts items with child components", async () => {
|
|
619
|
+
const root = ChildrenSort();
|
|
620
|
+
await wait();
|
|
621
|
+
|
|
622
|
+
let items = root.querySelectorAll('[data-id]');
|
|
623
|
+
let ids = Array.from(items).map(p => p.getAttribute('data-id'));
|
|
624
|
+
expect(ids).toEqual(["4", "2", "3", "1"]);
|
|
625
|
+
|
|
626
|
+
root.click();
|
|
627
|
+
await wait();
|
|
628
|
+
await wait();
|
|
629
|
+
|
|
630
|
+
items = root.querySelectorAll('[data-id]');
|
|
631
|
+
ids = Array.from(items).map(p => p.getAttribute('data-id'));
|
|
632
|
+
expect(ids).toEqual(["1", "2", "3", "4"]);
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
describe("filter", () => {
|
|
637
|
+
it("filters items preserving child components", async () => {
|
|
638
|
+
const root = ChildrenFilter();
|
|
639
|
+
await wait();
|
|
640
|
+
|
|
641
|
+
let items = root.querySelectorAll('[data-id]');
|
|
642
|
+
expect(items.length).toBe(6);
|
|
643
|
+
|
|
644
|
+
root.click();
|
|
645
|
+
await wait();
|
|
646
|
+
await wait();
|
|
647
|
+
|
|
648
|
+
items = root.querySelectorAll('[data-id]');
|
|
649
|
+
expect(items.length).toBe(3);
|
|
650
|
+
|
|
651
|
+
const text = root.textContent || '';
|
|
652
|
+
expect(text).toContain("even: 2");
|
|
653
|
+
expect(text).toContain("even: 4");
|
|
654
|
+
expect(text).toContain("even: 6");
|
|
655
|
+
expect(text).not.toContain("odd");
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// List with component children - Test: append
|
|
3
|
+
const items = $signal([1]);
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<div onclick={() => items([1, 2, 3])}>
|
|
7
|
+
<p #for={item in items()} data-id={item}>
|
|
8
|
+
<span #if={item % 2 === 0}>even: {{ item }}</span>
|
|
9
|
+
<span #else>odd: {{ item }}</span>
|
|
10
|
+
</p>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// List with component children - Test: filter
|
|
3
|
+
const items = $signal([1, 2, 3, 4, 5, 6]);
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<div onclick={() => items([2, 4, 6])}>
|
|
7
|
+
<p #for={item in items()} data-id={item}>
|
|
8
|
+
<span #if={item % 2 === 0}>even: {{ item }}</span>
|
|
9
|
+
<span #else>odd: {{ item }}</span>
|
|
10
|
+
</p>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// List with component children - Test: insert
|
|
3
|
+
const items = $signal([1, 4]);
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<div onclick={() => items([1, 2, 3, 4])}>
|
|
7
|
+
<p #for={item in items()} data-id={item}>
|
|
8
|
+
<span #if={item % 2 === 0}>even: {{ item }}</span>
|
|
9
|
+
<span #else>odd: {{ item }}</span>
|
|
10
|
+
</p>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// List with component children - Test: none → some
|
|
3
|
+
const items = $signal([]);
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<div onclick={() => items([1, 2, 3])}>
|
|
7
|
+
<p #for={item in items()} data-id={item}>
|
|
8
|
+
<span #if={item % 2 === 0}>even: {{ item }}</span>
|
|
9
|
+
<span #else>odd: {{ item }}</span>
|
|
10
|
+
</p>
|
|
11
|
+
</div>
|