Once upon a time a cy.session()…
Tags: cypress, testing, automation, qa
Published: 2024-04-27 22:18:49

**Cypress.io sessions made easy, and no more tales!**

---

### ACT 1: EXPOSITION

There are many comprehensive blogs about how to create and manage sessions in Cypress.io. But I must confess… this is NOT one of them, and it was NEVER intended to be! Despite what the blog’s title might suggest, I’m not here to spin you a child’s tale.

So, if you’re still reading and I haven’t lost you after that first paragraph, let me tell you what this blog is actually about:

**A straightforward recipe to get sessions working in your Cypress tests right away. That’s it!**

Nothing more, nothing less. And no tales!
&nbsp;  
I won’t bore you with explanations of what a Cypress session is or why you should use sessions in your tests (because you really should). If you’ve found your way to this blog post, you likely already know what a user session is and how it can benefit your tests.

What you might not yet know is how to implement them effectively, without unnecessary embellishments, and in a way that works. I’ve noticed that many QA engineers, particularly those who are new to Cypress, find it challenging to add user sessions to their tests. And I assure you, this is no fairy tale.

---

### ACT 2: CONFRONTATION

There are essentially two things you need to know about `cy.session()`:

1. If you want to share the session across all your tests in the spec file, you should run it in the `beforeEach()` hook, and NEVER in the `before()` hook. If you use it in the `before()` hook, only the first test in the spec file will be able to utilize that session.
2. After a session is created (or restored) by a test, you will need to perform an implicit `cy.visit()` to the page you want to test (even if the page to test is exactly the same as your website's landing page after login).
&nbsp;  
In my experience working with many QA engineers and testers, these two simple points are often overlooked and can be the cause of struggles when using `cy.session()` effectively.

**_So you might now ask: “How can I do it? But tell me no tales!”_**

&nbsp; 
 
#### FIRST
You might want to consider creating a custom command that encapsulates the creation of sessions for your tests. This allows you to reuse that command across all your test specs.

Hey… to be clear: We are talking about calling the custom command from different specs (adhering to the DRY principle), but you should not reuse the same user session between different specs. That’s a big NO-NO (you should also maintain the principle of test isolation as a good practice)!

In your **`cypress/support/commands.js`** file, create a custom command for logging into your app and creating a session. After the login, within the `cy.session()` block, I also recommend including a call to `cy.url()` to verify that your system navigates to the correct page.
&nbsp;  
Something like this:

``` javascript
// File cypress/support/commands.js

Cypress.Commands.add("createSession", (username, password) => {
    cy.session(
        // Session ID is going to be an array [user, password]
        [user, password], () => {
            cy.visit("/");
            cy.get('input[type="text"]').clear().type(username);
            cy.get('input[type="password"]').clear().type(password);
            cy.get('button[type="submit"]').click();

            // After login successfully it is supposed to goto the page '/shop'
            cy.url().should('contain', '/shop')
        }
    );
});
```

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/foqz6pcufx6t0vr7owuf.png" />
</p>
&nbsp;  
This approach has two significant advantages:

1. You can be certain that after a successful login, your app under test navigates to the intended page.
2. Since `cy.url()` is a query command, it will continuously retry checking the target URL until the navigation to that page occurs or a timeout is reached. While some people use the `validate` option available in `cy.session()`, in my opinion, it's not necessary in most cases.

&nbsp;  

#### SECOND
In your test spec file, invoke the custom command to create the session within a `beforeEach()` hook (_remember… not in the `before()` hook_).

This will **create a new session** before the first test in your spec runs (with session ID [user, password]), and will **automatically restore** that same session before running each subsequent test in the spec.

``` javascript
// File tests-spec.js 

beforeEach(() => {
    cy.createSession(user, password)
});
```

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wyu1et6q3ksv3fkvfrcl.png" />
</p>

&nbsp;  

#### THIRD (and final)
You need to perform an explicit visit to the page you want to test (_again remember… even if it’s the same as the landing page after login_).

If all your tests in the spec file target the same page, then simply place the `cy.visit()` call in the `beforeEach()` hook, following the session creation.

``` javascript
// File tests-spec.js with visit in beforeEach() hook (same page under test in all tests)

beforeEach(() => {
    cy.createSession(user, password)

    // Explicitelly visit the page target of the tests
    cy.visit('/shop')
});

it('Test Shop Page Items', () => {
    // Your test logic for Shop items here
    // ...
});

it('Test Shop Page Totals', () => {
    // Your test logic for Shop totals here
    // ...
});
```
&nbsp;  
However, if each of your tests in the spec file is checking a different page of your app, then it’s better to place the `cy.visit()` within each individual test.

``` javascript
// File tests-spec.js with visit within each individual test (different pages under test)

beforeEach(() => {
    cy.createSession(user, password)
});

it('Test Shop Page', () => {
    cy.visit('/shop')

    // Your test logic for Shop page test here
    // ...
});

it('Test Account Page', () => {
    cy.visit('/account')

    // Your test logic for Account page test here
    // ...
});
```

---

### ACT3: RESOLUTION

I would like to mention one last thing. I have noticed that when using sessions in Cypress, if you rerun the spec file again using the top-right ‘_refresh_’ button, the new execution of the spec will still use your previous session and restore it instead of creating a new one. This breaks the premise of test isolation!

If you go back to the Spec list and then select your spec again, the sessions are automatically cleared by Cypress.
&nbsp;  
So, if you want to ensure that two or more consecutive executions of the same spec using the ‘refresh’ button are session-independent, I have found it very useful to include a `before()` hook in the **`cypress/support/e2e.js`** file that clears all saved sessions.

``` javascript
// File cypress/support/e2e.js

before(() => {
    // Ensure that all sessions are cleared up even if you re-run the spec in the Cypress App UI (Test Runner)
    cy.log('close all sessions')
    Cypress.session.clearAllSavedSessions()
});
```

<p align="center">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oo9xlu95egu8k1e5myh5.png" />
</p>

That’s it! It’s that simple. And as promised… no tales! 🙂

**Don't forget to leave a comment, give a thumbs up, or follow my Cypress blog if you found this post useful.**

Happy reading!