Continuous Integration in JavaScript: a Guide (ft. Github Actions)

How do you automated tests when the code leaves your computer? Learn continuous integration in JavaScript with this easy to read guide. (Featuring Github Actions!).

Continuous Integration in JavaScript: a Guide

Automated testing and continuous integration in JavaScript: what you will learn

NOTE: even if you don’t like JavaScript I suggest reading the guide, continuous integration is not tied to any programming language in particular. The concepts you’ll learn here apply to any other language or platform.

In this guide you’ll learn:

  • what is automated testing
  • what is continuous integration
  • how to apply automated unit testing and continuous integration to a simple JavaScript project

Who this guide is for

If you know your way around JavaScript testing and want to learn continuous integration then this guide is for you.

If you’re still new to testing make sure to check out Getting started with Jest for JavaScript testing and then come back here.

The guide assumes a good knowledge of version control, Git and its terminology like commit and push. I suggest going through the first pages of Git book and then come back to this post if you’re new to Git and version control.

Enjoy!

What is automated testing?

Testing your code is crucial, we can all agree on that. These days testing on the local workstation is easy as pressing a button in your favorite IDE, but how do you enforce tests when the code leaves your computer? It’s also easy to let some unit test slip off when a new member joins the team and he/she is still not expert, after all we’re human.

So what? As you can see there’s the need for a tool which runs your tests in an automated fashion.

Automated testing is the ability to run tests without human intervention, in an environment that most of the times is not your local workstation anymore.

Automated testing is achieved with the help of specific tools running inside a so called continuous integration service. Let’s clarify what is continuous integration before taking a look at the tooling.

What is continuous integration?

Since the inception of software and web development there had always been the need to address some specific issues:

  • enforce testing before releasing to production
  • catch bugs before a product is shipped
  • get rapid feedback about the product

Since the early days there were pioneering attempts to streamline all these steps into a so called pipeline. A pipeline is made of a well defined set of steps, running one after another (or in parallel). Here’s how a pipeline looks like:

file changes -> trigger an automated test -> release to production

With time all these techniques got “standardized” under the name of continuous integration. More broadly continuous integration is a practice which prescribes to continuously integrate new code and new features into a shared codebase.

The theory is that the team can get rapid feedback, adjust errors and fix bugs more quickly if all the developers integrate changes into the same codebase, multiple time a day. The fundamental pre-requisite for continuous integration is version control. Every line of code, every line of configuration, should stay under version control.

Easier said than done? Continuous integration is not an easy beast to tame, but these days there are neat tools for creating pipelines in a bunch of lines of code. So let’s take a look at this modern tooling.

Automated Testing and Continuous Integration in JavaScript: choosing a CI/CD service

At the core of a continuous integration (CI from now on) system there is a pipeline.

A pipeline is a set of steps happening after a specific action. By action I mean a change in the codebase which is ideally hosted on a version control server. Once upon a time “there was” SVN, but eventually Git became the most popular version control system.

Once the developer changes some line of code, makes a commit and pushes to a repository the pipeline springs into action. What happens next depends on how you configured your CI service. As part of the pipeline you can:

  • test your code/software/UI
  • build a production version and deploy it

But what’s exactly a CI service? It’s a tool that runs your pipeline. You can install it on a server (on premise) or rent from an external provider (as a service). There are many CI services these days, some free, some paid: I can name TravisCI, CircleCI and GitLab CI. Pick your own!

These days you may also want to get rid of FTP for “deploying”. Most CI services are equipped with some sort of CD capability, short for continuous delivery. That’s why we call these tools “CI/CD services”.

Continuous delivery means releasing the software as soon as tests are passing. Continuous delivery is akin to continuous integration: after the automated test passes we can build a production artifact and then automatically deploy to production.

Hand tight, in the next sections you’ll finally make some practice with CI.

Automated Testing and Continuous Integration in JavaScript: configuring a CI/CD service, the workflow

Let’s recap what we’ve learned so far. Continuous integration is a practice . The core principle prescribes that everything must be under version control and developers must integrate code daily into a shared codebase.

Today continuous integration is practiced on CI/CD services where you create a so called pipeline which is triggered every time a developer makes changes.

