Write Better Ember Tests

If you’re not testing your code, well, you’ve got some nerve. For the rest of us rational people, let’s look at some basic tips for writing better Ember tests.

What Makes a Good Test

There are three core components:

1. Easy to Reason

Tests must be easy to understand. While [code quality is important](https://medium.com/@jonpitch code-quality-matters-4a7384f30f0e) for developers to understand, tests often communicate a business requirement or decision which is often more important.

2. Specificity

Tests must be very granular. Being specific is a great way of creating a manifest of all of the pathways, states and other vagaries that may not be immediately obvious.

3. Speed

Tests must be fast. The faster the test runs, the faster the developer can regression their code. The faster a developer can setup and write a test for their new code, the faster a developer can write more code and tests.

Be Verbose

By default, Ember uses QUnit under the hood. There are two ways we can leverage QUnit that make our tests easier to reason about.

Page Object

The Page Object Design pattern is a powerful one for writing re-usable, easy to understand tests. Here’s an example:

In this trivial example, the first test demonstrates a problem where as you start to add more tests, you will end up writing the same selectors multiple times. In the second test, it should be clear that the page variable could be refactored and re-used across tests. Now all of your tests reference page.$button; One change to the page object now updates all of your tests using it.

An even better approach would be to leverage the ember-cli-page-object addon:

In this example, we setup a page object which has all the parts of the page we care about, similar to the examples prior. With ember-cli-page-object, tests become much easier to reason because our assertions become almost human readable: page.button.isVisible could be understood by non-developers. ember-cli-page-object also makes writing tests faster for developers. Tests can be quickly read and understood without having to recall which jQuery selector to use to find your element.

Pro Tip: I have found id and class selectors volatile over time. I have found using a data-test attribute to be much more stable. For example:

<p class="strong" data-test="description">Something</p>

In this piece of HTML, we have a <p> tag that has two attributes, class and data-test. class may change over time as styles change, or naming convention changes. data-test is more of a universal selector for this element that denotes what the element is and signals to the developer that it’s used by tests and should be changed with hesitation.

Mock Server Requests

Chances are your application works with some kind of backend or API. Mocking your API in Ember is a great idea for several reasons:

There are a few ways to achieve this, but my personal favorite is ember-cli-mirage. TL;DR:

Pro Tip: ember-cli-mirage does not currently support the idea of scenarios. For example, I want GET /api/things to return a specific response most of the time, but in some different case, I want it to return something else.

Here’s what I have found to be a good solution:

This is recommended by Mirage and can be found in their documentation here.

Final Thoughts

Are you using a CI tool? You should be. There are a lot of options out there. A popular option, Travis, is free for open source projects. As application complexity increases, or the number of developers increases, it becomes pretty difficult for any one person to know everything. Writing lots of good tests and having them pass before integrating new code is important for the sanity of the team and it helps build confidence in the application’s stability over time. Find a bug? No worries, write a test that reproduces it, fix the bug and never worry about it again.

Make no mistake, tests can be challenging. They often involve the same amount, or more code than your application. And no matter how easy it is to write tests, they still take time, which could be time spent writing more features or fixing bugs. The real key to writing good tests is understanding their worth. Your time is the most valuable asset you have. Don’t waste it by debugging things a simple test would have caught.

Have some tips of your own? I’d love to hear them.