I am using angular-datatables in my project and I would like to write a Jasmine/Karma unit test for it.
This is code from my controller:
$scope.dtOptions = DTOptionsBuilder.fromSource('/api/books/')
.withBootstrap()
.withPaginationType('simple_numbers')
.withDisplayLength(10)
//.withOption('serverSide', true)
.withOption('processing', true)
.withOption('createdRow', createdRow);
$scope.dtColumns = [
DTColumnBuilder.newColumn('id').withTitle('ID'),
DTColumnBuilder.newColumn('name').withTitle('Name')
DTColumnBuilder.newColumn(null).withTitle('Actions').notSortable()
.renderWith(actionsHtml)
];
How can I now write a unit test for it, faking a JSON response from /api/books ?
var $scope, $state, DTColumnBuilder, DTOptionsBuilder, createController, $httpBackend;
beforeEach(function () {
DTColumnBuilder = {};
DTOptionsBuilder = {};
$state = {};
$httpBackend = {};
module('app', function ($provide) {
$provide.value('$state', $state);
$provide.value('$httpBackend', $httpBackend);
$provide.value('DTColumnBuilder', DTColumnBuilder);
$provide.value('DTOptionsBuilder', DTOptionsBuilder);
});
inject(function ($controller, $injector) {
$scope = $injector.get('$rootScope').$new();
$state = $injector.get('$state');
$httpBackend = $injector.get('$httpBackend');
DTColumnBuilder = $injector.get('DTColumnBuilder');
DTOptionsBuilder = $injector.get('DTOptionsBuilder');
aliasOfYourController = function () {
return $controller('originalNameOfController', {
$scope: scope,
$state: $state,
DTOptionsBuilder: DTOptionsBuilder,
DTColumnBuilder: DTColumnBuilder
});
}
spyOn($state, 'go');
$httpBackend.flush();
});
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
// Stub out the methods of interest.
DTOptionsBuilder.fromSource = angular.noop;
DTColumnBuilder.bar = function () { return 'bar'; };
});
The nature of a spy is that of letting the original implementation do its thing, but recording all of the calls to said function and an assortment of associated data.
A stub on the other hand is a spy with an extended API where you can completely modify the workings of said function. Return value, expected parameters, etc etc.
Assuming we used the aforementioned beforeEach block, DTOptionsBuilder.fromSource would be a noop at this point. As such it would be safe to spy on it and expect the method to have been called.
it('should have been called', function () {
var spy = spyOn(DTOPtionsBuilder, 'fromSource');
aliasOfYourController();
expect(spy).toHaveBeenCalled();
});
If you wanted to manipulate the return value of said function, I would grab sinonjs and make it a stub.
it('became "foo"', function () {
DTOptionsBuilder.fromSource = sinon.stub().returns('foo');
aliasOfYourController();
expect($scope.dtOptions).toEqual('foo');
});
Now, since you are working with promises it's a wee bit more complicated but the basics of stubbing out a promise based function would be to:
$q into your spec file.stub to return $q.when(/** value **/) in the case of a resolved promise.stub to return $q.reject(/** err **/) in the case of a rejected promise.$timeout.flush() to flush all deferred tasks. And If you are mocking an http response you use $httpBackend in your unit tests and $httpBackend.flush() to flush all deferred tasks.done callback to notify Jasmine that you are done waiting for async tasks (may not be needed). This depends on the test framework/runner. It could look something like so:
it('resolves with "foo"', function (done) {
DTOptionsBuilder.fromSource = sinon.stub().returns($q.when('foo'));
expect($scope.options).to.eventually.become('foo').and.notify(done); // this is taken from the chai-as-promised library, I'm not sure what the Jasmine equivalent would be (if there is one).
aliasOfYourController();
$timeout.flush();
});
And, If you want to test $state.go('toSomeState') then unit test case can be :
it('should redirected successfully', function() {
var stateParams = {
id: 22,
name: sample
}
functionNameInsideWhichItsBeenCalled(stateParams);
expect($state.go).toHaveBeenCalledWith('toSomeState', {
id: stateParams.id,
name: stateParams.name
});
});
Now, a lot of this is just guesswork at this point. It's quite hard to set up a fully working test suite without having the source code running right beside me for cross reference, but I hope this will at least give you some ideas of how to get going with your $httpBackend, spy and stubs.
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