11// tslint:disable:no-invalid-template-strings
2+ import { EMPTY , Subject } from 'rxjs' ;
3+ import { BeforeModelDestroyedEvent } from '../../model/events/before-model-destroyed-event' ;
24import { ModelChangedEvent } from '../../model/events/model-changed-event' ;
35import { ModelManager } from '../../model/manager/model-manager' ;
46import { PropertyLocation } from '../../model/property/property-location' ;
@@ -11,13 +13,15 @@ describe('Variable manager', () => {
1113 let mockLogger : Partial < Logger > ;
1214 let mockModelManager : Partial < ModelManager > ;
1315 let mockModelChangedEvent : Partial < ModelChangedEvent > ;
16+ let mockBeforeModelDestroyedEvent : Partial < BeforeModelDestroyedEvent > ;
1417 const model = { } ;
1518 const parent = { } ;
1619 const root = { } ;
1720
1821 beforeEach ( ( ) => {
1922 mockLogger = {
20- warn : jest . fn ( )
23+ warn : jest . fn ( ) ,
24+ error : jest . fn ( )
2125 } ;
2226 mockModelChangedEvent = {
2327 publishChange : jest . fn ( )
@@ -35,10 +39,15 @@ describe('Variable manager', () => {
3539 } )
3640 } ;
3741
42+ mockBeforeModelDestroyedEvent = {
43+ getBeforeDestructionObservable : jest . fn ( )
44+ } ;
45+
3846 manager = new VariableManager (
3947 mockLogger as Logger ,
4048 mockModelManager as ModelManager ,
41- mockModelChangedEvent as ModelChangedEvent
49+ mockModelChangedEvent as ModelChangedEvent ,
50+ mockBeforeModelDestroyedEvent as BeforeModelDestroyedEvent
4251 ) ;
4352 } ) ;
4453
@@ -106,6 +115,7 @@ describe('Variable manager reference tracking', () => {
106115 let mockLogger : PartialObjectMock < Logger > ;
107116 let mockModelManager : PartialObjectMock < ModelManager > ;
108117 let mockModelChangedEvent : PartialObjectMock < ModelChangedEvent > ;
118+ let mockBeforeModelDestroyedEvent : Partial < BeforeModelDestroyedEvent > ;
109119
110120 let mockParentLocation : PartialObjectMock < PropertyLocation > ;
111121 const parent = { } ;
@@ -132,6 +142,10 @@ describe('Variable manager reference tracking', () => {
132142 )
133143 } ;
134144
145+ mockBeforeModelDestroyedEvent = {
146+ getBeforeDestructionObservable : jest . fn ( ) . mockReturnValue ( EMPTY )
147+ } ;
148+
135149 mockModelLocation = {
136150 parentModel : model ,
137151 setProperty : jest . fn ( ) ,
@@ -147,7 +161,8 @@ describe('Variable manager reference tracking', () => {
147161 manager = new VariableManager (
148162 mockLogger as Logger ,
149163 mockModelManager as ModelManager ,
150- mockModelChangedEvent as ModelChangedEvent
164+ mockModelChangedEvent as ModelChangedEvent ,
165+ mockBeforeModelDestroyedEvent as BeforeModelDestroyedEvent
151166 ) ;
152167 } ) ;
153168
@@ -323,4 +338,45 @@ describe('Variable manager reference tracking', () => {
323338 'Attempted to resolve reference at modelProp which does not contain a registered reference'
324339 ) ;
325340 } ) ;
341+
342+ test ( 'removes dangling references after a model is destroyed' , ( ) => {
343+ const destroySubject = new Subject ( ) ;
344+ mockBeforeModelDestroyedEvent . getBeforeDestructionObservable = jest
345+ . fn ( )
346+ . mockReturnValue ( destroySubject . asObservable ( ) ) ;
347+
348+ manager . registerReference ( mockModelLocation as PropertyLocation , '${test}' ) ;
349+ manager . set ( 'test' , 'foo' , parent ) ;
350+
351+ destroySubject . next ( model ) ;
352+ destroySubject . complete ( ) ;
353+
354+ // Reference should no longer be tracked
355+ expect ( manager . isVariableReference ( mockModelLocation as PropertyLocation ) ) . toBe ( false ) ;
356+
357+ // Setting a value should not call model manager or set property
358+ ( mockModelManager . getParent as jest . Mock ) . mockClear ( ) ;
359+ manager . set ( 'test' , 'bar' , parent ) ;
360+
361+ expect ( mockModelManager . getParent ) . not . toHaveBeenCalled ( ) ;
362+ expect ( mockModelLocation . setProperty ) . not . toHaveBeenCalledWith ( 'bar' ) ;
363+ } ) ;
364+
365+ test ( 'dangling reference removal handles case where reference previously removed' , ( ) => {
366+ const destroySubject = new Subject ( ) ;
367+ mockBeforeModelDestroyedEvent . getBeforeDestructionObservable = jest
368+ . fn ( )
369+ . mockReturnValue ( destroySubject . asObservable ( ) ) ;
370+
371+ manager . registerReference ( mockModelLocation as PropertyLocation , '${test}' ) ;
372+ manager . set ( 'test' , 'foo' , parent ) ;
373+ manager . deregisterReference ( mockModelLocation as PropertyLocation ) ;
374+
375+ // Reference should no longer be tracked
376+ expect ( manager . isVariableReference ( mockModelLocation as PropertyLocation ) ) . toBe ( false ) ;
377+
378+ destroySubject . next ( model ) ;
379+ destroySubject . complete ( ) ;
380+ expect ( mockLogger . error ) . not . toHaveBeenCalled ( ) ;
381+ } ) ;
326382} ) ;
0 commit comments