2
2
3
3
import {
4
4
createComponent ,
5
+ createFor ,
5
6
createForSlots ,
6
7
createIf ,
7
8
createSlot ,
@@ -13,7 +14,14 @@ import {
13
14
setText ,
14
15
template ,
15
16
} from '../src'
16
- import { currentInstance , nextTick , ref } from '@vue/runtime-dom'
17
+ import {
18
+ type ComponentInternalInstance ,
19
+ currentInstance ,
20
+ getCurrentInstance ,
21
+ nextTick ,
22
+ ref ,
23
+ useSlots ,
24
+ } from '@vue/runtime-dom'
17
25
import { makeRender } from './_utils'
18
26
19
27
const define = makeRender < any > ( )
@@ -334,6 +342,200 @@ describe('component: slots', () => {
334
342
expect ( host . innerHTML ) . toBe ( '<div>fallback<!--slot--></div>' )
335
343
} )
336
344
345
+ // test case could be previewed at
346
+ // https://deploy-preview-241--vapor-repl.netlify.app/#__VAPOR__eNp9VMtu2zAQ/JWFcrAMOBKC9JRKQR/IoT00RVP0YuWgSCuFNkUK4kq1Yfjfu6QefsQNYAPi7nC4HM7uzvtc10HXonfnRSZrRE1gkNoaZKrKOPHIJN59okRV64bgq65qKBpdwSwI7cJunX2c8jtosID9ALG5RCUq08oQEG4IYgvwZzkWaStpNh+TadMMueXNYkov4PaZIYkqWpWR0ApIl6VEfw67RAGIAnzeGXSpbDGQqEp6hTiO4XYAgCXu00y/vHm2wT2gNHgZcHq2QyeKf1HYi8NS8IKwqmVKyCuASKi6JeiuK52jtJLxRRMPwj5rVXJf/D3ug6vhlCEBYCglkcEQHuDhyTkAb1iW9qjniSTfqrRilt2uF3vPhb8hOifprgvdcNWCIyCU1YOLv1ra9YFaal3fWWIHu0hsl9Nlo5eWiN/rUyZFtraiuIdjL/UfUdgDGHxC4i08oXLcBK9UySNP0rZGZmGJW8cy1sUeGJ2XNcgcf1JesqePTRh2NshWPNtjYaOZhzY4Ap3y+fyfB5VuFfmzq7SuZ/PJE1EuOhA518dxLi4KOXDPVyHD7i5EGayMVnwbZ7nEy1glIbF5rK2nucFY2eGFvVRK/fe7i1HT4mKMZ6+YrS/EV2ZjY4n3s0GDTcfiTDlKmxLZijb98PTD2XJKjlK+k/yFRsvW1tjDvrQq57KPcK7ab05Nocrf5mFDqMx4KVuoayGHTzzW1xrkf1c/lHsbfBhbj1Uc58z5iDqMpR20Bp+kJnPh2Xk6jVPGOEg8of1p/qxxaxM8WOJ7eHxZYUaBjfluC8PeGQDcFQ46H/rC2WFsK86ALgbAZNzI0sIdt6t1NScP88J557wr9v8AXg7dEA==
347
+ test ( 'should not delete new rendered slot when the old slot is removed in loop slot' , async ( ) => {
348
+ const loop = ref ( [ 1 , 'default' , 3 ] )
349
+
350
+ let childInstance
351
+ const t0 = template ( '<div></div>' )
352
+ const { component : Child } = define ( {
353
+ setup ( ) {
354
+ childInstance = getCurrentInstance ( )
355
+ const slots = useSlots ( )
356
+ const keys = ( ) => Object . keys ( slots )
357
+ return {
358
+ keys,
359
+ slots,
360
+ }
361
+ } ,
362
+ render : ( _ctx : any ) => {
363
+ const n0 = createFor (
364
+ ( ) => _ctx . keys ( ) ,
365
+ ( _ctx0 : any ) => {
366
+ const n5 = t0 ( )
367
+ const n4 = createSlot ( ( ) => _ctx0 [ 0 ] )
368
+ insert ( n4 , n5 as ParentNode )
369
+ return n5
370
+ } ,
371
+ )
372
+ return n0
373
+ } ,
374
+ } )
375
+
376
+ const t1 = template ( ' static default ' )
377
+ const { render } = define ( {
378
+ setup ( ) {
379
+ return createComponent (
380
+ Child ,
381
+ { } ,
382
+ {
383
+ default : ( ) => {
384
+ return t1 ( )
385
+ } ,
386
+ $ : [
387
+ ( ) =>
388
+ // @ts -expect-error TODO createForSlots
389
+ createForSlots ( loop . value , ( item , i ) => ( {
390
+ name : item ,
391
+ fn : ( ) => template ( item ) ( ) ,
392
+ } ) ) ,
393
+ ] ,
394
+ } ,
395
+ )
396
+ } ,
397
+ } )
398
+ const { html } = render ( )
399
+
400
+ expect ( childInstance ! . slots ) . toHaveProperty ( '1' )
401
+ expect ( childInstance ! . slots ) . toHaveProperty ( 'default' )
402
+ expect ( childInstance ! . slots ) . toHaveProperty ( '3' )
403
+ expect ( html ( ) ) . toBe (
404
+ '<div>1<!--slot--></div><div>3<!--slot--></div><div>default<!--slot--></div><!--for-->' ,
405
+ )
406
+ loop . value = [ 1 ]
407
+ await nextTick ( )
408
+ expect ( childInstance ! . slots ) . toHaveProperty ( '1' )
409
+ expect ( childInstance ! . slots ) . toHaveProperty ( 'default' )
410
+ expect ( childInstance ! . slots ) . not . toHaveProperty ( '3' )
411
+ expect ( html ( ) ) . toBe (
412
+ '<div>1<!--slot--></div><div> static default <!--slot--></div><!--for-->' ,
413
+ )
414
+ } )
415
+
416
+ test ( 'should cleanup all slots when loop slot has same key' , async ( ) => {
417
+ const loop = ref ( [ 1 , 1 , 1 ] )
418
+
419
+ let childInstance
420
+ const t0 = template ( '<div></div>' )
421
+ const { component : Child } = define ( {
422
+ setup ( ) {
423
+ childInstance = getCurrentInstance ( )
424
+ const slots = useSlots ( )
425
+ const keys = ( ) => Object . keys ( slots )
426
+ return {
427
+ keys,
428
+ slots,
429
+ }
430
+ } ,
431
+ render : ( _ctx : any ) => {
432
+ const n0 = createFor (
433
+ ( ) => _ctx . keys ( ) ,
434
+ ( _ctx0 : any ) => {
435
+ const n5 = t0 ( )
436
+ const n4 = createSlot ( ( ) => _ctx0 [ 0 ] )
437
+ insert ( n4 , n5 as ParentNode )
438
+ return n5
439
+ } ,
440
+ )
441
+ return n0
442
+ } ,
443
+ } )
444
+
445
+ const t1 = template ( ' static default ' )
446
+ const { render } = define ( {
447
+ setup ( ) {
448
+ return createComponent (
449
+ Child ,
450
+ { } ,
451
+ {
452
+ default : ( ) => {
453
+ return t1 ( )
454
+ } ,
455
+ $ : [
456
+ ( ) =>
457
+ // @ts -expect-error TODO createForSlots
458
+ createForSlots ( loop . value , ( item , i ) => ( {
459
+ name : item ,
460
+ fn : ( ) => template ( item ) ( ) ,
461
+ } ) ) ,
462
+ ] ,
463
+ } ,
464
+ )
465
+ } ,
466
+ } )
467
+ const { html } = render ( )
468
+ expect ( childInstance ! . slots ) . toHaveProperty ( '1' )
469
+ expect ( childInstance ! . slots ) . toHaveProperty ( 'default' )
470
+ expect ( html ( ) ) . toBe (
471
+ '<div>1<!--slot--></div><div> static default <!--slot--></div><!--for-->' ,
472
+ )
473
+ loop . value = [ 1 ]
474
+ await nextTick ( )
475
+ expect ( childInstance ! . slots ) . toHaveProperty ( '1' )
476
+ expect ( childInstance ! . slots ) . toHaveProperty ( 'default' )
477
+ expect ( html ( ) ) . toBe (
478
+ '<div>1<!--slot--></div><div> static default <!--slot--></div><!--for-->' ,
479
+ )
480
+ loop . value = [ 1 , 2 , 3 ]
481
+ await nextTick ( )
482
+ expect ( childInstance ! . slots ) . toHaveProperty ( '1' )
483
+ expect ( childInstance ! . slots ) . toHaveProperty ( '2' )
484
+ expect ( childInstance ! . slots ) . toHaveProperty ( '3' )
485
+ expect ( childInstance ! . slots ) . toHaveProperty ( 'default' )
486
+ expect ( html ( ) ) . toBe (
487
+ '<div>1<!--slot--></div><div>2<!--slot--></div><div>3<!--slot--></div><div> static default <!--slot--></div><!--for-->' ,
488
+ )
489
+ } )
490
+
491
+ test ( 'dynamicSlots should not cover high level slots' , async ( ) => {
492
+ const dynamicFlag = ref ( true )
493
+
494
+ let instance : ComponentInternalInstance
495
+ const { component : Child } = define ( {
496
+ render ( ) {
497
+ instance = getCurrentInstance ( ) !
498
+ return [ createSlot ( 'default' ) , createSlot ( 'others' ) ]
499
+ } ,
500
+ } )
501
+
502
+ const { render, html } = define ( {
503
+ render ( ) {
504
+ return createComponent (
505
+ Child ,
506
+ { } ,
507
+ {
508
+ default : ( ) => template ( 'default' ) ( ) ,
509
+ $ : [
510
+ ( ) =>
511
+ dynamicFlag . value
512
+ ? {
513
+ name : 'default' ,
514
+ fn : ( ) => template ( 'dynamic default' ) ( ) ,
515
+ }
516
+ : { name : 'others' , fn : ( ) => template ( 'others' ) ( ) } ,
517
+ ] ,
518
+ } ,
519
+ )
520
+ } ,
521
+ } )
522
+
523
+ render ( )
524
+
525
+ expect ( html ( ) ) . toBe ( 'default<!--slot--><!--slot-->' )
526
+
527
+ dynamicFlag . value = false
528
+ await nextTick ( )
529
+
530
+ expect ( html ( ) ) . toBe ( 'default<!--slot-->others<!--slot-->' )
531
+ expect ( instance ! . slots ) . haveOwnProperty ( 'others' )
532
+
533
+ dynamicFlag . value = true
534
+ await nextTick ( )
535
+ expect ( html ( ) ) . toBe ( 'default<!--slot--><!--slot-->' )
536
+ expect ( instance ! . slots ) . not . haveOwnProperty ( 'others' )
537
+ } )
538
+
337
539
test ( 'dynamic slot should be updated correctly' , async ( ) => {
338
540
const flag1 = ref ( true )
339
541
0 commit comments