<linearGradient id="sl-pl-bubble-svg-grad01" linear-gradient(90deg, #ff8c59, #ffb37f 24%, #a3bf5f 49%, #7ca63a 75%, #527f32)
Loading ...

QA essentials

Your go-to quality assurance source

How To Speed Up Cypress Tests With Reusable Sessions?

Test execution is all about speed. Lately we hear all the time about speed of execution of tests and which tool is faster. It has become the most important thing in the world of automated testing. It is all about how fast can we get a feedback about the latest changes. Having slow tests can cost organizations a lot of money. If they cannot get a fast response from test suite about the stability of the system under test it may happen that engineers skip running the tests. There are ways to speed up your tests. Today we will discuss how to reuse cookies within sessions to avoid multiple logins. Let’s answer the question: how to speed up Cypress tests?

The problem definition

A good practice in test automation is to make all your tests independent. If you have tests depending on each other then you may face chained failures and the dependent tests will be skipped. A good practice would be to clear session before each it block. Cypress lately does that by default unless you set it otherwise. Now, if you allow the test to start over for each it block that would mean that your test users have to login every time again. This means that we may need to duplicate the code for login. Yes, we can avoid this by using beforeEach and keep our tests DRY. But there would still be a matter of logging in several times which definitely slows down the execution of the tests. In the following example I have three simple tests which execute in 11 seconds.

describe('Debugging Cypress tests', () => {
  
    beforeEach('Open Demo Blaze website', () => {
        cy.loginWithoutReusableSession('qaEssentials', '123456789');
    });

    it('Should have 9 items on home page', () => {
        //check the number of items on the home page
        cy.get('.card').should('have.length', 9);
    })

    it('Should add Nexus 6 to the cart', () => {
        //click on Nexus 6
        cy.get('a').contains('Nexus 6').click();
        //check the response of the server
        cy.intercept('POST', 'https://api.demoblaze.com/view').as('view');
        //check name of the product
        cy.get('.name').should('have.text', 'Nexus 6');
        //click on Add to cart
        cy.get('.btn-success').click();
        //check the alert message
        cy.on('window:alert', (str) => {
            expect(str).to.equal('Product added');
            return true;
        });
    });
  
    it('Should check visibility of the Place order button', () => {
      //click on Cart button
      cy.get('.nav-link').contains('Cart').click();
      //check name of the product
      cy.get('[data-target="#orderModal"]').should('be.visible').and('be.enabled');
    });  
  });

And I have custom command for login like this:

Cypress.Commands.add('loginWithoutReusableSession', (username, password) => {
    cy.intercept('GET', 'https://api.demoblaze.com/entries').as('entries');
    cy.visit('https://www.demoblaze.com/index.html');
    cy.wait('@entries');
    cy.get('#login2').click();
    cy.get('#loginusername').should('be.enabled').type(username);
    cy.get('#loginpassword').should('be.enabled').type(password);
    cy.get('button').contains('Log in').click();
});
how to speed up cypress tests

A better approach

To improve the test speed I will change the custom command in commands.js file. I need to encapsulate the entire login logic with cy.session command.

Cypress.Commands.add('loginWithReusableSession', (username, password) => {
    cy.session([username, password], () => {
        cy.intercept('GET', 'https://api.demoblaze.com/entries').as('entries');
        cy.visit('https://www.demoblaze.com/index.html');
        cy.wait('@entries');
        cy.get('#login2').click();
        cy.get('#loginusername').should('be.enabled').type(username);
        cy.get('#loginpassword').should('be.enabled').type(password);
        cy.get('button').contains('Log in').click();
    });
});

Now in the test itself I will add this custom command in each it block along with cy.visit command to make this session reusable.

describe('Debugging Cypress tests', () => {

    // beforeEach('Open Demo Blaze website', () => {
    //     cy.loginWithReusableSession('qaEssentials', '123456789');
    // });

    it('Should have 9 items on home page', () => {
        cy.loginWithReusableSession('qaEssentials', '123456789');
        cy.visit('https://www.demoblaze.com/index.html');
        //check the number of items on the home page
        cy.get('.card').should('have.length', 9);
    })

    it('Should add Nexus 6 to the cart', () => {
        cy.loginWithReusableSession('qaEssentials', '123456789');
        cy.visit('https://www.demoblaze.com/index.html');
        //click on Nexus 6
        cy.get('a').contains('Nexus 6').click();
        //check the response of the server
        cy.intercept('POST', 'https://api.demoblaze.com/view').as('view');
        //check name of the product
        cy.get('.name').should('have.text', 'Nexus 6');
        //click on Add to cart
        cy.get('.btn-success').click();
        //check the alert message
        cy.on('window:alert', (str) => {
            expect(str).to.equal('Product added');
            return true;
        });
    });

    it('Should check visibility of the Place order button', () => {
        cy.loginWithReusableSession('qaEssentials', '123456789');
        cy.visit('https://www.demoblaze.com/index.html');
        //click on Cart button
        cy.get('.nav-link').contains('Cart').click();
        //check name of the product
        cy.get('[data-target="#orderModal"]').should('be.visible').and('be.enabled');
    });
});

The result I have achieved with this change:

how to speed up cypress tests

The entire spec with the same three tests like before was executed in 5 seconds. That is 6 seconds faster than the previous test run.

How do I know it is using the session? Well, first when I look at the execution I don’t see the user is logged in three times, before each test block. Second, I see in the runner when the session was created and when it was restored. Here is an example after I moved the custom command and cy.visit line in the beforeEach block to avoid code duplication.

how to speed up cypress tests

Alternative scenarios

The same can be used if you have different users, as Cypress documentation explains it. In this case you need to place the custom command in the specific it block where you want the second user to log in, pass the alternative credentials and this works just fine. There is also and option to make the session persistent across different specifications. In this case, you need to add another parameter to cy.session called cacheAcrossSpecs and assign true to it. My code would like this with that option.

Cypress.Commands.add('loginWithReusableSession', (username, password) => {
    cy.session([username, password], () => {
        cy.intercept('GET', 'https://api.demoblaze.com/entries').as('entries');
        cy.visit('https://www.demoblaze.com/index.html');
        cy.wait('@entries');
        cy.get('#login2').click();
        cy.get('#loginusername').should('be.enabled').type(username);
        cy.get('#loginpassword').should('be.enabled').type(password);
        cy.get('button').contains('Log in').click();
    }, {cacheAcrossSpecs: true});
});

You can use cy.session with API login as well. I didn’t have any publicly available application with API login which I can use for this example, so I will copy the code from the official Cypress pages.

cy.session(username, () => {
  cy.request({
    method: 'POST',
    url: '/login',
    body: { username, password },
  }).then(({ body }) => {
    window.localStorage.setItem('authToken', body.token)
  })
})

Conclusion

Cypress allows us to reuse the session with cookies created during login for example. Although this is most used example for session reusing I believe that in specific cases this command can be used for restoring all kinds of cookies and tokens. I tried with cookie consent as well and Cypress restored the cookies successfully. At the beginning of the article you asked how to speed up Cypress tests and cy.session is a definitive answer to this question. As you have seen in the above example, a significant time savings can be achieved with this command. If you use the possibility to restore the sessions across the specifications I believe that overall savings can be even more significant.

Oh hi there 👋
It’s nice to meet you.

Sign up to receive awesome content in your inbox, every month.

We don’t spam! We keep your data private and share it only with third parties that make this service possible. Read our privacy policy for more info.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.