- Example repo
- The first test
- Run tests on Netlify
- Testing Netlify functions
- Failing tests and artifacts
- Recording to Cypress Dashboard
- Cypress GitHub App and status checks
- Bonus: automate dependency updates
- See more
Example repo
I have cloned the Eleventy starter with serverless functions under my GitHub repo bahmutov/eleventyone. The site is deployed automatically from GitHub to Netlify and you can see it under https://eleventyone-test.netlify.app/.
Any time I open a Pull Request a new preview is deployed at Netlify automatically. I would like to run end-to-end tests against the deployed URL. Let's see how to do this.
The first test
First, install Cypress test runner as a dev dependency
1 | $ npm i -D cypress |
Second, let's write a few tests. We have the page itself which can be served locally using npm run dev
1 | $ npm run dev |
Great, we need to make sure this page loads and at least displays the heading text.
1 | /// <reference types="cypress" /> |
Our Cypress settings file cypress.json
specifies the base url when running locally. It also says that our project uses no fixtures, no plugins, and no support file.
1 | { |
Run Cypress from the second terminal to run the test with npx cypress open
.
Run tests on Netlify
Let's plugin into the Netlify build system to run our Cypress test after the deploy. We will install the netlify-plugin-cypress as another dev dependency.
1 | $ npm i -D netlify-plugin-cypress |
Update the netlify.toml file to include the netlify-plugin-cypress
and tell it to skip tests before the deployment and run them after the deployment using onSuccess
event.
1 | [build.environment] |
When Netlify runs its deploy, it will show the new messages from the Cypress plugin. The log shows the tests executing against the deployed URL and successfully passing.
Let's merge this pull #1 request since it is passing.
After GitHub has finished merging the code, Netlify builds the production version of the site, again running the E2E tests.
Testing Netlify functions
Our site includes a couple Netlify functions. For example, we can ask for a joke and functions/fetch-joke.js delivers one. To run both the static site and the Netlify functions locally we need to install netlify CLI:
1 | $ npm i -D netlify-cli |
Let's change our package.json
to include the dev:netlify
script:
1 | { |
Start the local Netlify environment from the first terminal using npm run dev:netlify
:
1 | > netlify dev |
Notice that Netlify proxies Eleventy to :8888 locally. Thus we should update the local base url to http://localhost:8888
in cypress.json
file. The netlify.toml
file defines an API redirect to the function:
1 | [[redirects]] |
Thus our Cypress test can use cy.request like this:
1 | it.only('delivers jokes', () => { |
I like working on a single test using it.only
while writing the test. Cypress watches the spec file automatically and reruns the test on any changes. The Command Log shows the Netlify function returning a joke:
We need to grab the body
of the response object, then parse it as JSON, and then confirm the msg
property is an non-empty string.
1 | it.only('delivers jokes', () => { |
Great, the test passes.
The PR pull/2 is green.
Let's ship it 🚢
Tip: for more on how Cypress can run API tests read Add GUI to your E2E API tests and Black box API testing with server logs blog posts.
Failing tests and artifacts
Now let's imagine a pull request that fails its tests. For example, if we change the landing page to have a different title "Netlify Cypress Tests" the tests would fail. Yet the pull/3 still shows the passing Netlify check!
The Netlify tab shows a warning
We can see the failed tests in the log, yet Netlify does not change the status of the deploy - after all, the deployment was successful! Related question: Cypress captures screenshots on test failures and a video of the test run, where can we see these test artifacts, marked with green arrows the screenshot below?
Let's see those test artifacts.
Recording to Cypress Dashboard
Most CI systems, including the Netlify Build, struggle to store and show the test artifacts well enough. Thus the simplest solution to record test results and store the test artifacts is to use the Cypress Dashboard. Let's set up the test recording for this project. We can set up recording by going to the "Runs" tab in the Test Runner
We should set the displayed record key as an environment variable CYPRESS_RECORD_KEY
in the deploy environment variables.
Then just add the record = true
input parameter to our netlify-plugin-cypress's settings:
1 | # run Cypress E2E tests |
Tip: grab the project's dashboard badge and add it to the README's markdown. At first it shows "no tests found", but will be updated after the first test run in the selected branch.
After we push the code we can see the test results including the error screenshot and the video of the test run.
Cypress GitHub App and status checks
Now let's make sure the pull request does not have all green status checks when the E2E tests fail. Install the Cypress GitHub App and give it access to the repo.
Tip: Cypress has the GitLab and BitBucket integrations in beta testing.
Let's trigger a new deployment - we can can do it right from the Netlify page.
After the deploy runs, you will see a GitHub comment posted by the Cypress app. It shows a failing test with a screenshot thumbnail. You also now have a red status check from the Cypress app - you know the pull request is breaking its tests.
Let's require the passing tests before the pull request can be merged. Under the GitHub repo's settings check these options and mark both status checks required.
Now switch back to the pull request #3 to see the updated message - the PR cannot be merged until we fix the tests.
Let's update the test and push it.
1 | cy.contains('h1', 'Netlify Cypress Tests').should('be.visible') |
Beautiful - our site is good again.
Bonus: automate dependency updates
This blog post describes the testing of this project as of February 2021. I would like the project and its tests to keep working without becoming obsolete for the future readers. Thus I recommend setting up Renovate bot to Keep Examples Up To Date. In the repo's root create renovate.json
file that once a week checks for new versions and opens a pull request. If the checks are green, the version update pull request gets automatically merged. We are only interested in a few dependencies, like Cypress, netlify-plugin-cypress
and the @11ty/eleventy
package.
1 | { |
Of course, to automatically upgrade dependencies we need to have more tests, thus I will add a few E2E tests to check the page navigation.
1 | /// <reference types="cypress" /> |
I activated the RenovateApp and it will keep my repo bahmutov/eleventyone up-to-date from now on. You can immediately see the master issue the RenovateApp opens that describes the actions it wants to take:
Most of the time the RenovateApp's actions are automatic and it can be trusted to merge its own pull requests, since our E2E tests against the deployed URLs give me enough confidence.
Version badges
Because the versions of Cypress and netlify-plugin-cypress
are important to anyone reading this blog post and looking at the source code, I like showing the current versions right in the README. To create a badge and update it after the RenovateApp upgrades dependencies, I use my own dependency-version-badge utility. I like running it using GitHub Actions. Here is my workflow file
1 | name: badges |
The above CI job runs when the listed files change and once at night. It keeps the version badges up-to-date in the README file.
Happy Testing!