This content originally appeared on DEV Community and was authored by Walmyr Filho
Learn how to make your automated tests faster by authenticating via API
Automated graphical user interface tests must be independent of each other. In addition, such tests must rely as little as possible on the graphical user interface to reach the desired state for the test itself to take place.
It seems counter-intuitive, but that's precisely it.
From the graphical user interface, we should test it only once. More than that is waste.
However, in most web applications, the user must be authenticated to access certain functionality. So, how to authenticate such a user without going through the login page?
That's precisely what I will show you in this pinch of Cypress.
Note: It is worth remembering that this is just an alternative and that it may not be suitable for your use case. For more examples, I recommend reading the Testing Strategies section of the Cypress official documentation.
To facilitate the explanation, I will use a real project to which I have contributed recently. The BR Modelo Web.
Let's imagine the following test case.
// 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')
}
Now, let's understand what this code does.
First, inside the test body, that is, inside the it
block, I use the cy.intercept
command. With such a command, I can “listen” 👂 to network calls, such as a GET
request to the application's API URL that fetches the models of the logged-in user. Then I give an alias to that intercept. The alias is getUserModels
.
Then comes the part where the programmatic authentication happens.
In this part, I use the cy.request
functionality to make a POST
request to the login URL, passing the username and password properties in the request body
, both coming from variables (using the Cypress.env()
functionality). I do this not to expose sensitive data.
Then, I chain to the cy.request()
command a .then()
, which takes as argument an arrow function, which takes as an argument the response of the cy.request()
.
In the body of this arrow function, I use the cy.setCookie()
functionality, as the name suggests, to set some cookies based on the body
of the request-response. These are precisely the cookies set when the user logs in via the graphical user interface.
With cookies set, I visit the application's homepage.
Finally, I do some checks.
First, I wait for the intercept request created earlier to occur, with cy.wait()
, passing it the alias created earlier ('@getUserModels'
).
And then, I check that a particular element is visible (an h2
with the text Models), which is only visible to authenticated users, proving that the login was successful.
Done! 🎉
Attention: When testing a login functionality, it is recommended that such testing takes place via the graphical user interface. However, for all other features that require the authenticated user, use login programmatically and save a few seconds on each test!
Bonus - Custom Command
Since more than one test suite will need to login programmatically, we can move that logic to a custom command, which can be reused as many times as needed.
Here's what the test code would look like.
// 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')
})
And the custom command.
// 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')
})
})
In the test, now all the logic of cy.request
and cy.setCookie
is abstracted. I just call the cy.loginViaAPI()
command, and it manages to do what needs to be done to authenticate the user.
In addition to having the previous logic of programmatic login, the custom command can now also receive an email and password as arguments. However, if no arguments are passed, such values already have defaults coming from variables.
Also, I decided to move the visit to the home page to the custom command.
See the test running and authenticating without going through the login page. It looks like magic! 🪄
That's it!
I hope you enjoyed it.
Access the final version in this public repository on my GitHub profile.
Or the BR Modelo Web App project.
Take the opportunity to leave a star! ⭐
Did you like the content? Leave a comment.
Curious and want to learn more about Cypress Testing Automation? Check out my courses on Udemy.
👋 Until next time and happy testing!
This post was originally published in Portuguese at the Talking About Testing blog.
This content originally appeared on DEV Community and was authored by Walmyr Filho
Walmyr Filho | Sciencx (2022-01-09T23:42:57+00:00) How to login programmatically with Cypress. Retrieved from https://www.scien.cx/2022/01/09/how-to-login-programmatically-with-cypress/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.