Cypress Testing - Getting started

Published: Nov 9, 2022 by Isaac Johnson

Cypress.io is a browser based test automation startup based in Atlanta, GA. Founded in 2015 by Brian Mann and Randall Kent, they saw a gap in front-end test automation tools and built their own JavaScript-based one from the ground up; the Cypress Test Runner.

I became aware of Cypress in a post on TL/DR and decided it was worth checking out. They are Open-Source based and have a pretty generous free tier.

Signup

To get started, go to https://dashboard.cypress.io/signup and signup.

I chose to signup with one of my federated accounts

/content/images/2022/11/cypress-02.png

We can see our options right at the start - I like the up-front pricing.

/content/images/2022/11/cypress-01.png

Once we select a model (I used Free), we go through a basic onboarding wizard.

/content/images/2022/11/cypress-03.png

Which will bring us to the dashboard.

/content/images/2022/11/cypress-04.png

In using Cypress, we will need our project ID and a key. I masked my key, of course, but the project ID just identifies our tenant.

Creating a basic App

Let’s go the quick path and setup a NodeJS app. You can also see these files in a public CypressHelloWorld repo I created

$ mkdir HelloWorld && cd HelloWorld
$ nvm use 10.22.1
$ npm init

We can now create a simple Hello World NodeJS app:

$ cat index.js
const http = require('http');
const hostname = 'localhost';
const port = 3000;
const server = http.createServer((req, res) => {
 console.log(req.headers);
 res.statusCode = 200;
 res.end('<html><body><h1>Hello, World!</h1></body></html>');
})
server.listen(port, hostname);
....

Now we can run it

builder@DESKTOP-72D2D9T:~/Workspaces/HelloWorld$ node index.js
{
  host: 'localhost:3000',
  connection: 'keep-alive',
  'sec-ch-ua': '"Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"',
  'sec-ch-ua-mobile': '?0',
  'sec-ch-ua-platform': '"Windows"',
  'upgrade-insecure-requests': '1',
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
  accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
  'sec-fetch-site': 'cross-site',
  'sec-fetch-mode': 'navigate',
  'sec-fetch-user': '?1',
  'sec-fetch-dest': 'document',
  referer: 'https://medium.com/@mohammedijas/hello-world-in-node-js-b333275ddc89',
  'accept-encoding': 'gzip, deflate, br',
  'accept-language': 'en-US,en;q=0.9',
  cookie: 'intercom-id-neveeefd=0e134d3d-98dd-4939-9000-406f2b15c44a; loft_access_key=jARz1l9LlLwBXnN9w9T2WXyilZBDO4Ob0LhRqUzE2zQQp7eWn6h35Ja4beG1C1UU; ajs_anonymous_id=de6893f8-4e53-475e-860c-fd9b250bc33a; ajs_group_id=8b00d0aeed9b9d4e5fbb1a45bc0f9d9013e5e1ae04e64a53b6707cffac1b145a; ajs_user_id=19ac21c1-e8c8-4d8d-a5a4-9ce3cec0c542'
}
{
  host: 'localhost:3000',
  connection: 'keep-alive',
  'sec-ch-ua': '"Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"',
  'sec-ch-ua-mobile': '?0',
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
  'sec-ch-ua-platform': '"Windows"',
  accept: 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
  'sec-fetch-site': 'same-origin',
  'sec-fetch-mode': 'no-cors',
  'sec-fetch-dest': 'image',
  referer: 'http://localhost:3000/',
  'accept-encoding': 'gzip, deflate, br',
  'accept-language': 'en-US,en;q=0.9',
  cookie: 'intercom-id-neveeefd=0e134d3d-98dd-4939-9000-406f2b15c44a; loft_access_key=jARz1l9LlLwBXnN9w9T2WXyilZBDO4Ob0LhRqUzE2zQQp7eWn6h35Ja4beG1C1UU; ajs_anonymous_id=de6893f8-4e53-475e-860c-fd9b250bc33a; ajs_group_id=8b00d0aeed9b9d4e5fbb1a45bc0f9d9013e5e1ae04e64a53b6707cffac1b145a; ajs_user_id=19ac21c1-e8c8-4d8d-a5a4-9ce3cec0c542'
}

/content/images/2022/11/cypress-13.png

If you are looking to clone this repo, you can do the following:

builder@DESKTOP-QADGF36:~/Workspaces$ git clone https://github.com/idjohnson/CypressHelloWorld.git
Cloning into 'CypressHelloWorld'...
remote: Enumerating objects: 19, done.
remote: Counting objects: 100% (19/19), done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 19 (delta 2), reused 19 (delta 2), pack-reused 0
Unpacking objects: 100% (19/19), 20.44 KiB | 634.00 KiB/s, done.
builder@DESKTOP-QADGF36:~/Workspaces$ cd CypressHelloWorld/
builder@DESKTOP-QADGF36:~/Workspaces/CypressHelloWorld$ npm install

> cypress@11.0.0 postinstall /home/builder/Workspaces/CypressHelloWorld/node_modules/cypress
> node index.js --exec install

Installing Cypress (version: 11.0.0)

✔  Downloaded Cypress
✔  Unzipped Cypress
✔  Finished Installation /home/builder/.cache/Cypress/11.0.0

You can now open Cypress by running: node_modules/.bin/cypress open

https://on.cypress.io/installing-cypress

npm WARN helloworld@1.0.0 No description
npm WARN helloworld@1.0.0 No repository field.

added 166 packages from 176 contributors and audited 166 packages in 14.42s

28 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
builder@DESKTOP-QADGF36:~/Workspaces/CypressHelloWorld$ npm start

> helloworld@1.0.0 start /home/builder/Workspaces/CypressHelloWorld
> node index.js

