sprae 6.1.1 → 7.0.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.
package/test/attrs.js DELETED
@@ -1,754 +0,0 @@
1
- // import { signal } from 'usignal/sync'
2
- import { signal } from '@preact/signals-core'
3
- import test, {is, any, throws} from 'tst'
4
- import {tick, time} from 'wait-please'
5
- import sprae from '../src/index.js'
6
- import h from 'hyperf'
7
-
8
-
9
- test.skip('autoinit', async () => {
10
- is(window.x.innerHTML, '1')
11
- })
12
-
13
- test('hidden: core', async () => {
14
- let el = h`<div :hidden="hidden"></div>`
15
- let params = sprae(el, {hidden:true})
16
- is(el.outerHTML, `<div hidden=""></div>`)
17
- params.hidden = false
18
- await tick()
19
- is(el.outerHTML, `<div></div>`)
20
- })
21
-
22
- test.skip('hidden: reactive', async () => {
23
- const hidden = signal(true)
24
- let el = h`<div :hidden="hidden"></div>`
25
- sprae(el, {hidden})
26
- is(el.outerHTML, `<div hidden=""></div>`)
27
- hidden.value = false
28
- is(el.outerHTML, `<div></div>`)
29
- })
30
-
31
- test('common: reactive', async () => {
32
- let el = h`<label :for="name" :text="name" ></label><input :id="name" :name="name" :type="name" :disabled="!name"/><a :href="url"></a><img :src="url"/>`
33
- let params = sprae(el, {name:'text', url:'//google.com'})
34
- is(el.outerHTML, `<label for="text">text</label><input id="text" name="text" type="text"><a href="//google.com"></a><img src="//google.com">`)
35
- params.name = 'email'
36
- await tick()
37
- is(el.outerHTML, `<label for="email">email</label><input id="email" name="email" type="email"><a href="//google.com"></a><img src="//google.com">`)
38
- })
39
-
40
- test('common: empty strings', async () => {
41
- let el = h`<x :="" :x=""></x>`
42
- sprae(el)
43
- is(el.outerHTML, `<x></x>`)
44
- })
45
-
46
- test('common: comments', async () => {
47
- let el = h`<x :="/* */" :x="/* */"></x>`
48
- sprae(el)
49
- is(el.outerHTML, `<x></x>`)
50
- })
51
-
52
- test('common: newlines', async () => {
53
- let el = h`<x :text="
54
- x
55
- "></x>`
56
- sprae(el, {x:1})
57
- is(el.outerHTML, `<x>1</x>`)
58
- })
59
-
60
- test('common: const in on', async () => {
61
- let el = h`<div :onx="() => {const x=1; y=x+1}"></div>`
62
- let state = sprae(el, {y:0})
63
- el.dispatchEvent(new CustomEvent('x'))
64
- is(state.y, 2)
65
- })
66
-
67
- test('common: const in with', async () => {
68
- let el = h`<div :with="{x(){let x = 1; y=x;}}" @x="x()"></div>`
69
- let state = sprae(el,{y:0})
70
- el.dispatchEvent(new CustomEvent('x'))
71
- is(state.y, 1)
72
- })
73
-
74
- test('style', async () => {
75
- let el = h`<x style="left: 1px" :style="style"></x>`
76
- let params = sprae(el, {style: "top: 1px"})
77
- is(el.outerHTML, `<x style="left: 1px; top: 1px"></x>`)
78
-
79
- params.style = {top: '2px'}
80
- await tick()
81
- is(el.outerHTML, `<x style="left: 1px; top: 2px;"></x>`)
82
-
83
- params.style = {'--x': 123}
84
- await tick()
85
- is(el.style.getPropertyValue('--x'), '123')
86
-
87
- params.style = {top:'1px', bottom:'2px'}
88
- await tick()
89
- is(el.outerHTML, `<x style="left: 1px; top: 1px; bottom: 2px;"></x>`)
90
-
91
- params.style = {top:'2px', bottom: null}
92
- // FIXME
93
- await tick()
94
- is(el.outerHTML, `<x style="left: 1px; top: 2px;"></x>`)
95
- })
96
-
97
- test('class', async () => {
98
- let el = h`<x class="base" :class="a"></x><y :class="[b, c]"></y><z :class="{b:true, c:d}"></z>`
99
- const c = signal('z')
100
- let params = sprae(el, {a:'x', b:'y', c, d:false});
101
- is(el.outerHTML, `<x class="base x"></x><y class="y z"></y><z class="b"></z>`);
102
- params.d = true;
103
- await tick()
104
- is(el.outerHTML, `<x class="base x"></x><y class="y z"></y><z class="b c"></z>`);
105
- // c.value = 'w'
106
- // is(el.outerHTML, `<x class="base x"></x><y class="y w"></y><z class="b c"></z>`);
107
- })
108
-
109
- test('class: undefined value', async () => {
110
- let el = h`<x :class="a"></x><y :class="[b]"></y><z :class="{c}"></z>`
111
- sprae(el, {a:undefined, b:undefined, c:undefined})
112
- is(el.outerHTML, `<x></x><y></y><z></z>`)
113
- })
114
-
115
- test('class: old svg fun', async () => {
116
- // raw html creates svganimatedstring
117
- let el = document.createElement('div')
118
- el.innerHTML = `<svg class="foo" :class="a ? 'x' : 'y'"></svg>`
119
-
120
- let s = sprae(el, {a:true})
121
- is(el.innerHTML, `<svg class="foo x"></svg>`)
122
- s.a = false
123
- await tick()
124
- is(el.innerHTML, `<svg class="foo y"></svg>`)
125
- })
126
-
127
- test('props: base', async () => {
128
- let el = h`<input :id="0" :="{for:1, title:2, help:3, type:4, placeholder: 5, value: 6, aB: 8}" :value="7"/>`
129
- let params = sprae(el)
130
- is(el.outerHTML, `<input id="0" for="1" title="2" help="3" type="4" placeholder="5" value="7" a-b="8">`)
131
- })
132
-
133
- test('props: sets prop', async () => {
134
- let el = h`<x :x="this.x=1" :y="this.y='abc'"></x>`
135
- sprae(el)
136
- is(el.x, 1)
137
- is(el.y, 'abc')
138
- })
139
-
140
- test('props: multiprop', async () => {
141
- let el = h`<input :id:name:for="0" />`
142
- let params = sprae(el)
143
- is(el.outerHTML, `<input id="0" name="0" for="0">`)
144
- })
145
-
146
- test('props: calculation', async () => {
147
- let el = h`<x :x="(()=>{ let a = 5; return Array.from({length: x}, (_,i)=>i).join('') })()"></x>`
148
- let state = sprae(el, {x:3});
149
- is(el.outerHTML, `<x x="012"></x>`)
150
- state.x = 4
151
- await tick()
152
- is(el.outerHTML, `<x x="0123"></x>`)
153
- })
154
-
155
- test.todo('props: semicols in expression', async () => {
156
- let el = h`<x :x="0; return Array.from({length: x}, (_,i)=>i).join('')"></x>`
157
- let state = sprae(el, {x:3});
158
- is(el.outerHTML, `<x x="012"></x>`)
159
- state.x = 4
160
- is(el.outerHTML, `<x x="0123"></x>`)
161
- })
162
-
163
-
164
- test.skip('data: base', async () => {
165
- let el = h`<input :data="{a:1, fooBar:2}"/>`
166
- let params = sprae(el)
167
- is(el.outerHTML, `<input data-a="1" data-foo-bar="2">`)
168
- })
169
-
170
- test.skip('aria: base', async () => {
171
- let el = h`<input type="text" id="jokes" role="combobox" :aria="{controls:'joketypes', autocomplete:'list', expanded:false, activeOption:'item1', activedescendant:'', xxx:null}"/>`
172
- sprae(el)
173
- is(el.outerHTML, `<input type="text" id="jokes" role="combobox" aria-controls="joketypes" aria-autocomplete="list" aria-expanded="false" aria-active-option="item1" aria-activedescendant="">`)
174
- })
175
-
176
- test('value: direct', async () => {
177
- let el = h`<input :value="a" />`
178
- let state = sprae(el, {a:1})
179
- is(el.value, '1')
180
- is(el.outerHTML, `<input value="1">`)
181
- state.a = 2
182
- await tick()
183
- is(el.value, '2')
184
- is(el.outerHTML, `<input value="2">`)
185
-
186
- el.value = 3
187
- // el.dispatchEvent(new window.Event('change'))
188
- // is(state.a, '3')
189
- })
190
-
191
- test('value: textarea', async () => {
192
- let el = h`<textarea :value="a"></textarea>`
193
- let state = sprae(el, {a: 'abcdefgh'})
194
- is(el.selectionStart, 8)
195
- is(el.selectionEnd, 8)
196
- el.setSelectionRange(1, 4)
197
- is(el.selectionStart, 1)
198
- is(el.selectionEnd, 4)
199
- state.a = 'xyzyvw'
200
- is(el.selectionStart, 1)
201
- is(el.selectionEnd, 4)
202
- })
203
-
204
- test('text: core', async () => {
205
- let el = h`<div :text="text"></div>`
206
- let params = sprae(el, {text:'abc'})
207
- is(el.outerHTML, `<div>abc</div>`)
208
- params.text = null
209
- await tick()
210
- is(el.outerHTML, `<div></div>`)
211
- })
212
-
213
- test('if: base', async () => {
214
- let el = h`<p>
215
- <span :if="a==1">a</span>
216
- <span :else :if="a==2">b</span>
217
- <span :else >c</span>
218
- </p>`
219
-
220
- const params = sprae(el, { a: 1 })
221
-
222
- is(el.innerHTML, '<span>a</span>')
223
- params.a = 2
224
- await tick()
225
- is(el.innerHTML, '<span>b</span>')
226
- params.a = 3
227
- await tick()
228
- is(el.innerHTML, '<span>c</span>')
229
- params.a = null
230
- await tick()
231
- is(el.innerHTML, '<span>c</span>')
232
- })
233
-
234
- test('if: short with insertions', async () => {
235
- let el = h`<p>
236
- <span :if="a==1" :text="'1:'+a"></span>
237
- <span :else :if="a==2" :text="'2:'+a"></span>
238
- <span :else :text="a"></span>
239
- </p>`
240
-
241
- const params = sprae(el, { a: 1 })
242
-
243
- is(el.innerHTML, '<span>1:1</span>')
244
- params.a = 2
245
- await tick()
246
- is(el.innerHTML, '<span>2:2</span>')
247
- params.a = 3
248
- await tick()
249
- is(el.innerHTML, '<span>3</span>')
250
- params.a = 4
251
- await tick()
252
- is(el.innerHTML, '<span>4</span>')
253
-
254
- params.a = 1
255
- await tick()
256
- is(el.innerHTML, '<span>1:1</span>')
257
- params.a = 4
258
- await tick()
259
- is(el.innerHTML, '<span>4</span>')
260
-
261
- params.a = null
262
- })
263
-
264
- test.skip('if: reactive values', async () => {
265
- let el = h`<p>
266
- <span :if="a==1" :text="'1:'+a"></span>
267
- <span :else :if="a==2" :text="'2:'+a"></span>
268
- <span :else :text="a"></span>
269
- </p>`
270
-
271
- const a = signal(1)
272
- sprae(el, { a })
273
-
274
- is(el.innerHTML, '<span>1:1</span>')
275
- a.value = 2
276
- is(el.innerHTML, '<span>2:2</span>')
277
- a.value = 3
278
- is(el.innerHTML, '<span>3</span>')
279
- a.value = 4
280
- is(el.innerHTML, '<span>4</span>')
281
-
282
- a.value = 1
283
- is(el.innerHTML, '<span>1:1</span>')
284
- a.value = 4
285
- is(el.innerHTML, '<span>4</span>')
286
- })
287
-
288
- test('if: (#3) subsequent content is not abandoned', async () => {
289
- let x = h`<x><y :if="!!y"></y><z :text="123"></z></x>`
290
- sprae(x, {y: false})
291
- is(x.outerHTML, `<x><z>123</z></x>`)
292
- })
293
-
294
- test('if: + :with doesnt prevent secondary effects from happening', async () => {
295
- let el = h`<div><x :if="x" :with="{}" :text="x"></x></div>`
296
- let state = sprae(el, {x:''})
297
- is(el.innerHTML, ``)
298
- state.x = '123'
299
- await tick()
300
- is(el.innerHTML, `<x>123</x>`)
301
-
302
- // NOTE: we ignore this case
303
- // let el2 = h`<div><x :if="x" :with="{x:cond}" :text="x"></x></div>`
304
- // let state2 = sprae(el, {cond:''})
305
- // is(el2.innerHTML, ``)
306
- // state2.cond = '123'
307
- // is(el2.innerHTML, `<x>123</x>`)
308
- })
309
-
310
- test('each: array', async () => {
311
- // FIXME: in some conspicuous reason jsdom fails to update text nodes somehow
312
- let el = h`<p>
313
- <span :each="a in b" :text="a"></span>
314
- </p>`
315
-
316
- const params = sprae(el, { b: [] })
317
-
318
- is(el.innerHTML, '')
319
- console.log('set 1,2')
320
- params.b = [1,2]
321
- await tick()
322
- is(el.innerHTML, '<span>1</span><span>2</span>')
323
- params.b = []
324
- await tick()
325
- is(el.innerHTML, '')
326
- params.b = null
327
- await tick()
328
- is(el.innerHTML, '')
329
- })
330
-
331
- test('each: object', async () => {
332
- // FIXME: in some conspicuous reason jsdom fails to update text nodes somehow
333
- let el = h`<p>
334
- <span :each="x,key in b" :text="[key,x]"></span>
335
- </p>`
336
-
337
- const params = sprae(el, { b: null })
338
-
339
- is(el.innerHTML, '')
340
- console.log('set 1,2')
341
- params.b = { x:1, y:2 }
342
- await tick()
343
- is(el.innerHTML, '<span>x,1</span><span>y,2</span>')
344
- params.b = []
345
- await tick()
346
- is(el.innerHTML, '')
347
- params.b = null
348
- await tick()
349
- is(el.innerHTML, '')
350
- })
351
-
352
- test('each: loop within loop', async () => {
353
- let el = h`<p>
354
- <x :each="b in c"><y :each="a in b" :text="a"></y></x>
355
- </p>`
356
-
357
- const params = sprae(el, { c: [[1,2], [3,4]] })
358
-
359
- is(el.innerHTML, '<x><y>1</y><y>2</y></x><x><y>3</y><y>4</y></x>')
360
- params.c = [[5,6], [3,4]]
361
- await tick()
362
- is(el.innerHTML, '<x><y>5</y><y>6</y></x><x><y>3</y><y>4</y></x>')
363
- // params.c[1] = [7,8]
364
- params.c = [params.c[0], [7,8]]
365
- await tick()
366
- is(el.innerHTML, '<x><y>5</y><y>6</y></x><x><y>7</y><y>8</y></x>')
367
- // is(el.innerHTML, '<span>1</span><span>2</span>')
368
- params.c = []
369
- await tick()
370
- is(el.innerHTML, '')
371
- // params.b = null
372
- // is(el.innerHTML, '')
373
- })
374
-
375
- test.skip('each: reactive values', async () => {
376
- let el = h`<p>
377
- <span :each="a in b" :text="a"></span>
378
- </p>`
379
-
380
- const b = signal([])
381
- const params = sprae(el, { b })
382
-
383
- is(el.innerHTML, '')
384
- b.value = [1,2]
385
- is(el.innerHTML, '<span>1</span><span>2</span>')
386
- b.value = []
387
- is(el.innerHTML, '')
388
- params.b = null
389
- is(el.innerHTML, '')
390
- })
391
-
392
- test('each: loop with condition', async () => {
393
- // NOTE: there doesn't seem to be much value in exactly that
394
- // also it creates confusion with :else directive
395
- // prohibitin that allows in-order directives init
396
- let el = h`<p>
397
- <span :each="a in b" :text="a" :if="c"></span>
398
- </p>`
399
-
400
- const params = sprae(el, { b: [1,2], c: false })
401
-
402
- is(el.innerHTML, '')
403
- params.c = true
404
- await tick()
405
- is(el.innerHTML, '<span>1</span><span>2</span>')
406
- params.b = [1]
407
- await tick()
408
- is(el.innerHTML, '<span>1</span>')
409
- params.b = null
410
- await tick()
411
- is(el.innerHTML, '')
412
- })
413
-
414
- test('each: condition with loop', async () => {
415
- let el = h`<p>
416
- <span :if="c" :each="a in b" :text="a"></span>
417
- <span :else :text="c"></span>
418
- </p>`
419
-
420
- const params = sprae(el, { b: [1,2], c: false })
421
-
422
- is(el.innerHTML, '<span>false</span>')
423
- params.c = true
424
- await tick()
425
- is(el.innerHTML, '<span>1</span><span>2</span>')
426
- params.b = [1]
427
- await tick()
428
- is(el.innerHTML, '<span>1</span>')
429
- params.b = null
430
- await tick()
431
- is(el.innerHTML, '')
432
- console.log('c=false')
433
- params.c = false
434
- await tick()
435
- is(el.innerHTML, '<span>false</span>')
436
- })
437
-
438
- test('each: loop within condition', async () => {
439
- let el = h`<p>
440
- <x :if="a==1"><y :each="i in a" :text="i"></y></x>
441
- <x :else :if="a==2"><y :each="i in a" :text="-i"></y></x>
442
- </p>`
443
-
444
- const params = sprae(el, { a: 1 })
445
-
446
- is(el.innerHTML, '<x><y>0</y></x>')
447
- params.a = 2
448
- await tick()
449
- is(el.innerHTML, '<x><y>0</y><y>-1</y></x>')
450
- params.a = 0
451
- await tick()
452
- is(el.innerHTML, '')
453
- })
454
-
455
- test('each: condition within loop', async () => {
456
- let el = h`<p>
457
- <x :each="a in b">
458
- <y :if="a==1" :text="'1:'+a"></y>
459
- <y :else :if="a==2" :text="'2:'+a"></y>
460
- <y :else :text="a"></y>
461
- </x>
462
- </p>`
463
-
464
- const params = sprae(el, { b: [1,2,3] })
465
-
466
- is(el.innerHTML, '<x><y>1:1</y></x><x><y>2:2</y></x><x><y>3</y></x>')
467
- params.b = [2]
468
- await tick()
469
- is(el.innerHTML, '<x><y>2:2</y></x>')
470
- params.b = null
471
- await tick()
472
- is(el.innerHTML, '')
473
- })
474
-
475
- test('each: next items have own "this", not single one', async () => {
476
- // FIXME: let el = h`<x :each="x in 3"></x>`
477
- let el = h`<div><x :each="x in 3" :data-x="x" :x="log.push(x, this.dataset.x)"></x></div>`
478
- let log = []
479
- let state = sprae(el, {log})
480
- is(state.log, [0,'0',1,'1',2,'2'])
481
- })
482
-
483
- test('each: unkeyed', async () => {
484
- let el = h`<div><x :each="x in xs" :text="x"></x></div>`
485
- let state = sprae(el, {xs:[1,2,3]})
486
- is(el.children.length, 3)
487
- is(el.textContent, '123')
488
- // let first = el.firstChild
489
- state.xs = [1,3,2]
490
- await tick()
491
- // is(el.firstChild, first)
492
- is(el.textContent, '132')
493
- state.xs = [3,3,3]
494
- await tick()
495
- is(el.textContent, '333')
496
- // is(el.firstChild, first)
497
- })
498
-
499
- test('each: keyed', async () => {
500
- // keyed
501
- let el = h`<div><x :each="x in xs" :text="x" :key="x"></x></div>`
502
- let state = sprae(el, {xs:[1,2,3]})
503
- is(el.children.length, 3)
504
- is(el.textContent, '123')
505
- let first = el.firstChild
506
- state.xs = [1,3,2]
507
- await tick()
508
- is(el.firstChild, first)
509
- is(el.textContent, '132')
510
- state.xs = [3,3,3]
511
- await tick()
512
- is(el.textContent, '3')
513
- // is(el.firstChild, first)
514
- })
515
-
516
- test('each: wrapped source', async () => {
517
- let el = h`<div><x :each="i in (x || 2)" :text="i"></x></div>`
518
- sprae(el, {x:0})
519
- is(el.innerHTML, `<x>0</x><x>1</x>`)
520
- })
521
-
522
- test('each: unmounted elements remove listeners', async () => {
523
- // let's hope they get removed without memory leaks :')
524
- })
525
-
526
- test('each: internal children get updated by state update, also: update by running again', async () => {
527
- let el = h`<><x :each="item, idx in items" :text="item" :key="idx"></x></>`
528
- let state = sprae(el, { items: [1,2,3] })
529
- is(el.textContent, '123')
530
- state.items = [2, 2, 3]
531
- await tick()
532
- is(el.textContent, '223')
533
- state = sprae(el, { items: [0,2,3] })
534
- await tick()
535
- is(el.textContent, '023')
536
- // NOTE: this doesn't update items, since they're new array
537
- console.log('set items')
538
- state.items[0] = 1
539
- // state.items = [...state.items]
540
- await tick()
541
- is(el.textContent, '123')
542
- })
543
-
544
- test('each: :id and others must receive value from context', () => {
545
- let el = h`<div><x :id="idx" :each="item, idx in items"></x></div>`
546
- sprae(el, {items:[1,2,3]})
547
- is(el.innerHTML,`<x id="1"></x><x id="2"></x><x id="3"></x>`)
548
- })
549
-
550
- test('each: key-based caching is in-sync with direct elements', () => {
551
- let el = h`<ul><li :each="i in x" :key="i" :id="i"></li></ul>`
552
- let el2 = h`<ul><li :each="i in x" :id="i"></li></ul>`
553
- let state = sprae(el, {x:2})
554
- let state2 = sprae(el2, {x:2})
555
- is(el.outerHTML, el2.outerHTML)
556
- el.firstChild.after(el.firstChild.cloneNode(true))
557
- el2.firstChild.after(el2.firstChild.cloneNode(true))
558
- state.x = 3
559
- state2.x = 3
560
- is(el.outerHTML, el2.outerHTML)
561
- })
562
-
563
- test('each: with :with', () => {
564
- let el = h`<ul><li :each="i in 3" :with="{x:i}" :text="x"></li></ul>`
565
- sprae(el)
566
- is(el.outerHTML, `<ul><li>0</li><li>1</li><li>2</li></ul>`)
567
- })
568
-
569
- test('with: inline', async () => {
570
- let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`
571
- let state = sprae(el, {baz: 'qux'})
572
- // FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
573
- is(el.innerHTML, `<y>barqux</y>`)
574
- state.baz = 'quux'
575
- await tick()
576
- is(el.innerHTML, `<y>barquux</y>`)
577
- })
578
- test.skip('with: inline reactive', () => {
579
- let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`
580
- let baz = signal('qux')
581
- sprae(el, {baz})
582
- // FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
583
- is(el.innerHTML, `<y>barqux</y>`)
584
- baz.value = 'quux'
585
- is(el.innerHTML, `<y>barquux</y>`)
586
- })
587
- test('with: data', async () => {
588
- let el = h`<x :with="x"><y :text="foo"></y></x>`
589
- let state = sprae(el, {x: {foo:'bar'}})
590
- is(el.innerHTML, `<y>bar</y>`)
591
- console.log('update', state.x)
592
- state.x.foo = 'baz'
593
- await tick()
594
- // Object.assign(state, {x:{foo:'baz'}})
595
- is(el.innerHTML, `<y>baz</y>`)
596
- })
597
- test('with: transparency', async () => {
598
- // NOTE: y:text initializes through directive, not through parent
599
- // therefore by default :text uses parent's state, not defined by element itself
600
- let el = h`<x :with="{foo:'foo'}"><y :with="b" :text="foo+bar"></y></x>`
601
- let params = sprae(el, {b:{bar:'bar'}})
602
- is(el.innerHTML, `<y>foobar</y>`)
603
- params.b.bar = 'baz'
604
- await tick()
605
- is(el.innerHTML, `<y>foobaz</y>`)
606
- })
607
- test.skip('with: reactive transparency', () => {
608
- let el = h`<x :with="{foo:1}"><y :with="b.c" :text="foo+bar"></y></x>`
609
- const bar = signal('2')
610
- sprae(el, {b:{c:{bar}}})
611
- is(el.innerHTML, `<y>12</y>`)
612
- bar.value = '3'
613
- is(el.innerHTML, `<y>13</y>`)
614
- })
615
- test('with: writes to state', async () => {
616
- let a = h`<x :with="{a:1}"><y :onx="e=>a++" :text="a"></y></x>`
617
- sprae(a)
618
- is(a.innerHTML, `<y>1</y>`)
619
- a.firstChild.dispatchEvent(new window.Event('x'))
620
- await tick()
621
- is(a.innerHTML, `<y>2</y>`)
622
- a.firstChild.dispatchEvent(new window.Event('x'))
623
- await tick()
624
- is(a.innerHTML, `<y>3</y>`)
625
- })
626
- test('with: one of children (internal number of iterations, cant see the result here)', async () => {
627
- let a = h `<div><x :text="x"></x><x :with={x:2} :text="x"></x><x :text="y">3</x></div>`
628
- sprae(a, {x:1,y:3})
629
- is(a.innerHTML,`<x>1</x><x>2</x><x>3</x>`)
630
- })
631
-
632
- test(':render by ref', async () => {
633
- let a = h`<template :ref="abc"><div :text="123"></div></template><x :render="abc">456</x>`
634
- sprae(a)
635
- is(a.outerHTML, `<template><div :text="123"></div></template><x><div>123</div></x>`)
636
- })
637
-
638
- test(':render state', async () => {
639
- let a = h`<template :ref="abc"><div :text="text"></div></template><x :render="abc" />`
640
- let state = sprae(a, {text:'abc'})
641
- is(a.outerHTML, `<template><div :text="text"></div></template><x><div>abc</div></x>`)
642
- state.text = 'def'
643
- await tick()
644
- is(a.outerHTML, `<template><div :text="text"></div></template><x><div>def</div></x>`)
645
- })
646
-
647
- test(':render :with', async () => {
648
- let a = h`<template :ref="tpl"><div :text="text"></div></template><x :render="tpl" :with="{text:'abc'}" />`
649
- let state = sprae(a)
650
- is(a.outerHTML, `<template><div :text="text"></div></template><x><div>abc</div></x>`)
651
- })
652
-
653
- test(':render nested items', async () => {
654
- let el = h`<template :ref="tpl"><div :each="item in items" :text="item.id"></div></template><x :render="tpl" :with="{items:[{id:'a'},{id:'b'}]}" />`
655
- let state = sprae(el)
656
- is(el.outerHTML, `<template><div :each="item in items" :text="item.id"></div></template><x><div>a</div><div>b</div></x>`)
657
- })
658
-
659
- test.todo(':render template after use', async () => {
660
- let a = h`<x :render="tpl" :with="{text:'abc'}" /><template :ref="tpl"><div :text="text"></div></template>`
661
- let state = sprae(a)
662
- is(a.outerHTML, `<x><div>abc</div></x><template><div :text="text"></div></template>`)
663
- })
664
-
665
-
666
- test('ref: base', async () => {
667
- let a = h`<a :ref="a" :init="log.push(a), null" :text="b"></a>`
668
- let state = sprae(a, {log:[], b:1})
669
- is(state.log[0], a)
670
- is(a.outerHTML, `<a>1</a>`)
671
- state.b = 2
672
- await tick()
673
- is(a.outerHTML, `<a>2</a>`)
674
- is(state.a, a, 'Exposes to the state');
675
- })
676
-
677
- test('ref: with :each', () => {
678
- let a = h`<y><x :ref="x" :each="item in items" :text="log.push(x), item"/></y>`
679
- let state = sprae(a, {log: [], items: [1,2]})
680
- is(a.innerHTML, `<x>1</x><x>2</x>`)
681
- is(state.log, [...a.children])
682
- })
683
-
684
- test.skip(':: reactive values', async () => {
685
- let a = new Promise((ok) => setTimeout(() => ok(2), 10))
686
-
687
- let el = h`<x :text="a">1</x>`
688
- sprae(el, {a})
689
- is(el.outerHTML, `<x></x>`)
690
-
691
- await time(20)
692
- is(el.outerHTML, `<x>2</x>`)
693
- })
694
-
695
- test(':: null result does nothing', async () => {
696
- let a = h`<x :="undefined"></x>`
697
- sprae(a)
698
- is(a.outerHTML, `<x></x>`)
699
- })
700
-
701
- test(':: scope refers to current element', async () => {
702
- let el = h`<x :text="log.push(this)"></x>`
703
- let state = sprae(el, {log:[]})
704
- is(state.log, [el])
705
- })
706
-
707
- test(':: scope directives must come first', async () => {
708
- // NOTE: we init attributes in order of definition
709
- let a = h`<x :text="y" :with="{y:1}" :ref="x"></x>`
710
- sprae(a, {})
711
- is(a.outerHTML, `<x>1</x>`)
712
- })
713
-
714
- test.todo('immediate scope', async () => {
715
- let el = h`<x :with="{arr:[], inc(){ arr.push(1) }}" :onx="e=>inc()" :text="arr[0]"></x>`
716
- sprae(el)
717
- is(el.outerHTML, `<x></x>`)
718
- el.dispatchEvent(new CustomEvent('x'))
719
- await tick()
720
- is(el.outerHTML, `<x>1</x>`)
721
- })
722
-
723
- test('getters', async () => {
724
- let x = h`<h2 :text="doubledCount >= 1 ? 1 : 0"></h2>`
725
- let state = sprae(x, {
726
- count:0,
727
- get doubledCount(){ return this.count * 2 }
728
- })
729
- is(x.outerHTML, `<h2>0</h2>`)
730
- state.count++
731
- await tick()
732
- is(x.outerHTML, `<h2>1</h2>`)
733
- })
734
-
735
- test('sandbox', async () => {
736
- let el = h`<x :x="log.push(typeof self, typeof console, typeof arguments, typeof __scope)"></x>`
737
- let log = []
738
- sprae(el.cloneNode(), {log})
739
- is(log, ['undefined', 'object', 'undefined', 'undefined'])
740
-
741
- log.splice(0)
742
- Object.assign(sprae.globals, { self: window })
743
- sprae(el.cloneNode(), {log})
744
- is(log, ['object', 'object', 'undefined', 'undefined'])
745
- })
746
-
747
- test('subscribe to array length', async () => {
748
- let el = h`<div :with="{likes:[]}"><x :onx="e=>likes.push(1)"></x><y :text="likes.length"></y></div>`
749
- sprae(el)
750
- is(el.innerHTML, `<x></x><y>0</y>`)
751
- el.firstChild.dispatchEvent(new CustomEvent('x'))
752
- await tick()
753
- is(el.innerHTML, `<x></x><y>1</y>`)
754
- })