I am trying to write a unit test for a angular factory:
define([], function () {
'use strict';
var factoryName = 'UserFactory';
var components = ['ProductFactory', '$state'];
var factory = function (ProductFactory, $state) {
var viewState = function(view, data) {
if(data.access[view] === true) {
return;
}
else {
$state.go('notAuth');
}
};
return {
viewState: viewState
};
};
components.push(factory);
return {
name: factoryName,
component: components
};
});
I have the following unit test:
define(['require', 'angular-mocks'], function (require) {
'use strict';
var angular = require('angular');
describe('<-- UserFactory Spec ------>', function () {
var scope, $httpBackend, userFactory;
beforeEach(angular.mock.module('UserFactory'));
beforeEach(inject(function (_$rootScope_, _UserFactory_) {
scope = _$rootScope_.$new();
userFactory = _UserFactory_;
spyOn(userFactory, 'viewState').and.returnValue({firstName:'Joe',lastName:'Smith',access:'read'});
scope.$apply();
}));
it('method viewState() was called', function () {
expect(userFactory.viewState).toHaveBeenCalled();
});
});
});
However i see the following error:
Expected spy viewState to have been called.
If you are trying to test the implementation of the viewState
function, you will need to call it in your test. You also don't need to test it was called (because the source code doesn't test it).
You don't need to mock it out, that defeats the purpose of testing it. This is because a mock does not call through to the actual implementation, unless you tell it to but you don't need that here.
Your test should look something like this:
describe('<-- UserFactory Spec ------>', function () {
var userFactory;
var $state = {
go: function(){}
};
beforeEach(angular.mock.module('UserFactory'));
// Set the $state injectable to be our mocked out $state (only for this test)
beforeEach(module(function ($provide) {
$provide.value('$state', $state);
}));
beforeEach(inject(function (_UserFactory_) {
userFactory = _UserFactory_;
// Mock out the $state.go method
spyOn($state, 'go');
}));
it('should redirect to the notAuth state', function () {
// Call the method we are testing
userFactory.viewState(/** pass in some conditions to make it call $state.go**/);
expect($state.go).toHaveBeenCalledWith('notAuth');
});
});
I have done a few things here:
$state.go function
- so we can test it was called.userFactory.viewState()
- so we can test the function.viewState()
- so we can test the actual implementation.To test that it is calling this method correctly, you can use some console.logs
.
var viewState = function(view, data) {
console.log('View ', view);
console.log('Data ', data);
console.log(data.access[view]);
console.log(data.access[view] === true);
if(data.access[view] === true) {
return;
}
else {
$state.go('notAuth');
}
};
Now just check that all the console logs are what you expect.
P.S I can't test this code so it might not be 100%, but this is the general gist.