Unit testing Knockout applications

In ideal case any View Model in Knockout based application should be completely unit-testable. The View Model of course interacts with other code but in majority of cases this would be either some UI code or the server side code, probably over REST API. The UI interaction should be minimal. If possible, the binding capabilities of Knockout should be leveraged. The REST API is not available while unit testing and thus has to be mocked or hidden by an abstraction layer.

This post describes how to mock the AJAX calls while unit testing Knockout View Models. At the end I also provide information about the ChutzPah test runner and the way that the tests can be run from within Visual Studio.

You might thing that the toDto method is useless if one uses the Knockout Mapping plug-in,
however in many cases the view models get much more complex and they
can’t be directly mapped to any kind of data transfer objects or domain
objects. Other than that, nothing should be surprising here. The
save method sends the dto over the wire and than treats the
response.

The unit test

Nowadays one has a choice between multiple JavaScript testing
frameworks, QUnit,
Jasmine or
Mocha being probably the most
common choices - I am staying with QUnit. Testing the updateData
with QUnit might look like this.

QUnit module function takes 2
parameters - name and a sort of configuration object. Configuration
object can contain a setup and tearDown methods. Their usage and intend
should be clear.

This test case is very simple for 2 reasons: it does not depend on any
external resources and it executes synchronously.

QUnit has 3 assert methods which can be used in the tests:

ok - One single argument which has to evaluate to true

equal - Compare two values

deepEqual - Recursively compare a objects properties

Asynchronous testing

Here is the test for the save method which calls the REST server interface.

functioninitTest(){$.mockjax({url:'/api/assets/Prague',type:'GET',responseTime:30,responseText:JSON.stringify({Name:"Prague",Country:"Czech Republic",Size:20})});}$(function(){QUnit.module("ViewModels/AssetViewModel",{setup:initTest});QUnit.asyncTest("testing the load method",function(){setTimeout(function(){ok(true,"Passed and ready to resume!");start();vm.load();QUnit.equal(vm.size(),20);},100);});});

I am using MockJax library
to mock the results of the REST calls. The initTest method setups
the desired behavior of the REST service call, the test is executed
after 100ms of waiting time. In this case the call is a GET and we
define the response simply as JSON data. QUnit has a method for
asynchronous tests called
asyncTest.

Currently there is a small issue in
MockJax regarding
the way that incoming JSON values are handled. That might get fixed in
future versions.

Mocking the server interface

Returning a simple JSON data may be sufficient for some case, for others
however we would maybe like to verify the integrity of the data sent to
the server, just like when testing the save method

varstoredAssets=[];functioninitTest(){$.mockjax({url:'/api/assets',type:'POST',responseTime:30,response:function(data){storedAssets.push(JSON.parse(data.data));}});}$(function(){QUnit.module("ViewModels/AssetViewModel",{setup:initTest});QUnit.asyncTest("save asset - check the update of the size",function(){vm.size(10);vm.save();setTimeout(function(){ok(true,"Passed and ready to resume!");start();equal(storedAssets.length,1);varstoredAssets=storedCharges[0];equal(storedAssets.Size,vm.size());},100);});});

In this case the save method passes the JSON data to the server
side. The server is mocked by MockJax which only adds the data to a
dump array, which can be then used to verify the integrity of the data.

Running Unit Tests in Visual Studio

There are 3 reasons for which I am using Visual Studio even for JavaScript project:

Usually the application has some backend written in .NET and I don’t
want to use 2 IDEs for one single application.

I can easily debug JS application from within VS. Of course Chrome’s
debugger is very useful as well - but if I can do everything from 1
IDE, why should I use other.

ReSharper has really good static analysis of JavaScript and
HTML files. That saves me a lot of time - typos, unknown references
and other issue are catch before I run the application.

I can run JavaScript unit tests right from the IDE.

To run the Unit Tests I am using ChutzPah test runner. ChutzPah
internally uses the PhantomJS in-memory browser, and interprets the
tests. While using this framework, one does not need the QUnit wrapper
HTML page and the Unit Tests can be run as they are.

Since your tests are just JavaScript files, without the HTML wrapper
page, ChutzPah needs to know what libraries do your View Models
reference and load them. This is handled using a configuration file
chutzpah.json which has to be placed alongside the unit tests. The
following is an example of configuration file that I am using for my
tests.

JSON DateTime serialization

This is more a side note. Dates in JSON are serialized into ISO format.
That is good, the problems is that if you try to deserialize an object
which contains a date, the date comes out as a string. The reason of
course is that since there is no type, the de-serializer does not know
that given property is a date - and keeps the value as a string. You can
read more on dates serialization in JSON
here.
Any time that you are mocking backend which handles dates you have to be
aware of this fact. Remember the mock of the back-end which inserts the
object to a dummy array that I have used above: