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
We can see our options right at the start - I like the up-front pricing.
Once we select a model (I used Free), we go through a basic onboarding wizard.
Which will bring us to the dashboard.
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'
}
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
Here I’ll choose E2E (end-to-end) testing
And Electron (Chromium) or Firefox would work, I opted for Firefox
I created a new Spec
Then did a basic Hello World test to access the cypress.io example site (https://example.cypress.io).
We can also send our spec to an IDE like VS Code to edit:
which can launch into VSC
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
And there is a short recording of our tests we can review
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:
which lets me easily run my Hello World test
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
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
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.