The pipeline takes care of building your code and running automated tests against it. But how does a CI/CD service work in practice? Well, most of the times you should configure the service with a configuration file.

As I was writing this guide I got beta access to Github actions, a new Github feature which includes also a CI/CD service (free for public repos). Actions are directly integrated with Github repos and it’s a great way to practice CI without relying on external services other than Github.

Most CI/CD service are configured through a YAML file which usually takes:

  • the name of the pipeline (Github calls it “workflow”)
  • a list of jobs to do
  • a list of steps for every job

If we want to translate the configuration to actual things to do we can configure the CI service for:

  • setting up a JavaScript environment (mostly Node.js)
  • installing the dependencies for the project
  • optionally building the project
  • running automated tests

In the next section we’ll configure a Github workflow for automating a couple of unit tests. Before getting to the next section take some time to look at the Workflow syntax for GitHub Actions to make yourself comfortable with the syntax.

Automated Testing and Continuous Integration in JavaScript: automated unit testing

In Getting started with Jest for JavaScript testing I covered the basics of testing and I left the reader with a simple JavaScript project. It has a bunch of unit tests for a function called filterByTerm.

Now let’s clone the repo for adding a testing pipeline with Github workflow:

git clone git@github.com:valentinogagliardi/getting-started-with-jest.git

Move inside the project folder, install the dependencies and run a quick test:

cd getting-started-with-jest
npm i
npm test

These are exactly the steps that we’re going to automate. Note that the first test should always happen on your local workstation, never commit failing code. It’s your responsibility to test the code before pushing to the repo. Now still in the repo create a new folder named .github/workflows/:

mkdir -p .github/workflows/

That folder is where Github expects to find your workflows (pipelines). Now we need a configuration file for the workflow, in YAML. Create a new file named javascript.yml in .github/workflows/.

I won’t go every through line, the configuration should be easy to grok. With the steps we outline before:

  • setting up a JavaScript environment (mostly Node.js)
  • installing the dependencies for the project
  • optionally building the project
  • running automated tests

we can configure our first workflow like so:

name: JavaScript workflow

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Use Node.js 12.x
      uses: actions/setup-node@v1
      with:
        node-version: "12.x"
    - name: npm install, and test
      run: |
        npm install
        npm test
      env:
        CI: true

The workflow has a name, “JavaScript workflow”, runs on every push, and as a result it creates a virtual Ubuntu environment with Node.js 12.x (see the steps above).

Not let’s make a commit, note that the workflow file should be pushed to the repo:

git add .github/
git commit -m  "Configuring a Github workflow"
git push origin HEAD

Now the workflow should run and I can confirm that it went well by going to the tab Actions on Github:

Automated Testing and Continuous Integration in JavaScript: automated unit testing with Github workflow

Test passing! Believe it or not this is all it takes to start with automated testing and continuous integration in JavaScript, with a bit of help from Github.

Of course real world projects will have different requirements and use more complex workflow configurations. But my point is that with the tools we have today there should be no more excuses for not practicing continuous integration and automated testing.

I suggest going through the documentation on Github for exploring what workflow have to offer.

Conclusions, and where to go from here

Continuous integration was first theorized in 1991 and later adopted by an ever growing number of teams and software developers all over the world.

Continuous integration is a discipline, more than a practice, it requires a complete shift in your approach to software and web development. But with the sacrifice of adopting CI/CD come a lot of perks.

Continuous integration builds on the following core principles:

  • code and configuration must stay under version control
  • everything should be automatically testable
  • if the test breaks then we must stop and fix the bug

Today continuous integration is made dead simple by a growing number of CI/CD services like Gitlab CI, Bitbucket pipelines, CircleCI, and Github workflow.

But is continuous integration really worth it? Considering how simple is to set up a build/test pipeline today there should be no more excuses for avoiding CI/CD, even when a project has a short-ish lifespan.

So where to go from here? After having learned about automated unit testing with this simple example try to automate some UI test in a Github workflow. (Or in your tool of choice). What steps should your YAML file take? For UI testing I strongly recommend using Cypress, you’ll have fun.

Thanks for reading and stay tuned!

One Reply to “Continuous Integration in JavaScript: a Guide (ft. Github Actions)”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.