During the last week I spent a few hours working on unit tests of JavaScript projects. Some of it happened in Babel where I made some contributions increasing overall test coverage. But the bigger part was for a new JavaScript project I started for myself where I take a testing-first approach. That means I dealt with a lot of failing tests and had to deal with their error messages. There is a number of ways of writing assertions, but I always try to keep it as simple as possible. I like to think that ideal tests should not only test code, but also provide insight into the API of modules and serve as living documentation. That is why I try to keep complexity and abstraction as low as possible in test files. But this week I looked into different ways of writing assertions and how introducing a bit of abstraction can make tests more helpful, especially failing ones. Below is a simplified example of how I improved my Mocha 1 test suite. In this case, the assertion tests whether the function returns an object of the correct class ( I understand that this can be done by a type system, however this is not the point of this post ).

import assert from 'assert'
import someFunc from './someFunc'
import Result from './Result'
  
describe('The return value of someFunc', () => {
	// Assume this returns 17
	const returnValue = someFunc()

	it('should be a Result instance', () => {
		// Useless error message: "AssertionError: false == true"
		assert(returnValue instanceof Result)

		// More helpful error message: "AssertionError: Expected Result instance."
		// But cumbersome to read and write
		assert(returnValue instanceof Result, 'Expected Result instance.')

		// Most helpful error message: "Expected 17 to be a Result instance."
		// Readable and reusable
		assertResult(returnValue)
	})
})

// Can be moved into a separate module if needed across different test files
function assertResult(val) {
	assert(val instanceof Result, `Expected ${val} to be a Result instance.`)
}

This is really just the power of functions but it felt like a major upgrade to my testing workflow. There is also a number of libraries that have generic version of these assertion functions that allow you to make more specific checks than Node’s assert 2. These obviously help with better error messages, but going with custom wrappers around raw assertions is quite nice as well. For my own project I have written 109 tests so far and am happy with this approach. Maybe I will introduce another assertion library on top in the future, but for now this provides a nice testing workflow to me.