Good Testing Karma with Marionette

Scott Walton
Marionette.js blog
Published in
5 min readOct 23, 2017
Auto-makers test their products and so should you

JavaScript provides myriad options for testing your applications in the browser. The sheer number of options and churn over the years makes it difficult to find up-to-date information for testing your application. In this article, I’ll be going through how we set up testing for Marionette using Karma, Mocha and Chai to cover basic Views and Behaviors as well as the standard Model/Collection tests. In addition, you’ll get the configuration files that will configure and run the tests for you.

JavaScript Testing

Let’s be honest, testing in JavaScript has historically been quite tricky. Even today, the last State of JavaScript Survey revealed developers still aren’t happy with testing! One way to improve this is to add new libraries, however one of the major challenges is the existing state of documentation. This post aims to help change that.

Our Toolkit

The biggest key to good testing is to make sure you’ve stocked your toolkit. I personally like to keep it as simple as possible and use Karma’s test runner, Mocha as my framework and Chai to provide the extra assertions.

Runner? Framework? This seems complicated!

I’ve introduced a couple of terms here that, if you’re not familiar with the world of JavaScript testing, can feel quite alien. Let’s have a quick dive into this.

A test runner starts your web browser and injects your test code into the page and runs the tests for you. What you want from your runner is to make sure it provides the scaffolding for you and provides solid output results. Strictly speaking, you don’t need a runner but it will make your life much easier if you want to test on anything other than Node directly.

A framework provides the scaffolding for running your tests. Your framework dictates your testing styling, so Jasmine will follow Behavior Driven Development, (BDD) whereas Mocha supports a range of approaches including Test Driven Development through assert and BDD through expect.

The Setup

Once you’ve settled on a runner and framework (Karma and Mocha in our case) the next step is to start piecing together your environment. When it comes to building a testing setup, there are a few moving parts you need to line up:

  • Installing your tools
  • Your karma config
  • Mocha
  • Your webpack config
  • Your Babel config

Installing Everything

Your installation will need to contain the following dependencies:

This will give you the basis of the packages you need.

Karma

Karma gives you a nice setup script to set good defaults for your setup. For the purposes of this post, I’ll skip over that and post a reasonable configuration that you can just tweak for your project, highlighting the key parts you’ll need:

The important parts of this configuration are the preprocessors and webpack settings. Make sure you include these as you’re about to setup Webpack, Babel and Mocha to build and run our tests.

Mocha

Create a test directory at the same level as your karma.conf.js file and put the following into test/mocha.opts:

Kick back and enjoy a Mocha

This will configure babel to compile your actual test code later.

Webpack

Your Webpack config will look pretty much standard. I’ve included a copy of a webpack.config.js below just to demonstrate this:

This assumes your core application code is under your app directory. If you follow some of the documentation, you’ll recognise the form.

Your Babel Config

The Babel config goes in .babelrc in the same folder as package.json:

This is pretty straightforward, use the babel-preset-env as your preset.

Writing Your First Test

Ok, that’s a lot of manual setup but now we can start testing our code! Let’s set up a simple TDD example with a custom Backbone.Model that gives us some custom logic.

We’ll start with a simple app/model.js file:

In true TDD fashion, I’ve deliberately left our implementation details un-set until we’ve defined our tests.

The Test Code

To test this, we create a file in test/model.test.js. The important part of this is that the file is in test and has the extension *.test.js as defined in your Karma configuration above. Let’s create the basic test below:

This simple test will (obviously) pass as our Model already implements the default counter value of 0. It does, however, give us a chance to quickly break down the important parts of this:

  • import { assert } from chai; brings in the Chai extensions to give us more assertion methods.
  • import { MyModel } from 'model'; uses our webpack.conf.js to setup the right paths for our model import.
  • describe() beforeEach() afterEach() and it() are imported automatically by Mocha as part of the test framework.

Hopefully the Mocha setup will be fairly straightforward. You use describe as a form of test case, with before and beforeEach functions to setup your test case either once for each describe (using before) or before each it clause (beforeEach). The same applies for after and afterEach. Those familiar with xUnit can think of these as rough analogues for setupBeforeClass, setUp, tearDownAfterClass, and tearDown. The main difference is you can nest describe clauses easily in Mocha to build up a form of sub test cases.

Running Your Tests

With this simple example in place, it’s time to quickly run this to verify it works. Simply do ./node_modules/.bin/karma start to run the tests. You can setup "test" in your package.json to karma start so you can run npm test and make your life a little easier.

Red-Green-Refactor

With a basic test in place to check our configuration works, let’s create some failing tests so we can build a working implementation that Kent Beck would be proud of. We’ll extend out above example with some tests for increment():

We’ve added a new describe clause for explicitly calling increment. Now run your tests as described above and you should see two test failures for calling increment() — this should be obvious as you’ve not implemented it!

The Green Light

I’ll leave the model improvements for you to complete. You should have the test failure to guide you — when your tests pass you have working code!

Best Practices

The best practices for testing can depend on your application and where your belongs. As a general rule, you should be looking to build tests that accurately reflect what your user needs to do.

My personal preference with Backbone + Marionette is to put as much logic into my Model layer as possible. This lets me test large parts of my application while minimising dependencies on my physical HTML layout. As part of this, I do write tests for Behaviours as they tend to get shared across the system.

Wrapping Up

This short article should give you enough to start building a testing process into your applications. There are ways to test your View layer — and generated HTML — and code that interacts with your backend using Sinon. We’ll cover these aspects in future posts.

If there’s anything you’d like to see covered, you can find us on Gitter or just Tweet Me!

--

--

Scott Walton
Marionette.js blog

Full Stack Developer at Hotjar, meet-up organiser and open source contributor publishing my musings and career life lessons.