Using config files for multiple environment variables in Cypress
Tags: cypress, k6, e2e, testing
Published: 2020-10-14 10:34:27

If you want a readable, easy-to-change, independent, and other superlatives you can think of, in terms of scaling your Cypress framework, then I suggest using [configuration files](https://docs.cypress.io/guides/references/configuration.html#Options) 😎. It is actually not as hard as some other options on [environment variables](https://docs.cypress.io/guides/guides/environment-variables.html#Setting) manipulation can do.

First, create a `config` folder under the project's root directory (a.k.a. outside the `cypress` folder). Your extreme patience is needed to answer the question why I would like it placed there.  
Next, create two `env.json` files, namely,  
`local.env.json`:
```json
{
 "env": {
  "domain": "localhost:8080",
  "description": "This is my local machine!",
  "protocol": "http://",
  "subDirectory": "helloworld"
 }
}
```
`test1.env.json`:
```json
{
 "env": {
  "domain": "test1.domain.com",
  "description": "This is awesome company's stage environment",
  "protocol": "https://",
  "subDirectory": "/helloworld"
 }
}
```

Then, go to `plugins/index.js` and insert the following script:
```javascript
const fs = require('fs-extra');
const path = require('path');

function getConfigurationByFile (file) {
    const pathToConfigFile = path.resolve('config', `${file}.json`);

    return fs.readJson(pathToConfigFile)
}

// plugins file
module.exports = (on, config) => {
    // accept a configFile value or use local by default
    const file = config.env.configFile || 'local';

    return getConfigurationByFile(file)
};
```
_Something I forgot: You may need to install the package [fs-extra](https://www.npmjs.com/package/fs-extra) as a pre-requisite (`npm i --save-dev fs-extra`)_  

Lastly, you can just invoke the environment variables on your tests under the `integration` folder:
`CheckTheUrl.js`
```javascript
const helloWorldUrl = Cypress.env('protocol') + Cypress.env('domain') + Cypress.env('subDirectory')
describe('Run this baby!', ()=> {
 it('Run this baby, I said!', ()=> {
  cy.visit(helloWorldUrl);
  cy.log('This is for demo purpose so I am not doing assertion!');
 });
});
```  

And, drop-dead last step is to execute the test via the CLI (whether it's your IDE's terminal or your CI pipeline) with the command below:
`npx cypress run --env configFile=local` and if you are feeling nerdy 🤓, remove the hard-coding and parameterise the value for `configFile` with something like `%envName%` where you can always interchange the value on your CI configurations / parameters.  

As a bonus, you can also include this script on your `package.json` with the following line:
```json
"scripts": {
    "cy:run": "node scripts/cypress.js",
    "e2e:ci": "cypress run --env 'configFile=%envName%'"
}
```  

So, why did I place the `config` sub-folder outside the `cypress` folder? Sorry for the anti-climax but it is simply due to the fact that I want to **re-use** these environment variables for my other frameworks such as [k6](https://k6.io/) (since these are just data in json format). I can create something like this:  
```javascript
import http from `k6/http`;
const config = JSON.parse(open('../config/local.env.json'));
import { sleep } from 'k6';

const helloWorldUrl = `${config.env.protocol}${config.env.domain}${config.env.subDirectory}`;

export let options = {
  vus: 50, // no. of virtual users
  duration: '30s',
};

export default function() {
  console.log(`Attacking the Hello World page, baby!`);
  http.get(`${helloWorldUrl}`);
  sleep(1);
}
```  

Putting it outside makes it cleaner, although a lazy engineer can always make a case to still point it to the `cypress` folder.