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