Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit b3878a3

Browse files
caitppetebacondarwin
authored andcommitted
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 Closes #11239
1 parent ebd84e8 commit b3878a3

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

src/ngMock/angular-mocks.js

+72
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,77 @@ angular.mock.$RootElementProvider = function() {
18021802
};
18031803
};
18041804

1805+
/**
1806+
* @ngdoc service
1807+
* @name $controller
1808+
* @description
1809+
* A decorator for {@link ng.$controller} with additional `bindings` parameter, useful when testing
1810+
* controllers of directives that use {@link $compile#-bindtocontroller- `bindToController`}.
1811+
*
1812+
*
1813+
* ## Example
1814+
*
1815+
* ```js
1816+
*
1817+
* // Directive definition ...
1818+
*
1819+
* myMod.directive('myDirective', {
1820+
* controller: 'MyDirectiveController',
1821+
* bindToController: {
1822+
* name: '@'
1823+
* }
1824+
* });
1825+
*
1826+
*
1827+
* // Controller definition ...
1828+
*
1829+
* myMod.controller('MyDirectiveController', ['log', function($log) {
1830+
* $log.info(this.name);
1831+
* })];
1832+
*
1833+
*
1834+
* // In a test ...
1835+
*
1836+
* describe('myDirectiveController', function() {
1837+
* it('should write the bound name to the log', inject(function($controller, $log) {
1838+
* var ctrl = $controller('MyDirective', { /* no locals */ }, { name: 'Clark Kent' });
1839+
* expect(ctrl.name).toEqual('Clark Kent');
1840+
* expect($log.info.logs).toEqual(['Clark Kent']);
1841+
* });
1842+
* });
1843+
*
1844+
* ```
1845+
*
1846+
* @param {Function|string} constructor If called with a function then it's considered to be the
1847+
* controller constructor function. Otherwise it's considered to be a string which is used
1848+
* to retrieve the controller constructor using the following steps:
1849+
*
1850+
* * check if a controller with given name is registered via `$controllerProvider`
1851+
* * check if evaluating the string on the current scope returns a constructor
1852+
* * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
1853+
* `window` object (not recommended)
1854+
*
1855+
* The string can use the `controller as property` syntax, where the controller instance is published
1856+
* as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
1857+
* to work correctly.
1858+
*
1859+
* @param {Object} locals Injection locals for Controller.
1860+
* @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
1861+
* to simulate the `bindToController` feature and simplify certain kinds of tests.
1862+
* @return {Object} Instance of given controller.
1863+
*/
1864+
angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
1865+
return function(expression, locals, later, ident) {
1866+
if (later && typeof later === 'object') {
1867+
var create = $delegate(expression, locals, true, ident);
1868+
angular.extend(create.instance, later);
1869+
return create();
1870+
}
1871+
return $delegate(expression, locals, later, ident);
1872+
};
1873+
}];
1874+
1875+
18051876
/**
18061877
* @ngdoc module
18071878
* @name ngMock
@@ -1830,6 +1901,7 @@ angular.module('ngMock', ['ng']).provider({
18301901
$provide.decorator('$$rAF', angular.mock.$RAFDecorator);
18311902
$provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
18321903
$provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
1904+
$provide.decorator('$controller', angular.mock.$ControllerDecorator);
18331905
}]);
18341906

18351907
/**

test/ngMock/angular-mocksSpec.js

+22
Original file line numberDiff line numberDiff line change
@@ -1751,6 +1751,28 @@ describe('ngMock', function() {
17511751
}));
17521752
});
17531753
});
1754+
1755+
1756+
describe('$controllerDecorator', function() {
1757+
it('should support creating controller with bindings', function() {
1758+
var called = false;
1759+
var data = [
1760+
{ name: 'derp1', id: 0 },
1761+
{ name: 'testname', id: 1 },
1762+
{ name: 'flurp', id: 2 }
1763+
];
1764+
module(function($controllerProvider) {
1765+
$controllerProvider.register('testCtrl', function() {
1766+
called = true;
1767+
expect(this.data).toEqual(data);
1768+
});
1769+
});
1770+
inject(function($controller, $rootScope) {
1771+
$controller('testCtrl', { scope: $rootScope }, { data: data });
1772+
expect(called).toBe(true);
1773+
});
1774+
});
1775+
});
17541776
});
17551777

17561778

0 commit comments

Comments
 (0)