Search code examples
cucumbercypressbdd

Verifying a text on a dialog box with Cypress and Cucumber


I'm trying to verify a text message on a dialog box using cypress and cucumber. The test cases are working perfectly fine when it's within "it function". Here is is the sample code :

    it ('Verify if the Login is successful', function()
    {
       
        cy.visit('loginTest.html')
        cy.get('#username').type('shahin')
        cy.get('#password').type('tala')
        cy.contains('Login').click() 
        cy.on('window:alert', (str) => {
            expect(str).to.equal(`Login Successfully`)
          })
    })

However when i add the BDD keywords it looks like the function doesn't get evaluated at all. It works for When but not the Then scenario. I think it needs to be handled in Js in a different way. I have uploaded the cypress log as well. Below is the code :

        When('I click on the login button', () => {
            cy.contains('Login').click()
        })
        Then('Successful POP up message should be displayed', () => {
            cy.on('window:alert',  (str) =>  {
                expect(str).to.equal(`Login Successfully`)

            })

Cypress Log

enter image description here


Solution

  • The first thing is cy.on('window:alert'... is a passive event listener, it does not do anything until an event is emitted by the app.

    This means you need to set it before the event is triggered (e.g Login click),

    When('I click on the login button', () => {
      cy.on('window:alert', ...something here...)   // set up the event listener
      cy.contains('Login').click()                  // action that triggers the event
    })
    

    If you do your expect() within the callback of the event listener it mucks up your BDD flow (Then() is redundant).

    Use a stub to catch the event, and assert the stub properties inside Then().

    let stub  // declare outside so it's visible in both When and Then
    
    When('I click on the login button', () => {
      stub = cy.stub()              // set stub here (must be inside a test)
      cy.on('window:alert', stub)   // capture call 
      cy.contains('Login').click()  
    })
    
    Then('message is displayed', () => {
      expect(stub).to.have.been.calledWith('Login Successful')
    })
    

    Why does it() work?

    Essentially, with it() all the code is within one block vs two blocks for When() Then().

    The async commands are queued for later exectution, but the synchronous cy.on() is executed immediately - even though it's the last line it gets executed first.

    it('...', () => {
    
      // Queued and executed (slightly) later
      cy.visit('loginTest.html')
      cy.get('#username').type('shahin')
      cy.get('#password').type('tala')
      cy.contains('Login').click() 
    
      // executed immediately (so actually first line to run)
      cy.on('window:alert', (str) => {
        expect(str).to.equal(`Login Successfully`)
      })
    })
    

    The When() and Then() blocks are executed in sequence, so you don't get the same pattern as with it().