Cypress Login With Redirect

Viewed 399

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!

2 Answers

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
        ...
    })
})

First of all, thank you for your quick and kind reply.

Based on your reply and this vid I updated my code to:

describe('User Session + Start a Discussion', () => {

// Creating User Session
beforeEach(() => {
    cy.session("User Session", () => {
                
        cy.visit('https://localhost:3000/')
        
        cy.contains('Log In')
            .click()
        
        cy.origin('https://staging.XXX.com/', () => {
            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()
        })

    })
})

// Runs the Discussion test
it('Starts a new Discussion', () => {
    cy.visit('https://localhost:3000/')
    
    cy.get('a[href="/discussions"]')
        .click()

    cy.contains('Start a discussion', { timeout: 10000})
        .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})

    cy.pause()
})

})

But I am still facing the problem with jumping out of the Cypress runner as once I click to the Log In button it redirects the user multiple times as shown on the following picture

enter image description here

I am able stay in the Cypress runner and also to log in when I visit directly the login page cy.visit('https://localhost:3000/login') but once the user is authenticated then the URL stays as 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 not https://localhost:3000/

So my conclusion is that if I would somehow manage to stay in the same window then your suggested code would be working.

Is there something like forceStayInThisTab function or any other idea how to force Cypress to do multiple redirects in the same window?

I checked the code of the Log In button and unfortunately it's not HTML target="_blank" but it's done via JavaScript..

Related