skip to Main Content

In this example on the website, they say there is a simple way to use data you create in before() or beforeEach() in a testcase it(). But when I tried it it said my this.variable was undefined. After a little more searching I found that all aliases are cleared before each test, making the example on the website not possible.

Example on the website under Sharing context:

describe('parent', () => {
  beforeEach(() => {
    cy.wrap('one').as('a')
  })

  context('child', () => {
    beforeEach(() => {
      cy.wrap('two').as('b')
    })

    describe('grandchild', () => {
      beforeEach(() => {
        cy.wrap('three').as('c')
      })

      it('can access all aliases as properties', function () {
        expect(this.a).to.eq('one') // true
        expect(this.b).to.eq('two') // true
        expect(this.c).to.eq('three') // true
      })
    })
  })
})

Briefly what I’m trying to do (I thought the way I get my data irrelevant to the question):

describe('myTests', () => {
  beforeEach(() => {
    // producing data resulting in a jquery list element
    cy.wrap($element).as('element')
  })

  it('firstTest', function () {
    this.element.click()
  })
}

This results on a TypeError (void 0) is undefined with an error to the beginning of this

edit:

So what I’m doing is getting a list element from a website. The second visible element in the main menu.

describe('Click test', () => {
    beforeEach(() => {
        let counter = 0
        cy.visit('https://www.qalybr.nl')
        cy.get('ul[class~=menu] li').each(($el) => {
            if($el.is(':visible')) {
                if(counter === 1) {
                    cy.wrap($el).as('werkenBij')
                }
                counter++;
            }
        })
    })

    it('Werken', () => {
        this.werkenBij.click()
    })
})

It wraps and aliases the element correctly, the cypress runner shows this, but then isn’t able to find this.

The TypeError

2

Answers


  1. It does actually depend on the way you are obtaining $element. If you follow the pattern in the documents you quoted, there is no problem.

    This passes

    beforeEach(() => {
      cy.get'some-selector-for-button').as('element')
    })
    
    it('uses element alias', function() {
      this.element.click()                
    })
    

    and of course this passes

    beforeEach(() => {
      cy.get'some-selector-for-button').as('element')
    })
    
    it('uses element alias', function() {
      cy.get('@element').click()                
    })
    

    Cypress tells you (on the linked page) that you should not use the return value from a query, because it may go stale.

    So don’t do this

    // BAD CODE
    
    beforeEach(() => {
      const $element = cy.get'some-selector-for-button')
      cy.wrap($element).as('element')
    })
    
    it('uses element alias', function() {
      this.element.click()                
    })
    

    Always chain the alias instead, even if you are working with $element inside a then()

    // GOOD CODE
    
    beforeEach(() => {
      cy.get'some-selector-for-button')
        .then($element => {
          const $elementText = $element.text()
    
          // use the text in some way
    
          return $element    // return the element for capturing in the alias
        })
        .as('element')
    })
    
    it('uses element alias', function() {
      this.element.click()                
    })
    
    Login or Signup to reply.
  2. The full example in the edit section is different to the example given above it.

    To use the this.werkenBij form of alias you must have a function() based callback, not a () => {} arrow-function based callback.

      it('Werken', function() {
        this.werkenBij.click()
      })
    

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search