Shave and a Haircut, Two Minutes

Written by Chris Sloan

After removing Ruby to process and run our JavaScript testing suite, we were able to cut down run time by two minutes via a pure NodeJS setup.

Shave and a haircut, two minutes

Time to deploy is crucial to our engineering team. We deploy multiple times a day and pride ourselves on that fact. When we see pain points in our deployment process, we take time to figure out how we can make things better. In this instance, we saw a need for our JavaScript testing environment and how it could be improved.


Our JavaScript testing environment for our main application was about two years old and definitely showing its age. When it was created, it was using Karma as the runner, but being piped through a rake task to spin up. It was set up this way because we wanted to utilize the Rails asset pipeline and its manifest files. With this setup, it cost our build process roughly two and a half minutes to run this specific task.

Not only was the build painful, local development was also. Running this rake task locally just to spin up our Karma runner had to load the Rails environment and cache all the associated files. Again, this took, while not as long as two and a half minutes, a significant amount of time. To add to the issues, Karma would sometimes get stuck and a hard kill -9 would be required.

A final pain point we saw, was that we were writing our test files in CoffeeScript. To those who love CoffeeScript — yes I used to be one of them — this may not seem like a big deal, but it was an unnecessary evil. JavaScript tests, as most know, can get nested very deeply with describe blocks to setup contexts. CoffeeScript requires indentions to do this, so things got very crazy, very quickly. Also, there weren’t any other noticeable benefits that ES2016 wasn’t already getting us.

Enough is Enough

The Front-end Guild decided to finally take steps to get rid of this painful and annoying toolset. We were already using an npm solution to manage our dependencies and testing for our new video player as well as some other components we were developing, so we figured we would apply this same mentality to our main Rails app.

Small Baby Steps

Our process is all about small, iterative, releasable steps. Again, we deploy multiple times a day to production so I wanted to take this same approach. After each step below, I was able to release that portion to production.

1. Convert All Our Spec Files to ES2016

I utilized an npm package called decaffeinate to convert all our CoffeeScript files over to ES2016. This was pretty simple to run all the files through a bash script and have the output duplicate files but without the CoffeeScript extension.

A couple of caveats with converting JavaScript test files I found with this tool were:

No easy way to rename the output files as it uses the original and just replaces coffee with js It throws return in every block which ultimately was returning expects which is unnecessary

2. Setup Node and Karma

Next, I set up the package.json to include everything I needed to get Karma to run our test suite. The old test suite was using the same setup, but was very outdated and again, running through a rake task.

I also took the time at this step to only load the JavaScript files I wanted and needed to load instead of loading all of the manifests. This cut down on roughly ten to fifteen files that we did not need to load.

Some other key components we added with this update include:

3. Get Continuous Integration to Run the Tests

We use CircleCI to build, run tests, and deploy our application. Getting this to work was as simple as adding the npm test command to the circle.yml file in the test block. Also, in order to keep dependency load down, I added the node_modules folder to the CircleCI cache so that when npm install is run, it only ever happens if new dependencies are needed to be matched.

4. Delete, Delete, Delete

With everything running smoothly, the final step was to delete old unnecessary files. With this, I was able to remove about 6,500 lines of code in our application.

The Outcome

Not only did we get a win with local development headaches by removing all references to using Ruby to run Karma, but we also removed a significant amount of time from our build test process. From the two and a half minute test run time, it now runs in 10 seconds!! Totally worth the effort put forth to make all of the Engineering group’s lives that much better.