Good assertion messages with EmberJS + sinon
Tags: ember, testing, javascript, sinon
Published: 2022-06-21 21:21:35

Good assertion messages in tests should help you quickly figure out what went wrong in case the test goes red. Bad assertion messages on the other hand ...


![90% of code comments be like a sticker saying "cat" attached to a cat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cayr3qf3vydvd71w9jws.png)

Since I work on quite a few [EmberJS](https://emberjs.com/) projects with different setups, I thought it would be a good idea to document the options.

## Initial setup

For `sinon` in your `EmberJS` project, you will probably want to install [ember-sinon-qunit](https://github.com/elwayman02/ember-sinon-qunit). This will also automatically pull in [ember-sinon](https://github.com/csantero/ember-sinon) for you.

## Assertions

Let's assume following test code with some `sinon` usage:

```js
import sinon from 'sinon';

test('my awesome test', function (assert) {
  const stub = sinon.stub().named('Awesome spy').returns('hello');

  stub('First call');
  stub('Second call');

  // Place for future assertions
});
```

### qunit

By default `qunit`, which is available in every `ember-cli` project offers `assert` functionality which [has quite a few methods](https://api.qunitjs.com/assert/). Then those can be used to examine what our `sinon` object experienced:

```js
assert.ok(spy.calledOnce);
```

Which would produce following error:


![failed, expected argument to be truthy, was: false](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/muf355kmq30nc3wep3jn.png)

Which is ... suboptimal. The message does not give us _context_ of why it failed. That we expected the function to be called exactly once.

We could, of course, do following:

```js
assert.ok(stub.calledOnce, 'Expected to be called only once');
```

Which would give us a nicer error:


![Expected to be called only once](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/brxze7frf6s0muehe7m8.png)

But this is:

1. More work
1. Prone to future refactoring errors

Can we do better?

### ember-sinon

Thanks to [ember-sinon](https://github.com/csantero/ember-sinon) package we can import `sinon` directly into our tests

```js
sinon.assert.calledOnce(stub);
```

Giving us following, slightly more informative error message: 

![Died on test #1: expected Awesome spy to be called once but was called twice](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9vrpn1h7iszth4q2gku.png)

This is better as it gives us more context, but:

1. One failed assertion will make your test die, not executing other assertions. Potentially hiding important information from you.
1. Passing assertions do not count towards assertion count, so if this is the only type in your `test`, then you will get `Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.` error.
1. Because of the point above, in case you have other types of assertions, it might be confusing to know which message belongs to which assertion.

Can we do better?

### qunit-sinon-assertions

Addon [qunit-sinon-assertions](https://github.com/PrecisionNutrition/qunit-sinon-assertions) was created exactly to address the shortcomings of the previous methods. So that this code:

```js
assert
  .spy(stub)
  .calledOnce()
  .calledWith(['John Doe'])
  .returnedWith('world');
```

Will produce following errors:

![A lot of cool error messages](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1bmonz41y773yjt5eiua.png)

## Conclusion

I do believe that easy-to-understand assertion messages are important. There are different methods to achieve this. Personally I prefer to write less code and lean on a convention that is provided by a tool.

-----

Photo by [Miguel Á. Padriñán](https://www.pexels.com/photo/close-up-shot-of-keyboard-buttons-2882552/)