Reputation: 1480
I met a problem with testing my controllers. I load them dynamically (lazy load, see after) so I wrote them like this :
angular.module('myApp').controllerProvider.register('DashboardCtrl', [
'$scope', function ($scope) {
$scope.foo = 'bar';
}
]);
I initialise my module like this :
var app = angular.module('myApp', [
'ngRoute',
'ngCookies',
'ngResource',
'ngSanitize',
'ui.router'
]);
app.run([
'$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}
]);
app.config(function ($stateProvider, $urlRouterProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
app.stateProvider = $stateProvider;
app.routeProvider = $urlRouterProvider;
app.controllerProvider = $controllerProvider;
app.compileProvider = $compileProvider;
app.filterProvider = $filterProvider;
app.provide = $provide;
$urlRouterProvider.otherwise('/');
$stateProvider
.state('dashboard', {
url : '/',
templateUrl : 'views/dashboard.html',
controller : 'DashboardCtrl',
resolve : {
deps : function ($q, $rootScope) {
var deferred = $q.defer();
curl('scripts/controllers/dashboard.js')
.then(function () {
$rootScope.$apply(function () {
deferred.resolve({});
});
});
return deferred.promise;
}
}
});
});
That works. Method is described there : http://ify.io/lazy-loading-in-angularjs/
But when I want to test, I get each time the error : Error: [ng:areq] Argument 'DashboardCtrl' is not a function, got undefined
My test script :
describe('Controller: DashboardCtrl', function () {
'use strict';
var DashboardCtrl,
scope;
// load the controller's module
beforeEach(function () {
var app = angular.module('cellierApp', [
'ngRoute',
'ngCookies',
'ngResource',
'ngSanitize',
'ui.router'
]);
app.run([
'$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}
]);
app.config(function ($stateProvider, $urlRouterProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
app.stateProvider = $stateProvider;
app.routeProvider = $urlRouterProvider;
app.controllerProvider = $controllerProvider;
app.compileProvider = $compileProvider;
app.filterProvider = $filterProvider;
app.provide = $provide;
});
inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
DashboardCtrl = $controller('DashboardCtrl', {
$scope : scope
});
});
});
it('should attach a list of awesomeThings to the scope', function () {
expect(scope.foo).toBeDefined();
expect(scope.foo).toBe('bar');
});
});
I don't know what I'm doing wrong. Is there someone who knows ? Thanks in advance
Upvotes: 0
Views: 3003
Reputation: 3392
I'm not sure whether Karma has support for Script.js loading, but for sure it has support for Require.js.
Since you followed that tutorial, have you checked out the final example he gave on github (It contains unit testing as well)? The idea is that you can convert everything to use Require.js instead of Script.js and use Karma with karma-requirejs for the testing.
Although it is not too difficult, there are quite a lot of changes. I won't post the working code here, but I would suggest reading the following: http://ify.io/unit-testing-lazily-loaded-angularjs-artefacts/ and http://karma-runner.github.io/0.8/plus/RequireJS.html
I can't link the final example because I don't have the reputation, but it's at the bottom of the tutorial you've linked.
To see a runnable example using Asynchronous Module Definitions with RequireJS, have a look at the sample app."
Upvotes: 2
Reputation: 10256
You don't load modules, but override the angular modules in this snippet:
var app = angular.module('cellierApp', [
'ngRoute',
'ngCookies',
'ngResource',
'ngSanitize',
'ui.router'
]);
The proper call would be
beforeEach(function() {
// the module to be tested
module('cellierApp');
});
Also, the var declaration of the app is very crappy imo. You have angular as a container, use it, don't create objects on global closure for no reason. Change this:
var app = angular.module('myApp', [
'ngRoute',
'ngCookies',
'ngResource',
'ngSanitize',
'ui.router'
]);
app.run...
To:
angular.module('myApp', [
'ngRoute',
'ngCookies',
'ngResource',
'ngSanitize',
'ui.router'
])
.config([...
.run([....
The unit test itself can be simplified so much:
describe('Controller: DashboardCtrl', function() {
'use strict';
var scope;
// load the controller's module
beforeEach(function() {
module('cellierApp');
});
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
$controller('DashboardCtrl', {
$scope: scope
});
}));
it('should attach a list of awesomeThings to the scope', function() {
expect(scope.foo).toBeDefined();
expect(scope.foo).toBe('bar');
});
});
Upvotes: 1
Reputation: 186
In your test you are not registering your controller
put your code for creating you controller in your test
app.controllerProvider.register('DashboardCtrl', [
'$scope', function ($scope) {
$scope.foo = 'bar';
}
]);
however depending on your test setup your app and controller files should be loaded through your test system and you should use
beforeEach(module('cellierApp'));
instead of creating your app directly in your test
Upvotes: 0