aarona
aarona

Reputation: 37253

Setting a variable in before cannot be accessed in a beforeEach after the first test

Why don't I have access to @testVariable after the first beforeEach? I should be able to have access to it for each test in this context.

describe('Testing before and beforeEach issue', () => {
  context('testing before and beforeEach', () => {
    before(() => {
      cy.wrap("TESTING 123").as("testVariable")
    })

    beforeEach(() => {
      // This fails after the first beforeEach call.
      cy.get("@testVariable").then((testVariable) => {
        cy.log(`THIS IS A TEST: ${testVariable}`)
      })
    })

    // This test is reached and passes
    it('Testing the variable one time', () => {
      cy.log("THIS IS LOG 1")
    })

    // This test should also pass but is not reached before
    // an error occurs in beforeEach
    it('Testing the variable a second time', () => {
      cy.log("THIS IS LOG 2")
    })
  })
})

Here is the test output:

  Testing before and beforeEach issue
    testing before and beforeEach
      ✓ Testing the variable one time
      1) "before each" hook for "Testing the variable a second time"


  1 passing (684ms)
  1 failing

  1) Testing before and beforeEach issue
       testing before and beforeEach
         "before each" hook for "Testing the variable a second time":
     CypressError: `cy.get()` could not find a registered alias for: `@testVariable`.
You have not aliased anything yet.

Because this error occurred during a `before each` hook we are skipping the remaining tests in the current suite: `testing before and beforeEach`

Upvotes: 2

Views: 903

Answers (1)

TesterDick
TesterDick

Reputation: 10525

It's by design, part of Cypress approach to minimal cross-test pollution (since beforeEach() is part of each test).

Aliases are reset before each test

Note: all aliases are reset before each test. A common user mistake is to create aliases using the before hook. Such aliases work in the first test only!

But there's a loophole. The alias sets up a variable of the same name on the Mocha context (this) and it's not cleared between tests.

Sharing Context

Under the hood, aliasing basic objects and primitives utilizes Mocha's shared context object: that is, aliases are available as this.* (i.e properties of this).

It goes on to say

Additionally these aliases and properties are automatically cleaned up after each test.

but if you run the following, you find that's not true - the alias is removed but not the context property.

describe('Testing before and beforeEach issue', () => {
  context('testing before and beforeEach', () => {
    before(() => {
      cy.wrap("TESTING 123").as("testVariable")
    })

    // beforeEach(function() {
    //   // This fails after the first beforeEach call.
    //   cy.get("@testVariable").then((testVariable) => {
    //     cy.log(`THIS IS A TEST: ${testVariable}`)
    //   })
    // })
    beforeEach(function() {
      cy.log(`THIS IS A TEST: ${this.testVariable}`)  // logged for each test
    })

    // This test is reached and passes
    it('Testing the variable one time', () => {
      cy.log("THIS IS LOG 1")
    })

    // This test should also pass but is not reached before
    // an error occurs in beforeEach
    it('Testing the variable a second time', () => {
      cy.log("THIS IS LOG 2")
    })
  })
})

Upvotes: 3

Related Questions