From 0dc945750c8831df695d6d16fb4f8eb4a1d67703 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Wed, 4 Mar 2015 12:14:40 -0500 Subject: [PATCH] feat(ngMock): allow mock $controller service to set up controller bindings Adds a new mock for the $controller service, in order to simplify testing using the bindToController feature. ```js var dictionaryOfControllerBindings = { data: [ { id: 0, phone: '...', name: '...' }, { id: 1, phone: '...', name: '...' }, ] }; // When the MyCtrl constructor is called, `this.data ~= dictionaryOfControllerBindings.data` $controller(MyCtrl, myLocals, dictionaryOfControllerBindings); ``` Closes #9425 --- src/ngMock/angular-mocks.js | 39 ++++++++++++++++++++++++++++++++ test/ngMock/angular-mocksSpec.js | 22 ++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index 1b8be7d77b96..314c7966d58e 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -1780,6 +1780,44 @@ angular.mock.$RootElementProvider = function() { }; }; +/** + * @ngdoc service + * @name $controller + * @description + * Mock $controller service, used to simplify testing controllers when using the + * bindToController feature. + * +* @param {Function|string} constructor If called with a function then it's considered to be the +* controller constructor function. Otherwise it's considered to be a string which is used +* to retrieve the controller constructor using the following steps: +* +* * check if a controller with given name is registered via `$controllerProvider` +* * check if evaluating the string on the current scope returns a constructor +* * if $controllerProvider#allowGlobals, check `window[constructor]` on the global +* `window` object (not recommended) +* +* The string can use the `controller as property` syntax, where the controller instance is published +* as the specified property on the `scope`; the `scope` must be injected into `locals` param for this +* to work correctly. +* +* @param {Object} locals Injection locals for Controller. +* @param {Object=} bindings Properties to add to the controller before invoking +* the constructor. This is used to simulate the `bindToController` feature +* and simplify certain kinds oftests. +* @return {Object} Instance of given controller. + */ +angular.mock.$ControllerDecorator = ['$delegate', function($delegate) { + return function(expression, locals, later, ident) { + if (later && typeof later === 'object') { + var create = $delegate(expression, locals, true, ident); + angular.extend(create.instance, later); + return create(); + } + return $delegate(expression, locals, later, ident); + }; +}]; + + /** * @ngdoc module * @name ngMock @@ -1808,6 +1846,7 @@ angular.module('ngMock', ['ng']).provider({ $provide.decorator('$$rAF', angular.mock.$RAFDecorator); $provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator); $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator); + $provide.decorator('$controller', angular.mock.$ControllerDecorator); }]); /** diff --git a/test/ngMock/angular-mocksSpec.js b/test/ngMock/angular-mocksSpec.js index 104ece1c0aa5..7472dda3345f 100644 --- a/test/ngMock/angular-mocksSpec.js +++ b/test/ngMock/angular-mocksSpec.js @@ -1751,6 +1751,28 @@ describe('ngMock', function() { })); }); }); + + + describe('$controllerDecorator', function() { + it('should support creating controller with bindings', function() { + var called = false; + var data = [ + { name: 'derp1', id: 0 }, + { name: 'testname', id: 1 }, + { name: 'flurp', id: 2 } + ]; + module(function($controllerProvider) { + $controllerProvider.register('testCtrl', function() { + called = true; + expect(this.data).toEqual(data); + }); + }); + inject(function($controller, $rootScope) { + $controller('testCtrl', { scope: $rootScope }, { data: data }); + expect(called).toBe(true); + }); + }); + }); });