Full disclosure...this is my first SO question. Please be kind if I leave anything out. ;-)
I'm starting to use Jasmin to test one of my client-side Javascript objects. This object in particular manages the use of a jQuery plugin called DataTables. The managed DataTables component will call a couple custom render methods to determine what to display for a couple columns and I am trying to test those methods.
The short question: How can I test the return value of methods for which I need to put a spy on?
The back story
Here is an shrunk down version of my Javascript object:
function Table(elemId) {
this._table = $('#'+elemId).dataTable({
"aoColumnDefs": [
{
"fnRender": function(oObj, id) {
return Table.renderIdColumn(oObj, id, lTable);
},
"aTargets": ["idColumn"],
"bUseRendered": false
},{
"fnRender": function(oObj, name) {
return Table.renderNameColumn(oObj, name, lTable);
},
"aTargets": ["nameColumn"],
"bUseRendered": false
}
],
"bJQueryUI": true,
"sPaginationType": "full_numbers"
});
}
Table.renderIdColumn = function(oObj, id, lTable) {
return '<input type="checkbox" value="' id + '" />';
};
Table.renderNameColumn = function(oObj, name, lTable) {
var id = oObj.aData[0];
return '<a href="/obj/edit/' + id + '">' + name + '</a>';
};
So when creating a Table object, I need to intercept the call to Table.RenderIdColumn and Table.renderNameColumn so that I can assert the results. Here is what I have in Jasmine so far:
describe("Table", function() {
var lTable;
// Write a DOM table that will be rendered by the jQuery DataTable plugin
beforeEach(function() {
$('<table id="storeTable"></table>').appendTo('body');
var headerCellClasses = ["idColumn","nameColumn"];
var headerRow = $('<tr></tr>');
$.each(headerCellClasses, function(index, value) {
headerRow.append('<th class="' + value + '"></th>')
});
$('<thead></thead>').append(headerRow).appendTo('#lTable');
$('<tbody></tbody>').appendTo('#lTable');
});
afterEach(function() {
// First remove DataTables enhancements
lTable.fnDestroy();
// Now remove from DOM
$('#lTable').remove();
});
describe("when edit links are shown", function() {
it("should render a checkbox in ID column", function() {
spyOn(Table, "renderIdColumn");
lTable = initializeDataTable();
var oSettings = lTable._table.fnSettings();
var id = 1;
var obj = {
oSettings: oSettings,
iDataColumn: 0,
iDataRow: 0,
mDataProp: 0,
aData: oSettings.aoData[0]._aData
}
var expected = '<input type="checkbox" value="'+ id +'" />';
expect(Table.renderIdColumn).toHaveBeenCalledWith(obj, id, lTable);
var results = Table.renderIdColumn(obj, id, lTable);
expect(results).toEqual(expected);
});
it("should render the name column with a proper link", function() {
spyOn(Table, "renderNameColumn");
lTable = initializeDataTable();
var oSettings = lTable._table.fnSettings();
var name = "Name";
var obj = {
oSettings: oSettings,
iDataColumn: 3,
iDataRow: 0,
mDataProp: 3,
aData: oSettings.aoData[0]._aData
}
var expected = '<a href="/obj/edit/1">Name</a>';
expect(Table.renderNameColumn).toHaveBeenCalledWith(obj, name, lTable);
var results = Table.renderNameColumn(obj, name, lTable);
expect(results).toEqual(expected);
});
});
});
function initializeDataTable() {
// Mock the AJAX call to the server from DataTables plugin
spyOn($.fn.DataTable.defaults, "fnServerData").andCallFake(function( sUrl, aoData, fnCallback, oSettings ) {
var json = {
iEcho: 1,
iTotalRecords: 1,
iTotalDisplayRecord: 1,
aaData: [
[1, "Name"]
]
}
fnCallback(json);
});
return new Table("lTable");
}
In both test cases, the variable "results" is 'undefined'. I need to test these methods to make sure they are rendering the correct HTML but I can't seem to figure out how to assert the return values. Once I have a spy on the method, it doesn't seem to return anything. I've tried inserting
Table.renderIdColumn.reset();
Table.renderNameColumn.reset();
But neither of those did anything...maybe because my methods are static? FYI, those methods are static because I can't properly assign the "spy" if they are instance methods. The Table constructor calls the DataTables plugin which will cause these methods to be called automatically so I can't construct a Table object and then put a spy on those methods.
When you write spyOn(Table, "renderIdColumn")
, you are (effectively) replacing Table.renderIdColumn
with a function that doesn't return anything.
If you want to assert it was called and still return the results of the original, write spyOn(Table, "renderIdColumn").andCallThrough()
.
The .reset()
syntax you mentioned will only reset the spy's internal call counts (IIRC).
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