@@ -245,4 +245,99 @@ describe('ReactMount', function() {
245245 'render the new components instead of calling ReactDOM.render.'
246246 ) ;
247247 } ) ;
248+
249+ it ( 'should not crash in node cache when unmounting' , function ( ) {
250+ var Component = React . createClass ( {
251+ render : function ( ) {
252+ // Add refs to some nodes so that they get traversed and cached
253+ return (
254+ < div ref = "a" >
255+ < div ref = "b" > b</ div >
256+ { this . props . showC && < div > c</ div > }
257+ </ div >
258+ ) ;
259+ } ,
260+ } ) ;
261+
262+ var container = document . createElement ( 'container' ) ;
263+
264+ ReactDOM . render ( < div > < Component showC = { false } /> </ div > , container ) ;
265+
266+ // Right now, A and B are in the cache. When we add C, it won't get added to
267+ // the cache (assuming markup-string mode).
268+ ReactDOM . render ( < div > < Component showC = { true } /> </ div > , container ) ;
269+
270+ // Remove A, B, and C. Unmounting C shouldn't cause B to get recached.
271+ ReactDOM . render ( < div > </ div > , container ) ;
272+
273+ // Add them back -- this shouldn't cause a cached node collision.
274+ ReactDOM . render ( < div > < Component showC = { true } /> </ div > , container ) ;
275+
276+ ReactDOM . unmountComponentAtNode ( container ) ;
277+ } ) ;
278+
279+ it ( 'should not crash in node cache when unmounting, case 2' , function ( ) {
280+ var A = React . createClass ( {
281+ render : function ( ) {
282+ return < a key = { this . props . innerKey } > { this . props . innerKey } </ a > ;
283+ } ,
284+ } ) ;
285+ var Component = React . createClass ( {
286+ render : function ( ) {
287+ return (
288+ < b >
289+ < i > { this . props . step === 1 && < q /> } </ i >
290+ { this . props . step === 1 && < A innerKey = { this . props . step } /> }
291+ </ b >
292+ ) ;
293+ } ,
294+ } ) ;
295+
296+ var container = document . createElement ( 'container' ) ;
297+
298+ ReactDOM . render ( < Component step = { 1 } /> , container ) ;
299+ ReactDOM . render ( < Component step = { 2 } /> , container ) ;
300+ ReactDOM . render ( < Component step = { 1 } /> , container ) ;
301+ ReactMount . getID ( container . querySelector ( 'a' ) ) ;
302+ } ) ;
303+
304+ it ( 'passes the correct callback context' , function ( ) {
305+ var container = document . createElement ( 'div' ) ;
306+ var calls = 0 ;
307+
308+ ReactDOM . render ( < div /> , container , function ( ) {
309+ expect ( this . nodeName ) . toBe ( 'DIV' ) ;
310+ calls ++ ;
311+ } ) ;
312+
313+ // Update, no type change
314+ ReactDOM . render ( < div /> , container , function ( ) {
315+ expect ( this . nodeName ) . toBe ( 'DIV' ) ;
316+ calls ++ ;
317+ } ) ;
318+
319+ // Update, type change
320+ ReactDOM . render ( < span /> , container , function ( ) {
321+ expect ( this . nodeName ) . toBe ( 'SPAN' ) ;
322+ calls ++ ;
323+ } ) ;
324+
325+ // Batched update, no type change
326+ ReactDOM . unstable_batchedUpdates ( function ( ) {
327+ ReactDOM . render ( < span /> , container , function ( ) {
328+ expect ( this . nodeName ) . toBe ( 'SPAN' ) ;
329+ calls ++ ;
330+ } ) ;
331+ } ) ;
332+
333+ // Batched update, type change
334+ ReactDOM . unstable_batchedUpdates ( function ( ) {
335+ ReactDOM . render ( < article /> , container , function ( ) {
336+ expect ( this . nodeName ) . toBe ( 'ARTICLE' ) ;
337+ calls ++ ;
338+ } ) ;
339+ } ) ;
340+
341+ expect ( calls ) . toBe ( 5 ) ;
342+ } ) ;
248343} ) ;
0 commit comments