My project is using AngularJS + Kendo-UI. I'm trying to test one of my Controllers that uses a Kendo-UI Grid:
angular.module('myApp')('DevicesCtrl', function ($scope) {
$scope.gridOptions = {
dataSource: {
transport: {
read: {
url: "/devices",
dataType: "json"
}
},
change: function(){
var view = this.view();
$scope.devices = [];
$.each(view, function(i, v) {
$scope.devices.push({id: v.id, description: v.name, status: v.status == 0 ? "failure" : "success"});
});
$scope.$apply();
}
},
columns: [
{
field: "name",
title: "Name",
width: 250,
template: function (item) {
var itemStatus = item.status == 0 ? 'failure' : 'success';
return '<div label size="small" operation="' + itemStatus + '" label="' + item.name + '"></div>';
}
},
{
field: "status",
title: "Status"
}
]
};
});
When I wrote my unit test, I expected that a GET request would be called:
describe('deviceCtrl', function () {
var scope, deviceCtrl, httpBackend, timeout;
beforeEach(module("myApp"));
beforeEach(module('src/modules/devices/views/device.html'));
beforeEach(inject(function ($controller, $rootScope, $httpBackend, $timeout, $state) {
scope = $rootScope.$new();
httpBackend = $httpBackend;
timeout = $timeout;
httpBackend.expectGET('languages/en_US.json').respond({});
deviceCtrl = $controller("DeviceCtrl", {
$scope: scope
});
$state.go("devices");
timeout.flush()
}));
it('should load the switch list', function () {
httpBackend.expectGET("/devices").respond(
[{"id":"1","name":"name 1","status":"1"},
{"id":"2","name":"name 2","status":"2"}]
);
httpBackend.flush();
});
});
But the expectation is never satisfied, no requests are made. So my question is: Is there a way to make Kendo Grid/Datasource to make this call, so I would be able to mock it?
I saw some samples on how to do it using Mockjax (http://www.telerik.com/forums/best-practice-mocking-with-datasource) but I would prefer to use angular libraries to do that.
After a lot of research I could find some ways to test Controllers that use Kendo Datasource.
Kendo has its own way to make the Ajax calls to fetch data and don’t use regular Angular $http to do that, so it’s a little bit trick to test using Angular tools (angular-mocks). Let’s go to the options:
1 – Use relguar Angular way to to the Ajax calls.
Kendo lets us to change the way it fetch data, so instead of doing:
dataSource: new kendo.data.DataSource({
transport: {
read: {
url: "/devices,
dataType: "json"
}
},
change: function(){
var view = this.view();
$scope.devices = [];
$.each(view, function(i, v) {
$scope.devices.push({id: v.id, description: v.name, status: v.status == 0 ? "failure" : "success"});
});
$scope.$apply();
}
});
We would change to:
dataSource: new kendo.data.DataSource({
transport: {
read: function(options){
$http.get("/devices").then(function(response){
options.success(response.data);
$scope.devices = [];
response.data.forEach(function(v){
$scope.devices.push({id: v.id, description: v.name, status: v.status == 0 ? "failure" : "success"});
});
});
}
}
});
Then we can use regular $httpBackend.expectGET(url) to mock the Ajax call. I personally like this approach because we have more control. Ps.: using the variable “options” inside the function we have access to the Grid filter, sorting and paging values.
2 – Mock the Kendo Ajax Call.
In this way we change almost nothing at the Controller, the only changed needed is to create a new Datasource using new kendo.data.DataSource({}) instead of just passing the options. This needed that because we call the read function inside the test case. I tried different ways to mock this Ajax request, but the only one I could make it work was using a tool called Jasmine-Ajax. And in the test case we would wrote something like:
var request = jasmine.Ajax.requests.mostRecent();
request.response(MockData);
I hope this can help other people.