Adding CI to your JAMstack with Cypress, GitHub Actions and Netlify Deploy Preview
Tags: testing, jamstack, github, serverless
Published: 2020-01-25 19:31:04

With Netlify Deploy Preview, we get a new URL for every pull request in the code repository. This is perfect for JAMstack websites because they are generated at build time: what we get in the Preview Deploy is exactly what we will get when merging the pull request. This gives us great confidence. But it can be slow and tedious to manually test the Preview Deploy. Wouldn't it be amazing to have the powerful Cypress E2E testing framework do the tests for us? Our ideal workflow would be like this:

1. A contributor opens a pull request
2. Netlify builds a Preview Deploy
3. Cypress launches our test suite against the Preview URL.

Does this sound complex? Well, it is, but fortunately we can rely on GitHub Actions to orchestrate and automate our workflow. And the Cypress Team published a GitHub Action that abstracts away the complexity. (But of course, you still need to write the actual tests 😆)

Here an example configuration file for a [Nuxt app](https://github.com/mornir/copywork-portfolio), but the principle is the same for other static site generators:

```yml
name: End-to-end tests
on: [pull_request]
jobs:
  cypress-run:
    runs-on: ubuntu-16.04
    steps:
      - name: Checkout
        uses: actions/checkout@v1
      - name: Use Node.js 12.x
        uses: actions/setup-node@v1
        with:
          node-version: 12.x
      - name: Cypress run
        uses: cypress-io/github-action@v1
        env:
          CYPRESS_baseUrl: 'https://deploy-preview-${{ github.event.number }}--copywork.netlify.app'
        with:
          wait-on: 'https://deploy-preview-${{ github.event.number }}--copywork.netlify.app'
          wait-on-timeout: 90
```
The anatomy of a Preview URL is:
`https://deploy-preview-PULL_REQUEST_NUMBER--WEBSITE_NAME.netlify.app`

We access the pull request number from `github.event.number`. Then we have everything we need to create the Preview URL.

With the `env` parameter, we pass all environment variables needed to build the site. These variables will of course depend on the specific site, but it should at least contain the [baseUrl variable for Cypress](https://docs.cypress.io/guides/guides/environment-variables.html).

With the `wait-on` parameter, we wait for max. 90 seconds that Netlify finishes building the Preview Deploy before starting the tests. We can adjust that value depending on the time Netlify takes to build our site.

Commit & push the YAML config file and voilà! Our website is now being tested in real conditions! 🥳

## 📼 Record test results on Cypress Dashboard

One of the main advantages of Cypress is that we are able to view our entire test suit. When running in CI, we don't see Cypress running the tests. However, we can watch the recordings in the Cypress Dashboard! Here a series of links to have our test runs recorded to the Dashboard:

1. [Create a new Cypress project](https://docs.cypress.io/guides/dashboard/projects.html)
2. [Store the record key to GitHub secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets#creating-encrypted-secrets) (as CYPRESS_RECORD_KEY)
3. [Edit the YAML config to record tests](https://github.com/cypress-io/github-action#record-test-results-on-cypress-dashboard)


## 🏅 Getting rewarded for our efforts with fancy badges

We can get a badge that indicates whether our workflow with GitHub Actions passed or failed. [Here is how to get the dynamic URL for the SVG](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/configuring-a-workflow#adding-a-workflow-status-badge-to-your-repository). If like me you don't like the default look, you get a shinier badge thanks to [shields.io](https://shields.io/). Here's my styled badge with the associated markdown below.

[![GitHub Actions](https://img.shields.io/github/workflow/status/mornir/copywork-portfolio/End-to-end%20tests?label=build&logo=github&style=for-the-badge)](https://github.com/mornir/copywork-portfolio/actions)

```md
[![GitHub Actions](https://img.shields.io/github/workflow/status/mornir/copywork-portfolio/End-to-end%20tests?label=build&logo=github&style=for-the-badge)](https://github.com/mornir/copywork-portfolio/actions)
```
If the recordings in the Cypress Dashboard are public, [you can display test status and test counts](https://www.cypress.io/blog/2020/09/02/highlight-your-projects-test-status-with-cypress-readme-badges/):

[![Cypress Dashboard](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/detailed/rkg74b/master&style=for-the-badge&logo=cypress)](https://dashboard.cypress.io/projects/rkg74b/runs)

```md
[![Cypress Dashboard](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/detailed/rkg74b/master&style=for-the-badge&logo=cypress)](https://dashboard.cypress.io/projects/rkg74b/runs)
```

Finally, and you probably already know it, you can easily grab your Netlify deploy status badge from the site account: **Settings** → **General** → **Status badges**.

## 💭 Closing Words

With new services like GitHub Actions, it has become easier to set up complex continuous deployment pipelines. We can build upon our workflow and add more tasks, e.g. running unit tests.

What do you think of this workflow? Does it make sense to you? Do you see any problems or limitations with it? Feel free to share your opinion!