How we achieved green builds in an enterprise Ember.js app

Shibu Lijack
Jan 25 · 4 min read

Hello there! I’m a software developer at Freshworks, predominantly working on Ember.js. Buckle up, for I’m going to talk about:

  1. Testing
  2. Migration
How different people react to words like “testing” & “migration”

We started using Ember about 3 years back. At that time Mocha seemed to be ahead of QUnit in terms of features. Also, it was similar to RSpec and so it made our transition much easier. Hence we chose Mocha as the testing framework. But a lot has changed since then.

  • QUnit not only caught up with Mocha but sprinted ahead.
  • Our codebase grew exponentially with thousands of test cases, slowly but steadily introducing flaky tests. At one point in time, it was very difficult to see a green build since some tests would almost always randomly fail.

Before things got out of hand, we brainstormed a solution to stabilise the test pipeline in the CI. Enter QUnit.

QUnit is a powerful, easy-to-use JavaScript unit testing framework. Performance: QUnit is not only easy, but fast. Opinionated and lean API, but extensible.

Why QUnit?

  • Ember-QUnit is the default unit testing helper suite for Ember which means new features are introduced in ember-qunit more rapidly than in ember-mocha.
  • Tests in QUnit run faster than mocha.
  • ember-exam not only has better integration with QUnit but also some additional features like --load-balance are available only with QUnit.
  • Testing issues such as async leakages and global mutations are better thrown by QUnit.

Mocha to QUnit migration

#STEP 1: Setup the testbed

Our testing codebase is huge. We had more than 5000 tests, with developers adding to that number every single day. So we had to find a way to seamlessly migrate the existing test cases. Hence, we wrote an in-repo addon (to be open-sourced soon!) which would enable both Mocha and QUnit tests to be run simultaneously in our CI.

#STEP 2: Build the tools

Ember community has a pretty good collection of codemods, but unfortunately, there wasn’t one to convert Mocha to QUnit (although the inverse was available).

#2.1 Before we jumped into writing codemods, we wanted to analyse the existing test assertions which were written using Chai and obtain a list of unique expect statements. So we wrote this tiny node JS tool:

#2.2 Once we had the list of unique assertions in Chai, we started mapping the corresponding alternatives in QUnit assertions. However, QUnit has a very basic collection of assertions, especially when compared to something like chai. So we wrote this Ember addon to address the custom assertions:

#2.3 Finally we started writing the actual codemod transform which would automagically convert all the tests to QUnit — mocha-to-qunit. During pilot runs, we observed that we had a lot of async leakages in our test suites resulting in this error:

Assertion failed: You have turned on testing mode, which disabled the run-loop’s autorun. You will need to wrap any code with asynchronous side-effects in an Ember.run

So we wrote another codemod transform to fix that — async-leaks.

#STEP 3: Incremental migration

Thanks to the parallel testbed setup and the tooling, we could migrate the code module-by-module without any blockers or dependencies. We wrote a cookbook on “how to migrate from Mocha to QUnit” along with a “best practices guide for writing tests using QUnit” and shared it across the teams.

One month and 5000 test cases later, here we are, with more stable tests and green builds.

Shibu Lijack

Written by

Frontend Web Developer | Technophile | Music Lover | Foodie

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade