How to Unit Test Knockout.js Components?

The latest version of Knockout.js, version 3.2, has a new functionality: the ability to define and/or load components. Each component is defined with a viewModel and a html template. This means you can make your code even more modular.

Previously, you would have to manually apply view model bindings to a specific dom element, but this had one big problem: you would have to provide the specific element or somehow be able to identify it each time you would like to apply bindings. An alternative would be to create a custom binding handler or a plugin which would do that for you, but now it's implemented in the very core.

I've been creating a lot of knockout components since the 3.2 release and so far I've been very pleased with the functionality, however in time I noticed I have a big problem.

As it's possible to nest multiple components and define the dependencies either in the view model or directly in the template, I realized that even though I write a lot of unit tests for my viewModels, there was not an easy way to test the interaction between it and it's template. No matter how I tested the view model, I would often have to open the real page to be certain that the binding would be applied successfully, especially if I used two or more components. Just a small typo in the template or viewModel would break everything.

Then I thought of writing my own test module which would make it easier to test these components and let me stop repeating code. Later I extended it to aid me in testing the binding handlers.

It's name is kotest and it's available on my GitHub and bower. You can install it via:

bower install kotest

The only dependencies are knockout and mochajs. The kotest library can be loaded as an AMD module, or as a global object. Mocha should, because of the way it's written, always be loaded globally.

If your component is already registered, here is an example of the basic usage:

kotest().component('my-component', paramsObj/*, html */)
    .test('test description', function(ctx) {

        //
        // write usual describe() and it() mocha test defs here
        //

    });

We defined a test case for a component my-component. The paramsObj will be set as it's params binding argument. The third argument is optional, it can be used to provide a specific html to set the data-bind: component... to. If you want to test how your component behaves only on form elements, you would type <form></form>. If this argument is not provided, <div></div> is used.

Then we called the test() function. The first argument was the test name, and the second was a callback. Note that the callback has the ctx argument. The ctx is an object which contains two properties:

  • element - the component element
  • container - element's parent

It will be set once the it()'s callback is executed. A test DOM element will be created and attached to the #test element. This is how the element will look like:

<div data-bind="component: 'my-component', params: paramsObj"></div>

After that the bindings are applied and tests are executed. Once the test ends, elements are detached, and DOM nodes cleaned.

To see what else you can do with it, visit the project's GitHub page or check the API reference.