Cypress tests have two different sets of values: the config values and the user values. The config values are controlling the test runner itself: the spec pattern, the viewport resolution, even the baseUrl
is the config value (which is why you need to set it using the config block, see the video How to correctly use the baseUrl to visit a site in Cypress). The user values are everything else: the username and the password to enter into the site under the test, the API key to use with the cy.request
command, the item name to search for. These values are called in Cypress-speak "env values" and you can access them using the Cypress.env command.
Cypress v10 has merged the plugins file with the cypress.json
file into a single cypress.config.js
file. By adding the component testing into the mix, the config file is confusing: where should we add our user values? Should they go into the top-level env
object? Or be under the e2e
property? What if we put them into both places? And how can we control these values using the setupNodeEvents
callback? Let's start playing with the source code in bahmutov/cypress-env-v10-example repo:
1 | const { defineConfig } = require('cypress') |
So what do we see for the above configuration? Launch the Test Runner and look at the "Settings" tab right under the "Specs" tab. Look at the "Project Settings". Scroll down to the "Resolved configuration", which is a large object. We see only the environment variables from the e2e block. The top level config object is meant only for the test runner's own configuration properties.
So here is our first find: no root level env
block.
Custom logic
What about the setupNodeEvents
callback? What can it do for our user values? Notice that it gets the config
passed as the second argument. Let's print the config.env
to the terminal.
1 | setupNodeEvents(on, config) { |
Great, so whatever you see in the resolved project settings is also passed into the setupNodeEvents
callback. But there is more: you can change the config.env
object in that callback. You can remove / change / add new values to that object! Just remember to return the updated config object from the setupNodeEvents
callback (I forget to return it regularly, and then curse myself hours later when I notice the mistake).
The cypress.config.js
file runs from a Node (Electron) Cypress process, thus it can access your local environment, unlike the spec or support files that run in the browser. Thus we can access the process environment variables, or read local files, etc. For example, let's say we want to pass the username and the password to our tests. We could use the process environment variables to do this securely:
1 | $ USERNAME=Joe PASSWORD=Smart12345 npx cypress open |
Here is what we could do in our cypress.config.js
file to use the USERNAME
and the PASSWORD
values
1 | setupNodeEvents(on, config) { |
Open the Test Runner with USERNAME=Joe PASSWORD=Smart12345 npx cypress open
command and see the resolved config; it now includes the e2e.env
object plus the values added by the setupNodeEvents
callback
💡 Windows OS has its own syntax for setting the process environment variables. No matter what your operating system is, I recommend using as-a to inject such values.
Read JSON file
Since cypress.config.js
file is JavaScript, you can code up reading JSON file (or any other type of file) and add those values to the config.env
object to be returned from setupNodeEvents
function:
1 | const { readFileSync } = require('fs') |
Tip: you can even control the JSON file to load by passing it via --env <name>
parameter
1 | const { readFileSync } = require('fs') |
You can read the environment values for QA
environment from qa.json
file by using cypress run --env name=qa
Cypress prefix
Instead of reading the process.env
values in the setupNodeEvents
callback, we can let Cypress automatically read these values. Cypress is nice enough to automatically read any process environment values that start with the CYPRESS_
prefix, and if the name does not match any built-in config values, it is added to the env
object automatically. Let's remove our custom logic from the cypress.config.js
file
1 | // go back to printing the parsed `config.env` object |
We could have achieved the same env
object by opening Cypress with the following process environment variables
1 | $ CYPRESS_registered=true \ |
Cypress automatically parses such variables, making sure they have the right type, and any JSON stringified objects are parsed into the JS objects.
Set env variable from the plugin
Some of the plugins like @bahmutov/code-coverage use the config.env
object to set the variable to let the browser code know the plugin has been registered:
1 | // plugin code |