Aprenda como tornar seus testes automatizados mais rápidos autenticando via API
Testes automatizados de interface gráfica de usuário devem ser independentes uns dos outros. Além disso, tais testes devem depender o mínimo possível da interface gráfica de usuário para chegar no estado desajado para que o teste propriamente dito ocorra.
Parece contra intuitivo, mas é isso mesmo.
Pela interface gráfica de usuário, devemos testar só uma vez. Mais do que isso é desperdício.
No entanto, na maioria das aplicações web, para testarmos certas funcionalidades, o(a) usuário(a) deve estar autenticado(a) no sistema. Porém, como autenticar tal usuário(a) sem passar pela página de login?
É exatamente isso que vou te mostrar nessa pitada de Cypress.
Obs.: Vale lembrar que esta é só uma alternativa, e que talvez não seja adequada para o seu caso de uso. Para mais exemplos, recomendo ler a seção de estratégias de teste (testing strategies) da documentação oficial do Cypress.
Para facilitar a explicação, vou utilizar como exemplo um projeto real para o qual tenho contribuído recentemente. O BR Modelo Web.
Imaginemos o seguinte caso de teste.
// cypress/integration/programmaticLogin.spec.js
it('successfully logs in programmatically', () => {
cy.intercept('GET', `${Cypress.env('apiUrl')}/models?userId=*`)
.as('getUserModels')
cy.request('POST', `${Cypress.env('apiUrl')}/users/login`, {
username: Cypress.env('userEmail'),
password: Cypress.env('userPassword'),
}).then((response) => {
cy.setCookie('sessionId', response.body.sessionId)
cy.setCookie('userId', response.body.userId)
cy.setCookie('userName', response.body.userName)
})
cy.visit('/#!/main')
cy.wait('@getUserModels')
cy.contains('h2', 'Models').should('be.visible')
}
Deixei destacada a parte do código que realiza a autenticação de forma programática.
De qualquer forma, vamos entender o que todo o teste faz.
Primeiro, dentro do corpo do teste, ou seja, dentro do bloco it, uso o comando cy.intercept. Com tal comando, posso “escutar” 👂 chamadas de rede, tal como uma requisição do tipo GET para a URL da API da aplicação que busca as modelagens do usuário logado. Depois, dou um alias (algo como um apelido) à tal intercept. O alias é getUserModels.
Daí, vem a parte onde começa a autenticação de forma programática.
Nessa parte, uso a funcionalidade cy.request para fazer uma requisição do tipo POST para a URL de login, passando no body da requisição as propriedades username e password, ambas vindo de variáveis (usando a funcionalidade Cypress.env()). Faço isso para não expor dados sensíveis.
Depois, encadeio ao comando cy.request() um .then(), o qual recebe como argumento uma arrow function, a qual recebe como argumento a resposta da requisição do cy.request().
No corpo dessa arrow function, utilizo a funcionalidade cy.setCookie() para, como o nome propõe, setar alguns cookies com base no corpo (body) da resposta da requisição. Estes são exatamente os cookies que são setados quando o(a) usuário(a) realiza o login via interface gráfica de usuário.
Com os cookies setados, visito a página inicial da aplicação.
Por fim, faço algumas verificações.
Primeiro, aguardo pela requisição do intercept criado anteriormente ocorrer, com o cy.wait(), passando ao mesmo o alias criado anteriormente (‘@getUserModels’).
E então, verifico que certo elemento está visível (um h2 com o texto Models), o qual somente é visível para usuários autenticados, provando que o login ocorreu com sucesso.
Pronto! 🎉
Atenção: Quando testando a funcionalidade de login, é recomendado que tal teste ocorra via interface gráfica de usuário. No entanto, para todas as outras funcionalidades que requerem o(a) usuário(a) autenticado(a), utilize o login de forma programática e salve alguns segundos em cada teste!
Bônus – comando customizado
Visto que mais de uma suite de testes necessitará fazer o login de forma programática, podemos mover tal lógica para um comando customizado, o qual pode ser reaproveitado quantas vezes forem necessárias.
Veja como ficaria o código do teste
// cypress/integration/programmaticLogin.spec.js
it('successfully logs in via GUI', () => {
cy.intercept('GET', `${Cypress.env('apiUrl')}/models?userId=*`)
.as('getUserModels')
cy.loginViaAPI()
cy.wait('@getUserModels')
cy.contains('h2', 'Models').should('be.visible')
})
E o comando customizado.
// cypress/support/commands.js
Cypress.Commands.add('loginViaAPI', (
email = Cypress.env('userEmail'),
password = Cypress.env('userPassword')
) => {
cy.request('POST', `${Cypress.env('apiUrl')}/users/login`, {
username: email,
password,
}).then((response) => {
cy.setCookie('sessionId', response.body.sessionId)
cy.setCookie('userId', response.body.userId)
cy.setCookie('userName', response.body.userName)
cy.visit('/#!/main')
})
})
No teste, agora toda a lógica de cy.request e cy.setCookie fica abstrata. Somente chamo o comando cy.loginViaAPI() e ele se vira em fazer o que precisa para autenticar o(a) usuário(a).
Já o comando customizado, além de possuir a lógica anterior, agora também pode receber um email e senha como argumentos. Porém, caso nenhum argumento seja passado, tais valores já tem padrões vindo de variáveis.
Além disso, resolvi mover a visita à página inicial para o comando customizado.
Veja o teste rodando e autenticando sem precisar passar pela página de login. Parece mágica! 🪄
É isso aí!
Espero que tenha gostado.
Acesse a versão final nesse repositório público em meu perfil no GitHub.
Ou então, o repositório do projeto BR Modelo Web App.
Aproveita pra deixar uma star! ⭐
Gostou do conteúdo? Deixa um comentário.
Ficou curioso(a) e quer aprender mais sobre automação de testes com Cypress? Conheça meus cursos no Udemy.
- Cypress básico
- Cypress intermediário
- Cypress avançado
- Boas práticas em automação de testes com Cypress
- Testes end-to-end com Cypress
- Testes de regressão visual com Cypress e Percy (básico)
👋 Até a próxima e bons testes!
Este conteúdo foi traduzido para inglês e pode ser encontrado no DEV Community.
Parabéns, um passo a passo que me facilitaria muito a algum tempo atrás.
Obrigado por deixar o caminho das pedras um pouco mais facil!
É um prazer compartilhar um pouco de conhecimento com a comunidade Eduardo.