Why does cypress variable inside of it() stay as the last value assigned to that variable, whereas outside of it() it works correctly? (Example)

Viewed 230

If my code is:

context('The Test', () => {
  let testStr = 'Test A'
  it(`This test is ${testStr}`, () => {
    expect(testStr).to.eq('Test A')
  })

  testStr = 'Test B'
  it(`This test is ${testStr}`, () => {
    expect(testStr).to.eq('Test B')
  })

  testStr = 'Test C'
  it(`This test is ${testStr}`, () => {
    expect(testStr).to.eq('Test C')
  })
})

This image has the resulting tests -- My usage of testStr inside the backticks works the way I want it to (indicated by output having the correct test titles of Test A, Test B, and Test C), but the usage of testStr in the expect(testStr).to.eq cases fails the first 2 tests because testStr is always 'Test C' for these checks. Why does this occur, and how can I write this differently to do what I want?

2 Answers

it()'s callbacks will be executed only after parent's one (context in your case). You can play with it in debugger and see it live: enter image description here

So mocha will assign the final 'Test C' value and call the first it() callback after that.

To solve the problem as close as possible to the structure of you current approach, you can use mocha context to capture the value at the time you define the it() case. Unfortunately, I found the mocha shares the context object between all of it siblings. So I had to wrap each of the case inside a child context:

context('The Test', function () {
  let curTestStr = 'Test A'

  context(`This test is ${curTestStr}`, () => {
    it("test", function() {
      expect(this.curTestStr).to.eq('Test A')
    })
  }).ctx.curTestStr = curTestStr;

  curTestStr = 'Test B'
  context(`This test is ${curTestStr}`, () => {
    it("test", function() {
      expect(this.curTestStr).to.eq('Test B')
    })
  }).ctx.curTestStr = curTestStr;

  curTestStr = 'Test C'
  context(`This test is ${curTestStr}`, () => {
    it("test", function() {
      expect(this.curTestStr).to.eq('Test C')
    })
  }).ctx.curTestStr = curTestStr;
})

Please also note that you have to use a function callback to access variables from this. It will not work with an arrow function expression () => {}

I don't have enough proof but i believe that it must be because it() must be asynchronous like the following code

let a= 10;
setTimeout(function(){ console.log(a); }, 1000);
a = 11;
setTimeout(function(){ console.log(a); }, 1000);

by the time setTimeout are executed the value of a becomes 11.

Found this for your use case

Related