11import * as React from 'react' ;
2+ import { default as dxRender } from 'devextreme/core/renderer' ;
23import { useEffect , useContext } from 'react' ;
34import { TemplateWrapper } from '../template-wrapper' ;
45import { cleanup , render } from '@testing-library/react' ;
56import * as events from 'devextreme/events' ;
67import { RemovalLockerContext , UpdateLocker } from '../contexts' ;
78import { TemplateFunc } from '../types' ;
89
9- function TemplateComponent ( args : { data , index , onRendered ?, effect ? } ) {
10- const { data, index, onRendered, effect } = args ;
10+ function TemplateComponent ( args : { data , index , onRendered ?, effect ?, multipleRoots } ) {
11+ const { data, index, onRendered, effect, multipleRoots } = args ;
1112
1213 effect ?.( ) ;
1314
1415 useEffect ( ( ) => {
1516 onRendered ?.( ) ;
1617 } , [ onRendered ] ) ;
1718
18- return (
19- < div className = 'template-element' > { `${ data . text } - ${ index } ` } </ div >
20- ) ;
19+ return multipleRoots
20+ ? (
21+ < >
22+ < div className = 'template-element-1' > { `${ data . text } - ${ index } ` } </ div >
23+ < div className = 'template-element-2' > { `${ data . text } - ${ index } ` } </ div >
24+ </ >
25+ )
26+ : (
27+ < div className = 'template-element' > { `${ data . text } - ${ index } ` } </ div >
28+ ) ;
2129}
2230
23- function getComponentTemplateFunction ( effect ?) {
31+ function getComponentTemplateFunction ( effect ?, multipleRoots = false ) {
2432 return ( { data, index, onRendered } ) => {
2533 return (
2634 < TemplateComponent
2735 data = { data }
2836 index = { index }
2937 onRendered = { onRendered }
3038 effect = { effect }
39+ multipleRoots = { multipleRoots }
3140 />
3241 ) ;
3342 } ;
@@ -43,7 +52,7 @@ describe('Template Wrapper', () => {
4352 cleanup ( ) ;
4453 } ) ;
4554
46- it ( 'works with locker in the context correctly' , ( ) => {
55+ it ( 'works with locker in the context correctly' , async ( ) => {
4756 let onRemovedFired = false ;
4857 let removalLocker : UpdateLocker | undefined = undefined ;
4958
@@ -86,6 +95,7 @@ describe('Template Wrapper', () => {
8695
8796 events . triggerHandler ( document . querySelector ( '.template-element' ) ! , 'dxremove' ) ;
8897
98+ await Promise . resolve ( ) ;
8999 expect ( onRemovedFired ) . toBeTruthy ( ) ;
90100
91101 onRemovedFired = false ;
@@ -107,6 +117,7 @@ describe('Template Wrapper', () => {
107117 removalLocker . lock ( ) ;
108118 events . triggerHandler ( document . querySelector ( '.template-element' ) ! , 'dxremove' ) ;
109119
120+ await Promise . resolve ( ) ;
110121 expect ( onRemovedFired ) . toBeFalsy ( ) ;
111122
112123 rerender (
@@ -127,6 +138,7 @@ describe('Template Wrapper', () => {
127138 removalLocker . lock ( ) ;
128139 events . triggerHandler ( document . querySelector ( '.template-element' ) ! , 'dxremove' ) ;
129140
141+ await Promise . resolve ( ) ;
130142 expect ( onRemovedFired ) . toBeFalsy ( ) ;
131143
132144 rerender (
@@ -147,10 +159,11 @@ describe('Template Wrapper', () => {
147159 removalLocker . unlock ( ) ;
148160 events . triggerHandler ( document . querySelector ( '.template-element' ) ! , 'dxremove' ) ;
149161
162+ await Promise . resolve ( ) ;
150163 expect ( onRemovedFired ) . toBeTruthy ( ) ;
151164 } ) ;
152165
153- it ( 'does not fire onRemove when the event comes from wrappers' , ( ) => {
166+ it ( 'does not fire onRemove when the event comes from wrappers' , async ( ) => {
154167 let onRemovedFired = false ;
155168
156169 const onRemoved = ( ) => {
@@ -182,6 +195,7 @@ describe('Template Wrapper', () => {
182195
183196 events . triggerHandler ( document . querySelector ( '.template-element' ) ! , 'dxremove' , { isUnmounting : true } ) ;
184197
198+ await Promise . resolve ( ) ;
185199 expect ( onRemovedFired ) . toBeFalsy ( ) ;
186200
187201 rerender (
@@ -201,6 +215,7 @@ describe('Template Wrapper', () => {
201215
202216 events . triggerHandler ( document . querySelector ( '.template-element' ) ! , 'dxremove' ) ;
203217
218+ await Promise . resolve ( ) ;
204219 expect ( onRemovedFired ) . toBeTruthy ( ) ;
205220 } ) ;
206221
@@ -355,7 +370,7 @@ describe('Template Wrapper', () => {
355370 . toBe ( '<div class="template-container">My template - 1<div style="display: none;"></div><span style="display: none;"></span></div>' ) ;
356371 } ) ;
357372
358- it ( 'triggers onRemove when the element is removed' , ( ) => {
373+ it ( 'triggers onRemove when the element is removed' , async ( ) => {
359374 let onRemovedFired = false ;
360375
361376 const onRemoved = ( ) => {
@@ -383,15 +398,17 @@ describe('Template Wrapper', () => {
383398 />
384399 </ >
385400 ) ;
386-
401+
402+ await Promise . resolve ( ) ;
387403 expect ( onRemovedFired ) . toBeFalsy ( ) ;
388404
389405 events . triggerHandler ( document . querySelector ( '.template-element' ) ! , 'dxremove' ) ;
390406
407+ await Promise . resolve ( ) ;
391408 expect ( onRemovedFired ) . toBeTruthy ( ) ;
392409 } ) ;
393410
394- it ( 'removes text templates when the removal listener is removed' , ( ) => {
411+ it ( 'removes text templates when the removal listener is removed' , async ( ) => {
395412 let onRemovedFired = false ;
396413
397414 const onRemoved = ( ) => {
@@ -420,6 +437,7 @@ describe('Template Wrapper', () => {
420437 </ >
421438 ) ;
422439
440+ await Promise . resolve ( ) ;
423441 expect ( onRemovedFired ) . toBeFalsy ( ) ;
424442
425443 const containerChildren = document . querySelector ( '.template-container' ) ?. children ! ;
@@ -428,10 +446,11 @@ describe('Template Wrapper', () => {
428446 events . triggerHandler ( containerChildren [ i ] , 'dxremove' ) ;
429447 }
430448
449+ await Promise . resolve ( ) ;
431450 expect ( onRemovedFired ) . toBeTruthy ( ) ;
432451 } ) ;
433452
434- it ( 'returns all the elements to DOM on unmount to avoid upsetting React' , ( ) => {
453+ it ( 'returns the element and hidden nodes to DOM on unmount to avoid upsetting React' , ( ) => {
435454 const templateFunction : TemplateFunc = getComponentTemplateFunction ( ) ;
436455
437456 const { rerender, unmount } = render (
@@ -458,10 +477,45 @@ describe('Template Wrapper', () => {
458477 const children = container . children ;
459478
460479 for ( var i = 0 ; i < children . length ; i ++ ) {
461- container . removeChild ( children [ i ] ) ;
480+ dxRender ( children [ i ] ) . remove ( ) ;
481+ }
482+
483+ expect ( ( ) => unmount ( ) ) . not . toThrow ( ) ;
484+ expect ( container . children . length ) . toBe ( 0 ) ;
485+ } ) ;
486+
487+ it ( 'returns multiple template root elements to DOM on unmount to avoid upsetting React' , ( ) => {
488+ const templateFunction : TemplateFunc = getComponentTemplateFunction ( void 0 , true ) ;
489+
490+ const { rerender, unmount } = render (
491+ < >
492+ < div className = 'template-container' />
493+ </ >
494+ ) ;
495+
496+ rerender (
497+ < >
498+ < div className = 'template-container' />
499+ < TemplateWrapper
500+ templateFactory = { templateFunction }
501+ data = { { text : 'My template' } }
502+ index = { 1 }
503+ onRendered = { ( ) => undefined }
504+ container = { document . querySelector ( '.template-container' ) ! }
505+ onRemoved = { ( ) => undefined }
506+ />
507+ </ >
508+ ) ;
509+
510+ const container = document . querySelector ( '.template-container' ) ! ;
511+ const children = container . children ;
512+
513+ for ( var i = 0 ; i < children . length ; i ++ ) {
514+ dxRender ( children [ i ] ) . remove ( ) ;
462515 }
463516
464517 expect ( ( ) => unmount ( ) ) . not . toThrow ( ) ;
518+ expect ( container . children . length ) . toBe ( 0 ) ;
465519 } ) ;
466520
467521 it ( 'portals its component to the specified container' , ( ) => {
0 commit comments