Aprenda como fazer login em diferentes ambientes com Cypress, protegendo dados sensíveis como usuário e senha
Em outro post da série Pitadas de Cypress, escrevi sobre como alterar a baseUrl via linha de comando com Cypress.
Mas e os dados sensíveis, como as credenciais de autenticação da mesma aplicação, quando implantada em diferentes ambientes? É exatamente isso que vou te ensinar neste conteúdo!
Vamos imaginar uma aplicação implantada em três ambientes diferentes, cada um com suas credenciais específicas:
- Local (seu computador)
- Staging
- Produção
O e-mail e a senha do usuário são necessários para fazer login na aplicação (em qualquer um dos ambientes).
Vamos também assumir que no arquivo de configuração do Cypress (cypress.config.js), a baseUrl aponta por padrão para o ambiente de desenvolvimento local, conforme abaixo:
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
allowCypressEnv: false,
e2e: {
baseUrl: 'http://localhost:3000'
}
})
Note a configuração allowCypressEnv: false. Ela desabilita o uso de Cypress.env() para leitura de variáveis de ambiente no browser, incentivando o uso do comando mais seguro cy.env() (falaremos mais sobre isso a seguir).
Os ambientes de staging e produção possuem as seguintes URLs, respectivamente:
https://example.staging.comhttps://example.com
Vamos também assumir que no arquivo package.json, temos os seguintes scripts para executar os testes em cada ambiente específico:
"scripts": {
"test": "cypress run",
"test:staging": "cypress run --config baseUrl=https://example.staging.com --expose environment=staging",
"test:prod": "cypress run --config baseUrl=https://example.com --expose environment=prod"
}
O script test executa os testes no ambiente local, pois a baseUrl não é sobrescrita.
Nos scripts test:staging e test:prod, a baseUrl é sobrescrita via linha de comando. Além disso, usamos a flag --expose para passar uma variável chamada environment com um valor que identifica cada ambiente (staging e prod). Diferente de --env, o --expose é destinado a valores de configuração não sensíveis que você deseja acessar de forma síncrona via Cypress.expose().
No ambiente local, podemos ter um arquivo não versionado (incluído no .gitignore) chamado cypress.env.json, com a seguinte estrutura:
{
"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"
}
}
Observações:
- Também recomendo criar um arquivo versionado chamado
cypress.env.example.jsoncom valores de exemplo, para que outros membros da equipe possam usá-lo como modelo para criar seus próprios arquivoscypress.env.jsonnão versionados. - Em um ambiente de integração contínua, tais valores (
STAGING_USERePROD_USER) podem ser definidos como secrets, com o prefixoCYPRESS_, ou seja,CYPRESS_STAGING_USEReCYPRESS_PROD_USER, com seus respectivos valores.
A distinção de segurança: Cypress.expose vs cy.env
O Cypress oferece duas APIs diferentes para acessar valores externos, e entender a diferença é importante para a segurança:
Cypress.expose(key)— síncrono, destinado a valores de configuração não sensíveis, como o nome do ambiente atual. Os valores são passados via flag--exposena linha de comando.cy.env([keys])— assíncrono, destinado a dados sensíveis como credenciais. Recebe um array de nomes de chaves e expõe apenas as variáveis solicitadas, mantendo-as fora do estado geral do browser. Os valores vêm docypress.env.jsonou de variáveis de ambiente com o prefixoCYPRESS_.
Agora que temos as credenciais e entendemos as APIs, vamos implementar um comando customizado para fazer login com base no ambiente em que os testes estão sendo executados.
// cypress/support/commands.js
Cypress.Commands.add('login', () => {
const environment = Cypress.expose('environment')
cy.log(`Logging into the ${environment ? environment : 'local'} environment`)
let userKey = 'LOCAL_USER'
if (environment === 'staging') userKey = 'STAGING_USER'
if (environment === 'prod') userKey = 'PROD_USER'
cy.visit('/login')
cy.env([userKey]).then((vars) => {
cy.get('[data-cy="emailField"]')
.should('be.visible')
.type(vars[userKey].email, { log: false })
cy.get('[data-cy="passwordField"]')
.should('be.visible')
.type(vars[userKey].password, { log: false })
cy.contains('button', 'Login')
.should('be.visible')
.click()
})
})
No comando customizado de login:
Cypress.expose('environment')lê de forma síncrona o nome do ambiente não sensível passado via--expose.- Dois blocos
ifdefinem auserKeycorreta dependendo do ambiente, com valor padrãoLOCAL_USER. cy.env([userKey])busca de forma segura apenas o objeto de credenciais necessário para aquele ambiente, e.then()dá acesso aos valores dentro da cadeia de comandos do Cypress.- O e-mail e a senha são digitados com
{ log: false }para mantê-los fora do log de comandos do Cypress.
Além disso, registramos a frase “Logging into the [environment] environment” no log de comandos do Cypress, dependendo do ambiente onde os testes estão sendo executados. Se a variável environment for passada, ela é utilizada; caso contrário, o padrão é o valor local.
Portanto, se o valor da variável environment for, por exemplo, staging, o seguinte seria “impresso” no log de comandos do Cypress:
Logging into the staging environment.
E o teste de login ficaria assim:
// cypress/e2e/login.cy.js
it('logs in', () => {
cy.login()
cy.get('[data-cy="avatar"]')
.should('be.visible')
})
Como você pode ver, no teste em si, apenas chamamos o comando customizado cy.login, que autentica a aplicação com as credenciais corretas.
É isso! Espero que você tenha aprendido algo novo.
Para mais detalhes sobre como o Cypress funciona, recomendo a leitura da documentação oficial.
Gostou do conteúdo? Deixe um comentário.
Este conteúdo foi traduzido para o inglês e pode ser encontrado no DEV Community.
Ficou curioso(a) e quer aprender mais sobre automação de testes com Cypress? Conheça os cursos da Escola TAT.
👋 Até a próxima e bons testes!
Cara, vai me ajudar muito essa dica, para configurar os ambientes em uma POC que estou fazendo aqui na empresa. Muito obrigado mesmo
Fico feliz em ajudar Quintiliano!
Sua orientação foi muito válida, e me ajusou a configurar meu ambiente aqui, sempre me intriguei, porque não conseguiria usar mais de uma configuração de ambiente, agora, sim, vai para frente, obrigado. Implementei agora a tarde e deu Certinho, sem problemas, ja vou começar a inserir mais variáveis que irei utilizar hehe.
Fico feliz que meu conteúdo te ajudou Frederico. Aproveito pra te convidar pra conhecer meu canal no YouTube https://www.youtube.com/c/talkingabouttesting. 👋
Walmyr, eu consegui configurar isto no meu teste, porém, eu só consigo rodar o teste com sucesso via linha de comando. Se eu rodo o comando “npx cypress open” para abrir o cypress e ver em tempo real o teste rodando, o teste falha, e eu tomo um erro na parte ali do “nome”. Error: Cannot read properties of undefined (reading ‘nome’)
Eu só consigo fazer o teste rodar com sucesso via linha de comando com esse tipo de configuração?
Oi Nathália,
Por favor, faça um commit do seu código (com todas suas mudanças), publique no GitHub (com um git push) e compartilhe o link do seu repositório para que eu possa baixar o código em meu computador e tentar reproduzir o problema. Dessa forma, mais facilmente poderei te ajudar.
Fico no aguardo.
Ei Walmyr, seu blog sempre ajudando demais!
Porém essa configuração de vários ambientes (a do vídeo), para versão 11 do cypress, não funciona mais, até tentei adaptar, sem sucesso.
Alguma chance de lançar uma atualização para versões mais recentes?
Muito obrigada
O que você quer dizer com não funcionará mais? A idéia é a mesma, deve funcionar sim. Por qual motivo não funcionaria?
Se não funcionou pra você, já pensou que talvez tenha feito algo errado, ou que algum detalhe esteja faltando?
Acabei de testar com a versão 12.5.1 e funcionou perfeitamente.
Oi, Walmir. Tudo bem? Primeiramente muito obrigado pelo conteúdo.
Tentei utilizar essa mesma lógica mas colocando URLs diferentes dentro do .env, ficou assim:
Cypress.Commands.add(‘loginAPI’, () => {
if (Cypress.env(‘environment’) === ‘homolog’) {
Cypress.env(‘URL’, Cypress.env(‘url_local’))
Cypress.env(‘user’, Cypress.env(‘homologUser’))
} else if (Cypress.env(‘environment’) === ‘prod’) {
Cypress.env(‘URL’, Cypress.env(‘url_prod’))
Cypress.env(‘user’, Cypress.env(‘prodUser’))
} else {
Cypress.env(‘URL’, Cypress.env(‘url_local’))
Cypress.env(‘user’, Cypress.env(‘localUser’))
}
Apesar disso não funcionou, ele simplesmente pega somente a primeira URL do env e desconsidera as outras.
Consegue me dar uma luz de como trabalhar com URLs diferentes? No caso não coloco só uma BASE_URL pois tenho diferentes URL pra testar front e back.
Agradeço sua ajuda. Abraço
Opa Lucas, o blog post demonstra uma solução simples para lidar com várias URLs, que é sobrescrever a mesma via linha de comando (ex. cypress run –config baseUrl=https://example.com). Por qual motivo fazer diferente?
Opa, Walmir. No caso eu tenho duas URLs dentro do mesmo ambiente (front e back).
Meu .env está dessa forma, por exemplo:
{
“url_local”: {
“front”: “http://localhost:4200”,
“back”: “http://localhost:8080”
},
[…]
Tentei de todas as formas aqui mas não consegui setar o script para a URL correta. Teria alguma forma?
Desde já obrigado pela ajuda e atenção!
Lucas, neste caso, te convido a conhecer meu serviço de revisão de código. Se tiver interesse em contratar posso te ajudar.
https://talkingabouttesting.com/servicos/code-review-as-a-service/
parabens por dividir seu conhecimento .
queria saber sobre o repositorio desse projeto, se vc pode compartilhar para eu estudar e entender
Oi Fabio, obrigado pelo comentário!
Este projeto só tenho em repositórios privados.
Se quiser, te convido a contratar a mentoria da Talking About Testing e te ajudo a implementar isso juntos.
Segue o link para mais detalhes: https://talkingabouttesting.com/servicos/mentoria-coaching/