Here is part of my controller:
$scope.isLoggedIn = function () {
return Boolean($sessionStorage.isLoggedIn);
};
$scope.login = function () {
//If the browser fills in the username and password field then angular's model will not be updated so we need
//to manually pull them out of the DOM :(. See this issue for details: https://github.com/angular/angular.js/issues/1460
var username = $('#usernameInput').val();
var password = $('#passwordInput').val();
$scope.loginErrMsg = null;
$http.jsonp("http://ldap-auth.otpp.me" + '/login?callback=JSON_CALLBACK&username=' + encodeURIComponent(username) + '&password=' + encodeURIComponent(password))
.success(function (data, isLoggedIn) {
// This app is for internal use only, security is not a major concern.
// So using sessionStorage to store the login status is OK.
$sessionStorage.displayName = data.displayName;
$sessionStorage.isLoggedIn = true;
})
.error(function () {
$scope.loginErrMsg = "Invalid username or password";
});
};
Here is my test:
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('uiappApp'));
var MainCtrl,
$httpBackend,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($injector, $controller, $rootScope) {
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope
});
$httpBackend = $injector.get('$httpBackend');
}));
it('should login', function () {
var isLoggedIn = scope.isLoggedIn();
expect(isLoggedIn).toBe(false);
var username = $('<input type="text" id="usernameInput"/>');
var password = $('<input type="text" id="passwordInput"/>');
$('body').html('<div>')
.find('div')
.append(username)
.append(password);
username.val('username');
password.val('password');
var response = $httpBackend.expectJSONP('http://ldap-auth.otpp.me/login?callback=JSON_CALLBACK&username=username&password=password');
response.respond({displayName: 'userX'}, {'A-Token': 'xxx'});
scope.login();
expect(scope.isLoggedIn()).toEqual(true);
$('body').empty();
});
});
However the test always fails (Expected false to equal true.). It seems that I didn't get $httpBackend working. But I cannot figure out where was wrong. Basically I want to mock $http.jsonp() response to provide a mocked-up json when unit testing and then test the user login.
Thanks very much if you can help!
@HackedByChinese After folloing your step, I have:
it('should login', function () {
var isLoggedIn = scope.isLoggedIn();
expect(isLoggedIn).toBe(false);
var username = $('<input type="text" id="usernameInput"/>');
var password = $('<input type="text" id="passwordInput"/>');
$('body').html('<div>')
.find('div')
.append(username)
.append(password);
username.val('username');
password.val('password');
var response = $httpBackend.expectJSONP('http://ldap-auth.otpp.me/login?callback=JSON_CALLBACK&username=username&password=password');
response.respond({displayName: 'userX'}, {'A-Token': 'xxx'});
scope.login();
$httpBackend.flush();
expect(scope.isLoggedIn()).toEqual(true);
$('body').empty();
});
But I got the following error message:
Error: Unexpected request: GET views/main.html
No more request expected
at $httpBackend (C:/repo/docserver-ui/UIApp/app/bower_components/angular-mocks/angular-mocks.js:1177:9)
at sendReq (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:7967:9)
at $get.serverRequest (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:7708:16)
at deferred.promise.then.wrappedCallback (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:11100:81)
at deferred.promise.then.wrappedCallback (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:11100:81)
at C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:11186:26
at Scope.$get.Scope.$eval (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:12175:28)
at Scope.$get.Scope.$digest (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:12004:31)
at Function.$httpBackend.flush (C:/repo/docserver-ui/UIApp/app/bower_components/angular-mocks/angular-mocks.js:1435:16)
at null.<anonymous> (C:/repo/docserver-ui/UIApp/test/spec/controllers/main.js:43:22)
Process finished with exit code 0
And here is my partial html:
<form class="navbar-form navbar-right" role="form" ng-show="!isLoggedIn()">
<p class="navbar-text" id="loginErrMsg">{{loginErrMsg}}</p>
<div class="form-group">
<input type="text" placeholder="User Name" id="usernameInput"
class="form-control"
ng-class="{'error-fields': loginErrMsg}">
</div>
<div class="form-group">
<input type="password" placeholder="Password" id="passwordInput" class="form-control" ng-class="{'error-fields': loginErrMsg}">
</div>
<button type="submit" class="btn btn-success" ng-click="login()">Sign in</button>
</form>
After calling scope.login() and before your expect(...), you need to call $httpBackend.flush() for it to respond with the specified expectations.
This is not specific to JSONP, but unit testing $http calls in general.
To summarize, here are the steps to unit test code that makes $http requests:
$httpBackend.$http call(s).$httpBackend.flush() to make it respond to any pending requests with the expectations you set up.See the docs regarding flush.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With