Search code examples
cypresssession-cookiescypress-login

Cypress Login With Redirect


I would like to create Cypress script that does the following:

  1. Logs into the platform
  2. Stores the session for the following tests - so I do not have to log in each time it executes a new test
  3. Executes the rest of the tests

1. WORKING, but not ideal

I did manage to make it work when I start the script by visiting

cy.visit('https://localhost:3000/login')

but then I have two problems:

A. Rest of the code needs to be in the origin function:

cy.origin('https://localhost:3000/login', () => {
    cy.visit('https://localhost:3000')
    // test script
})

B. More important:

  • It does not keep the session
  • After several logins the user somehow stops working and is no longer authenticated by the platform.

2. NOT WORKING, ideal

So I wanted to start the script the proper way by visiting

cy.visit('https://localhost:3000/')

then clicking on the Log In button

cy.contains('Log In')
    .click()

and here is the tricky part - Once the user clicks to the Log In button the URL is https://localhost:3000/login (Status Code 302) redirects the user to

https://staging.XXX.com/login?redirect_uri=https%3A%2F%2Flocalhost%3A3000%2Freturn_from_login&client_id=CLIENT_ID&scope=%7B%22full%22%3A+true%7D

and once I am making the script working that way I have two problems:

a. Chrome asks me to allow redirect

b. Once allowed, I am redirected outside of the Cypress so the left sidebar disappears completely

Cypress sidebar is gone

Does anybody know how to solve this?

The whole code is

describe('User Session + Start a Discussion', () => {
    const username = "username";
    const password = "password";

    before(() => {
        cy.session("User Session", () => {

            cy.visit('https://localhost:3000')

            cy.contains('Log In')
                .click()
            
            cy.contains('Allow All Cookies', { timeout: 60000 })
                .should('be.visible')

            cy.contains('Allow All Cookies')
                .click()

            cy.get('input[placeholder="Username or Email"]')
                .type(username)
        
            cy.contains('Next')
                .click()
            
            cy.get('input[placeholder="Password"]')
                .type(password)
            
            cy.contains('Log In')
                .click()

            cy.get('button[data-bind="html: actionButtonHTML, click: consentToGrantAction, disable: busy"]', { timeout: 120000 })
                .should('be.visible')

            cy.get('button[data-bind="html: actionButtonHTML, click: consentToGrantAction, disable: busy"]')
                .click()
        })
    })


    it('Starts a new Discussion', () => {
        cy.visit('https://localhost:3000')
        
        cy.get('a[href="/discussions"]', { timeout: 120000 }).should('be.visible')

        cy.get('a[href="/discussions"]')
            .click()

        cy.contains('Start a discussion', { timeout: 20000})
            .click()

        cy.contains('Attach to Discussion...')
            .click()

        cy.get('#object-selector-modal-1').should('be.visible')

        cy.get('[data-classname="file"]')
            .click()

        cy.get(':nth-child(1) > .media > .media-body > label > input')
            .click()            

        cy.get('[data-bind="click: save, css: {disabled: !canSave()}, disable: !canSave()"]')
            .click()

        cy.get('textarea[class="ace_text-input"]')
            .type("New Discussion", {force: true})

        cy.contains('Publish')
            .click({force: true})

        cy.contains('Publish selected objects')
            .click({force: true})
    })

})

I tried to check Gleb's youtube vids and also Cypress documentation but I did not manage to make it work :-(

I was also trying to create as a smaller parts of the code like

it('Homepage', () => {
    cy.visit('https://localhost:3000')
})


it('Login', () => { 
    cy.visit('https://localhost:3000/login')
    // Login code
})

it('Test', () => {  
    // Do sth once logged in
})

But I was not authorized as the user when I tried that this way..

I have this in my cypress.config.js file:

"experimentalSessionAndOrigin": true

Any ideas, tips on how to solve it? Big thank you in advance!


Solution

  • Your code is pretty close, here's what I think you need to change.

    Avoiding frame-busting

    You should be able to avoid the redirect jumping out of the Cypress runner by visiting it directly inside the cy.session().

    Calling pattern for cy.session()

    cy.session() should be in a beforeEach() not a before(). It's purpose is to reinstate the auth cookies for each it(), so it must be called before each test.

    Visit main URL at the top of each test

    cy.visit('https://localhost:3000') is required for every test, see session

    Because the page is cleared at the beginning of each test, cy.visit() must be explicitly called at the beginning of each test.

    Origin command isn't required

    cy.origin() is not required when the two origins are in different execution blocks, i.e https://staging.XXX.com/login in the beforeEach() and https://localhost:3000 in the it() block.


    Here is the general pattern, I've left out some lines for clarity

    describe('User Session + Start a Discussion', () => {
    
        beforeEach(() => {
            cy.session("User Session", () => {
                cy.visit('https://staging.XXX.com/login')
                cy.contains('Log In').click()
                ...          
                cy.get('input[placeholder="Username or Email"]').type(username)
                cy.contains('Next').click()
                cy.get('input[placeholder="Password"]').type(password)
                cy.contains('Log In').click()
                ...
            })
        })
    
        it('Starts a new Discussion', () => {
            cy.visit('https://localhost:3000')       //  logged-in state
            ...
        })
    
        it('Further test', () => {
            cy.visit('https://localhost:3000')       //  logged-in state
            ...
        })
    })