@ryupold/vode 1.8.7 → 1.8.10

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.
@@ -1,16 +1,16 @@
1
- import { app, createState, memo } from "../src/vode"
1
+ import { app, ContainerNode, createState, memo } from "../src/vode"
2
2
  import { ARTICLE, ASIDE, DIV, INPUT, MAIN, NAV, P, SECTION, SPAN } from "../src/vode-tags";
3
- import { expect } from "./helper";
3
+ import { expect, ExpectationError } from "./helper";
4
4
 
5
5
  function setup() {
6
6
  const root = document.createElement("div");
7
7
  const container = document.createElement("div");
8
8
  root.appendChild(container);
9
- return container;
9
+ return container as unknown as ContainerNode;
10
10
  }
11
11
 
12
12
  export default {
13
- "onMount(): called when node is attached to the DOM": () => {
13
+ "onMount(): called when node is attached to the DOM": async () => {
14
14
  const container = setup();
15
15
  let mountCalled = false;
16
16
  app(container, {}, () =>
@@ -18,7 +18,7 @@ export default {
18
18
  [ARTICLE,
19
19
  {
20
20
  onMount: (s: unknown, ele: HTMLElement) => {
21
- expect(ele.tagName).toEqual("ARTICLE");
21
+ if (ele.tagName !== "ARTICLE") throw new ExpectationError(expect(ele), `Expected ARTICLE, got ${ele.tagName}`);
22
22
  mountCalled = true;
23
23
  }
24
24
  },
@@ -27,11 +27,11 @@ export default {
27
27
  ]
28
28
  );
29
29
 
30
- expect(mountCalled)
30
+ await expect(mountCalled)
31
31
  .toEqual(true);
32
32
  },
33
33
 
34
- "onMount(): called in order of child nodes first, then parent onMounts": () => {
34
+ "onMount(): called in order of child nodes first, then parent onMounts": async () => {
35
35
  const container = setup();
36
36
  const mounts: string[] = [];
37
37
  app(container, {}, () =>
@@ -55,11 +55,11 @@ export default {
55
55
  ]
56
56
  );
57
57
 
58
- expect(mounts)
58
+ await expect(mounts)
59
59
  .toEqual(["mount inner", "mount outer"]);
60
60
  },
61
61
 
62
- "onMount(): deep nesting 4+ levels with onMount at each level": () => {
62
+ "onMount(): deep nesting 4+ levels with onMount at each level": async () => {
63
63
  const container = setup();
64
64
  const mounts: string[] = [];
65
65
  app(container, {}, () =>
@@ -96,7 +96,7 @@ export default {
96
96
  ]
97
97
  );
98
98
 
99
- expect(mounts)
99
+ await expect(mounts)
100
100
  .toEqual([
101
101
  "mount article",
102
102
  "mount section",
@@ -105,7 +105,7 @@ export default {
105
105
  ]);
106
106
  },
107
107
 
108
- "onMount(): multiple siblings with onMount on initial render": () => {
108
+ "onMount(): multiple siblings with onMount on initial render": async () => {
109
109
  const container = setup();
110
110
  const mounts: string[] = [];
111
111
  app(container, {}, () =>
@@ -129,11 +129,11 @@ export default {
129
129
  ]
130
130
  );
131
131
 
132
- expect(mounts)
132
+ await expect(mounts)
133
133
  .toEqual(["mount p", "mount span"]);
134
134
  },
135
135
 
136
- "onMount(): A->A path - onMount added during update does NOT fire": () => {
136
+ "onMount(): A->A path - onMount added during update does NOT fire": async () => {
137
137
  const container = setup();
138
138
  const mounts: string[] = [];
139
139
  const state = createState({ addMount: false });
@@ -150,12 +150,12 @@ export default {
150
150
  ]
151
151
  );
152
152
 
153
- expect(mounts).toEqual([]);
153
+ await expect(mounts).toEqual([]);
154
154
  patch({ addMount: true });
155
- expect(mounts).toEqual([]);
155
+ await expect(mounts).toEqual([]);
156
156
  },
157
157
 
158
- "onMount(): A->A path - onMount removed during update does not cause issues": () => {
158
+ "onMount(): A->A path - onMount removed during update does not cause issues": async () => {
159
159
  const container = setup();
160
160
  const mounts: string[] = [];
161
161
  const state = createState({ removeMount: false });
@@ -172,12 +172,12 @@ export default {
172
172
  ]
173
173
  );
174
174
 
175
- expect(mounts).toEqual(["mount p"]);
175
+ await expect(mounts).toEqual(["mount p"]);
176
176
  patch({ removeMount: true });
177
- expect(mounts).toEqual(["mount p"]);
177
+ await expect(mounts).toEqual(["mount p"]);
178
178
  },
179
179
 
180
- "onMount(): A->A path - onMount changed during update does NOT fire the new one": () => {
180
+ "onMount(): A->A path - onMount changed during update does NOT fire the new one": async () => {
181
181
  const container = setup();
182
182
  const mounts: string[] = [];
183
183
  const state = createState({ version: "a" });
@@ -194,12 +194,12 @@ export default {
194
194
  ]
195
195
  );
196
196
 
197
- expect(mounts).toEqual(["mount a"]);
197
+ await expect(mounts).toEqual(["mount a"]);
198
198
  patch({ version: "b" });
199
- expect(mounts).toEqual(["mount a"]);
199
+ await expect(mounts).toEqual(["mount a"]);
200
200
  },
201
201
 
202
- "onMount(): A->B path - element replaced with different tag fires new onMount": () => {
202
+ "onMount(): A->B path - element replaced with different tag fires new onMount": async () => {
203
203
  const container = setup();
204
204
  const mounts: string[] = [];
205
205
  const state = createState({ showArticle: true });
@@ -225,12 +225,12 @@ export default {
225
225
  ]
226
226
  );
227
227
 
228
- expect(mounts).toEqual(["mount article"]);
228
+ await expect(mounts).toEqual(["mount article"]);
229
229
  patch({ showArticle: false });
230
- expect(mounts).toEqual(["mount article", "mount aside"]);
230
+ await expect(mounts).toEqual(["mount article", "mount aside"]);
231
231
  },
232
232
 
233
- "onMount(): A->B path - swap back fires the other element's onMount": () => {
233
+ "onMount(): A->B path - swap back fires the other element's onMount": async () => {
234
234
  const container = setup();
235
235
  const mounts: string[] = [];
236
236
  const state = createState({ showArticle: true });
@@ -256,13 +256,13 @@ export default {
256
256
  ]
257
257
  );
258
258
 
259
- expect(mounts).toEqual(["mount article"]);
259
+ await expect(mounts).toEqual(["mount article"]);
260
260
  patch({ showArticle: false });
261
- expect(mounts).toEqual(["mount article", "mount aside"]);
261
+ await expect(mounts).toEqual(["mount article", "mount aside"]);
262
262
  patch({ showArticle: true });
263
- expect(mounts).toEqual(["mount article", "mount aside", "mount article"]);
263
+ await expect(mounts).toEqual(["mount article", "mount aside", "mount article"]);
264
264
  patch({ showArticle: false });
265
- expect(mounts)
265
+ await expect(mounts)
266
266
  .toEqual([
267
267
  "mount article",
268
268
  "mount aside",
@@ -271,7 +271,7 @@ export default {
271
271
  ]);
272
272
  },
273
273
 
274
- "onMount(): A->B path - children's onMounts also fire in new tree": () => {
274
+ "onMount(): A->B path - children's onMounts also fire in new tree": async () => {
275
275
  const container = setup();
276
276
  const mounts: string[] = [];
277
277
  const state = createState({ showArticle: true });
@@ -301,12 +301,12 @@ export default {
301
301
  ]
302
302
  );
303
303
 
304
- expect(mounts).toEqual(["mount p"]);
304
+ await expect(mounts).toEqual(["mount p"]);
305
305
  patch({ showArticle: false });
306
- expect(mounts).toEqual(["mount p", "mount div"]);
306
+ await expect(mounts).toEqual(["mount p", "mount div"]);
307
307
  },
308
308
 
309
- "onMount(): text -> element fires new element's onMount": () => {
309
+ "onMount(): text -> element fires new element's onMount": async () => {
310
310
  const container = setup();
311
311
  const mounts: string[] = [];
312
312
  const state = createState({ showElement: false });
@@ -325,12 +325,12 @@ export default {
325
325
  ]
326
326
  );
327
327
 
328
- expect(mounts).toEqual([]);
328
+ await expect(mounts).toEqual([]);
329
329
  patch({ showElement: true });
330
- expect(mounts).toEqual(["mount article"]);
330
+ await expect(mounts).toEqual(["mount article"]);
331
331
  },
332
332
 
333
- "onMount(): mixed onMount presence in tree": () => {
333
+ "onMount(): mixed onMount presence in tree": async () => {
334
334
  const container = setup();
335
335
  const mounts: string[] = [];
336
336
  app(container, {}, () =>
@@ -358,10 +358,10 @@ export default {
358
358
  ]
359
359
  );
360
360
 
361
- expect(mounts).toEqual(["mount p", "mount section"]);
361
+ await expect(mounts).toEqual(["mount p", "mount section"]);
362
362
  },
363
363
 
364
- "onMount(): sibling subtree depths fire in correct order": () => {
364
+ "onMount(): sibling subtree depths fire in correct order": async () => {
365
365
  const container = setup();
366
366
  const mounts: string[] = [];
367
367
  app(container, {}, () =>
@@ -394,7 +394,7 @@ export default {
394
394
  ]
395
395
  );
396
396
 
397
- expect(mounts)
397
+ await expect(mounts)
398
398
  .toEqual([
399
399
  "mount p-deep",
400
400
  "mount div",
@@ -402,7 +402,7 @@ export default {
402
402
  ]);
403
403
  },
404
404
 
405
- "onMount(): added children from count increase fire onMount": () => {
405
+ "onMount(): added children from count increase fire onMount": async () => {
406
406
  const container = setup();
407
407
  const mounts: string[] = [];
408
408
  const state = createState({ count: 1 });
@@ -416,14 +416,14 @@ export default {
416
416
  ]
417
417
  );
418
418
 
419
- expect(mounts).toEqual(["mount p0"]);
419
+ await expect(mounts).toEqual(["mount p0"]);
420
420
  patch({ count: 2 });
421
- expect(mounts).toEqual(["mount p0", "mount p1"]);
421
+ await expect(mounts).toEqual(["mount p0", "mount p1"]);
422
422
  patch({ count: 3 });
423
- expect(mounts).toEqual(["mount p0", "mount p1", "mount p2"]);
423
+ await expect(mounts).toEqual(["mount p0", "mount p1", "mount p2"]);
424
424
  },
425
425
 
426
- "onMount(): conditional child fires onMount when added": () => {
426
+ "onMount(): conditional child fires onMount when added": async () => {
427
427
  const container = setup();
428
428
  const mounts: string[] = [];
429
429
  const state = createState({ show: false });
@@ -443,12 +443,12 @@ export default {
443
443
  ]
444
444
  );
445
445
 
446
- expect(mounts).toEqual([]);
446
+ await expect(mounts).toEqual([]);
447
447
  patch({ show: true });
448
- expect(mounts).toEqual(["mount span"]);
448
+ await expect(mounts).toEqual(["mount span"]);
449
449
  },
450
450
 
451
- "onUnmount(): called when node is removed from the DOM": () => {
451
+ "onUnmount(): called when node is removed from the DOM": async () => {
452
452
  const container = setup();
453
453
  const unmounts: string[] = [];
454
454
  const state = createState({ showArticle: true });
@@ -465,12 +465,12 @@ export default {
465
465
  ]
466
466
  );
467
467
 
468
- expect(unmounts).toEqual([]);
468
+ await expect(unmounts).toEqual([]);
469
469
  patch({ showArticle: false });
470
- expect(unmounts).toEqual(["unmount article"]);
470
+ await expect(unmounts).toEqual(["unmount article"]);
471
471
  },
472
472
 
473
- "onUnmount(): called for all child nodes that have registerd when parent node is removed from the DOM": () => {
473
+ "onUnmount(): called for all child nodes that have registerd when parent node is removed from the DOM": async () => {
474
474
  const container = setup();
475
475
  const unmounts: string[] = [];
476
476
  const state = createState({ showArticle: true });
@@ -495,13 +495,13 @@ export default {
495
495
  ]
496
496
  );
497
497
 
498
- expect(unmounts).toEqual([]);
498
+ await expect(unmounts).toEqual([]);
499
499
  patch({ showArticle: false });
500
- expect(unmounts).toEqual(["unmount inner", "unmount outer"]);
500
+ await expect(unmounts).toEqual(["unmount inner", "unmount outer"]);
501
501
  },
502
502
 
503
- "onUnmount(): A->A path - onUnmount added during update fires on later removal": () => {
504
- const container = setup();
503
+ "onUnmount(): A->A path - onUnmount added during update fires on later removal": async () => {
504
+ const container = setup() as unknown as ContainerNode;
505
505
  const unmounts: string[] = [];
506
506
  const state = createState({ toggle: false, remove: false });
507
507
  const patch = app<typeof state>(container, state, (s) =>
@@ -512,26 +512,35 @@ export default {
512
512
  unmounts.push("unmount section");
513
513
  }
514
514
  } : {},
515
- [P, "text"]
515
+ [P, {
516
+ onUnmount: s.toggle && ((s: unknown, ele: HTMLElement) => {
517
+ unmounts.push("unmount p");
518
+ })
519
+ }, "text"]
516
520
  ]
517
521
  ]
518
522
  );
519
523
 
520
- expect(unmounts).toEqual([]);
524
+ await expect(unmounts).toEqual([]);
525
+ let before = container._vode.stats.syncRenderCount;
521
526
  patch({ toggle: true });
522
- expect(unmounts).toEqual([]);
527
+ await expect(() => expect(container._vode.stats.syncRenderCount).toBeGreaterThan(before))
528
+ .toSucceedAsync();
529
+ await expect(unmounts).toEqual([]);
530
+ before = container._vode.stats.syncRenderCount;
523
531
  patch({ remove: true });
524
- expect(unmounts).toEqual(["unmount section"]);
532
+ await expect(() => expect(container._vode.stats.syncRenderCount).toBeGreaterThan(before)).toSucceedAsync();
533
+ await expect(unmounts).toEqual(["unmount p", "unmount section"]);
525
534
  },
526
535
 
527
- "onUnmount(): A->A path - onUnmount removed during update does not fire": () => {
536
+ "onUnmount(): A->A path - onUnmount removed during update does not fire": async () => {
528
537
  const container = setup();
529
538
  const unmounts: string[] = [];
530
539
  const state = createState({ toggle: false, remove: false });
531
540
  const patch = app<typeof state>(container, state, (s) =>
532
541
  [DIV,
533
542
  !s.remove && [SECTION,
534
- s.toggle ? {} : {
543
+ !s.toggle && {
535
544
  onUnmount: (s: unknown, ele: HTMLElement) => {
536
545
  unmounts.push("unmount section");
537
546
  }
@@ -541,14 +550,12 @@ export default {
541
550
  ]
542
551
  );
543
552
 
544
- expect(unmounts).toEqual([]);
545
- patch({ toggle: true });
546
- expect(unmounts).toEqual([]);
547
- patch({ remove: true });
548
- expect(unmounts).toEqual([]);
553
+ await expect(unmounts).toEqual([]);
554
+ patch({ remove: true, toggle: false });
555
+ await expect(unmounts).toEqual([]);
549
556
  },
550
557
 
551
- "onUnmount(): A->A path - onUnmount changed during update fires the new one": () => {
558
+ "onUnmount(): A->A path - onUnmount changed during update fires the new one": async () => {
552
559
  const container = setup();
553
560
  const unmounts: string[] = [];
554
561
  const state = createState({ version: "a", remove: false });
@@ -565,14 +572,17 @@ export default {
565
572
  ]
566
573
  );
567
574
 
568
- expect(unmounts).toEqual([]);
575
+ await expect(unmounts).toEqual([]);
576
+ const before = container._vode.stats.syncRenderCount;
569
577
  patch({ version: "b" });
570
- expect(unmounts).toEqual([]);
578
+ await expect(async () => await expect(container._vode.stats.syncRenderCount).toBeGreaterThan(before))
579
+ .toSucceedAsync();
580
+ await expect(unmounts).toEqual([]);
571
581
  patch({ remove: true });
572
- expect(unmounts).toEqual(["unmount b"]);
582
+ await expect(unmounts).toEqual(["unmount b"]);
573
583
  },
574
584
 
575
- "onUnmount(): A->B path - element replaced with different tag fires old onUnmount": () => {
585
+ "onUnmount(): A->B path - element replaced with different tag fires old onUnmount": async () => {
576
586
  const container = setup();
577
587
  const unmounts: string[] = [];
578
588
  const state = createState({ showArticle: true });
@@ -598,12 +608,12 @@ export default {
598
608
  ]
599
609
  );
600
610
 
601
- expect(unmounts).toEqual([]);
611
+ await expect(unmounts).toEqual([]);
602
612
  patch({ showArticle: false });
603
- expect(unmounts).toEqual(["unmount article"]);
613
+ await expect(unmounts).toEqual(["unmount article"]);
604
614
  },
605
615
 
606
- "onUnmount(): A->B path - swap back fires the other element's onUnmount": () => {
616
+ "onUnmount(): A->B path - swap back fires the other element's onUnmount": async () => {
607
617
  const container = setup();
608
618
  const unmounts: string[] = [];
609
619
  const state = createState({ showArticle: true });
@@ -629,18 +639,18 @@ export default {
629
639
  ]
630
640
  );
631
641
 
632
- expect(unmounts).toEqual([]);
642
+ await expect(unmounts).toEqual([]);
633
643
  patch({ showArticle: false });
634
- expect(unmounts).toEqual(["unmount article"]);
644
+ await expect(unmounts).toEqual(["unmount article"]);
635
645
  unmounts.length = 0;
636
646
  patch({ showArticle: true });
637
- expect(unmounts).toEqual(["unmount aside"]);
647
+ await expect(unmounts).toEqual(["unmount aside"]);
638
648
  unmounts.length = 0;
639
649
  patch({ showArticle: false });
640
- expect(unmounts).toEqual(["unmount article"]);
650
+ await expect(unmounts).toEqual(["unmount article"]);
641
651
  },
642
652
 
643
- "onUnmount(): A->B path - replaced element's children onUnmounts also fire": () => {
653
+ "onUnmount(): A->B path - replaced element's children onUnmounts also fire": async () => {
644
654
  const container = setup();
645
655
  const unmounts: string[] = [];
646
656
  const state = createState({ showArticle: true });
@@ -673,12 +683,12 @@ export default {
673
683
  ]
674
684
  );
675
685
 
676
- expect(unmounts).toEqual([]);
686
+ await expect(unmounts).toEqual([]);
677
687
  patch({ showArticle: false });
678
- expect(unmounts).toEqual(["unmount p", "unmount article"]);
688
+ await expect(unmounts).toEqual(["unmount p", "unmount article"]);
679
689
  },
680
690
 
681
- "onUnmount(): element -> text fires onUnmount": () => {
691
+ "onUnmount(): element -> text fires onUnmount": async () => {
682
692
  const container = setup();
683
693
  const unmounts: string[] = [];
684
694
  const state = createState({ showElement: true });
@@ -697,12 +707,12 @@ export default {
697
707
  ]
698
708
  );
699
709
 
700
- expect(unmounts).toEqual([]);
710
+ await expect(unmounts).toEqual([]);
701
711
  patch({ showElement: false });
702
- expect(unmounts).toEqual(["unmount article"]);
712
+ await expect(unmounts).toEqual(["unmount article"]);
703
713
  },
704
714
 
705
- "onUnmount(): text -> element registers onUnmount that fires later": () => {
715
+ "onUnmount(): text -> element registers onUnmount that fires later": async () => {
706
716
  const container = setup();
707
717
  const unmounts: string[] = [];
708
718
  const state = createState({ showElement: false, remove: false });
@@ -722,14 +732,17 @@ export default {
722
732
  ]
723
733
  );
724
734
 
725
- expect(unmounts).toEqual([]);
735
+ await expect(unmounts).toEqual([]);
736
+ const before = container._vode.stats.syncRenderCount;
726
737
  patch({ showElement: true });
727
- expect(unmounts).toEqual([]);
738
+ await expect(() => expect(container._vode.stats.syncRenderCount).toBeGreaterThan(before))
739
+ .toSucceedAsync();
740
+ await expect(unmounts).toEqual([]);
728
741
  patch({ remove: true });
729
- expect(unmounts).toEqual(["unmount article"]);
742
+ await expect(unmounts).toEqual(["unmount article"]);
730
743
  },
731
744
 
732
- "onUnmount(): deep nesting 4+ levels with onUnmount at each level": () => {
745
+ "onUnmount(): deep nesting 4+ levels with onUnmount at each level": async () => {
733
746
  const container = setup();
734
747
  const unmounts: string[] = [];
735
748
  const state = createState({ show: true });
@@ -767,9 +780,9 @@ export default {
767
780
  ]
768
781
  );
769
782
 
770
- expect(unmounts).toEqual([]);
783
+ await expect(unmounts).toEqual([]);
771
784
  patch({ show: false });
772
- expect(unmounts)
785
+ await expect(unmounts)
773
786
  .toEqual([
774
787
  "unmount article",
775
788
  "unmount section",
@@ -778,7 +791,7 @@ export default {
778
791
  ]);
779
792
  },
780
793
 
781
- "onUnmount(): multiple siblings - remove one fires only that sibling's subtree": () => {
794
+ "onUnmount(): multiple siblings - remove one fires only that sibling's subtree": async () => {
782
795
  const container = setup();
783
796
  const unmounts: string[] = [];
784
797
  const state = createState({ showFirst: true, showSecond: true });
@@ -817,12 +830,12 @@ export default {
817
830
  ]
818
831
  );
819
832
 
820
- expect(unmounts).toEqual([]);
833
+ await expect(unmounts).toEqual([]);
821
834
  patch({ showFirst: false });
822
- expect(unmounts).toEqual(["unmount first-child", "unmount first"]);
835
+ await expect(unmounts).toEqual(["unmount first-child", "unmount first"]);
823
836
  },
824
837
 
825
- "onUnmount(): multiple siblings - remove parent fires all": () => {
838
+ "onUnmount(): multiple siblings - remove parent fires all": async () => {
826
839
  const container = setup();
827
840
  const unmounts: string[] = [];
828
841
  const state = createState({ show: true });
@@ -849,12 +862,12 @@ export default {
849
862
  ]
850
863
  );
851
864
 
852
- expect(unmounts).toEqual([]);
865
+ await expect(unmounts).toEqual([]);
853
866
  patch({ show: false });
854
- expect(unmounts).toEqual(["unmount second", "unmount first"]);
867
+ await expect(unmounts).toEqual(["unmount second", "unmount first"]);
855
868
  },
856
869
 
857
- "onUnmount(): stale children cleanup - fewer new children than old fires removed children's onUnmounts": () => {
870
+ "onUnmount(): stale children cleanup - fewer new children than old fires removed children's onUnmounts": async () => {
858
871
  const container = setup();
859
872
  const unmounts: string[] = [];
860
873
  const state = createState({ count: 3 });
@@ -868,12 +881,12 @@ export default {
868
881
  ]
869
882
  );
870
883
 
871
- expect(unmounts).toEqual([]);
884
+ await expect(unmounts).toEqual([]);
872
885
  patch({ count: 1 });
873
- expect(unmounts).toEqual(["unmount p1", "unmount p2"]);
886
+ await expect(unmounts).toEqual(["unmount p1", "unmount p2"]);
874
887
  },
875
888
 
876
- "onUnmount(): mixed onUnmount presence in tree - only elements with onUnmount fire": () => {
889
+ "onUnmount(): mixed onUnmount presence in tree - only elements with onUnmount fire": async () => {
877
890
  const container = setup();
878
891
  const unmounts: string[] = [];
879
892
  const state = createState({ show: true });
@@ -902,12 +915,12 @@ export default {
902
915
  ]
903
916
  );
904
917
 
905
- expect(unmounts).toEqual([]);
918
+ await expect(unmounts).toEqual([]);
906
919
  patch({ show: false });
907
- expect(unmounts).toEqual(["unmount p", "unmount section"]);
920
+ await expect(unmounts).toEqual(["unmount p", "unmount section"]);
908
921
  },
909
922
 
910
- "onUnmount(): sibling ordering - sibling subtree depths": () => {
923
+ "onUnmount(): sibling ordering - sibling subtree depths": async () => {
911
924
  const container = setup();
912
925
  const unmounts: string[] = [];
913
926
  const state = createState({ show: true });
@@ -941,12 +954,12 @@ export default {
941
954
  ]
942
955
  );
943
956
 
944
- expect(unmounts).toEqual([]);
957
+ await expect(unmounts).toEqual([]);
945
958
  patch({ show: false });
946
- expect(unmounts).toEqual(["unmount nav", "unmount p-deep", "unmount div"]);
959
+ await expect(unmounts).toEqual(["unmount nav", "unmount p-deep", "unmount div"]);
947
960
  },
948
961
 
949
- "onUnmount(): A->A path - children's unmounts shift when previous sibling's subtree changes": () => {
962
+ "onUnmount(): A->A path - children's unmounts shift when previous sibling's subtree changes": async () => {
950
963
  const container = setup();
951
964
  const unmounts: string[] = [];
952
965
  const state = createState({ showExtraChild: true, remove: false });
@@ -981,11 +994,11 @@ export default {
981
994
  ]
982
995
  );
983
996
 
984
- expect(unmounts).toEqual([]);
997
+ await expect(unmounts).toEqual([]);
985
998
  patch({ showExtraChild: false });
986
- expect(unmounts).toEqual(["unmount span"]);
999
+ await expect(unmounts).toEqual(["unmount span"]);
987
1000
  patch({ remove: true });
988
- expect(unmounts)
1001
+ await expect(unmounts)
989
1002
  .toEqual([
990
1003
  "unmount span",
991
1004
  "unmount aside",
@@ -993,7 +1006,7 @@ export default {
993
1006
  ]);
994
1007
  },
995
1008
 
996
- "onUnmount(): root element replacement fires root's onUnmount": () => {
1009
+ "onUnmount(): root element replacement fires root's onUnmount": async () => {
997
1010
  const container = setup();
998
1011
  const unmounts: string[] = [];
999
1012
  const state = createState({ showDiv: true });
@@ -1017,12 +1030,12 @@ export default {
1017
1030
  ]
1018
1031
  );
1019
1032
 
1020
- expect(unmounts).toEqual([]);
1033
+ await expect(unmounts).toEqual([]);
1021
1034
  patch({ showDiv: false });
1022
- expect(unmounts).toEqual(["unmount div"]);
1035
+ await expect(unmounts).toEqual(["unmount div"]);
1023
1036
  },
1024
1037
 
1025
- "onUnmount(): child onUnmount fires when element is falsified after onUnmount was added via A->A update": () => {
1038
+ "onUnmount(): child onUnmount fires when element is falsified after onUnmount was added via A->A update": async () => {
1026
1039
  const container = setup();
1027
1040
  const unmounts: string[] = [];
1028
1041
  const state = createState({ addUnmount: false, show: true });
@@ -1039,14 +1052,17 @@ export default {
1039
1052
  ]
1040
1053
  );
1041
1054
 
1042
- expect(unmounts).toEqual([]);
1055
+ await expect(unmounts).toEqual([]);
1056
+ const before = container._vode.stats.syncRenderCount;
1043
1057
  patch({ addUnmount: true });
1044
- expect(unmounts).toEqual([]);
1058
+ await expect(async () => await expect(container._vode.stats.syncRenderCount).toEqual(before + 1))
1059
+ .toSucceedAsync();
1060
+ await expect(unmounts).toEqual([]);
1045
1061
  patch({ show: false });
1046
- expect(unmounts).toEqual(["unmount article"]);
1062
+ await expect(unmounts).toEqual(["unmount article"]);
1047
1063
  },
1048
1064
 
1049
- "onUnmount(): A->B path - onUnmount from old children fire when switching tags": () => {
1065
+ "onUnmount(): A->B path - onUnmount from old children fire when switching tags": async () => {
1050
1066
  const container = setup();
1051
1067
  const unmounts: string[] = [];
1052
1068
  const state = createState({ showArticle: true });
@@ -1076,12 +1092,12 @@ export default {
1076
1092
  ]
1077
1093
  );
1078
1094
 
1079
- expect(unmounts).toEqual([]);
1095
+ await expect(unmounts).toEqual([]);
1080
1096
  patch({ showArticle: false });
1081
- expect(unmounts).toEqual(["unmount p-inner"]);
1097
+ await expect(unmounts).toEqual(["unmount p-inner"]);
1082
1098
  },
1083
1099
 
1084
- "onUnmount(): memo hit + earlier sibling growth corrupts unmount indices": () => {
1100
+ "onUnmount(): memo hit + earlier sibling growth corrupts unmount indices": async () => {
1085
1101
  const container = setup();
1086
1102
  const fired: string[] = [];
1087
1103
  const state = createState({ expanded: false, showB: true });
@@ -1112,16 +1128,16 @@ export default {
1112
1128
  ]
1113
1129
  );
1114
1130
 
1115
- expect(fired).toEqual([]);
1131
+ await expect(fired).toEqual([]);
1116
1132
 
1117
1133
  patch({ expanded: true });
1118
- expect(fired).toEqual([]);
1134
+ await expect(fired).toEqual([]);
1119
1135
 
1120
1136
  patch({ showB: false });
1121
- expect(fired).toEqual(["unmount B"]);
1137
+ await expect(fired).toEqual(["unmount B"]);
1122
1138
  },
1123
1139
 
1124
- "onUnmount(): excess child removal + same-render sibling growth": () => {
1140
+ "onUnmount(): excess child removal + same-render sibling growth": async () => {
1125
1141
  const container = setup();
1126
1142
  const fired: string[] = [];
1127
1143
  const state = createState({ expanded: false, showB: true });
@@ -1152,12 +1168,12 @@ export default {
1152
1168
  ]
1153
1169
  );
1154
1170
 
1155
- expect(fired).toEqual([]);
1171
+ await expect(fired).toEqual([]);
1156
1172
  patch({ expanded: true, showB: false });
1157
- expect(fired).toEqual(["unmount B"]);
1173
+ await expect(fired).toEqual(["unmount B"]);
1158
1174
  },
1159
1175
 
1160
- "onMount() + onUnmount: symmetry of calls": () => {
1176
+ "onMount() + onUnmount: symmetry of calls": async () => {
1161
1177
  const container = setup();
1162
1178
  const state = createState({
1163
1179
  startTime: 0,
@@ -1168,18 +1184,16 @@ export default {
1168
1184
  type State = typeof state;
1169
1185
  const logs: string[] = [];
1170
1186
 
1171
- const patch = app<State>(container, state, (s) =>
1172
- [DIV,
1187
+ const patch = app<State>(container, state, (s) => {
1188
+ return [DIV,
1173
1189
  s.showInput && [INPUT, {
1174
1190
  type: 'text',
1175
1191
  placeholder: 'Auto-focused on mount',
1176
1192
  onMount: (s: State, ele: HTMLElement) => {
1177
- //(ele as HTMLInputElement).focus();
1178
1193
  logs.push('Input mounted');
1179
1194
  return { inputReady: true };
1180
1195
  },
1181
1196
  onUnmount: (s: State, ele: HTMLElement) => {
1182
- // console.log('Input removed');
1183
1197
  logs.push('Input removed');
1184
1198
  return { inputReady: false };
1185
1199
  }
@@ -1188,25 +1202,34 @@ export default {
1188
1202
  s.showTimer && [P, {
1189
1203
  onMount: (s: State, ele: HTMLElement) => {
1190
1204
  logs.push('Timer started');
1191
- s.patch({ startTime: Date.now() });
1205
+ return { startTime: Date.now() };
1192
1206
  },
1193
1207
  onUnmount: (s: State, ele: HTMLElement) => {
1194
- console.log('Timer stopped after', Date.now() - s.startTime, 'ms');
1195
1208
  logs.push('Timer removed');
1196
1209
  }
1197
1210
  }, 'Mount/unmount lifecycle demo']
1198
1211
  ]
1212
+ }
1199
1213
  );
1200
1214
 
1201
- expect(state.inputReady)
1215
+ await expect(state.inputReady)
1202
1216
  .toEqual(true);
1203
- expect(state.startTime != 0)
1217
+ await expect(state.startTime != 0)
1204
1218
  .toEqual(true);
1205
1219
  patch({ showInput: false });
1206
- expect(state.inputReady)
1207
- .toEqual(false);
1220
+
1221
+ await expect(
1222
+ async () => await expect(state.inputReady).toEqual(false, "expected: inputReady == false")
1223
+ ).toSucceedAsync();
1224
+
1208
1225
  patch({ showTimer: false });
1209
- expect(logs).toEqual([
1226
+
1227
+ await expect(
1228
+ async () => await expect(container._vode.stats.syncRenderCount >= 4)
1229
+ .toEqual(true)
1230
+ ).toSucceedAsync();
1231
+
1232
+ await expect(logs).toEqual([
1210
1233
  'Input mounted',
1211
1234
  'Timer started',
1212
1235
  'Input removed',
@@ -1214,7 +1237,7 @@ export default {
1214
1237
  ]);
1215
1238
  },
1216
1239
 
1217
- "onMount(): with catched component, replacement vode's onMount fires when error occurs": () => {
1240
+ "onMount(): with catched component, replacement vode's onMount fires when error occurs": async () => {
1218
1241
  const container = setup();
1219
1242
  const mounts: string[] = [];
1220
1243
  const broken: any = () => { throw new Error("boom"); };
@@ -1234,10 +1257,10 @@ export default {
1234
1257
  ]
1235
1258
  );
1236
1259
 
1237
- expect(mounts).toEqual(["mount fallback"]);
1260
+ await expect(mounts).toEqual(["mount fallback"]);
1238
1261
  },
1239
1262
 
1240
- "onMount(): with catched component, returned vode's onMount fires and receives error": () => {
1263
+ "onMount(): with catched component, returned vode's onMount fires and receives error": async () => {
1241
1264
  const container = setup();
1242
1265
  const mounts: string[] = [];
1243
1266
  const caughtErrors: string[] = [];
@@ -1261,11 +1284,11 @@ export default {
1261
1284
  ]
1262
1285
  );
1263
1286
 
1264
- expect(mounts).toEqual(["mount fallback"]);
1265
- expect(caughtErrors).toEqual(["boom"]);
1287
+ await expect(mounts).toEqual(["mount fallback"]);
1288
+ await expect(caughtErrors).toEqual(["boom"]);
1266
1289
  },
1267
1290
 
1268
- "onUnmount(): with catched component, replacement vode's onUnmount fires when removed": () => {
1291
+ "onUnmount(): with catched component, replacement vode's onUnmount fires when removed": async () => {
1269
1292
  const container = setup();
1270
1293
  const unmounts: string[] = [];
1271
1294
  const state = createState({ show: true });
@@ -1288,12 +1311,12 @@ export default {
1288
1311
  ]
1289
1312
  );
1290
1313
 
1291
- expect(unmounts).toEqual([]);
1314
+ await expect(unmounts).toEqual([]);
1292
1315
  patch({ show: false });
1293
- expect(unmounts).toEqual(["unmount fallback"]);
1316
+ await expect(unmounts).toEqual(["unmount fallback"]);
1294
1317
  },
1295
1318
 
1296
- "onUnmount(): with catched component, deep replacement tree fires in post-order": () => {
1319
+ "onUnmount(): with catched component, deep replacement tree fires in post-order": async () => {
1297
1320
  const container = setup();
1298
1321
  const unmounts: string[] = [];
1299
1322
  const state = createState({ show: true });
@@ -1331,12 +1354,12 @@ export default {
1331
1354
  ]
1332
1355
  );
1333
1356
 
1334
- expect(unmounts).toEqual([]);
1357
+ await expect(unmounts).toEqual([]);
1335
1358
  patch({ show: false });
1336
- expect(unmounts).toEqual(["unmount span", "unmount p", "unmount article"]);
1359
+ await expect(unmounts).toEqual(["unmount span", "unmount p", "unmount article"]);
1337
1360
  },
1338
1361
 
1339
- "onMount()/onUnmount(): with catched component, full lifecycle symmetry of catch replacement": () => {
1362
+ "onMount()/onUnmount(): with catched component, full lifecycle symmetry of catch replacement": async () => {
1340
1363
  const container = setup();
1341
1364
  const logs: string[] = [];
1342
1365
  const state = createState({ show: true });
@@ -1362,12 +1385,12 @@ export default {
1362
1385
  ]
1363
1386
  );
1364
1387
 
1365
- expect(logs).toEqual(["mount article"]);
1388
+ await expect(logs).toEqual(["mount article"]);
1366
1389
  patch({ show: false });
1367
- expect(logs).toEqual(["mount article", "unmount article"]);
1390
+ await expect(logs).toEqual(["mount article", "unmount article"]);
1368
1391
  },
1369
1392
 
1370
- "onMount(): with catched component, original element's onMount does NOT fire when error caused replacement": () => {
1393
+ "onMount(): with catched component, original element's onMount does NOT fire when error caused replacement": async () => {
1371
1394
  const container = setup();
1372
1395
  const logs: string[] = [];
1373
1396
  const broken: any = () => { throw new Error("boom"); };
@@ -1399,6 +1422,6 @@ export default {
1399
1422
 
1400
1423
  // SECTION never finishes mounting (its child broke), so its onMount must not fire.
1401
1424
  // The catch on DIV replaces the broken subtree with ARTICLE whose onMount must fire.
1402
- expect(logs).toEqual(["mount fallback"]);
1425
+ await expect(logs).toEqual(["mount fallback"]);
1403
1426
  },
1404
1427
  }