{ host: 'localhost:3000',
  connection: 'keep-alive',
  'sec-ch-ua':
   '"Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"',
   ... snip ...

Adding Cypress

We can install Cypress with NPM like any other NodeJS package.

$ npm install --save cypress

After we install Cypress, we need to configure it

builder@DESKTOP-72D2D9T:~/Workspaces/HelloWorld$ cat cypress.config.js
module.exports = {
  // The rest of the Cypress config options go here...
  projectId: "54ggqn",

  e2e: {
    setupNodeEvents(on, config) {
      // implement node event listeners here
    },
  }
}

We can then launch to use it interactively.

Since I’m on Win11, it will actually launch the X based version with GTK

builder@DESKTOP-72D2D9T:~/Workspaces/HelloWorld$ node_modules/.bin/cypress open
Still waiting to connect to Firefox, retrying in 1 second (attempt 18/62)
Still waiting to connect to Firefox, retrying in 1 second (attempt 18/62)
Still waiting to connect to Firefox, retrying in 1 second (attempt 19/62)
Still waiting to connect to Firefox, retrying in 1 second (attempt 19/62)
Still waiting to connect to Firefox, retrying in 1 second (attempt 20/62)
Still waiting to connect to Firefox, retrying in 1 second (attempt 20/62)
GET /__/ 200 13.054 ms - -
GET /__/assets/index.f7acf50b.css 200 30.045 ms - -
GET /__/assets/polyfills.f25d072f.js 200 30.569 ms - -
GET /__/assets/index.fb1aa47f.js 200 36.757 ms - -
GET /__cypress/runner/cypress_runner.css 200 18.803 ms - -
GET /__cypress/runner/favicon.ico?v2 200 18.569 ms - -
GET /__/assets/Specs.6e234103.js 200 28.282 ms - 485
GET /__/assets/Index.0a84bae0.css 200 7.378 ms - -
GET /__/assets/CreateSpecModal.315eb5ce.css 200 23.125 ms - 368
GET /__/assets/settings_x16.f856ddfd.js 200 53.650 ms - -
GET /__/assets/SpecPatterns.0279d756.js 200 37.879 ms - -
GET /__/assets/user-outline_x16.df6881a8.js 200 34.976 ms - -
GET /__/assets/ResultCounts.619acb5c.js 200 33.989 ms - -
GET /__/assets/CreateSpecModal.2e21bad6.js 200 33.806 ms - -
GET /__/assets/Index.9b393b90.js 200 57.641 ms - -
GET /__/assets/Index.9b393b90.js 200 38.921 ms - -
GET /__/assets/ResultCounts.619acb5c.js 304 2.569 ms - -
GET /__/assets/CreateSpecModal.2e21bad6.js 304 8.486 ms - -
GET /__/assets/user-outline_x16.df6881a8.js 304 19.776 ms - -
GET /__/assets/SpecPatterns.0279d756.js 304 20.021 ms - -
GET /__/assets/settings_x16.f856ddfd.js 304 6.960 ms - -
GET /__/assets/cypress_s.29af549a.png 200 11.116 ms - 4425
GET /__cypress/runner/cypress_runner.js 200 19.546 ms - -
GET /__/assets/firefox.9be61e66.svg 200 2.426 ms - -
GET /__/assets/electron.fb07f5cc.svg 200 11.180 ms - -
GET /__/assets/FiraCode-VariableFont_wght.16865a4d.ttf 200 2.614 ms - -
GET /__/assets/onigasm.b63d2d2d.wasm 200 3.059 ms - -
GET /__/assets/Runner.d2b9b65e.css 200 1.468 ms - -
GET /__/assets/refresh_x16.7e325db2.js 200 5.544 ms - -
GET /__/assets/Switch.84421b92.js 200 4.151 ms - -
GET /__/assets/Runner.2409152f.js 200 3.817 ms - -
GET /__/assets/Runner.2409152f.js 304 0.801 ms - -
GET /__/assets/Switch.84421b92.js 304 0.660 ms - -
GET /__/assets/refresh_x16.7e325db2.js 304 1.105 ms - -
GET /__cypress/iframes/cypress%2Fe2e%2Fspec.cy.js 200 18.707 ms - 852
GET /__cypress/tests?p=cypress/e2e/spec.cy.js 200 1886.126 ms - -
GET /__cypress/tests?p=cypress/support/e2e.js 200 1912.196 ms - -
GET /__/ 200 2.824 ms - -
GET /__/assets/polyfills.f25d072f.js 200 2.148 ms - -
GET /__/assets/index.f7acf50b.css 200 15.164 ms - -
GET /__/assets/index.fb1aa47f.js 200 13.191 ms - -
GET /__cypress/runner/cypress_runner.css 200 9.258 ms - -
GET /__cypress/runner/favicon.ico?v2 200 6.459 ms - -
GET /__/assets/Specs.6e234103.js 200 6.169 ms - 485
GET /__/assets/Runner.d2b9b65e.css 200 16.965 ms - -
GET /__/assets/CreateSpecModal.315eb5ce.css 200 70.420 ms - 368
GET /__/assets/refresh_x16.7e325db2.js 200 14.286 ms - -
GET /__/assets/Runner.2409152f.js 200 14.965 ms - -
GET /__/assets/Switch.84421b92.js 200 20.910 ms - -
GET /__/assets/SpecPatterns.0279d756.js 200 8.609 ms - -
GET /__/assets/CreateSpecModal.2e21bad6.js 200 19.513 ms - -
GET /__/assets/Runner.2409152f.js 200 13.064 ms - -
GET /__/assets/CreateSpecModal.2e21bad6.js 304 1.338 ms - -
GET /__/assets/Switch.84421b92.js 304 5.957 ms - -
GET /__/assets/refresh_x16.7e325db2.js 304 2.641 ms - -
GET /__/assets/SpecPatterns.0279d756.js 304 0.665 ms - -
GET /__/assets/cypress_s.29af549a.png 200 6.030 ms - 4425
GET /__cypress/runner/cypress_runner.js 200 18.141 ms - -
GET /__/assets/firefox.9be61e66.svg 200 2.145 ms - -
GET /__/assets/electron.fb07f5cc.svg 200 30.746 ms - -
GET /__cypress/iframes/cypress%2Fe2e%2Fspec.cy.js 200 3.430 ms - 853
GET /__cypress/tests?p=cypress/support/e2e.js 200 20.179 ms - -
GET /__cypress/tests?p=cypress/e2e/spec.cy.js 200 19.234 ms - -
GET / 200 92.673 ms - -
GET /assets/css/vendor/bootstrap.min.3cdc65ed.css 200 269.778 ms - -
GET /assets/css/vendor/fira.css 200 430.329 ms - -
GET /assets/css/styles.188b2993.css 200 363.467 ms - -
GET /assets/js/vendor/jquery-1.12.0.min.cbb11b58.js 200 325.420 ms - -
GET /assets/js/scripts.4a26d59a.js 200 443.522 ms - -
GET /assets/js/vendor/highlight.pack.4cbe7783.js 200 360.332 ms - -
GET /assets/js/vendor/bootstrap.min.c5b5b2fa.js 200 342.107 ms - -
GET /assets/fonts/woff/FiraSans-Regular.woff 200 136.761 ms - -
GET /assets/fonts/woff/FiraSans-Medium.woff 200 212.766 ms - -
GET /__/assets/Runs.78461f26.css 200 2.337 ms - 707
GET /__/assets/ResultCounts.619acb5c.js 200 5.222 ms - -
GET /__/assets/CloudConnectButton.000e6a3d.js 200 7.446 ms - -
GET /__/assets/user-outline_x16.df6881a8.js 200 5.855 ms - -
GET /__/assets/Runs.d763ac02.js 200 6.707 ms - -
GET /__/assets/Runs.d763ac02.js 200 7.164 ms - -
GET /__/assets/CloudConnectButton.000e6a3d.js 304 1.496 ms - -
GET /__/assets/ResultCounts.619acb5c.js 304 0.576 ms - -
GET /__/assets/user-outline_x16.df6881a8.js 304 0.703 ms - -
GET /__/assets/Settings.db1ebf2a.css 200 4.315 ms - 820
GET /__/assets/Settings.b51d35bf.js 200 6.110 ms - -
GET /__/assets/settings_x16.f856ddfd.js 200 4.515 ms - -
GET /__/assets/Settings.b51d35bf.js 304 0.638 ms - -
GET /__/assets/settings_x16.f856ddfd.js 304 0.555 ms - -
GET /__/assets/Index.0a84bae0.css 200 2.386 ms - -
GET /__/assets/Index.9b393b90.js 200 3.610 ms - -
GET /__/assets/Index.9b393b90.js 200 2.320 ms - -
GET /__cypress/iframes/cypress%2Fe2e%2Fspec.cy.js 304 5.001 ms - -
GET /__cypress/iframes/cypress%2Fe2e%2Fspec.cy.js 304 1.422 ms - -
GET /__cypress/tests?p=cypress/support/e2e.js 200 5.684 ms - -
GET /__cypress/tests?p=cypress/e2e/spec.cy.js 200 4.562 ms - -
GET / 200 9.585 ms - -
The automation client disconnected. Cannot continue running tests.
builder@DESKTOP-72D2D9T:~/Workspaces/HelloWorld$

This launches the GUI for Cypress

/content/images/2022/11/cypress-05.png

Here I’ll choose E2E (end-to-end) testing

/content/images/2022/11/cypress-06.png

And Electron (Chromium) or Firefox would work, I opted for Firefox

/content/images/2022/11/cypress-07.png

I created a new Spec

/content/images/2022/11/cypress-08.png

Then did a basic Hello World test to access the cypress.io example site (https://example.cypress.io).

/content/images/2022/11/cypress-09.png

We can also send our spec to an IDE like VS Code to edit:

/content/images/2022/11/cypress-16.png

which can launch into VSC

/content/images/2022/11/cypress-10.png

We can see the created e2e spec

builder@DESKTOP-72D2D9T:~/Workspaces/HelloWorld$ cat cypress/e2e/spec.cy.js
describe('empty spec', () => {
  it('passes', () => {
    cy.visit('https://example.cypress.io')
  })
})

Now that I have some tests created, I can run it from the command line

builder@DESKTOP-72D2D9T:~/Workspaces/HelloWorld$ npx cypress run --record --key asdfasdf-asdf-asdf-asdf-asdfasdfasdfsa

====================================================================================================

  (Run Starting)

  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ Cypress:        11.0.0                                                                         │
  │ Browser:        Electron 106 (headless)                                                        │
  │ Node Version:   v14.19.0 (/home/builder/.nvm/versions/node/v14.19.0/bin/node)                  │
  │ Specs:          1 found (spec.cy.js)                                                           │
  │ Searched:       cypress/e2e/**/*.cy.{js,jsx,ts,tsx}                                            │
  │ Params:         Tag: false, Group: false, Parallel: false                                      │
  │ Run URL:        https://dashboard.cypress.io/projects/54ggqn/runs/1                            │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘


────────────────────────────────────────────────────────────────────────────────────────────────────

  Running:  spec.cy.js                                                                      (1 of 1)


  empty spec
    ✓ passes (1391ms)


  1 passing (6s)


  (Results)

  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ Tests:        1                                                                                │
  │ Passing:      1                                                                                │
  │ Failing:      0                                                                                │
  │ Pending:      0                                                                                │
  │ Skipped:      0                                                                                │
  │ Screenshots:  0                                                                                │
  │ Video:        true                                                                             │
  │ Duration:     6 seconds                                                                        │
  │ Spec Ran:     spec.cy.js                                                                       │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘


  (Video)

  -  Started processing:  Compressing to 32 CRF
  -  Finished processing: /home/builder/Workspaces/HelloWorld/cypress/videos/spec.cy.    (2 seconds)
                          js.mp4


  (Uploading Results)

  - Done Uploading (1/1) /home/builder/Workspaces/HelloWorld/cypress/videos/spec.cy.js.mp4

====================================================================================================

  (Run Finished)


       Spec                                              Tests  Passing  Failing  Pending  Skipped
  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ ✔  spec.cy.js                               00:06        1        1        -        -        - │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘
    ✔  All specs passed!                        00:06        1        1        -        -        -


───────────────────────────────────────────────────────────────────────────────────────────────────────

  Recorded Run: https://dashboard.cypress.io/projects/54ggqn/runs/1

builder@DESKTOP-72D2D9T:~/Workspaces/HelloWorld$

And we can view the results

/content/images/2022/11/cypress-11.png

And there is a short recording of our tests we can review

/content/images/2022/11/cypress-12.png

Recording

Adding more tests

I’ve now cloned to a new host. I just need to do the same cypress open

builder@DESKTOP-QADGF36:~/Workspaces/CypressHelloWorld$ node_modules/.bin/cypress open
It looks like this is your first time using Cypress: 11.0.0

✔  Verified Cypress! /home/builder/.cache/Cypress/11.0.0/Cypress

Opening Cypress...

I decided to pivot and launch this in a Windows Command prompt which was interesting as when I did the startup wizard, I saw more options like Chrome and Edge:

/content/images/2022/11/cypress-14.png

which lets me easily run my Hello World test

/content/images/2022/11/cypress-15.png

I can write a basic test of my Harbor site:

describe('empty spec', () => {
  beforeEach(() => {
    cy.visit('https://harbor.freshbrewed.science/')
  })

  
  it('.focus() - focus on a DOM element', () => {
    // https://on.cypress.io/focus
    cy.get('.username [type="text"]').type('fake.username').should('have.value', 'fake.username')
  })

})

And run it to see it fill in a text box

/content/images/2022/11/cypress-17.png

I can of course now run outside the UI in the command line and make it part of my tests.

Here I’ll run just the E2E test I updated:

$ npx cypress run --record --spec "cypress/e2e/spec.cy.js"  --key asdfasfsadf-asdf-asdf-asdfasdsd

/content/images/2022/11/cypress-18.png

Recording:

About Cypress

In the How It Works Guide, they made it clear that Cypress was written from the ground up - it’s not just a wrapper around selenium as many tools often are. Cypress is focused just on JS but written to be used by Dev and QA alike.

To quote their site:

Most testing tools operate by running outside of the browser and executing remote commands across the network. Cypress is the exact opposite. Cypress is executed in the same run loop as your application. Behind Cypress is a Node.js server process. Cypress and the Node.js process constantly communicate, synchronize, and perform tasks on behalf of each other. Having access to both parts (front and back) gives us the ability to respond to your application's events in real time, while at the same time work outside of the browser for tasks that require a higher privilege.

Cypress also operates at the network layer by reading and altering web traffic on the fly. This enables Cypress to not only modify everything coming in and out of the browser, but also to change code that may interfere with its ability to automate the browser.

Cypress ultimately controls the entire automation process from top to bottom, which puts it in the unique position of being able to understand everything happening in and outside of the browser. This means Cypress is capable of delivering more consistent results than any other testing tool.

Because Cypress is installed locally on your machine, it can additionally tap into the operating system itself for automation tasks. This makes performing tasks such as taking screenshots, recording videos, general file system operations and network operations possible.

As far as the company, I see various pages showing 50 to 139 employees and Cypress.io presently in Series B funding (the latest being $40m in 2020).

Three years after founding it, the founders brought in Drew Lanham as CEO who had past experience as a VP at Good Tech (Motorola), Yahoo! and Nexidia (NICE). I would guess at the start, Brian was the key engineer (as he has been a lead at InspectAll prior and Randal is now “Director of Revenue Operations”). Their largest funder is the VC Firm Bessemer Venture Partners which has a pretty expansive portfolio.

Summary

We just scratched the surface with what Cypress.io can do. In the free tier we can have 3 users and 500 tests. This could be enough to do basic system tests. I plan to use it to work out some uptime tests for various apps.

I’ve generally used Uptime Kuma for a lot of quick ping tests. And I could use Synthetic Monitors in hosted suites like Datadog. But having a quick way to write interactive JavaScript-based tests will allow me to work out test frameworks for things that are harder for which to write Unit Tests, such as black box containerized apps or 3rd party tools.

nodejs cypress testing

Have something to add? Feedback? You can use the feedback form

Isaac Johnson

Isaac Johnson

Cloud Solutions Architect

Isaac is a CSA and DevOps engineer who focuses on cloud migrations and devops processes. He also is a dad to three wonderful daughters (hence the references to Princess King sprinkled throughout the blog).

Theme built by C.S. Rhymes