Reputation: 15702
I have such controller:
$scope.signIn = (user) ->
if user.email != '' and user.password != ''
UserService.signIn(user)
I have such service:
signIn: (user) ->
$http.post '/user/signin', user
.success (data) ->
AuthService.set 'email', data.user.local.email
.success () ->
$state.go 'auth.profile'
.error () ->
throw Error(err)
I have such test so far:
describe 'AuthController Unit Tests', ->
beforeEach module('kreditorenApp')
AuthController = undefined
scope = undefined
AuthService = undefined
UserService = undefined
$httpBackend = undefined
$controller = undefined
$location = undefined
user = undefined
HTTPInterceptor = undefined
$alert = undefined
resUser =
"status": "OK"
"error": "Erfolgreich Authentifiztiert"
"type": "success"
"token": "TOKEN STRING"
"user":
"__v": 0
"_id": "5512a0dfcbc8ea974647f493"
"local":
"password": "HASH STRING"
"email": "dieter"
beforeEach inject(($rootScope, _$controller_, _$httpBackend_, _UserService_, _AuthService_, _$location_, _$alert_, _HTTPInterceptor_) ->
scope = $rootScope.$new()
$controller = _$controller_
$httpBackend = _$httpBackend_
$location = _$location_
UserService = _UserService_
AuthService = _AuthService_
HTTPInterceptor = _HTTPInterceptor_
# Stubs
#
httpFake = () ->
bla:
"bla"
userFake = () ->
signIn:
"SUCCESS"
# Spies
#
spyOn(HTTPInterceptor, 'response').and.callFake(httpFake)
# spyOn(UserService, 'signIn').and.callFake(userFake)
$httpBackend.expectPOST('/user/signin', user).respond(200, {user":"local":"email":"emperorRudolf"})
$httpBackend.expectGET('app/controller/auth/auth.html').respond(200)
$httpBackend.expectGET('app/controller/auth/partials/profile.html').respond(200)
AuthController = $controller('AuthController', $scope:scope)
)
afterEach ->
$httpBackend.verifyNoOutstandingExpectation()
$httpBackend.verifyNoOutstandingRequest()
it 'should signIn user & ui-route to auth.profile & invoke HTTPInterceptor', ->
# Tests
#
scope.signIn ({email:'mail', password:'pass'})
$httpBackend.flush()
#expect(HTTPInterceptor.response).toHaveBeenCalled
#expect many more things later
The test is failing with
TypeError: 'undefined' is not an object (evaluating 'data.user')
I want to mock out as few as possible.
Edit: The data object is always undefined. $http
's rather unique .success
method is not accessible or known to my tests. How do I test this properly?
Upvotes: 0
Views: 1014
Reputation: 15702
This is how it is done, for an error
. Grab a reference to the promise that we reject, provide an error message, and catch the error. I am still working on the .success promise
and will update as soon as I got it running. I think I will switch to Sinon because this seems much to complicated for testing my controller/service duo.
describe 'AuthController Unit Tests', ->
beforeEach module('myApp')
UserService = undefined
httpMock = undefined
$q = undefined
$scope = undefined
beforeEach module('myApp', ($provide) ->
httpMock = jasmine.createSpyObj('$http', ['post'])
$provide.value('$http', httpMock)
return
)
beforeEach inject((_$controller_, $rootScope, _$q_, _UserService_) ->
$scope = $rootScope.$new()
$controller = _$controller_
$q = _$q_
UserService = _UserService_
AuthController = $controller('AuthController',
$scope: $scope
)
)
it 'should catch an error', ->
errorMsg = 'Unauthorized'
defer = $q.defer()
defer.reject(errorMsg)
httpMock.post.and.returnValue(defer.promise)
UserService.signIn('1').catch (error) ->
expect(error).toEqual(errorMsg)
$scope.$digest();
return
Please note the return
after $provide.value('$http', httpMock)
is mandatory otherwise CoffeeScript will come and haunt you. Props to Simon Bailey's Angular Testing Cookbook for providing help in this matter.
Upvotes: 1
Reputation: 691715
You code posts to /user/signin
, and expects to get back a response body containing a user:
$http.post '/user/signin', user
.success (data) ->
AuthService.set 'email', data.user.local.email
But when you're mocking the backend, you make it return the following:
$httpBackend.expectPOST('/user/signin', user).respond(200, {"asd":"asd"})
So, obviously, trying to access user.local.email
on the object {"asd":"asd"}
won't work.
Upvotes: 0