Automated CI with Cypress and Github Actions
At the day job, we've introduced a development pipeline that consists of creating feature branches that deploy to their own environments, and using Cypress tests to validate that the build is good before merging. I've known enough about it to talk about it with my team, but not do it in practice. So I've followed some guidelines using some free tools that help me get there.
It consists of using Github with Github Actions, Cypress with Cypress Dashboard, and Vercel to handle deployments. Here's how to set this up from scratch.
Set up a local repo
Instructions below are true as of the last-updated date, and at least on my machine.
- In a terminal, type
yarn create next-app
- Name the app. Let's pretend it's
twitter-killer
cd twitter-killer
- Open in code, and add a
pages/index.js
file with the following contents, and save:
export default function Home() {
return (
<div>
<h1>Hello</h1>
<p>How are you</p>
</div>
)
}
- Back in the terminal at project root, add cypress:
yarn add cypress --dev
Set up a Cypress test locally
- Still in the terminal at project root:
yarn run cypress open
- Within the Cypress app, select e2e testing.
- Accept defaults and continue, choosing Chrome for the browser, and continue.
- Select the
Create new empty spec
option - Accept default path of
cypress/e2e/spec.cy.js
and click "Create spec". - Then "Ok, run the spec"
- It works! Now close cypress.
- Open
cypress.config.js
, and as a sibling tosetupNodeEvents
, addbaseUrl: 'http://localhost:3000'
, so it ends up looking like this:
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
baseUrl: 'http://localhost:3000'
},
- Open
spec.cy.js
and changecy.visit
line tocy.visit('/')
- Then add an additional test:
cy.get('h1').should('contain.text', 'Welcome to').should('be.visible')
- Validate this works by running the app (
yarn dev
) and also running cypress (yarn run cypress open
) - Do a git add / commit to capture this.
Add to GitHub
- Visit github.com and create a new repo
- Follow the directions to push an existing repository from local.
- There should now be a 'main' branch in GitHub.
Configure Vercel
- Log into vercel.
- Create a new project, and enable the new git repo to be added.
- Proceed with the deployment
Cypress Dashboard projectId and record key
- In Cypress Dashboard's UI, create a new project, adding 'GitHub Actions' as the CI.
- You'll be given a projectId to add to your cypress.config.js file. Add it, and follow the instructions to run the npx command with the record key.
- Copy the record key. (If already navigated away, go to Cypress Dashboard for that project, and go to Project Settings. The record key should be listed.
- Within the GitHub UI for the project, navigate to Settings -> Secrets -> Actions -> New Repository Secret.
- Name it CYPRESS_RECORD_KEY, and paste in your record key
Now add a GitHub workflow
- Within the GitHub project -> Actions -> Set up a workflow yourself
- Name it deploy.yml
- Paste in the yaml
name: Cypress Tests
on:
pull_request:
push:
branches: main
jobs:
runTestsAgainstPreview:
name: Run Tests Against Preview URL
runs-on: "ubuntu-latest"
steps:
- name: Capture Vercel preview URL
id: waitFor200
uses: patrickedqvist/wait-for-vercel-preview@v1.2.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
max_timeout: 60
- name: Checkout
uses: actions/checkout@v2
- name: Run Cypress
uses: cypress-io/github-action@v4
id: runCypress
with:
record: true
parallel: true
ci-build-id: '${{ github.sha }}-${{ github.workflow }}-${{ github.event_name }}'
config: baseUrl=${{steps.waitFor200.outputs.url}}
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Add Label
uses: actions-ecosystem/action-add-labels@v1
with:
labels: automerge
if: ${{ steps.runCypress.outcome == 'success' }}
automerge:
runs-on: ubuntu-latest
needs: runTestsAgainstPreview
steps:
- id: automerge
name: automerge
uses: "pascalgn/automerge-action@v0.15.3"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
MERGE_RETRIES: 10
MERGE_RETRY_SLEEP: 10000
- By going through with that commit in the GitHub UI, it should now trigger that deploy.yml file, so switch over to 'Actions' tab and check it out. It will fail, as we haven't pushed up the projectId edit that we made locally earlier.
- So locally, first, add
cypress/videos/
to the gitignore. - Things may still fail, as I got
HttpError: Empty value for parameter 'issue_number': undefined
. I should try this as a pull request instead. git checkout -b feature-copy-edit
- Make change and push up a new branch, and intitiate the pull request within GitHub. Actions should now run, and automerge
- Should be live!
Lock down main
branch in GitHub to enforce good habits
- Github project -> Settings -> Branches
- Add rule, that matches branch name
main
- Check "Require a pull request before merging"
- Check "Require status checks to pass before merging"
- In the 'Search for status checks...' field, enter 'Run Tests Against Preview URL', which is defined in the yaml
- Check "Do not allow bypassing the above settings"
In summary, the new workflow
Going forward, to make changes to this repo, proceed as follows:
- Create a branch
- Make your changes
- Commit and push up feature branch. (Vercel will deploy)
- Initiate PR. (Cypress will run against the deployment)
If Cypress fails...
- The pull request doesn't merge automatically.
- Continue pushing up new commits to the pull request until this is fixed.
If Cypress passes...
- The pull request is given a label of
automerge
. - Upon merging into 'main' branch, vercel deploys to production url.
Missing parts of my notes
- I've done the create next-app 3 times and not getting consistent results with the creation of a gitignore file.
- How does this work with Netlify?
- Don't we need some automated way for older preview environments to close down?
August 17, 2022🏷cypresscivercelgithub actions