Angular JS unit testing - angularjs

Angular noob - stuck on a unit testing scenario. In brief:
var app = angular.module("app");
app.controller('Ctrl', ['$scope', '$filter', '$parse', '$http', '$window', '$location', Ctrl]);
function Ctrl($scope, $filter, $parse, $http, $window, $location)
{
$scope.change = function(data)
{
$http.post('url', p).then(function(response)
{
//code to process 'change'
}
}
}
//unit test
beforeEach(inject(function ($controller, $rootScope, $httpBackend)
{
httpBackend = $httpBackend;
scope = $rootScope.$new();
ctrl = $controller('Ctrl', { $scope: scope });
httpBackendHandler =
httpBackend.when("POST","/url").respond(createServerResponse());
}));
In a test that I'm writing, I need to test the code that runs after the http.post().then(). Currently, I call $scope.change() followed by $scope.apply().
The code "inside" the .then is called, but AFTER the test's resulting "expect"s get executed, thereby returning incorrect results. How do I "timeout" until the .then() code has executed so that test can get accurate results?

Related

controller is not registered error while running testcase via Jasmine Karma

I am trying to write test case for angularjs controller via karma jasmine
Getting below error
Error: [$controller:ctrlreg] The controller with the name 'ApproveRejectPackageController' is not registered.
This is my controller code and supporting test case
(function() {
angular.module('Citi.iv.FC')
.controller('ApproveRejectPackageController', ['$scope', '$filter', '$timeout','$uibModal','$sce', '$stateParams', function ($scope,$filter, $timeout, $uibModal, $sce, $stateParams) {});
describe('myserv', function () {
var service;
var data;
beforeAll(function () {
module('Citi.iv.FC')
});
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope;
secondController = $controller('ApproveRejectPackageController', {$scope: scope});
}));
it('ServiceTestSpec', function () {
expect(2 + 3).toBe(6);
});
});
Please suggest how to fix this.
I have included controller in karma-config file

Scope variable how to access in jasmine framework using angularjs

I injected controller all dependencies into spec.js file and trying to access the scope variable but am getting TypeError: Cannot read property 'itemsByPage' of undefined spec.js file mocked below;
`describe('baseController', function() {
beforeEach(module('seApp'));
var $controller,$scope,$compile, $timeout, $mdSidenav, $log,
$http,$uibModal, $routeParams, $window,$mdDialog;
inject(function($controller,$rootScope,$compile, $timeout,$mdSidenav,
$log, $http,$uibModal, $routeParams, $window,$mdDialog){
$scope = $rootScope.$new();
$compile = $compile,
$timeout =$timeout,
$mdSidenav =$mdSidenav,
$log = $log,
$http = $http,
$routeParams = $routeParams,
$window = $window,
$mdDialog =$mdDialog,
$uibModal = $uibModal;
baseController = $controller('baseController', {
$scope : $scope,
$compile : $compile,
$timeout :$timeout,
$mdSidenav :$mdSidenav,
$log : $log,
$http : $http,
$routeParams : $routeParams,
$window : $window,
$mdDialog : $mdDialog,
$uibModal : $uibModal
});
});
it('check the base controller', function() {
expect(1).toBe(1);
});
describe('check scope', function() {
it('check itemsBy page', function() {
expect($scope.itemsByPage).toEqual('8');
}); });});`
execution report is Executed 2 of 2 (1 FAILED) controller is passing but not able to access scope variable inside the controller. please suggest me am new for jasmine framework

how to passing data from one controller to another controller using angular js 1

hi all i using angular js i need to transfer the value from one page controller to another page controller and get that value into an a scope anybody help how to do this
code Page1.html
var app = angular.module("app", ["xeditable", "angularUtils.directives.dirPagination", "ngNotify", "ngCookies","ngRoute"]);
app.controller('Controller1', ['$scope', '$http', '$window', '$filter','$notify','$cookieStore',
function ($scope, $http, $window, $filter, $notify, $cookieStore)
{
$scope.Message="Hi welcome"
}]);
now i want to show scope message into page2 controller
var app = angular.module("app", ["xeditable", "angularUtils.directives.dirPagination", "ngNotify", "ngCookies","ngRoute"]);
app.controller('Controller2', ['$scope', '$http', '$window', '$filter','$notify','$cookieStore',
function ($scope, $http, $window, $filter, $notify, $cookieStore)
{
///here i want get that scope value
}]);
You can use $rootScope instead of $scope:
// do not forget to inject $rootScope as dependency
$rootScope.Message="Hi welcome";
But the best practice is using a service and share data and use it in any controller you want.
You should define a service and write getter/setter functions on this.
angular.module('app').service('msgService', function () {
var message;
this.setMsg = function (msg) {
message = msg;
};
this.getMsg = function () {
return message;
};
});
Now you should use the setMeg function in Controller1 and getMsg function in Controller2 after injecting the dependency like this.
app.controller('Controller1', ['$scope', '$http', '$window', '$filter','$notify','$cookieStore', 'msgService',
function ($scope, $http, $window, $filter, $notify, $cookieStore, msgService)
{
$scope.Message="Hi welcome"
msgService.setMsg($scope.Message);
}]);
app.controller('Controller2', ['$scope', '$http', '$window', '$filter','$notify','$cookieStore', 'msgService',
function ($scope, $http, $window, $filter, $notify, $cookieStore, msgService)
{
///here i want get that scope value
console.log('message from contoller 1 is : ', msgService.getMsg());
}]);
You should use services for it .
Services
app.factory('myService', function() {
var message= [];
return {
set: set,
get: get
}
function set(mes) {
message.push(mes)
}
function get() {
return message;
}
});
And in ctrl
ctrl1
$scope.message1= 'Hi';
myService.set($scope.message1);
ctrl2
var message = myService.get()
Sharing data from one controller to another using service
We can create a service to set and get the data between the controllers and then inject that service in the controller function where we want to use it.
Service :
app.service('setGetData', function() {
var data = '';
getData: function() { return data; },
setData: function(requestData) { data = requestData; }
});
Controllers :
app.controller('Controller1', ['setGetData',function(setGetData) {
// To set the data from the one controller
$scope.Message="Hi welcome";
setGetData.setData($scope.Message);
}]);
app.controller('Controller2', ['setGetData',function(setGetData) {
// To get the data from the another controller
var res = setGetData.getData();
console.log(res); // Hi welcome
}]);
Here, we can see that Controller1 is used for setting the data and Controller2 is used for getting the data. So, we can share the data from one controller to another controller like this.

Error in Jasmine Test in Angular Js

i want to test functions in angular js using jasmine. i have created one controller in which one scope function which is given below.
app.controller('NavigationCtrl', ['$scope', '$route', '$rootScope', function ($scope, $route, $rootScope) {
$scope.title="Hello World";
$scope.testMe = function () {
$scope.title = "Welcome";
}
}]);
Also, i want to call above controller function i.e $scope.testMe from another controller using jasmine test case. so, i create another controller and try to call functions from this controller.
app.controller('RunTestCaseCtrl', ['$scope', '$http', '$location', '$route', '$routeParams', '$rootScope', '$timeout', 'MDT_Constant', function ($scope, $http, $location, $route, $routeParams, $rootScope, $timeout, MDT_Constant) {
describe('mycontroller', function () {
beforeEach(module('app'));
it('scopeTestSpec',
inject(function ($controller, $rootScope) {
var $scope = $rootScope.$new();
$controller('NavigationCtrl', {
$scope: $scope
});
$controller.testMe();
expect($scope.title).toEqual('Welcome');
console.log('ok');
}));
});
}]);
this will give the error "module is not defined".
so, how can i call controller method from another controller using jasmine test

AngularJS $injector.invoke - ParentController is not defined

I have 2 controllers defined:
var myApp = angular.module('nestedControllersModule',[]);
myApp.controller('ParentController', ['$scope', function($scope) {
}]);
myApp.controller('ChildController', ['$scope', '$injector', function($scope, $injector) {
$injector.invoke(ParentController, this, {$scope: $scope});
}]);
This gives: ReferenceError: ParentController is not defined.
This code works only if ParentController is defined as:
function ParentController($scope) {}
I am trying to inject the parent in the child as then I can inherit the common functions defined in the parent.
var myApp = angular.module('nestedControllersModule',[]);
myApp.controller('ParentController', ['$scope', function($scope) {
$scope.name = 'ParentName';
$scope.Type = 'ParentType';
$scope.clickme = function() {
alert('This is parent controller "ParentController" calling');
}
}]);
myApp.controller('ChildController', ['$scope', '$injector', '$ParentController', function($scope, $injector, $ParentController) {
$injector.invoke(ParentController, this, {$scope: $scope});
$scope.name = 'Child';
}]);
myApp.controller('ParentController', ['$scope', function($scope) {
}]);
myApp.controller('ChildController', ['$scope', 'ParentController', function($scope, ParentController) {
// ok now you have ParentController
}]);
But I think you need to use Services to share data/functions between Controllers or using PubSub model:
What's the correct way to communicate between controllers in AngularJS?
This reduces coupling between parts of your app.
This is a basic workaround to achieve what you're after:
var myApp = angular.module('nestedControllersModule',[]);
myApp.factory('ParentControllerFactory', function () {
function ParentControllerFactory($scope) {
$scope.name = 'ParentName';
$scope.Type = 'ParentType';
$scope.clickme = function() {
alert('This is parent controller "ParentController" calling');
}
}
return (ParentControllerFactory);
})
.controller('ParentController', ['$scope', '$injector', 'ParentControllerFactory', function ($scope, $injector, ParentControllerFactory) {
$injector.invoke(ParentControllerFactory, this, {
$scope: $scope
});
}])
.controller('ChildController', ['$scope', '$injector', 'ParentControllerFactory', function ($scope, $injector, ParentControllerFactory) {
$injector.invoke(ParentControllerFactory, this, {
$scope: $scope
});
}]);
I say workaround because it's probably worthwhile looking into properly implementing a service to manage any commonality as previously mentioned (or better yet, splitting commonality into directives, clickme for example is a good candidate)
...also note that $injector.invoke(ParentControllerFactory as it is above will most likely chuck a hissy fit if/when you minify your scripts later on, so be careful where and how it used.
Consider using the Mixin pattern possible by using the $controller service.
In your example, you would replace the $injector service with the $controller service:
var myApp = angular.module('nestedControllersModule',[]);
myApp.controller('ParentController', ['$scope', function($scope) {
$scope.name = 'ParentName';
$scope.Type = 'ParentType';
$scope.clickme = function() {
alert('This is parent controller "ParentController" calling');
}
}]);
myApp.controller('ChildController', ['$scope', '$controller', '$ParentController', function($scope, $controller, $ParentController) {
$controller('ParentController',{$scope: $scope})
$scope.name = 'Child';
}]);
This is a good overview of using the $controller service:
http://vadimpopa.com/split-large-angularjs-controllers-using-the-mixin-pattern/

Resources