I have two functions in login controller both functions are
implementing login purpose ,
In this controller !scope.isLoggedIn condition satistified need to check if inside condition.
i need to permanate login in application so i store userid and password credienticals in local sessionStorage
whenever values are available in localStorage i need to execute automaticLogin function,
i checked localStorage data is available or not in if condition
if both userid and password is available in localStorage i need to execute automaticLoginUser function
if not no need to execute automaticLogin function
whenever i am try to execute that automaticLoginUser function getting error
TypeError: scope.automaticLoginUser is not a function error.
Thank you in advanced..!
app.controller('LoginCtrl', ['$scope',
'userService', '$state', '$rootScope','BackendService', 'CartService',
function(scope, userService, $state, rootScope, BackendService, CartService) {
scope.user = {};
scope.isLoggedIn = false;
scope.userId = CartService.getuserId();
scope.userPassword = CartService.getuserPassword();
if (!scope.isLoggedIn) {
console.log('in side isLoggedIn');
if (scope.userId !== undefined && scope.userPassword !== undefined) {
var loginId = scope.userId;
var password = scope.userPassword;
scope.user.loginId = loginId;
scope.user.password = password;
console.log('after user' + scope.user);
var user = scope.user;
scope.automaticLoginuser(user);
}
scope.automaticLoginuser = function(user) {
alert("Inside automaticLoginuser");
CartService.saveuserId(scope.user.loginId);
CartService.saveuserPassword(scope.user.password);
userService.loginuser(user)
.then(function(response) {
scope.userUuid = response.data.userUuid;
userService.setuserUuid(scope.userUuid);
if (response.data.status === 'success') {
CartService.saveFuuid(scope.fuuid);
$state.go("app.userHome");
} else {
$state.go("app.login");
}
});
};
scope.loginuser = function(user) {
CartService.saveuserId(scope.user.loginId);
CartService.saveuserPassword(scope.user.password);
userService.loginuser(user)
.then(function(response) {
scope.userUuid = response.data.userUuid;
userService.setuserUuid(scope.userUuid);
if (response.data.status === 'success') {
$state.go("app.userHome");
} else {
$state.go("app.login");
}
});
};
}
]);
First I cannot overstate how ill advised it is to save a users username and password anywhere on the front end including local session storage. Hope you hashed it in some way.
Secondly, the issue you are facing is because you are trying to call scope within the controller before it is declared. This is unnecessary anyway as $scope is an instance of this which angular instantiates with the controller for you to be able to call it from the DOM.
So the correct thing will be to define the function normally since you only plan to call it in your controller.
function automaticLoginuser(user) {
alert("Inside automaticLoginuser");
CartService.saveuserId(scope.user.loginId);
CartService.saveuserPassword(scope.user.password);
userService.loginuser(user)
.then(function(response) {
scope.userUuid = response.data.userUuid;
userService.setuserUuid(scope.userUuid);
if (response.data.status === 'success') {
CartService.saveFuuid(scope.fuuid);
$state.go("app.userHome");
} else {
$state.go("app.login");
}
});
};
And then just call it normally
automaticLoginuser(user);
You just need to re-order your functions.
var app = angular.module("myApp", []);
app.controller('LoginCtrl', ['$scope',
/*'userService', '$state', '$rootScope','BackendService', 'CartService',*/
function(scope /*, userService, $state, rootScope, BackendService, CartService*/ ) {
scope.automaticLoginuser = function(user) {
alert("Inside automaticLoginuser");
/*CartService.saveuserId(scope.user.loginId);
CartService.saveuserPassword(scope.user.password);
userService.loginuser(user)
.then(function(response) {
scope.userUuid = response.data.userUuid;
userService.setuserUuid(scope.userUuid);
if (response.data.status === 'success') {
CartService.saveFuuid(scope.fuuid);
$state.go("app.userHome");
} else {
$state.go("app.login");
}
});*/
};
scope.loginuser = function(user) {
/*CartService.saveuserId(scope.user.loginId);
CartService.saveuserPassword(scope.user.password);
userService.loginuser(user)
.then(function(response) {
scope.userUuid = response.data.userUuid;
userService.setuserUuid(scope.userUuid);
if (response.data.status === 'success') {
$state.go("app.userHome");
} else {
$state.go("app.login");
}
});*/
};
scope.user = {};
scope.isLoggedIn = false;
scope.userId = 'admin'; //CartService.getuserId();
scope.userPassword = 'admin'; //CartService.getuserPassword();
if (!scope.isLoggedIn) {
console.log('in side isLoggedIn');
if (scope.userId !== undefined && scope.userPassword !== undefined) {
var loginId = scope.userId;
var password = scope.userPassword;
scope.user.loginId = loginId;
scope.user.password = password;
console.log('after user' + scope.user);
var user = scope.user;
scope.automaticLoginuser(user);
}
}
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="LoginCtrl">
</div>
Controllers don't really have "constructors" - they're typically used just like functions. But you can place initialization in your controller function and it will be executed initially, like a constructor:
function exampleController($scope) {
$scope.firstMethod = function() {
//initialize the sampleArray
};
$scope.secondMethod = function() {
$scope.firstMethod();
};
$scope.firstMethod();
}
scope.automaticLoginuser is being defined after your if statement. The first thing to do would be define the method higher up in the controller.
Related
I have this script in my app.js:
app.run(['$http', '$location', 'myAppConfig', function ($http, $location, myAppConfig) {
if (myAppConfig.webAPIPath.main == '') {
var getconfigDone = false;
$http.get('fileHandler.ashx?action=getconfig')
.then(function (result) {
if (JSON.parse(result.data.Data).APIURL !== undefined && JSON.parse(result.data.Data).APIURL != '') {
var apiURL = JSON.parse(result.data.Data).APIURL;
if (apiURL.lastIndexOf('/') + 1 == apiURL.length) {
apiURL = apiURL.substring(0, apiURL.lastIndexOf('/'))
}
myAppConfig.webAPIPath.main = apiURL + "/";
myAppConfig.webAPIPath.account = myAppConfig.webAPIPath.main + '/api/OnlineApplicationPortal/v1/Account/';
myAppConfig.webAPIPath.dashboard = myAppConfig.webAPIPath.main + '/OnlineApplicationPortal/v1/Dashboard/';
}
else {
$location.path('Action/Welcome/apiUrlError');
}
//debugger
getconfigDone = true;
}, function (response) { debugger }
);
}
}]);
Also I have got this factory object which uses the myAppConfig in app.js:
(function () {
angular
.module('app.data')
.factory('accountDS', ['$http', '$routeParams', 'myAppConfig', function ($http, $routeParams, myAppConfig) {
var pathPrefix = myAppConfig.webAPIPath.account;
var createAccount = function (account, email) {
var OnlineApplicationPortalModel = {
Name: account.firstName,
Surname: account.lastName,
Email: email,
Password: account.password
};
return $http.post(pathPrefix + 'CreateAccount', OnlineApplicationPortalModel)
.then(function (response) {
return response;
});
};
var confirmEmail = function () {
var data = {
guid: $routeParams.guid
};
return $http.post(pathPrefix + 'ConfirmEmail', data)
.then(function (response) {
return response;
});
}
return {
createAccount: createAccount,
confirmEmail: confirmEmail
};
}]);
})();
The service object needs to use myAppConfig.webAPIPath.account which is resolved in the function in app.js run function. Now the problem is sometimes the browser reaches the service code sooner than than the AJAX call is returned, a race condition. I know that it is not possible in AngularJS to make a sync AJAX call. So how can I solve this?
If I correctly understand you, you want to myAppConfig.webAPIPath.account resolve this value to use it later in your code, but ajax call which provides you value for this variable is not always called before assignment. I think you could use https://docs.angularjs.org/api/ng/service/$q to solve your problem. Your code in myAppConfig should be inside function, so you can call it inside your factory and return deferred object, which then when your .account variable is set should call code from accountDS factory.
So, I'm trying to learn Ionic Framework, but, I've got a problem already, I'm running the Ionic Backand Starter app (like an example app) and I've got two different results when testing it.
Ripple: When I run it from VS on Ripple, it works perfectly fine, the Database is how it is supposed to be, everything is running fine.
Device: When I run it from VS on my Android Device (Samsung Galaxy S5 Mini, without root), the application has a problem when loading the Backand Database. It looks completely empty.
Im going to leave prints of the 2 trials and also my Controller.js, App.js and Services.js, also, I'm leaving the github project link, in case you want more detailed stuff.
GitHub Project:
GitHub Backand Ionic Starter Project
Prints:
Device: http://prntscr.com/a3iq45
Ripple: http://prntscr.com/a3iqgd
CODES:
App.js:
// Ionic template App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'SimpleRESTIonic' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('SimpleRESTIonic', ['ionic', 'backand', 'SimpleRESTIonic.controllers', 'SimpleRESTIonic.services'])
.run(function ($ionicPlatform) {
$ionicPlatform.ready(function () {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleLightContent();
}
});
})
.config(function (BackandProvider, $stateProvider, $urlRouterProvider, $httpProvider) {
BackandProvider.setAppName('ionicstarter'); // change here to your app name
BackandProvider.setSignUpToken('4ce88904-75c5-412c-8365-df97d9e18a8f'); //token that enable sign up. see http://docs.backand.com/en/latest/apidocs/security/index.html#sign-up
BackandProvider.setAnonymousToken('87c37623-a2d2-42af-93df-addc65c6e9ad'); // token is for anonymous login. see http://docs.backand.com/en/latest/apidocs/security/index.html#anonymous-access
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: '/tabs',
abstract: true,
templateUrl: 'templates/tabs.html'
})
.state('tab.dashboard', {
url: '/dashboard',
views: {
'tab-dashboard': {
templateUrl: 'templates/tab-dashboard.html',
controller: 'DashboardCtrl as vm'
}
}
})
.state('tab.login', {
url: '/login',
views: {
'tab-login': {
templateUrl: 'templates/tab-login.html',
controller: 'LoginCtrl as login'
}
}
});
$urlRouterProvider.otherwise('/tabs/dashboard');
$httpProvider.interceptors.push('APIInterceptor');
})
.run(function ($rootScope, $state, LoginService, Backand) {
function unauthorized() {
console.log("user is unauthorized, sending to login");
$state.go('tab.login');
}
function signout() {
LoginService.signout();
}
$rootScope.$on('unauthorized', function () {
unauthorized();
});
$rootScope.$on('$stateChangeSuccess', function (event, toState) {
if (toState.name == 'tab.login') {
signout();
}
else if (toState.name != 'tab.login' && Backand.getToken() === undefined) {
unauthorized();
}
});
})
Controller.js:
angular.module('SimpleRESTIonic.controllers', [])
.controller('LoginCtrl', function (Backand, $state, $rootScope, LoginService) {
var login = this;
function signin() {
LoginService.signin(login.email, login.password)
.then(function () {
onLogin();
}, function (error) {
console.log(error)
})
}
function anonymousLogin(){
LoginService.anonymousLogin();
onLogin();
}
function onLogin(){
$rootScope.$broadcast('authorized');
$state.go('tab.dashboard');
}
function signout() {
LoginService.signout()
.then(function () {
//$state.go('tab.login');
$rootScope.$broadcast('logout');
$state.go($state.current, {}, {reload: true});
})
}
login.signin = signin;
login.signout = signout;
login.anonymousLogin = anonymousLogin;
})
.controller('DashboardCtrl', function (ItemsModel, $rootScope) {
var vm = this;
function goToBackand() {
window.location = 'http://docs.backand.com';
}
function getAll() {
ItemsModel.all()
.then(function (result) {
vm.data = result.data.data;
});
}
function clearData(){
vm.data = null;
}
function create(object) {
ItemsModel.create(object)
.then(function (result) {
cancelCreate();
getAll();
});
}
function update(object) {
ItemsModel.update(object.id, object)
.then(function (result) {
cancelEditing();
getAll();
});
}
function deleteObject(id) {
ItemsModel.delete(id)
.then(function (result) {
cancelEditing();
getAll();
});
}
function initCreateForm() {
vm.newObject = {name: '', description: ''};
}
function setEdited(object) {
vm.edited = angular.copy(object);
vm.isEditing = true;
}
function isCurrent(id) {
return vm.edited !== null && vm.edited.id === id;
}
function cancelEditing() {
vm.edited = null;
vm.isEditing = false;
}
function cancelCreate() {
initCreateForm();
vm.isCreating = false;
}
vm.objects = [];
vm.edited = null;
vm.isEditing = false;
vm.isCreating = false;
vm.getAll = getAll;
vm.create = create;
vm.update = update;
vm.delete = deleteObject;
vm.setEdited = setEdited;
vm.isCurrent = isCurrent;
vm.cancelEditing = cancelEditing;
vm.cancelCreate = cancelCreate;
vm.goToBackand = goToBackand;
vm.isAuthorized = false;
$rootScope.$on('authorized', function () {
vm.isAuthorized = true;
getAll();
});
$rootScope.$on('logout', function () {
clearData();
});
if(!vm.isAuthorized){
$rootScope.$broadcast('logout');
}
initCreateForm();
getAll();
});
Services.js:
angular.module('SimpleRESTIonic.services', [])
.service('APIInterceptor', function ($rootScope, $q) {
var service = this;
service.responseError = function (response) {
if (response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return $q.reject(response);
};
})
.service('ItemsModel', function ($http, Backand) {
var service = this,
baseUrl = '/1/objects/',
objectName = 'items/';
function getUrl() {
return Backand.getApiUrl() + baseUrl + objectName;
}
function getUrlForId(id) {
return getUrl() + id;
}
service.all = function () {
return $http.get(getUrl());
};
service.fetch = function (id) {
return $http.get(getUrlForId(id));
};
service.create = function (object) {
return $http.post(getUrl(), object);
};
service.update = function (id, object) {
return $http.put(getUrlForId(id), object);
};
service.delete = function (id) {
return $http.delete(getUrlForId(id));
};
})
.service('LoginService', function (Backand) {
var service = this;
service.signin = function (email, password, appName) {
//call Backand for sign in
return Backand.signin(email, password);
};
service.anonymousLogin= function(){
// don't have to do anything here,
// because we set app token att app.js
}
service.signout = function () {
return Backand.signout();
};
});
Thanks!!
In my Angular controller, "authenticated is not defined. I want to show the Update button only when the user is logged in. I am using ng-show when the user is logged in, otherwise hide the button. Can someone guide me what I am doing wrong?
JavaScript
$scope.signIn = function () {
$rootScope.auth.$login('password', {
email: $scope.email,
password: $scope.password
}).then(function (user) {
Materialize.toast('Logged in successfully', 1000);
console.log(authenticated);
$scope.authenticated = true;
}, function (error) {
if (error = 'INVALID_EMAIL') {
Materialize.toast('Email invalid or not signed up — trying to sign you up!', 5000);
$scope.signUp();
} else if (error = 'INVALID_PASSWORD') {
console.log('wrong password!');
Materialize.toast('Invalid password', 1000);
} else {
console.log(error);
}
});
};
$scope.loggedin = false;
Template
<div ng-if="loggedin">
<a class="btn waves-effect waves-red" ng-href="/#/editWelcome/{{welcome._id}}">Update
</a>
</div>
There is a typo:
console.log(authenticated);
maybe You wanted like this:
console.log('authenticated');
or maybe:
console.log(user);
because of authenticated variable does not exists, it does not move to next line to set $scope.authenticated = true;
You use <div ng-if="loggedin"> to toggle the Update link.
But in your controller, you never set the value of loggedin. Instead, you set $scope.authenticated = true;. I think you need to set $scope.loggedin = true;.
To answer the question with an example, you had multiple issues, the variable names are inconsistent, your console.log has an undefined object called authenticated,
$scope.authenticated = true; VS $scope.isLoggedIn = false.
You should use code below which sets the logged in at the controller and $rootScope. It includes getting yourself away from using $scope in the controller in favor of 'controller as vm', I suggest looking at http://www.johnpapa.net/angular-style-guide/
The code also provides a logging utility as this will help you with the logging error because you can add try/catch in the service.
Controller and Logging Utility JS
(function () {
var moduleId = 'app';
var controllerId = 'AngularController';
//define controller
angular
.module(moduleId)
.controller(controllerId, angularController);
angularController.$inject = ['$rootScope', 'logUtil'];
//Your controller code
function angularController($rootScope, logUtil) {
var vm = this;
vm.title = 'Your controller title';
vm.isLoggedIn = angular.isDefined($rootScope.isLoggedIn) ? $rootScope.isLoggedIn : false;
vm.signIn = signIn;
vm.signUp = signUp;
function signIn() {
$rootScope.auth.$login('password', {
email: $scope.email,
password: $scope.password
}).then(function (user) {
Materialize.toast('Logged in successfully', 1000);
logUtil.logDebug('authenticated');
vm.userId = user.id;
$rootScope.isLoggedIn = true;
vm.isLoggedIn = true;
}, function (error) {
$rootScope.isLoggedIn = false;
vm.isLoggedIn = false;
if (error === 'INVALID_EMAIL') {
logUtil.logDebug('no user');
Materialize.toast('Email invalid or not signed up — trying to sign you up!', 5000);
vm.signUp();
} else if (error === 'INVALID_PASSWORD') {
logUtil.logDebug('wrong password');
Materialize.toast('Invalid password', 1000);
} else {
logUtil.logError(error);
}
});
};
function signUp() {
//sign up function
}
activate();
function activate() {
logUtil.logDebug('Controller activated: ' + controllerId);
}
};
//logging utility constants
angular.module(moduleId).constant('logUtilConstants', {
LOG_ERROR_MESSAGES: true,
LOG_DEBUG_MESSAGES: true
});
//logging service
angular.module(moduleId).service('logUtil', logUtil);
logUtil.$inject = ['$log','logUtilConstants'];
function logUtil($log, logUtilConstants) {
var service = {
logError: function (logMessage) {
if (logUtilConstants.LOG_ERROR_MESSAGES) {
$log.error(logMessage);
}
},
logDebug: function () {
try {
if (logUtilConstants.LOG_DEBUG_MESSAGES) {
var args = Array.prototype.slice.call(arguments, 0);
var strArgs = args.join(' ');
$log.debug(strArgs);
}
} catch (e) {
console.log('log debug error', e);
}
}
}
return service;
}
})();
Controller Markup
<div ng-controller="AngularController as vm">
{{ vm.title }}
</div>
Conditional Div Markup
<div ng-if="vm.loggedin">
<a class="btn waves-effect waves-red" ng-href="/#/editWelcome/{{vm.userId}}">Update</a>
</div>
I am using Angular 1.3.15 and UI-Router, hosted on IIS 7.5.
The following code contains setup for the $stateChangeStart event. When the app has been loaded from the main link, this code is invoked correctly; when a user accesses a state with a role, there is no issue. When you try to hit a link manually via the address bar or refresh the current page that you are on and the application reloads, the function runs but any property on the authentication.profile object is empty. You'll see that I am doing a console.dir(authentication.profile) when $stateChangeStart first fires off. This shows that there is indeed data there, and methods on the object. But if i try console.dir(authentication.profile.token), it is empty.
I am unsure if this is related to the refresh of the app from a different path or something totally different.
Any help would be appreciated.
'use strict';
var serviceId = 'authentication';
angular.module('app').factory(serviceId,
['common', '$localForage', '$injector', authentication]);
angular.module('app').run(['$rootScope','$state', '$stateParams',
'authentication', function ($rootScope,$state, $stateParams, authentication) {
$rootScope.$on('$stateChangeStart',
function (e, toState, toParams, fromState, fromParams) {
console.dir(authentication.profile);
if (toState.data.roles.length > 0) {
console.log('has roles');
console.dir(authentication.profile.roles());
if (!authentication.profile.isInAnyRole(toState.data.roles)) {
e.preventDefault();
$state.go('home');
}
}
});
}]);
Authentication service:
function authentication(common, $localForage, $injector) {
var USERKEY = "utoken";
var setProfile = function (username, token) {
profile.username = username;
profile.token = token;
localforage.setItem(USERKEY, {
'username': username,
'token': token
})
};
var initialize = function () {
var user = {
username: "",
token: "",
isAuthenticated: function () {
return this.token;
},
isUserInRole : function (role) {
if (this.token != "") {
var decoded = jwt_decode(this.token);
return decoded.role.indexOf(role) != -1;
}
else return false;
},
isInAnyRole: function (roles) {
for (var i = 0; i < roles.length; i++) {
if (this.isUserInRole(roles[i])) return true;
}
return false;
},
roles: function(){
if (this.token != "") {
var decoded = jwt_decode(this.token);
return decoded.role;
}
else return false;
},
isTokenExpired: function () {
var decoded = jwt_decode(this.token);
if (moment.unix(decoded.exp).isBefore( moment())) {
return true;
}
else
return false;
}
};
var localUser = null;
$localForage.getItem(USERKEY).then(function (data) {
localUser = data;
if (localUser) {
user.username = localUser.username;
user.token = localUser.token;
if (user.isTokenExpired())
logout();
}
});
return user;
};
var logout = function () {
profile.username = "";
profile.token = "";
$localForage.removeItem(USERKEY);
$injector.get('$state').transitionTo('home');
};
var profile = initialize();
return {
setProfile: setProfile,
profile: profile,
logout: logout
};
};
Which behavior do you expect? When you reload the page or navigate to the URL 'manually' the app starts from scratch. And you never call authentication.setProfile().
To keep the session, once logged in, on reload or manual navigation you have to keep this data for offline usage. You can use cookies or localStorage service.
Then in your state tracking code you will read the storage/cookies once you detect a missing profile and attempt to restore it from storage/cookie
I am trying to write a jasmine test on some javascript using spyon over a method that uses $http. I have mocked this out using $httpBackend and unfortunately the spy doesn't seem to be picking up the fact the method has indeed been called post $http useage. I can see it being called in debug, so unsure why it reports it hasn't been called. I suspect I have a problem with my scope usage ? or order of $httpBackend.flush\verify ?:
Code under test
function FileUploadController($scope, $http, SharedData, uploadViewModel) {
Removed variables for brevity
.....
$scope.pageLoad = function () {
$scope.getPeriods();
if ($scope.uploadViewModel != null && $scope.uploadViewModel.UploadId > 0) {
$scope.rulesApplied = true;
$scope.UploadId = $scope.uploadViewModel.UploadId;
$scope.linkUploadedData();
} else {
$scope.initDataLinkages();
}
}
$scope.initDataLinkages = function () {
$http({ method: "GET", url: "/api/uploadhistory" }).
success(function (data, status) {
$scope.status = status;
$scope.setUploadHistory(data);
}).
error(function (data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
}
$scope.setUploadHistory = function (data) {
if ($scope.UploadId > 0) {
$scope.currentUpload = data.filter(function (item) {
return item.UploadId === $scope.UploadId;
})[0];
//Remove the current upload, to prevent scaling the same data!
var filteredData = data.filter(function (item) {
return item.UploadId !== $scope.UploadId;
});
var defaultOption = {
UploadId: -1,
Filename: 'this file',
TableName: null,
DateUploaded: null
};
$scope.UploadHistory = filteredData;
$scope.UploadHistory.splice(0, 0, defaultOption);
$scope.UploadHistoryId = -1;
$scope.UploadTotal = $scope.currentUpload.TotalAmount;
} else {
$scope.UploadHistory = data;
}
}
Test setup
beforeEach(module('TDAnalytics'));
beforeEach(inject(function (_$rootScope_, $controller, _$httpBackend_) {
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
var sharedData = { currentBucket: { ID: 1 } };
controller = $controller('FileUploadController', { $scope: $scope, SharedData: sharedData, uploadViewModel: null });
$httpBackend.when('GET', '/api/Periods').respond(periods);
$httpBackend.when('GET', '/api/uploadhistory').respond(uploadHistory);
$scope.mappingData = {
FieldMappings: [testDescriptionRawDataField, testSupplierRawDataField],
UserFields: [testDescriptionUserField, testSupplierUserField]
};
}));
afterEach(function() {
testDescriptionRawDataField.UserFields = [];
testSupplierRawDataField.UserFields = [];
testTotalRawDataField.UserFields = [];
$httpBackend.flush();
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
Working test:
it('pageLoad should call linkUploadedData when user has navigated to the page via the Data Upload History and uploadViewModel.UploadId is set', function () {
// Arrange
spyOn($scope, 'linkUploadedData');
$scope.uploadViewModel = {UploadId: 1};
// Act
$scope.pageLoad();
// Assert
expect($scope.rulesApplied).toEqual(true);
expect($scope.linkUploadedData.calls.count()).toEqual(1);
});
Test that doesn't work (but should. returns count-0 but is called)
it('pageLoad should call setUploadHistory when data returned successfully', function () {
// Arrange
spyOn($scope, 'setUploadHistory');
// Act
$scope.initDataLinkages();
// Assert
expect($scope.setUploadHistory.calls.count()).toEqual(1);
});
The issue is you call httpBackend.flush() after the expect, which means success is called after you do your tests. You must flush before the expect statement.
it('pageLoad should call setUploadHistory when data returned successfully',
inject(function ($httpBackend, $rootScope) {
// Arrange
spyOn($scope, 'setUploadHistory');
// Act
$scope.initDataLinkages();
$httpBackend.flush();
$rootScope.$digest()
// Assert
expect($scope.setUploadHistory.calls.count()).toEqual(1);
}));
You may need to remove the flush statement from after your tests, but it probably should not be there anyway because usually it's a core part of testing behaviour and should be before expect statements.