How to login programmatically with Cypress
Tags: cypress, testing, authentication, javascript
Published: 2022-01-09 23:42:57

## 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 relly 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**](https://docs.cypress.io/guides/overview/why-cypress).

To ease the explanation, I will use a project I have recently contributed to — the [**BR Modelo Web**](https://www.brmodeloweb.com/lang/en/index.html).

Let's imagine the following test case.

```js
// cypress/e2e/programmaticLogin.cy.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`**](https://docs.cypress.io/api/commands/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`**](https://docs.cypress.io/api/commands/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()`**](https://docs.cypress.io/api/cypress-api/env) functionality). I do this not to expose sensitive data.

Then, I chain to the `cy.request()` command a [**`.then()`**](https://docs.cypress.io/api/commands/then), which takes as argument an [**arrow function**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions), which takes as an argument the response of the `cy.request()`.

In the body of this arrow function, I use the [**`cy.setCookie()`**](https://docs.cypress.io/api/commands/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()`**](https://docs.cypress.io/api/commands/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](https://docs.cypress.io/api/cypress-api/custom-commands)

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.

```js
// cypress/e2e/programmaticLogin.cy.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.

```js
// 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! 🪄

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4uolfkeca3igt60e8pda.gif)

That's it!

I hope you enjoyed it.

___

Access the final version in this [**public repository**](https://github.com/wlsf82/programmatic-login-with-cypress) on my GitHub profile.

Or the [**BR Modelo Web App**](https://github.com/brmodeloweb/brmodelo-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**](https://udemy.com/user/walmyr).

___

👋 Until next time and happy testing!

___

This post was originally published in Portuguese at the [**Talking About Testing**](https://talkingabouttesting.com/2021/12/14/como-fazer-login-de-forma-programatica-com-cypress/) blog.