I am trying to make a small test work that validates wether the controller is defined.
The error I am receiving is:
myApp.orders module Order controller should .... FAILED
Error: [$injector:unpr] Unknown provider: $scopeProvider <- $scope <- OrdersCtrl
Reading similar errors it has something to do with the dependencies, but I don't know what's wrong.
Controller:
'use strict';
angular.module('myApp.orders', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/orders', {
templateUrl: 'orders/orders.template.html',
controller: 'OrdersCtrl'
});
}])
.controller('OrdersCtrl', function($scope, $location) {
$scope.changeView = function(view){
$location.path(view); // path not hash
}
});
Test:
'use strict';
describe('myApp.orders module', function() {
beforeEach(module('myApp.orders'));
describe('Order controller', function(){
it('should ....', inject(function($controller) {
//spec body
var OrdersCtrl = $controller('OrdersCtrl');
expect(OrdersCtrl).toBeDefined();
}));
});
});
This is because you are not passing the $scope variabl einside the controller when you are creating it in test. And the controller tries to define $scope.changeView, but it finds $scope as undefined.
You need to pass a $scope variable to the controller in your test.
var $rootScope, $scope, $controller;
beforeEach(function() {
module('myApp.orders');
inject(function (_$rootScope_, _$controller_) {
$rootScope = _$rootScope_;
$scope = _$rootScope_.$new();
$controller = _$controller_;
});
});
and in your test,
var OrdersCtrl = $controller('OrdersCtrl', { $scope: $scope });
Restructure your unit test slightly. We have a pattern where the controller is defined in the beforeEach() so it's ready for the test. You also need to import the controller you're testing:
import ControllerToTest from 'path/to/your/real/controller';
describe('myApp.orders module',() => {
let vm;
beforeEach(() => {
inject(($controller, $rootScope) => {
vm = $controller(ControllerToTest,
{
$scope: $rootScope.$new()
};
});
});
describe('Order Controller', () => {
it('should do something', () => {
expect(vm).toBeDefined();
});
});
});
Chaneg your controller like this
.controller('OrdersCtrl',['$scope', '$location', function($scope, $location) {
$scope.changeView = function(view){
$location.path(view); // path not hash
}
}]);
Related
I make one controller in Angularjs and try to test that controller using Jasmine. I got this error Cannot read property 'message' of undefined why ?
Here is my code.
controller
(function(){
'use strict';
angular.module('app.home').controller('homeCntrl',homeCntrl);
function homeCntrl(){
var home=this;
home.clickbtn=function(){
home.message='test';
alert(home.message)
}
}
})();
Testing
(function(){
'use strict';
describe('http controller test', function() {
var $rootScope,
$scope,
controller,
$q,
$httpBackend;
beforeEach(function() {
module('app');
inject(function($injector) {
$rootScope = $injector.get('$rootScope');
$scope = $rootScope.$new();
controller = $injector.get('$controller')('homeCntrl', {
$scope: $scope
})
})
})
describe('Init value', function() {
it('check name value', function() {
expect(controller.message).toBeUndefined();
})
})
it('it should be true', function() {
expect(true).toBeTruthy();
})
})
})();
any update ?durning testing I got this error .. ? can we do testing of this controller ?Every thing is fine on angular js code problem is on test code..only check appspec.js
Just an hint
app
(function() {
'use strict';
function HomeController() {
var home = this;
home.title = 'Home';
}
angular.module('home.controllers', [])
.controller('HomeController', HomeController);
})();
test
'use strict';
describe('home controller', function() {
var $controller;
var scope;
beforeEach(module('home.controllers'));
beforeEach(inject(function(_$controller_, $rootScope) {
$controller = _$controller_;
scope = $rootScope.$new();
$controller('HomeController as home', {$scope: scope});
}));
it('should have text = "Home"', function() {
expect(scope.home.title).toEqual('Home');
});
});
in your case the test should be like
scope.home.clickbtn();
expect(scope.home.message).toEqual('test');
Take a look at http://www.bradoncode.com/tutorials/angularjs-unit-testing/ to master unit test in angular
I try to write a controller test using karma with jasmine.
I get this error "Error: [$injector:unpr] Unknown SettingsProvider <- settings"
I been stuck for hours googling around but I can't found a solution for this.
My test Case
describe('MyController', function() {
var $scope, controller;
beforeEach(module('MyApp'));
beforeEach(inject(function ($rootScope, $controller) {
$scope = $rootScope.$new();
controller = $controller('MyController', {
$scope: $scope
});
}));
it('sets the options to "valid" if the type is val', function() {
var type = 'val';
$scope.callOptions(type);
expect($scope.options).toBeTruthy();
});
});
My karma.config.js
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/jquery/dist/jquery.min.js',
'app/node_modules/angular-mocks/angular-mocks.js',
'app/bower_components/angular-resource/angular-resource.js',
'app/bower_components/angular-ui-router/release/angular-ui-router.js',
'app/bower_components/angular-ui-router/release/angular-ui-router.min.js',
'app/metronic/assets/global/plugins/angularjs/plugins/angular-ui-router.min.js',
'app/bower_components/ui-router-extras/release/modular/ct-ui-router-extras.sticky.js',
'app/bower_components/ngDraggable/ngDraggable.js',
'app/metronic/assets/global/plugins/angularjs/angular-sanitize.min.js',
'app/metronic/assets/global/plugins/jquery.min.js',
'app/metronic/assets/global/plugins/bootstrap/js/bootstrap.min.js',
'app/metronic/assets/global/plugins/angularjs/plugins/ui-bootstrap-tpls.min.js',
'app/bower_components/ngstorage/ngStorage.min.js',
'app/bower_components/oclazyload/dist/ocLazyLoad.min.js',
'app/metronic/assets/global/plugins/angularjs/plugins/angular-file-upload/angular-file-upload.min.js',
'app/js/services/myProvider.js',
'app/js/app.js',
'app/controllers/MyController.js'
]
My controller :
MetronicApp.controller('MyController',
['$http',
'$rootScope',
'$scope',
'$window',
function ($http, $rootScope, $scope, $window) {
$scope.callOptions = function (type) {
if (type == 'val') {
return $scope.optionsVal;
}
;
if (type == 'Num') {
return $scope.optionsNum;
}
;
};
});
EDIT
I delete some file from my karma.config.js and now I get this error $scope is undefined ..This is a screen shot of the error :
I think the way you injected $rootScope and $controller is incorrect.Please try following code snippet.It will do the thing.
describe('MyController', function() {
var $scope, controller;
beforeEach(module('MyApp'));
beforeEach(inject(function ($injector) {
$scope = $injector.get("$rootScope").$new();
controller = $injector.get("$controller")('MyController', {
$scope: $scope
});
}));
it('sets the options to "valid" if the type is val', function() {
var type = 'val';
$scope.callOptions(type);
expect($scope.options).toBeTruthy();
});
});
I'm having issues attempting to use the $scope service in my controller. The controller is basically taken from the angular-seed project.
'use strict';
angular.module('regApp.nameAddress', ['ngRoute'])
.config([
'$routeProvider', function($routeProvider) {
$routeProvider.when('/nameAddress', {
templateUrl: 'views/NameAddress.html',
controller: 'NameAddressController'
});
}
])
.controller('NameAddressController', ['$scope',
function($scope) {
$scope.x = 1;
}
]);
Here's the Jasmine test code I'm using:
'use strict';
describe('regApp.nameAddress module', function() {
beforeEach(function() { module('regApp.nameAddress') });
describe('Name and Address Controller', function () {
var scope;
var httpBackend;
beforeEach(inject(function ($rootScope, $controller, $injector) {
scope = $rootScope.$new();
httpBackend = $injector.get("$httpBackend");
$controller("NameAddressController", {
$scope: scope
});
}));
it('should exist', inject(function($controller) {
//spec body
var sut = $controller("NameAddressController");
expect(sut).toBeDefined();
}));
});
});
And when I run the test here is the error and stack trace I'm getting:
15 specs, 1 failure Spec List | Failures
regApp.nameAddress module Name and Address Controller should exist
Error: [$injector:unpr] Unknown provider: $scopeProvider <- $scope
http://errors.angularjs.org/1.2.28/$injector/unpr?p0=%24scopeProvider%20%3C-%20%24scope
Error: [$injector:unpr] Unknown provider: $scopeProvider <- $scope
http://errors.angularjs.org/1.2.28/$injector/unpr?p0=%24scopeProvider%20%3C-%20%24scope
at Anonymous function (http://localhost:30489/js/lib/angular/angular.js:3801:13)
at getService (http://localhost:30489/js/lib/angular/angular.js:3929:11)
at Anonymous function (http://localhost:30489/js/lib/angular/angular.js:3806:13)
at getService (http://localhost:30489/js/lib/angular/angular.js:3929:11)
at invoke (http://localhost:30489/js/lib/angular/angular.js:3953:9)
at instantiate (http://localhost:30489/js/lib/angular/angular.js:3976:7)
at Anonymous function (http://localhost:30489/js/lib/angular/angular.js:7315:7)
at Anonymous function (http://localhost:30489/specs/NameAddressController_tests.js:25:13)
at invoke (http://localhost:30489/js/lib/angular/angular.js:3965:7)
at workFn (http://localhost:30489/js/lib/angular-mocks/angular-mocks.js:2177:11)
undefined
It has to be like this (you miss the $scope parameter in your second call to $controller):
'use strict';
describe('regApp.nameAddress module', function() {
var sut;
beforeEach(function() { module('regApp.nameAddress') });
describe('Name and Address Controller', function () {
var scope;
var httpBackend;
beforeEach(inject(function ($rootScope, $controller, $injector) {
scope = $rootScope.$new();
httpBackend = $injector.get("$httpBackend");
sut = $controller("NameAddressController", {
$scope: scope
});
}));
it('should exist', inject(function($controller) {
//spec body
expect(sut).toBeDefined();
}));
});
});
In your test, you're instantiating the controller without passing it a $scope:
$controller("NameAddressController");
That is not allowed. $scope is not an injectable service. It must be created and passed explicitely to the controller, as you're doing in your beforeEach() function.
I have this controller:
angular.module('clientApp')
.controller('MainCtrl', function ($scope, projects) {
$scope.projects = projects;
});
projects is a resolve from a database. It works in the view.
This is my service:
angular.module('clientApp.services', ['ngResource'])
.factory('Projects', function($resource){
return $resource('/api/project/:prj_id', {'prj_id':'#prj_id'});
})
.factory('MultiProjectsLoader',['Projects', '$q', '$stateParams',
function(Projects, $q) {
return function() {
var delay = $q.defer();
Projects.query(function(projects) {
delay.resolve(projects);
}, function() {
delay.reject('Unable to fetch sizes');
});
return delay.promise;
};
}
]);
And this is my app.js
$stateProvider
.state('home', {
url: '/',
templateUrl: 'views/home.html',
resolve:{
projects: ['MultiProjectsLoader', function(MultiProjectsLoader){
return new MultiProjectsLoader();
}]
},
controller: 'MainCtrl'
});
Trying to write a test for this:
'use strict';
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('clientApp'));
beforeEach(function () {
angular.module('clientApp.services');
});
var MainCtrl,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope
});
}));
it('should attach a list of projects to the scope', function () {
expect(scope.projects.length).toBeGreaterThan(1);
});
});
I get:
Error: [$injector:unpr] Unknown provider: projectsProvider <- projects
I guess I need to include the service somehow beforeEach(..). But I can't get it working. Any ideas?
You can inject the service a couple ways but my recommended way is to mock the service.
describe('Controller: MainCtrl', function () {
var
projectServiceMock = {
getData: function() {}
},
DATA_FROM_SERVER = {}
;
// load the controller's module
beforeEach(module('clientApp'));
beforeEach(function () {
angular.module('clientApp.services');
//angular.module('project'); // But dont use this method as you will be testing the service in the controller:
});
var MainCtrl,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
spyOn(projectServiceMock, 'getData').andReturn(DATA_FROM_SERVER);
MainCtrl = $controller('MainCtrl', {
$scope: scope,
project: projectServiceMock
});
}));
it('should attach a list of projects to the scope', function () {
expect(projectServiceMock.getData).toHaveBeenCalledWith(DATA_FROM_SERVER);
expect(scope.projects.length).toBeGreaterThan(1);
});
});
Your service should expose a method for returning the data it has gotten from the server not just straight data through project.
For example:
project.getData();
I have this simple controller, UserService is a service which return JSON
"use strict";
angular.module("controllers").controller('profileCtrl', ["$scope", "UserService",
function ($scope, UserService) {
$scope.current_user = UserService.details(0);
}
]);
I can not make the test. However this is my try
'use strict';
describe('profileCtrl', function () {
var scope, ctrl;
beforeEach(angular.mock.module('controllers'), function($provide){
$provide.value("UserService", {
details: function(num) { return "sdfsdf"; }
});
});
it('should have a LoginCtrl controller', function() {
expect(controllers.profileCtrl).toBeDefined();
});
beforeEach(angular.mock.inject(function($rootScope, $controller){
scope = $rootScope.$new();
$controller('profileCtrl', {$scope: scope});
}));
it('should fetch list of users', function(){
expect(controllers.scope.current_user.length).toBe(6);
expect(controllers.scope.current_user).toBe('sdfsdf');
});
});
The usage of $controller is correct, that's the way to instantiate a controller for a unit test. You can mock the UserService instance it gets directly in the $controller invocation.
You should be using its return value - this is the instance of your controller you're going to test.
You're trying to read stuff from controllers but its not defined anywhere in the test, I guess you're referring to the module.
This is how I would go about it + fiddle
//--- CODE --------------------------
angular.module('controllers', []).controller('profileCtrl', ["$scope", "UserService",
function ($scope, UserService) {
$scope.current_user = UserService.details(0);
}]);
// --- SPECS -------------------------
describe('profileCtrl', function () {
var scope, ctrl, userServiceMock;
beforeEach(function () {
userServiceMock = jasmine.createSpyObj('UserService', ['details']);
userServiceMock.details.andReturn('sdfsdf');
angular.mock.module('controllers');
angular.mock.inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
ctrl = $controller('profileCtrl', {
$scope: scope,
UserService: userServiceMock
});
});
});
it('should have a LoginCtrl controller', function () {
expect(ctrl).toBeDefined();
});
it('should fetch list of users', function () {
expect(scope.current_user).toBe('sdfsdf');
});
});
You're welcome to change the fiddle online to see how it affects testing results.