jeudi 5 février 2015

Unit testing AngularJS controller which makes a service call from the ng-submit directive

I am getting started with unit testing a new AngularJs application with Karma, Jasmine and Sinon.


I have a very basic controller, service and template.


The service makes a call to the our service layer which gets some data from the Twitter API:



// Data Service factory
angular
.module('ttn')
.factory('dataservice', dataservice);

dataservice.$inject = ['$http'];

function dataservice ($http){
return {
getCuratedList: getCuratedList
};

function getCuratedList(params){
return $http.post('/ttn-server/twitter/curatedList', {
screenName: params.screenName
}).then(getCuratedListSuccess).catch(getCuratedListFail);

function getCuratedListSuccess(response){
return response.data;
}

function getCuratedListFail(error){
return console.log(error);
}
}

}


The controller is very thin:



angular.module('ttn').controller('TwitterList', TwitterList);

TwitterList.$inject = ['dataservice', 'results'];

function TwitterList(dataservice, results){

var vm = this;

vm.screenName = '';
vm.results = results;
vm.submit = submit;

function submit(event){
event.preventDefault();
return dataservice.getCuratedList({
screenName: vm.screenName
}).then(function (data) {
vm.results = data;
}).catch(function (error) {
console.warn(error);
});
}

}


As is the template HTML:



<h2>Twitter Curated List</h2>

<form ng-submit="vm.submit($event)">
<p>
<label for="listSearch">Get lists by screen name:</label>
<input type="text" id="listSearch" ng-model="vm.screenName"/>
<input type="submit" id="submit" value="Search" />
</p>
</form>

<img src="{{vm.results.user.profileImage}}" alt=""/>
<p>Curated by: {{vm.results.user.screenName}}</p>
<p>List Name: <strong>{{vm.results.user.listName}}</strong></p>
<p>Number of members: {{vm.results.user.listMemberCount}}</p>

<ul>
<li ng-repeat="member in vm.results.members">
<img src="{{member.profileImage}}" alt=""/>
<p>@{{member.screenName}}</p>
<p>{{member.description}}</p>
</li>
</ul>


I have written some tests which seem good and valid except the final one where i want to test that calling the controller submit function also calls the ttnDataservice.getCuratedList method but I am not sure how to do this.



describe('Controller: TwitterList', function () {

var controller,
ttnDataservice,
stub = sinon.stub();

stub.withArgs('FooBar').returns([{}, {}, {}, {}]);

beforeEach(module('ttn'));

beforeEach((function () {
var mocks = angular.module('ttnMocks', []);
mocks.factory('dataservice', function () {
return {
getCuratedList: stub
};
});
module('ttnMocks');
}));

beforeEach(inject(function ($controller, dataservice) {
controller = $controller('TwitterList', {
results: [{}, {}, {}]
});
ttnDataservice = dataservice;
}));

it('should be the Twitter list controller', function () {
expect(controller).toBeDefined();
});

it('should instantiate the screen name to an empty string', function () {
expect(controller.screenName).toEqual('');
});

it('should instantiate with the results array', function(){
expect(controller.results).toEqual([{},{},{}]);
});

it('should instantiate with a submit function', function () {
expect(controller.submit).toBeDefined();
});

it('should inject the data service layer', function(){
expect(ttnDataservice).toBeDefined();
});

it('should have the getCuratedList method', function(){
expect(ttnDataservice.getCuratedList).toBeDefined();
});

it('should call the getCuratedList service', function(){
ttnDataservice.getCuratedList();
expect(ttnDataservice.getCuratedList.called).toBe(true);
});

it('should call the getCuratedList service with a Twitter screen name', function(){
ttnDataservice.getCuratedList('FooBar');
expect(ttnDataservice.getCuratedList.calledWith('FooBar')).toBe(true);
});

it('should call the getCuratedList service with a Twitter screen name and return an array of objects', function(){
var result = ttnDataservice.getCuratedList('FooBar');
expect(result).toEqual([{}, {}, {}, {}]);
});

it('should call the getCuratedList service from the form submission', function(){
var event = {preventDefault: jasmine.createSpy()};
controller.submit(event);
expect(ttnDataservice.getCuratedList.called).toBe(true);
});

});

Aucun commentaire:

Enregistrer un commentaire