diff --git a/src/auto/injector.js b/src/auto/injector.js index c4f4262364b2..d295827b89cf 100644 --- a/src/auto/injector.js +++ b/src/auto/injector.js @@ -796,7 +796,7 @@ function createInjector(modulesToLoad, strictDi) { } var args = [], - $inject = annotate(fn, strictDi, serviceName), + $inject = createInjector.$$annotate(fn, strictDi, serviceName), length, i, key; @@ -835,7 +835,7 @@ function createInjector(modulesToLoad, strictDi) { invoke: invoke, instantiate: instantiate, get: getService, - annotate: annotate, + annotate: createInjector.$$annotate, has: function(name) { return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); } diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index 43006fefb41c..9a32fe0a0415 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -2047,7 +2047,7 @@ angular.mock.e2e.$httpBackendDecorator = * * In addition to all the regular `Scope` methods, the following helper methods are available: */ -angular.mock.$RootScopeDecorator = function($delegate) { +angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) { var $rootScopePrototype = Object.getPrototypeOf($delegate); @@ -2119,24 +2119,38 @@ angular.mock.$RootScopeDecorator = function($delegate) { return count; } -}; +}]; if (window.jasmine || window.mocha) { var currentSpec = null, + annotatedFunctions, isSpecRunning = function() { return !!currentSpec; }; + var hookedAnnotate = angular.injector.$$annotate; + angular.injector.$$annotate = function(fn) { + if (typeof fn === 'function' && !fn.$inject) { + annotatedFunctions.push(fn); + } + return hookedAnnotate.apply(this, arguments); + }; + (window.beforeEach || window.setup)(function() { + annotatedFunctions = []; currentSpec = this; }); (window.afterEach || window.teardown)(function() { var injector = currentSpec.$injector; + annotatedFunctions.forEach(function(fn) { + delete fn.$inject; + }); + angular.forEach(currentSpec.$modules, function(module) { if (module && module.$$hashKey) { module.$$hashKey = undefined; diff --git a/test/auto/injectorSpec.js b/test/auto/injectorSpec.js index 984deb4ac2d2..0ca8877811e1 100644 --- a/test/auto/injectorSpec.js +++ b/test/auto/injectorSpec.js @@ -220,7 +220,9 @@ describe('injector', function() { it('should publish annotate API', function() { - expect(injector.annotate).toBe(annotate); + function fn() {} + expect(injector.annotate(fn)).toEqual([]); + expect(fn.$inject).toEqual([]); }); }); diff --git a/test/ngMock/angular-mocksSpec.js b/test/ngMock/angular-mocksSpec.js index c22c95f462ad..7298e6a00c48 100644 --- a/test/ngMock/angular-mocksSpec.js +++ b/test/ngMock/angular-mocksSpec.js @@ -767,6 +767,39 @@ describe('ngMock', function() { expect(testFn.$$hashKey).toBeUndefined(); }); }); + + describe('$inject cleanup', function() { + function testFn() { + + } + + it('should add $inject when invoking test function', inject(function($injector) { + $injector.invoke(testFn); + expect(testFn.$inject).toBeDefined(); + })); + + it('should cleanup $inject after previous test', function() { + expect(testFn.$inject).toBeUndefined(); + }); + + it('should add $inject when annotating test function', inject(function($injector) { + $injector.annotate(testFn); + expect(testFn.$inject).toBeDefined(); + })); + + it('should cleanup $inject after previous test', function() { + expect(testFn.$inject).toBeUndefined(); + }); + + it('should invoke an already annotated function', inject(function($injector) { + testFn.$inject = []; + $injector.invoke(testFn); + })); + + it('should not cleanup $inject after previous test', function() { + expect(testFn.$inject).toBeDefined(); + }); + }); }); describe('in DSL', function() {