DEV Community

Cover image for Logging into different environments with Cypress
Walmyr
Walmyr

Posted on

Logging into different environments with Cypress

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.

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:

{
  "baseUrl": "http://localhost:3000"
}
Enter fullscreen mode Exit fullscreen mode

Above is the configuration file before Cypress version 10.

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

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000'
  }
})
Enter fullscreen mode Exit fullscreen mode

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:

"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"
}
Enter fullscreen mode Exit fullscreen mode

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:

{
  "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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

// 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()
})
Enter fullscreen mode Exit fullscreen mode

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:

Logging into the staging environment.
Enter fullscreen mode Exit fullscreen mode

And the login test would look something like this:

// 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')
})
Enter fullscreen mode Exit fullscreen mode

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.


Did you like the content? Leave a comment.


This blog post was originally published in Portuguese at the Talking About Testing 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 ☁.

I hope you like it, and happy testing!

Top comments (2)

Collapse
 
jorshcr profile image
Jorsh

Thanks for article, really helpful, now I do have a doubt, hopefully you can help me understand

So you mention to use for instanceCYPRESS_STAGING_USER in let's say github actions, I know that CYPRESS_ will be removed once it is read by cypress but my two questions are:

  1. Should I get the secrets like this? run: echo "CYPRESS_STAGING_USER=${{secrets.CYPRESS_STAGING_USER}}" >> $GITHUB_ENV ?

  2. once I got the env in a continuos integration setup, and in this case where the cypress.env.json is not versioned there, where do these values are coming from if they are not in the repo?
    .type(Cypress.env('user').email
    .type(Cypress.env('user').password

Collapse
 
walmyrlimaesilv profile image
Walmyr

No, your secret on GitHub action will already be in a JSON format.