AngularJS Unknown provider: $scopeProvider - angularjs

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.

Related

TypeError: undefined is not a constructor (evaluating 'angular.controller('myView')')

I'm getting the below error while doing karma/jasmine unit testing for both the test cases.I tried by modifying the controller by adding angular.controller in the spec file even then it is not working.Is there any way to fix?
TypeError: undefined is not a constructor (evaluating 'angular.controller('myView')')
myView.spec.js
// myView.spec.js
(function(){
describe('controller: myView', function(){
var module,myView,$q, $rootScope, $scope, uiGridConstants, overviewService, commonService, $timeout;
beforeEach(function() {
module = angular.module('app.myView');
controller= angular.controller('myView')
});
beforeEach(inject(function ($controller, _$q_, _$rootScope_, _$timeout_) {
$q= _$q_;
$rootScope = _$rootScope_;
$timeout= _$timeout_;
myView= $controller('myView', {
$q : _$q_,
$rootScope : _$rootScope_,
$timeout: _$timeout_
});
}));
describe("myViewto be defined", function() {
it("should be created successfully", function () {
expect(controller).toBeDefined();
});
it("overview should be defined", function () {
expect(myView()).toBeDefined();
});
});
});
})();
and myView.js
(function() {
'use strict';
angular
.module('app.myView')
.controller('myView', myView);
function myView($q, $rootScope, $scope, uiGridConstants, myViewService, commonService, $timeout) {
var vm = this;
vm.callFeedback = function () { };
})();
Sharing following code
// myView.spec.js
(function(){
describe('myView', function(){
var $controller, myView;
//we use angular-mocks to specify which modules we'll need within this
//test file.
beforeEach(angular.mock.module('app.myView'));
// Inject the $controller service to create instances of the controller
//(myView) we want to test
beforeEach(inject(function(_$controller_) {
$controller = _$controller_;
myView = $controller('myView', {});
}));
// Verify our controller exists
it('should be defined', function() {
expect(myView).toBeDefined();
});
});
})();
We set _$controller_to the $controller variable we created and then create an instance of our controller by calling $controller('myView', {}). The first argument is the name of the controller we want to test and the second argument is an object of the dependencies for our controller.
You should pass the injected parameters to your controller as shown:
(function() {
'use strict';
angular
.module('app.myView')
.controller($q,$rootScope,$scope,uiGridConstants,'myView', myView);
function myView($q, $rootScope, $scope, uiGridConstants, myViewService, commonService, $timeout) {
var vm = this;
vm.callFeedback = function () { };
})();
Also make sure that your module has all the necesary dependences in the angular.module('app.myView',['uiGridConstants', ...'etc']);

Unknown provider: $scopeProvider <- $scope

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
}
}]);

How to check if a function is available in instantiated controller for unit testing in Jasmine

I am trying to unittest a controller in AngularJS for the first time. I want to test if the login-function in this controller calls the right service but I get the error, that the function doesn't exist in the controller. What did I do wrong? Do I have to mock more? But I shouldn't have to mock the functions in the controller to be tested because if I would do that the whole testing would be senseless, or am I wrong?
Controller-Snippet:
function LoginController($scope, $state, myService, ngToast) {
$scope.loginUser = loginUser;
activate();
function activate() {}
function loginUser(credentials) {
myService.authenticate(/*things*/);
}
}
Test-Code:
describe('Login Controller', function () {
'use strict';
//globals
var controller, scope;
var $controller, $state, myService, ngToast;
//needed modules
beforeEach(module('app.login'));
beforeEach(module('app.core'));
beforeEach(module('ui.router'));
//instanciate Controller
beforeEach(inject(function (_$controller_, _$state_, _myService_, _ngToast_) {
scope = {};
$state = _$state_;
myService = _myService_;
ngToast = _ngToast_;
$controller = _$controller_;
controller = $controller('LoginCtrl', {
$scope: scope,
$state: $state,
myService: myService,
ngToast: ngToast
});
}));
it('should have an existing controller', function () {
expect(controller).toBeDefined();
});
/*************************** unit-tests ***************************/
describe('.loginUser()', function () {
it('should exist', function () {
expect(controller.loginUser).toBeDefined();
});
});
});
The Error I am getting when running karma start:
.loginUser()
✗ should exist
TypeError: controller.loginUser is not a function
at Object.<anonymous> (src/login/login.controller.spec.js:74:31)
But it seems to me that the controller does exist, because this test doesn't fail:
Login Controller
✓ should have an existing controller
it is because loginUser is defined on $scope and not on the controller so loginUser is not bound to your controller object in your test.
To test loginUser please do the following:
Inject $rootScope in your beforeEach
Set scope = $rootScope.$new()
The controller should be created with this scope
Your test should check if loginUser is defined on the scope
describe('Login Controller', function () {
'use strict';
//globals
var controller, scope;
var $controller, $state, myService, ngToast;
//needed modules
beforeEach(module('app.login'));
beforeEach(module('app.core'));
beforeEach(module('ui.router'));
//instanciate Controller
beforeEach(inject(function (_$controller_, _$state_, _myService_, _ngToast_, _$rootScope_) {
scope = _$rootScope_.$new();
$state = _$state_;
myService = _myService_;
ngToast = _ngToast_;
$controller = _$controller_;
controller = $controller('LoginCtrl', {
$scope: scope,
$state: $state,
myService: myService,
ngToast: ngToast
});
}));
it('should have an existing controller', function () {
expect(controller).toBeDefined();
});
/*************************** unit-tests ***************************/
describe('.loginUser()', function () {
it('should exist', function () {
expect(scope.loginUser).toBeDefined();
});
});
});
If you want to test loginUser on the controller itself then make use of the controller as syntax where you would set this.loginUser = loginUser instead of $scope.loginUser = loginUser. Then you will be able to use controller.loginUser in your test.

why the message property is undefined?

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

Unit test of controller angularjs

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.

Resources