Skip to content

Commit

Permalink
feat(ngMock): allow mock $controller service to set up controller bin…
Browse files Browse the repository at this point in the history
…dings

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 angular#9425
  • Loading branch information
caitp committed Mar 4, 2015
1 parent 4374f89 commit 94606d8
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
39 changes: 39 additions & 0 deletions src/ngMock/angular-mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}]);

/**
Expand Down
22 changes: 22 additions & 0 deletions test/ngMock/angular-mocksSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});
});


Expand Down

0 comments on commit 94606d8

Please sign in to comment.