Testing return value of spied methods using Jasmine
datatables, jasmine, jquery
Solution
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).
Problem
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.