@@ -2408,9 +2408,134 @@ describe('ngMockE2E', function() {
2408
2408
} ) ;
2409
2409
} ) ;
2410
2410
2411
+
2411
2412
describe ( 'make sure that we can create an injector outside of tests' , function ( ) {
2412
2413
//since some libraries create custom injectors outside of tests,
2413
2414
//we want to make sure that this is not breaking the internals of
2414
2415
//how we manage annotated function cleanup during tests. See #10967
2415
2416
angular . injector ( [ function ( $injector ) { } ] ) ;
2416
2417
} ) ;
2418
+
2419
+
2420
+ describe ( 'don\'t leak memory between tests' , function ( ) {
2421
+ var jQuery = window . jQuery ;
2422
+ var prevRootElement ;
2423
+ var prevRemoveDataSpy ;
2424
+ var prevCleanDataSpy ;
2425
+
2426
+ it ( 'should run a test to keep track of `removeData()`/`cleanData()` calls for later inspection' ,
2427
+ function ( ) {
2428
+ module ( function ( $provide ) {
2429
+ $provide . decorator ( '$rootElement' , function ( $delegate ) {
2430
+ // Spy on `.removeData()` and `jQuery.cleanData()`,
2431
+ // so the next test can verify that they have been called as necessary
2432
+ prevRootElement = $delegate ;
2433
+ prevRemoveDataSpy = spyOn ( $delegate , 'removeData' ) . andCallThrough ( ) ;
2434
+
2435
+ if ( jQuery ) {
2436
+ prevCleanDataSpy = spyOn ( jQuery , 'cleanData' ) . andCallThrough ( ) ;
2437
+ }
2438
+
2439
+ return $delegate ;
2440
+ } ) ;
2441
+ } ) ;
2442
+
2443
+ // Inject the `$rootElement` to ensure it has been created
2444
+ inject ( function ( $rootElement ) {
2445
+ expect ( $rootElement . injector ( ) ) . toBeDefined ( ) ;
2446
+ } ) ;
2447
+ }
2448
+ ) ;
2449
+
2450
+ it ( 'should clean up `$rootElement`-related data after each test' , function ( ) {
2451
+ // One call is made by `testabilityPatch`'s `dealoc()`
2452
+ // We want to verify the subsequent call, made by `angular-mocks`
2453
+ // (Since `testabilityPatch` re-wrapps `$rootElement` and because jQuery
2454
+ // returns a different object, we don't capture the 1st call when using jQuery)
2455
+ expect ( prevRemoveDataSpy . callCount ) . toBe ( jQuery ? 1 : 2 ) ;
2456
+
2457
+ if ( jQuery ) {
2458
+ // One call is made by `testabilityPatch`'s `dealoc()`
2459
+ // We want to verify the subsequent call, made by `angular-mocks`
2460
+ expect ( prevCleanDataSpy . callCount ) . toBe ( 2 ) ;
2461
+
2462
+ var cleanUpElems = prevCleanDataSpy . calls [ 1 ] . args [ 0 ] ;
2463
+ expect ( cleanUpElems . length ) . toBe ( 1 ) ;
2464
+ expect ( cleanUpElems [ 0 ] [ 0 ] ) . toBe ( prevRootElement [ 0 ] ) ;
2465
+ }
2466
+ } ) ;
2467
+ } ) ;
2468
+
2469
+ describe ( 'don\'t leak memory between tests with mocked `$rootScope`' , function ( ) {
2470
+ var jQuery = window . jQuery ;
2471
+ var prevOriginalRootElement ;
2472
+ var prevOriginalRemoveDataSpy ;
2473
+ var prevRootElement ;
2474
+ var prevRemoveDataSpy ;
2475
+ var prevCleanDataSpy ;
2476
+
2477
+ it ( 'should run a test to keep track of `removeData()`/`cleanData()` calls for later inspection' ,
2478
+ function ( ) {
2479
+ module ( function ( $provide ) {
2480
+ $provide . decorator ( '$rootElement' , function ( $delegate ) {
2481
+ // Mock `$rootElement` to be able to verify that the correct object is cleaned up
2482
+ var mockRootElement = angular . element ( '<div></div>' ) ;
2483
+
2484
+ // Spy on `.removeData()` and `jQuery.cleanData()`,
2485
+ // so the next test can verify that they have been called as necessary
2486
+ prevOriginalRootElement = $delegate ;
2487
+ prevOriginalRemoveDataSpy = spyOn ( $delegate , 'removeData' ) . andCallThrough ( ) ;
2488
+
2489
+ prevRootElement = mockRootElement ;
2490
+ prevRemoveDataSpy = spyOn ( mockRootElement , 'removeData' ) . andCallThrough ( ) ;
2491
+
2492
+ if ( jQuery ) {
2493
+ prevCleanDataSpy = spyOn ( jQuery , 'cleanData' ) . andCallThrough ( ) ;
2494
+ }
2495
+
2496
+ return mockRootElement ;
2497
+ } ) ;
2498
+ } ) ;
2499
+
2500
+ // Inject the `$rootElement` to ensure it has been created
2501
+ inject ( function ( $rootElement ) {
2502
+ expect ( $rootElement ) . toBe ( prevRootElement ) ;
2503
+ expect ( prevOriginalRootElement . injector ( ) ) . toBeDefined ( ) ;
2504
+ expect ( prevRootElement . injector ( ) ) . toBeUndefined ( ) ;
2505
+
2506
+ // If we don't clean up `prevOriginalRootElement`-related data now, `testabilityPatch` will
2507
+ // complain about a memory leak, because it doesn't clean up after the original
2508
+ // `$rootElement`.
2509
+ // This is a false alarm, because `angular-mocks` will clean up later.
2510
+ prevOriginalRootElement . removeData ( ) ;
2511
+ prevOriginalRemoveDataSpy . reset ( ) ;
2512
+
2513
+ expect ( prevOriginalRemoveDataSpy . callCount ) . toBe ( 0 ) ;
2514
+ } ) ;
2515
+ }
2516
+ ) ;
2517
+
2518
+ it ( 'should clean up after the `$rootElement` (both original and decorated) after each test' ,
2519
+ function ( ) {
2520
+ // Only `angular-mocks` cleans up after the original `$rootElement`, not `testabilityPatch`
2521
+ expect ( prevOriginalRemoveDataSpy . callCount ) . toBe ( 1 ) ;
2522
+
2523
+ // One call is made by `testabilityPatch`'s `dealoc()`
2524
+ // We want to verify the subsequent call, made by `angular-mocks`
2525
+ // (Since `testabilityPatch` re-wrapps `$rootElement` and because jQuery
2526
+ // returns a different object, we don't capture the 1st call when using jQuery)
2527
+ expect ( prevRemoveDataSpy . callCount ) . toBe ( jQuery ? 1 : 2 ) ;
2528
+
2529
+ if ( jQuery ) {
2530
+ // One call is made by `testabilityPatch`'s `dealoc()`
2531
+ // We want to verify the subsequent call, made by `angular-mocks`
2532
+ expect ( prevCleanDataSpy . callCount ) . toBe ( 2 ) ;
2533
+
2534
+ var cleanUpElems = prevCleanDataSpy . calls [ 1 ] . args [ 0 ] ;
2535
+ expect ( cleanUpElems . length ) . toBe ( 2 ) ;
2536
+ expect ( cleanUpElems [ 0 ] [ 0 ] ) . toBe ( prevOriginalRootElement [ 0 ] ) ;
2537
+ expect ( cleanUpElems [ 1 ] [ 0 ] ) . toBe ( prevRootElement [ 0 ] ) ;
2538
+ }
2539
+ }
2540
+ ) ;
2541
+ } ) ;
0 commit comments