New to Jasmine tests for angular. I am trying to test if the controller I defined is defined or not to begin with but I am getting error saying Expected undefined to be defined.
Here is my main code:
// controller logic MatchController.js
(function () {
'use strict';
angular.module('app.match')
.controller('MatchController', MatchController);
MatchController.$inject = ['APP_CONFIG', '$authUser', '$http', '$rootScope', '$state', '$stateParams', 'SearchService', 'ConfirmMatchService', 'MusicOpsService', 'ContentOpsService', 'MatchstickService', 'MatchService', 'Restangular'];
function MatchController(APP_CONFIG, $authUser, $http, $rootScope, $state, $stateParams, searchService, confirmMatchService, musicOpsService, contentOpsService, matchstickService, matchService, Restangular) {
var vm = this;
.
.
.
}
})();
Here is the test file
// MatchController.spec.js
(function(){
'use strict';
describe('Match Controller Tests', function(){
var module, MatchTestController;
beforeEach(function() {
module = angular.module('app.match');
});
beforeEach(inject(function ($controller) {
MatchTestController = $controller('MatchController', {});
}));
describe("Match controller to be defined", function() {
it("should be created successfully", function () {
expect(MatchTestController).toBeDefined();
});
});
});
})();
I keep getting the error:
TypeError: 'undefined' is not a function (evaluating 'angular.controller('MatchController')')
undefined
at /Users/rgoti/match-ui/match-ui/public/src/app/match/match.controller.spec.js:16
at invoke (/Users/rgoti/match-ui/match-ui/public/bower_components/angular/angular.js:4219)
at workFn (/Users/rgoti/match-ui/match-ui/public/bower_components/angular-mocks/angular-mocks.js:2475)
Expected undefined to be defined.
at /Users/rgoti/match-ui/match-ui/public/src/app/match/match.controller.spec.js:22
Not sure what I am doing wrong here.
You should inject all the dependencies in the controller first before mocking it.
Try this:
// MatchController.spec.js
(function(){
'use strict';
describe('controller: MatchController', function(){
var module, MatchController, APP_CONFIG, $authUser, $http, $rootScope, $state, $stateParams, SearchService, ConfirmMatchService, MusicOpsService, ContentOpsService, MatchstickService, MatchService, Restangular;
beforeEach(function() {
module = angular.module('app.match');
});
beforeEach(inject(function ($controller, _APP_CONFIG_, _$authUser_, _$http_, _$rootScope_, _$state_, _$stateParams_, _SearchService_, _ConfirmMatchService_, _MusicOpsService_, _ContentOpsService_, _MatchstickService_, _MatchService_, _Restangular_) {
APP_CONFIG = _APP_CONFIG_;
$authUser = _$authUser_;
$http = _$http_;
$rootScope = _$rootScope_;
$state = _$state_;
$stateParams = _$stateParams_;
SearchService = _SearchService_;
ConfirmMatchService = _ConfirmMatchService_;
MusicOpsService = _MusicOpsService_;
ContentOpsService = _ContentOpsService_;
MatchstickService = _MatchstickService_;
MatchService = _MatchService_;
Restangular = _Restangular_;
MatchController = $controller('MatchController', {
APP_CONFIG: _APP_CONFIG_,
$authUser: _$authUser_,
$http: _$http_,
$rootScope: _$rootScope_,
$state: _$state_,
$stateParams: _$stateParams_,
SearchService: _SearchService_,
ConfirmMatchService: _ConfirmMatchService_,
MusicOpsService: _MusicOpsService_,
ContentOpsService: _ContentOpsService_,
MatchstickService: _MatchstickService_,
MatchService: _MatchService_,
Restangular: _Restangular_
});
}));
describe("Match controller to be defined", function() {
it("should be created successfully", function () {
expect(MatchController).toBeDefined();
});
});
});
})();
Related
Using Jasmine and chutzpah unable to access the $scope and $rootscope inside the success of http call.
In the jasmine code the var test = $rootScope.langCode is coming as 'undefined'. Which is inside the success callback of $http from factory.
Following are the controller code need to be tested.
app.controller('catalogCtrl', ['$scope', '$rootScope', '$window', 'catalogService', '$routeParams', '$location', '$timeout', '$filter', function ($scope, $rootScope, $window, catalogService, $routeParams, $location, $timeout, $filter) {
$scope.init = function (callback, params) {
catalogService.labeldata().then(function successCallback(response) {
$rootScope.langCode = "test";
}, function errorCallback(response) {
console.log(JSON.parse(JSON.stringify(response)));
$rootScope.langCode = "test1";
});
};
}]);
Following is the Factory where am doing the http call
app.factory('catalogService', ['$http', function ($http) {
return {
labeldata: function () {
return $http({
method: 'GET',
url: "/Content/Index/"
});
}
}
}]);
Jasmine code to test catalogCtrl
describe('catalogCtrl', function () {
var httpBackend, $rootScope, $scope, createController, authRequestHandler, myservice, $controller, $q;
beforeEach(module('catalogModule'));
beforeEach(function () {
module('catalogModule');
inject(function (_$controller_, _$rootScope_, $injector, _$q_) {
// inject removes the underscores and finds the $controller Provider
$controller = _$controller_;
$rootScope = _$rootScope_;
$scope = _$rootScope_.$new();
// Injecting Service references and HttpBackend Object :-
httpBackend = $injector.get('$httpBackend');
$q = _$q_;
myserv = $injector.get('catalogService');
});
});
it('Catalog Content', function () {
var $scope = {}; var $rtScope = {};
// $controller takes an object containing a reference to the $scope
var controller = $controller('catalogCtrl', { $scope: $scope, $rtScope: $rootScope });
// the assertion checks the expected result
var obj = { "COUNTRYCODE": "au", "KEY": "MERCHANDISE", "LANGCODE": "en", "VALUE": "Merchandise" };
var arr = [obj];
var returnData = {};
returnData.data = arr;
//returnData = arr;
//httpBackend.expectGET("/Content/Index/").respond(returnData);
httpBackend.when('GET', "/Content/Index/").respond(returnData);
var returnedData;
myserv.labeldata().then(function (returnData) {
// check that returned result contains
returnedData = result;
expect(returnedData).toEqual({ bar: 'foo' });
});
$scope.init();
var test = $rootScope.langCode;
});
});
I'm trying to write test cases for a javascript method but my jasmine is not able to call the js method. It is giving me error that the function is not defined.
Below is Controller Code
(function () {
"use strict";
angular.module('rbApp').controller('PQRCtrl', PQRCtrl);
PQRCtrl.$inject = ['$scope', '$state', 'baseURL', 'PQRCtrlFactory', '$cookieStore'];
function PQRCtrl($scope, $state, baseURL, PQRCtrlFactory, $cookieStore) {
var funcB= function(){
console.log("This line should called from jasmine ")
}
}
}());
My jasmine spec
describe('PQRCtrl Controller Test Suite', function() {
var mockPQRCtrl,mockrootScope, mockscope, mockstate,mockcookies, mockstateparams, mockgetSourcePostsService, mockPQRCtrlFactory;
var baseURL = "****";
beforeEach(module('rbApp'));
beforeEach(module("ui.router"));
beforeEach(module("ngRoute"));
beforeEach(module("ngCookies"));
beforeEach(module("ui.bootstrap"));
beforeEach(module("toggle-switch"));
beforeEach(module("ngFileUpload"));
beforeEach(module("ngDraggable"));
beforeEach(module("angular-loading-bar"));
beforeEach(module("ngAnimate"));
beforeEach(module("ngGrid"));
beforeEach(module("kendo.directives"));
beforeEach(module('ui.bootstrap'));
beforeEach(inject(function($injector, _$rootScope_, _$controller_, _$httpBackend_, _$stateParams_, _$state_,_$cookieStore_,_PQRCtrlFactory_){
var userData = {'token' : 'abc'};
mockrootScope = _$rootScope_;
mockstateparams = _$stateParams_;
mockscope = mockrootScope.$new();
mockstate = _$state_;
mockcookies = _$cookieStore_;
mockPQRCtrlFactory = _PQRCtrlFactory_;
mockcookies.put('userInfo', userData);
var userInfo = mockcookies.get('userInfo');
var token = userInfo.token;
mockPQRCtrlFactory = _$controller_('PQRCtrl',
{
'$scope': mockscope,
'$state': mockstate,
'baseURL' : baseURL,
'PQRCtrlFactory': mockPQRCtrlFactory ,
'$cookieStore' : mockcookies
});
}));
it("Test: PQRCtrl Controller exists or not", function() {
expect(mockPQRCtrl).toBeDefined();
});
it("Test: funcB() Success", function() {
funcB(); // its not calling my actual function in the controller
// it is saying that its not defined
})
});
Your funcB is defined inside the controller PQRCtrl. Put it outside:
(function () {
"use strict";
var funcB;
angular.module('rbApp').controller('PQRCtrl', PQRCtrl);
PQRCtrl.$inject = ['$scope', '$state', 'baseURL', 'PQRCtrlFactory', '$cookieStore'];
function PQRCtrl($scope, $state, baseURL, PQRCtrlFactory, $cookieStore) {
funcB = function(){
console.log("This line should called from jasmine ")
}
}
If my unit test is calling function which is in controller and that function is having a service call to fetch the details. Will it call service(StationService)?
My Karma unit test is not able to inject StationService and not able to call service.
My Code.
/// controller
var policyControllers = angular.module('policyControllers', []);
policyControllers.controller('StationListController', ['$translate', '$scope','$rootScope','$state', 'StationService', 'StationListExportService', function ($translate, $scope, $rootScope, $state, StationService, StationListExportService) {
...
$scope.getFilterDetails = function(StationService, filterDetails ){
StationService.get(filterDetails).$promise.then(function (filteredDetails) {
console.log(" Web services Result - ", JSON.stringify(filteredDetails));
},function(error) {
console.log(" Error ");
});
};
///Service
var policyServices = angular.module('policyServices', ['ngResource']);
policyServices.factory('StationService', ['$resource', function($resource) {
return $resource(policyConfig.mock? 'modules/policymanager/services/mock/stations.json': 'http://10.132.240.25:7640/policy/api/v1/stationpolicy/stations',{},{
get:{method: 'POST',isArray: false, url:'modules/policymanager/services/mock/stations.json'}
});
}]);
/// Unit test
describe('station filter', function(){
var scope;
var ctrl;
var translate, scope, rootScope, state;
var StationService, StationListExportService;
beforeEach(module('policyServices'));
beforeEach(module('policyControllers'));
beforeEach(inject(function(_StationService_, _StationListExportService_, $rootScope, $controller, $translate, $state) {
StationService = _StationService_;
StationListExportService = _StationListExportService_;
translate = $translate;
rootScope = $rootScope;
state = $state;
scope = $rootScope.$new();
ctrl = $controller('StationListController', {$scope: scope});
}));
it('Stations Inject test case', inject(['StationService',function(StationService){
var data = {"recency":"","countries":[],"policies":[],"stations":[{"stationName":"Test"}],"status":"ready","regions":[]};
scope.getFilterDetails(StationService, data);
/// Getting StationService is undifiened
}]));
Try using only one application say policyServices and use the same to define the controller as well. In addition to it try defining your service before you use them in your controller.
var policyServices = angular.module('policyServices', ['ngResource']);
policyServices.factory('StationService', ['$resource', function($resource)
{
return $resource(policyConfig.mock? 'modules/policymanager/services/mock/stations.json': 'http://10.132.240.25:7640/policy/api/v1/stationpolicy/stations',{},{
get:{method: 'POST',isArray: false, url:'modules/policymanager/services/mock/stations.json'}
});
}]);
policyServices.controller('StationListController', ['$translate', '$scope','$rootScope','$state', 'StationService', 'StationListExportService', function ($translate, $scope, $rootScope, $state, StationService, StationListExportService) {
...
$scope.getFilterDetails = function(StationService, filterDetails ){
StationService.get(filterDetails).$promise.then(function (filteredDetails) {
console.log(" Web services Result - ", JSON.stringify(filteredDetails));
},function(error) {
console.log(" Error ");
});
};
In my controller I am using $resource: ng.resource.IResourceService the could help me to fetch data from the server.
controllers.controller("testController", [
"$scope", "$resource", "$rootScope", "$http",
"$window", "$location", "resourceService",
function ($scope, $resource: ng.resource.IResourceService, $rootScope: IRootScope,
$http, $window, $location, resourceService: services.IResourceService) { ...//implementation
}]);
And here is my attempt of Jasmine unit test. However, I am getting
Error: [$injector:unpr] Unknown provider: $resourceProvider <- $resource
How would you mock $resourceProvider?
describe("testController Tests", function (): void {
var vm: createDailylog.IViewModel;
var $scope: ng.IScope;
var $rootScope;
var $httpBackend: ng.IHttpBackendService;
//var $injector = angular.injector(['ng', 'ngResource']);
var $resource = $injector.get('$resource');
beforeEach(function (): void {
module("controllers");
});
beforeEach(inject(function (_$controller_: ng.IControllerService,
_$httpBackend_, _$resource_, _$rootScope_: IRootScope, $injector) {
$httpBackend = _$httpBackend_;
//$resource = _$resource_;
this.$httpBackend = $httpBackend;
$rootScope = _$rootScope_.$new();
$rootScope.config = {
serverUrl: "https://test.domainName.net/",
serverVersion: "test",
title: "Test Server Reference"
};
//instantiating controller
vm = _$controller_('testController', {
$scope: $scope,
$resource: $injector.get("$resource"),
$rootScope: _$rootScope_,
$window: {},
$location: {}
});
}));
//afterEach(function () {
// $httpBackend.verifyNoOutstandingExpectation();
// $httpBackend.verifyNoOutstandingRequest();
//});
describe('when populate method is called', function () {
it("should create controller!", function () {
$httpBackend.flush();
expect(true).toBe(true);
});
});
);
});
});
Why do you need to mock $resource? You should only be mocking data, which is coming from $http; you seem to be doing that already.
My controller:
angularMoonApp.controller('SourceController', ['$scope', '$rootScope', '$routeParams', 'fileService', function ($scope, $rootScope, $routeParams, fileService) {
$scope.init = function() {
$rootScope.currentItem = 'source';
fileService.getContents($routeParams.path).then(function(response) {
$scope.contents = response.data;
$scope.fileContents = null;
if(_.isArray($scope.contents)) {
// We have a listing of files
$scope.breadcrumbPath = response.data[0].path.split('/');
} else {
// We have one file
$scope.breadcrumbPath = response.data.path.split('/');
$scope.breadcrumbPath.push('');
$scope.fileContents = atob(response.data.content);
fileService.getCommits(response.data.path).then(function(response) {
$scope.commits = response.data;
});
}
});
}
$scope.init();
}]);
My unit test:
(function() {
describe('SourceController', function() {
var $scope, $rootScope, $httpBackend, $routeParams, $q, createController, fileService, deferred;
beforeEach(module('angularMoon'));
beforeEach(inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
$rootScope = $injector.get('$rootScope');
$routeParams = $injector.get('$routeParams');
$scope = $rootScope.$new();
$q = $injector.get('$q');
deferred = $q.defer();
fileService = $injector.get('fileService');
var $controller = $injector.get('$controller');
createController = function() {
return $controller('SourceController', {
'$scope': $scope,
'$routeParams': $routeParams,
'fileService': fileService
});
};
}));
it("should set the current menu item to 'source'", function() {
createController();
$scope.init();
expect($rootScope.currentItem).toBe('source');
});
it("should get test the getContents call of the fileService", function() {
spyOn(fileService, 'getContents').andCallThrough();
createController();
$scope.init();
expect(fileService.getContents).toHaveBeenCalled();
});
it("should return an object with multiple files", function() {
var multipleFiles = [{path: '.DS_Store'}, {path: '.bowerrc'}];
deferred.resolve(multipleFiles);
spyOn(fileService, 'getContents').andReturn(deferred.promise);
createController();
$scope.init();
expect($scope.contents).toBe(multipleFiles);
expect($scope.breadcrumbPath).toBe('');
});
});
})();
The last test fails with:
Expected undefined to be [ { path : '.DS_Store' }, { path : '.bowerrc' } ].
Expected undefined to be ''.
Why is the $scope undefined here?
Your controller is expecting you to inject in $rootScope which you are not doing in your unit test.
You have:
createController = function() {
return $controller('SourceController', {
'$scope': $scope,
'$routeParams': $routeParams,
'fileService': fileService
});
But but should have:
createController = function() {
return $controller('SourceController', {
'$scope': $scope,
'$rootScope': $rootScope,
'$routeParams': $routeParams,
'fileService': fileService
});
Also, you will want to call this code:
createController();
$scope.init();
before you resolve your promise:
deferred.resolve(multipleFiles);
The scope is not undefined. What is undefined is $scope.contents and $scope.breadcrumbPath.
And that's because promise callbacks are always being called asynchronously. You need to call
$scope.$apply()
before verifying your expectations.