Logging into different environments with Cypress
Tags: cypress, testing, webdev, javascript
Published: 2024-01-26 06:30:00

## Learn how to log into different environments with Cypress, protecting sensitive data, such as username and password

In another blog post of the **Pinches of Cypress** series, I wrote about [how to change the baseUrl via the command line with Cypress](https://dev.to/walmyrlimaesilv/how-to-change-the-baseurl-via-command-line-with-cypress-1olm).

But what about sensitive data, such as credentials for authentication in the same application, deployed in different environments? That's precisely what I'll teach you in this content!

Let's imagine an application deployed in three different environments, each with its specific credentials:

- Local (your computer)
- Staging
- Production

The user's email and password are required to log into the application (in any of the environments).

Let's also assume that in the Cypress configuration file (`cypress.json`, or `cypress.config.js` – from version 10 onwards), the `baseUrl` points by default to the local development environment, as shown below:

```json
{
  "baseUrl": "http://localhost:3000"
}
```

Above is the configuration file before Cypress version 10.

```js
// cypress/config/cypress.config.js (from version 10 onwards)

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000'
  }
})
```

Above is the configuration file from Cypress version 10 onwards.

However, the staging and production environments have the following URLs, respectively:

- `https://example.staging.com`
- `https://example.com`

Let's also assume that in the `package.json` file, we have the following scripts for running tests in each specific environment:

```json
"scripts": {
  "test": "cypress run",
  "test:staging": "cypress run --config baseUrl=https://example.staging.com --env environment=staging",
  "test:prod": "cypress run --config baseUrl=https://example.com --env environment=prod"
}
```

The `test` script executes the tests against the local environment since the `baseUrl` is not overridden.

In the `test:staging` and `test:prod` scripts, the `baseUrl` is overridden via the command line. Additionally, we pass a variable called `environment` with a value that identifies each environment (`staging` and `prod`).

In the local environment, we can have an unversioned file (included in the `.gitignore` file) called `cypress.env.json`, which would have the following structure:

```json
{
  "LOCAL_USER": {
    "email": "local@user.com",
    "password": "the-password-of-the-above-user"
  },
  "STAGING_USER": {
    "email": "some-user@example.staging.com",
    "password": "the-password-of-the-above-user"
  },
  "PROD_USER": {
    "email": "another-user@example.com",
    "password": "the-password-of-the-above-user"
  }
}
```

**Note:** I also recommend creating a versioned file called `cypress.env.example.json` with example values so other team members can use it as a template for creating their own unversioned `cypress.env.json` files.

**Note 2:** In a continuous integration environment, such values (`STAGING_USER` and `PROD_USER`) could be set as secrets, with the prefix `CYPRESS_`, i.e., `CYPRESS_STAGING_USER` and `CYPRESS_PROD_USER`, with their respective values.

Now that we have the credentials let's implement a custom command for logging in based on the environment where the tests are being executed.

```js
// cypress/support/commands.js

Cypress.Commands.add('login', () => {
  cy.log(`Logging into the ${Cypress.env('environment') ? Cypress.env('environment') : 'local'} environment`)

  if (Cypress.env('environment') === 'staging') {
    Cypress.env('user', Cypress.env('STAGING_USER'))
  } else if (Cypress.env('environment') === 'prod') {
    Cypress.env('user', Cypress.env('PROD_USER'))
  } else {
    Cypress.env('user', Cypress.env('LOCAL_USER'))
  }

  cy.visit('/login')

  cy.get('[data-cy="emailField"]')
    .should('be.visible')
    .type(Cypress.env('user').email, { log: false })
  cy.get('[data-cy="passwordField"]')
    .should('be.visible')
    .type(Cypress.env('user').password, { log: false })
  cy.contains('button', 'Login')
    .should('be.visible')
    .click()
})
```

In the login custom command, we dynamically set the `user` variable depending on the environment passed via the command line in the npm script. Thus, we can use this variable in commands that enter the user's email and password.

Additionally, we log the phrase _"Logging into the [environment] environment"_ in the Cypress command log, depending on the environment where the tests are running. If the `environment` variable is passed, we use it; otherwise, the default is the `local` value.

So, if the value of the `environment` variable is, for example, `staging`, the following would be "printed" in the Cypress command log:

```sh
Logging into the staging environment.
```

And the login test would look something like this:

```js
// cypress/integration/login.spec.js (before Cypress version 10)
// or cypress/e2e/login.cy.js (from Cypress version 10 onwards)

it('logs in', () => {
  cy.login()

  cy.get('[data-cy="avatar"]')
    .should('be.visible')
})
```

As you can see, in the actual test, we only call the custom command `cy.login`, which authenticates the application with the correct credentials.

That's it! I hope you learned something new.

___

For more details on how Cypress works, I recommend reading the [official documentation](https://docs.cypress.io/).

___

Did you like the content? Leave a comment.

___

This blog post was originally published in Portuguese at the [Talking About Testing](https://talkingabouttesting.com/2021/10/09/como-fazer-login-com-cypress-em-diferentes-ambientes/) blog.

___

Would you like to learn Cypress in a hands-on course?

I introduce you to my newest course, [🌲 Cypress, from Zero to the Cloud ☁️](https://www.udemy.com/course/cypress-from-zero-to-the-cloud/?referralCode=CABCDDFA5ADBB7BE2E1A).

I hope you like it, and happy testing!