whenDELETE : undefined is not a function - angularjs

Here is what I am doing :
controller.js
var app = angular.module('app', [ 'angularFileUpload' ]);
app.controller('MyCtrl', [ '$scope', '$http', '$timeout', '$upload',
function($scope, $http, $timeout, $upload) {
$scope.something;
$scope.deleteFile = function(fileId) {
$http({
method : 'DELETE',
url : "http://xxx.xxx.xx.xx:8080/fileId
}).success(function(response) {
scope.something=response;
console.log(response);
});
});
controllerspec.js
ddescribe("MyCtrl test cases ",function(){
var scope , controller ,httpBackend;
beforeEach(angular.mock.module('app'));
beforeEach(angular.mock.inject(function($rootScope,$controller,$http, $timeout, $upload){
scope = $rootScope.$new();
httpBackend = $http;
$controller('MyCtrl',{
$scope:scope,
$http:httpBackend,
$timeout:$timeout,
$upload:$upload
});
}));
it("should delete selected file ",function(){
/*HERE*/ httpBackend.when('DELETE','http://xxx.xxx.xx.xx:8080/1').respond
({
"deleted"
});
httpBackend.flush();
scope.deleteFile(1);
expect(scope.something).toBeDefined();
});
I get TypeError: Undefined is not a function at line "HERE".
What am I missing ?

You have error in your code because of following piece of code
Instead of
beforeEach(angular.mock.inject(function($rootScope,$controller,$http, $timeout, $upload){
scope = $rootScope.$new();
httpBackend = $http;
$controller('MyCtrl',{
$scope:scope,
$http:httpBackend,
$timeout:$timeout,
$upload:$upload
});
use
beforeEach(angular.mock.inject(function($rootScope,$controller,$httpBackend, $timeout, $upload){
scope = $rootScope.$new();
httpBackend = $httpBackend;
$controller('MyCtrl',{
$scope:scope,
$timeout:$timeout,
$upload:$upload
});
$httpBackend is used for mocking http requests, no need to inject it inside controller, instead you may inject $http service. Also you had error as you didn't injected httpBackend service and were trying to use its function that why you got undefined error.

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

Error: Injector already created, can not register a module

I am trying to test if window.location is set to a specific URL by end of the method, but I get this error:
Error: Injector already created, can not register a module!
The code:
describe('Home controller', function() {
var $controller, $location, $window, $http, $timeout, $filter, $scope, $resource;
beforeEach(module('app', function($provide) {
$provide.value('$window', {
location: {
href: ''
}
});
}));
beforeEach(inject(function(_$controller_, _$location_, _$window_, _$rootScope_, _$http_,
_$resource_, _$timeout_, _$filter_) {
$controller = _$controller_;
$location = _$location_;
$window = _$window_;
$http = _$http_;
$timeout = _$timeout_;
$filter = _$filter_;
$scope = _$rootScope_.$new();
}));
it('check Home Ctrl', inject(function($rootScope, $httpBackend, API_URL) {
var ctrlInstance = $controller('HomeCtrl', {
$scope: $scope,
$rootScope: $rootScope,
$http: $http,
$resource: $resource,
$location: $location,
$window: $window,
$timeout: $timeout,
API_URL: API_URL
});
$scope.goEditUser({
userId: 2
});
expect($window.location.href).toContain('/switch-user/2');
}));
});
Why am I getting the error even when inject is called after module?
You can try to use single inject method :
var ctrlInstance;
beforeEach(module('app');
beforeEach(module(function($provide) {...})
and something like this
it('check Home Ctrl', inject(function($controller, _$location_, _$window_, _$rootScope_, _$http_, _$resource_, _$timeout_, _$filter_) {
var ctrlInstance = $controller('HomeCtrl', {
$location : _$location_,
$window : _$window_,
$http : _$http_,
$timeout : _$timeout_,
$filter : _$filter_,
$scope : _$rootScope_.$new(),
$rootScope: _$rootScope_,
$resource: _$resource_,
API_URL: API_URL
});
$scope.goEditUser({
userId: 2
});
expect($window.location.href).toContain('/switch-user/2');
}));

Mocking $location service in angular unit test

I am new to developing in angular, and am trying to learn how to test angular controllers. The controller I am testing uses $location.seach().something. I looked at the docs for $location, but don't quickly see how I am supposed to mock this in karma/jasmine.
The controller:
rmtg.controller('ErrorCtrl', ['Session', '$location', '$routeParams', '$scope', '$window',
function(Session, $location, $routeParams, $scope, $window) {
console.log('ErrorCtrl(%o, %o, %o)', $location.path(), $location.search(), $routeParams);
$scope.status = $location.search().status;
$scope.message = $location.search().message;
$scope.isAuthorized = (typeof(Session.auth) === 'object');
$scope.signin = function() {
$window.location = '/signin/#/' + $routeParams.origin + (Session.auth ? '?email=' + Session.auth.email : '');
};
}]);
My current spec attempt:
'user strict';
describe('Testing the errorCtrl controller', function(){
beforeEach(module("rmtg"));
var errorCtrl, scope;
beforeEach(inject(function($controller, $rootScope){
scope = $rootScope;
errorCtrl = $controller("ErrorCtrl", {
$scope: scope
});
}));
it('$scope.status should be set to 404 when location is set to 404', function(){
//set the $location.search values so that the scope is correct
$location.search('status', '404');
expect(scope.status).toBe('404');
});
});
And the current error message:
Testing the errorCtrl controller $scope.status should be set to 404 when location is set to 404 FAILED
Expected undefined to be '404'.
at Object. (/Users/adamremeeting/git/mrp-www/app/tests/example.js:20:24)
I'd also really appreciate links to resources on tdd with angular 1.5 and how I mock and stub correctly.
Edit After Answer
So I updated the test as per user2341963 suggestions, and did my best to look through his plunker example, but still don't have a passing test.
the current spec (controller has not changed from above)
'user strict';
describe('ErrorCtrl', function(){
beforeEach(module("rmtg"));
var scope, $location, $controller;
beforeEach(inject(function(_$controller_, _$rootScope_, _$location_){
scope = _$rootScope_.$new();
$location = _$location_
$controller = $_controller_;
}));
describe('$scope.status', function(){
it('should set status to 404', function(){
//set the $location.search values so that the scope is correct
$location.search('status', '404');
//init controller
$controller('ErrorCtrl', {
$scope: scope,
$location: $location
});
expect(scope.status).toBe('404');
});
});
});
But I am getting an error now that $controller is not defined.
You are getting undefined in your test because you are not setting $location anywhere.
Based on your controller, the search parameters must be set before the controller is initialised. See plunker for full example.
describe('testApp', function() {
describe('MainCtrl', function() {
var scope, $location, $controller;
beforeEach(module('myApp'));
beforeEach(inject(function(_$rootScope_, _$controller_, _$location_) {
scope = _$rootScope_.$new();
$location = _$location_;
$controller = _$controller_;
}));
it('should set status to 404', function() {
// Set the status first ...
$location.search('status', '404');
// Then initialise the controller
$controller('MainCtrl', {
$scope: scope,
$location: $location
});
expect(scope.status).toBe('404');
});
});
});
As for resources, so far I've found the angular docs are good enough.

jasmine test $scope is undefinded

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

AngularJs Testing Sinon spy

I am new with Sinon so I wanted to check whether a specific function is being called, this is what I got:
terminalController.controller('CashAcceptorController', [
'PaymentService',
'$rootScope',
'$scope',
'PayingInfo',
'$interval',
'$location',
function (PaymentService, $rootScope, $scope, PayingInfo, $interval, $location) {
PaymentService.start();
....
]);
In tests, I try to check that PaymentService.start() is called on controller instantiation:
describe('CashAcceptorController', function() {
var PaymentService, rootScope, scope, PayingInfo, $interval, $location;
var mySpy = sinon.spy(PaymentService.start());;
beforeEach(module('eshtaPayTerminalApp.controllers'));
beforeEach(module('eshtaPayTerminalApp.services'));
beforeEach(inject(function($controller,
$rootScope, _PaymentService_, _$interval_, _PayingInfo_) {
$interval = _$interval_;
scope = $rootScope.$new();
rootScope = $rootScope.$new();
PaymentService = _PaymentService_;
PayingInfo = _PayingInfo_;
rootScope.serviceNumber = 'm1';
rootScope.phoneNumber = '05135309';
$controller('CashAcceptorController', {
$rootScope : rootScope,
$scope : scope,
$location : $location,
_PaymentService_ : PaymentService,
_$interval_:$interval,
_PayingInfo_:PayingInfo
});
}));
it('should call start paying', function() {
expect(mySpy.callCount).to.equal(1);
});
But this assertion fails. What am I doing wrong? Help please :)
There's a couple of issues with your code
The PaymentService object needs to be assigned before you can spy on it
To add a spy with sinon you need pass the method name as a string eg. sinon.spy(PaymentService, 'start');
I've created a working plunk of the above at http://plnkr.co/edit/AvqS3L?p=preview
Here's the updated test code:
describe('CashAcceptorController', function() {
var PaymentService;
var $controller;
beforeEach(module('eshtaPayTerminalApp.controllers'));
beforeEach(module('eshtaPayTerminalApp.services'));
beforeEach(inject(function(_PaymentService_, _$controller_) {
PaymentService = _PaymentService_;
$controller = _$controller_;
}));
it('should call start paying', function() {
var mySpy = sinon.spy(PaymentService, 'start');
$controller('CashAcceptorController', { PaymentService: PaymentService });
chai.expect(mySpy.callCount).to.equal(1);
// another way of checking that it was called once
chai.assert(PaymentService.start.calledOnce);
});
});

Resources