Today, in “Pinches of Cypress”, learn how to protect credentials, such as username and password
The scenario is as follows. We have an end-to-end test for the login functionality, and several other tests also depend on the user being logged in as a precondition.
However, it is bad practice to version credentials, such as username and password.
An alternative I have used several times to solve this problem is the cypress.env.json file (when working in a local development environment).
Such a file allows us to store sensitive data (for example), but we do not version it (that is, it is included in the .gitignore file).
Let's look at a practical example.
The cypress.env.json file would look like this:
{
"user_name": "admin",
"user_password": "s3creT-p@ssw0rd"
}
Remember that this file would only be available on my computer. And if other developers use different usernames and passwords on their computers, the credentials would be different but not versioned.
And the login test would look like this:
describe('Login', () => {
it('successfully', () => {
cy.visit('https://example.com/login')
cy.env(['user_name', 'user_password']).then(({ user_name, user_password }) => {
cy.get('#user').type(user_name)
cy.get('#password').type(user_password)
cy.contains('Login').click()
cy.get('.navbar-top .avatar')
.should('be.visible')
})
})
})
Tada! 🎉
That way, I don't expose such sensitive data, and my tests can still log in.
Besides, this approach lets us expose credentials as environment variables (prefixed by CYPRESS_) in continuous integration services, which run tests against environments other than our local one.
That is, sensitive data is protected, and we can run the same tests in different environments (local, staging, production, etc.) 💯
Finally, if you want to protect your password from “leaking”, pass the option { log: false } as the second argument of the .type() command, and that command will not be listed in Cypress's command logs (see below.)
describe('Login', () => {
it('successfully', () => {
cy.visit('https://example.com/login')
cy.env(['user_name', 'user_password']).then(({ user_name, user_password }) => {
cy.get('#user').type(user_name)
cy.get('#password').type(user_password, { log: false })
cy.contains('Login').click()
cy.get('.navbar-top .avatar')
.should('be.visible')
})
})
})
I'm curious. What do you think about the series?
I'm looking forward to hearing your feedback!
This post was originally published in Portuguese on the Talking About Testing blog.
Would you like to learn about test automation with Cypress? Get to know my online courses on Udemy.
Want to go deeper?
I built the Cypress Simulator — a hands-on course designed to take you from your first test to a full end-to-end testing workflow with confidence.
You'll learn how to test real user interactions, catch accessibility issues early, and run your tests automatically in CI/CD pipelines — through 20 interactive lessons, coding challenges, and quizzes.
Top comments (4)
Sorry. Not secure enough.
Even though the password in not stored in the source code it can still be accessed.
If your tests run in Cypress dashboard which is public (which you can't make private until you have a paid Cy Dashboard subscription), anyone can look at your test recordings and can easily view the password in the Test runner.
Follow this guide from Gleb, in conjunction with what you have posted above to completely protect password/sensitive data :
glebbahmutov.com/blog/keep-passwor...
Hi, @abhimassive ,
For that, we can pass the option
{ log: false }when typing the password.E.g.,
cy.get('#password').type(Cypress.env('user_password'), { log: false }).Why is it terrible if on CI you could have the same sensitive data as secrets prefixed by CYPRESS_?
I even mention that in the following paragraph:
Besides, such an approach gives us the advantage of being able to expose such credentials as environment variables (prefixed by CYPRESS_ or cypress_) in continuous integration services, which perform tests against environments other than our local one.