@@ -223,6 +223,129 @@ describe('providers', () => {
223
223
expect ( logs ) . toEqual ( [ 'OnDestroy Existing' ] ) ;
224
224
} ) ;
225
225
226
+ it ( 'should invoke ngOnDestroy with the correct context when providing a type provider multiple times on the same node' ,
227
+ ( ) => {
228
+ const resolvedServices : ( DestroyService | undefined ) [ ] = [ ] ;
229
+ const destroyContexts : ( DestroyService | undefined ) [ ] = [ ] ;
230
+ let parentService : DestroyService | undefined ;
231
+ let childService : DestroyService | undefined ;
232
+
233
+ @Injectable ( )
234
+ class DestroyService {
235
+ constructor ( ) { resolvedServices . push ( this ) ; }
236
+ ngOnDestroy ( ) { destroyContexts . push ( this ) ; }
237
+ }
238
+
239
+ @Directive ( { selector : '[dir-one]' , providers : [ DestroyService ] } )
240
+ class DirOne {
241
+ constructor ( service : DestroyService ) { childService = service ; }
242
+ }
243
+
244
+ @Directive ( { selector : '[dir-two]' , providers : [ DestroyService ] } )
245
+ class DirTwo {
246
+ constructor ( service : DestroyService ) { childService = service ; }
247
+ }
248
+
249
+ @Component ( { template : '<div dir-one dir-two></div>' , providers : [ DestroyService ] } )
250
+ class App {
251
+ constructor ( service : DestroyService ) { parentService = service ; }
252
+ }
253
+
254
+ TestBed . configureTestingModule ( { declarations : [ App , DirOne , DirTwo ] } ) ;
255
+ const fixture = TestBed . createComponent ( App ) ;
256
+ fixture . detectChanges ( ) ;
257
+ fixture . destroy ( ) ;
258
+
259
+ expect ( parentService ) . toBeDefined ( ) ;
260
+ expect ( childService ) . toBeDefined ( ) ;
261
+ expect ( parentService ) . not . toBe ( childService ) ;
262
+ expect ( resolvedServices ) . toEqual ( [ parentService , childService ] ) ;
263
+ expect ( destroyContexts ) . toEqual ( [ parentService , childService ] ) ;
264
+ } ) ;
265
+
266
+ onlyInIvy ( 'Destroy hook of useClass provider is invoked correctly' )
267
+ . it ( 'should invoke ngOnDestroy with the correct context when providing a class provider multiple times on the same node' ,
268
+ ( ) => {
269
+ const resolvedServices : ( DestroyService | undefined ) [ ] = [ ] ;
270
+ const destroyContexts : ( DestroyService | undefined ) [ ] = [ ] ;
271
+ const token = new InjectionToken < any > ( 'token' ) ;
272
+ let parentService : DestroyService | undefined ;
273
+ let childService : DestroyService | undefined ;
274
+
275
+ @Injectable ( )
276
+ class DestroyService {
277
+ constructor ( ) { resolvedServices . push ( this ) ; }
278
+ ngOnDestroy ( ) { destroyContexts . push ( this ) ; }
279
+ }
280
+
281
+ @Directive (
282
+ { selector : '[dir-one]' , providers : [ { provide : token , useClass : DestroyService } ] } )
283
+ class DirOne {
284
+ constructor ( @Inject ( token ) service : DestroyService ) { childService = service ; }
285
+ }
286
+
287
+ @Directive (
288
+ { selector : '[dir-two]' , providers : [ { provide : token , useClass : DestroyService } ] } )
289
+ class DirTwo {
290
+ constructor ( @Inject ( token ) service : DestroyService ) { childService = service ; }
291
+ }
292
+
293
+ @Component ( {
294
+ template : '<div dir-one dir-two></div>' ,
295
+ providers : [ { provide : token , useClass : DestroyService } ]
296
+ } )
297
+ class App {
298
+ constructor ( @Inject ( token ) service : DestroyService ) { parentService = service ; }
299
+ }
300
+
301
+ TestBed . configureTestingModule ( { declarations : [ App , DirOne , DirTwo ] } ) ;
302
+ const fixture = TestBed . createComponent ( App ) ;
303
+ fixture . detectChanges ( ) ;
304
+ fixture . destroy ( ) ;
305
+
306
+ expect ( parentService ) . toBeDefined ( ) ;
307
+ expect ( childService ) . toBeDefined ( ) ;
308
+ expect ( parentService ) . not . toBe ( childService ) ;
309
+ expect ( resolvedServices ) . toEqual ( [ parentService , childService ] ) ;
310
+ expect ( destroyContexts ) . toEqual ( [ parentService , childService ] ) ;
311
+ } ) ;
312
+
313
+ onlyInIvy ( 'ngOnDestroy hooks for multi providers were not supported in ViewEngine' )
314
+ . it ( 'should not invoke ngOnDestroy on multi providers' , ( ) => {
315
+ // TODO(FW-1866): currently we only assert that the hook was called,
316
+ // but we should also be checking that the correct context was passed in.
317
+ let destroyCalls = 0 ;
318
+ const SERVICES = new InjectionToken < any > ( 'SERVICES' ) ;
319
+
320
+ @Injectable ( )
321
+ class DestroyService {
322
+ ngOnDestroy ( ) { destroyCalls ++ ; }
323
+ }
324
+
325
+ @Injectable ( )
326
+ class OtherDestroyService {
327
+ ngOnDestroy ( ) { destroyCalls ++ ; }
328
+ }
329
+
330
+ @Component ( {
331
+ template : '<div></div>' ,
332
+ providers : [
333
+ { provide : SERVICES , useClass : DestroyService , multi : true } ,
334
+ { provide : SERVICES , useClass : OtherDestroyService , multi : true } ,
335
+ ]
336
+ } )
337
+ class App {
338
+ constructor ( @Inject ( SERVICES ) s : any ) { }
339
+ }
340
+
341
+ TestBed . configureTestingModule ( { declarations : [ App ] } ) ;
342
+ const fixture = TestBed . createComponent ( App ) ;
343
+ fixture . detectChanges ( ) ;
344
+ fixture . destroy ( ) ;
345
+
346
+ expect ( destroyCalls ) . toBe ( 2 ) ;
347
+ } ) ;
348
+
226
349
} ) ;
227
350
228
351
describe ( 'components and directives' , ( ) => {
0 commit comments