@@ -474,6 +474,190 @@ describe('defineCustomElement', () => {
474474 '<div><span>1 is number</span><span>true is boolean</span></div>' ,
475475 )
476476 } )
477+
478+ test ( 'should patch all props together' , async ( ) => {
479+ let prop1Calls = 0
480+ let prop2Calls = 0
481+ const E = defineCustomElement ( {
482+ props : {
483+ prop1 : {
484+ type : String ,
485+ default : 'default1' ,
486+ } ,
487+ prop2 : {
488+ type : String ,
489+ default : 'default2' ,
490+ } ,
491+ } ,
492+ data ( ) {
493+ return {
494+ data1 : 'defaultData1' ,
495+ data2 : 'defaultData2' ,
496+ }
497+ } ,
498+ watch : {
499+ prop1 ( _ ) {
500+ prop1Calls ++
501+ this . data2 = this . prop2
502+ } ,
503+ prop2 ( _ ) {
504+ prop2Calls ++
505+ this . data1 = this . prop1
506+ } ,
507+ } ,
508+ render ( ) {
509+ return h ( 'div' , [
510+ h ( 'h1' , this . prop1 ) ,
511+ h ( 'h1' , this . prop2 ) ,
512+ h ( 'h2' , this . data1 ) ,
513+ h ( 'h2' , this . data2 ) ,
514+ ] )
515+ } ,
516+ } )
517+ customElements . define ( 'my-watch-element' , E )
518+
519+ render ( h ( 'my-watch-element' ) , container )
520+ const e = container . childNodes [ 0 ] as VueElement
521+ expect ( e ) . toBeInstanceOf ( E )
522+ expect ( e . _instance ) . toBeTruthy ( )
523+ expect ( e . shadowRoot ! . innerHTML ) . toBe (
524+ `<div><h1>default1</h1><h1>default2</h1><h2>defaultData1</h2><h2>defaultData2</h2></div>` ,
525+ )
526+ expect ( prop1Calls ) . toBe ( 0 )
527+ expect ( prop2Calls ) . toBe ( 0 )
528+
529+ // patch props
530+ render (
531+ h ( 'my-watch-element' , { prop1 : 'newValue1' , prop2 : 'newValue2' } ) ,
532+ container ,
533+ )
534+ await nextTick ( )
535+ expect ( e . shadowRoot ! . innerHTML ) . toBe (
536+ `<div><h1>newValue1</h1><h1>newValue2</h1><h2>newValue1</h2><h2>newValue2</h2></div>` ,
537+ )
538+ expect ( prop1Calls ) . toBe ( 1 )
539+ expect ( prop2Calls ) . toBe ( 1 )
540+
541+ // same prop values
542+ render (
543+ h ( 'my-watch-element' , { prop1 : 'newValue1' , prop2 : 'newValue2' } ) ,
544+ container ,
545+ )
546+ await nextTick ( )
547+ expect ( e . shadowRoot ! . innerHTML ) . toBe (
548+ `<div><h1>newValue1</h1><h1>newValue2</h1><h2>newValue1</h2><h2>newValue2</h2></div>` ,
549+ )
550+ expect ( prop1Calls ) . toBe ( 1 )
551+ expect ( prop2Calls ) . toBe ( 1 )
552+
553+ // update only prop1
554+ render (
555+ h ( 'my-watch-element' , { prop1 : 'newValue3' , prop2 : 'newValue2' } ) ,
556+ container ,
557+ )
558+ await nextTick ( )
559+ expect ( e . shadowRoot ! . innerHTML ) . toBe (
560+ `<div><h1>newValue3</h1><h1>newValue2</h1><h2>newValue1</h2><h2>newValue2</h2></div>` ,
561+ )
562+ expect ( prop1Calls ) . toBe ( 2 )
563+ expect ( prop2Calls ) . toBe ( 1 )
564+ } )
565+
566+ test ( 'should patch all props together (async)' , async ( ) => {
567+ let prop1Calls = 0
568+ let prop2Calls = 0
569+ const E = defineCustomElement (
570+ defineAsyncComponent ( ( ) =>
571+ Promise . resolve (
572+ defineComponent ( {
573+ props : {
574+ prop1 : {
575+ type : String ,
576+ default : 'default1' ,
577+ } ,
578+ prop2 : {
579+ type : String ,
580+ default : 'default2' ,
581+ } ,
582+ } ,
583+ data ( ) {
584+ return {
585+ data1 : 'defaultData1' ,
586+ data2 : 'defaultData2' ,
587+ }
588+ } ,
589+ watch : {
590+ prop1 ( _ ) {
591+ prop1Calls ++
592+ this . data2 = this . prop2
593+ } ,
594+ prop2 ( _ ) {
595+ prop2Calls ++
596+ this . data1 = this . prop1
597+ } ,
598+ } ,
599+ render ( ) {
600+ return h ( 'div' , [
601+ h ( 'h1' , this . prop1 ) ,
602+ h ( 'h1' , this . prop2 ) ,
603+ h ( 'h2' , this . data1 ) ,
604+ h ( 'h2' , this . data2 ) ,
605+ ] )
606+ } ,
607+ } ) ,
608+ ) ,
609+ ) ,
610+ )
611+ customElements . define ( 'my-async-watch-element' , E )
612+
613+ render ( h ( 'my-async-watch-element' ) , container )
614+
615+ await new Promise ( r => setTimeout ( r ) )
616+ const e = container . childNodes [ 0 ] as VueElement
617+ expect ( e ) . toBeInstanceOf ( E )
618+ expect ( e . _instance ) . toBeTruthy ( )
619+ expect ( e . shadowRoot ! . innerHTML ) . toBe (
620+ `<div><h1>default1</h1><h1>default2</h1><h2>defaultData1</h2><h2>defaultData2</h2></div>` ,
621+ )
622+ expect ( prop1Calls ) . toBe ( 0 )
623+ expect ( prop2Calls ) . toBe ( 0 )
624+
625+ // patch props
626+ render (
627+ h ( 'my-async-watch-element' , { prop1 : 'newValue1' , prop2 : 'newValue2' } ) ,
628+ container ,
629+ )
630+ await nextTick ( )
631+ expect ( e . shadowRoot ! . innerHTML ) . toBe (
632+ `<div><h1>newValue1</h1><h1>newValue2</h1><h2>newValue1</h2><h2>newValue2</h2></div>` ,
633+ )
634+ expect ( prop1Calls ) . toBe ( 1 )
635+ expect ( prop2Calls ) . toBe ( 1 )
636+
637+ // same prop values
638+ render (
639+ h ( 'my-async-watch-element' , { prop1 : 'newValue1' , prop2 : 'newValue2' } ) ,
640+ container ,
641+ )
642+ await nextTick ( )
643+ expect ( e . shadowRoot ! . innerHTML ) . toBe (
644+ `<div><h1>newValue1</h1><h1>newValue2</h1><h2>newValue1</h2><h2>newValue2</h2></div>` ,
645+ )
646+ expect ( prop1Calls ) . toBe ( 1 )
647+ expect ( prop2Calls ) . toBe ( 1 )
648+
649+ // update only prop1
650+ render (
651+ h ( 'my-async-watch-element' , { prop1 : 'newValue3' , prop2 : 'newValue2' } ) ,
652+ container ,
653+ )
654+ await nextTick ( )
655+ expect ( e . shadowRoot ! . innerHTML ) . toBe (
656+ `<div><h1>newValue3</h1><h1>newValue2</h1><h2>newValue1</h2><h2>newValue2</h2></div>` ,
657+ )
658+ expect ( prop1Calls ) . toBe ( 2 )
659+ expect ( prop2Calls ) . toBe ( 1 )
660+ } )
477661 } )
478662
479663 describe ( 'attrs' , ( ) => {
0 commit comments