Search code examples
javascriptcypressmocha.js

A way to initialize variable in beforeEach and use it further - Mocha


I am using Mocha, Typescript and Cypress to write tests.
This is visualization of what I am trying to achieve (so far unsuccessfully :():

// this is in example-spec.ts file
context('Sharing variable test', function() {
  let ctx: string;

  beforeEach(function() {
    ctx = 'Value given in beforeEach';
  });

  console.log(ctx); // prints undefined
  consumeCtx(ctx);
});

// this is in separate example-template.ts file
export function consumeCtx(ctx: string) {
    console.log(ctx); // this is undefined
    // use ctx here
    describe('Testing my stuff', function () {
        it('should do something', function () {
          // use ctx here  
          cy.log('This is a test');
        });
      });
}

I would like I could somehow fill the ctx data in beforeEach and then use it after that through calling a function which accepts ctx as parameter.
The idea is to have 2 different spec files (e.g. example1-spec.ts and example2-spec.ts) which can be run separately.
But they still share the same test logic defined in example-template.ts file.
And the test data ctx specific to each spec file is provided in the spec file and then just passed to the common test logic in template file.
Is there a way to achieve this in the set up that I have created?
Is my approach completely wrong? How would you do it better?
Thanks!

[EDIT] This is how I reorganized it based on the answers:

In each spec file there is mocha structure.

context('Voucher tests', function () {
    let ctx: string;

    beforeEach(function () {
        ctx = 'Value given in beforeEach';
        cy.wrap(ctx).as('ctx');
    });

    describe('Logged in user', function () {
        it('valid voucher ', function () {
            cy.get<string>('@ctx').then((ctx) => {
                console.log(ctx); // should print the value of ctx now
                validCtxTest(ctx);
            });
        });

        it('invalid voucher ', function () {
            cy.get<string>('@ctx').then((ctx) => {
                console.log(ctx); // should print the value of ctx now
                invalidCtxTest(ctx);
            });
        });
    });
});  

And in separate template file I have the shared logic.

export function validCtxTest(ctx: string) {
  cy.log('Logic for valid test', ctx);
}

export function invalidCtxTest(ctx: string) {
  cy.log('Logic for invalid test', ctx);
}  

Solution

  • I learnt this the hard way. But you need to wrap ctx, provide an alias, and then call that alias to be passed to your function. I am not a type script person, but hope this helps. [Edit: adding a working script and result]

    context("blah",()=> {
        let ctx
        beforeEach( function()  {
            const uuid = () => Cypress._.random(0, 1e3)
            const id = uuid()
            ctx=`some random number ${id}`
            cy.wrap(ctx).as('ctx')
            
        })
        describe("Spec", () => {
            
            it("Test1", function()  {
                cy.get('@ctx').then(ctx=> {
                    console.log(ctx)
                })
                
            })
        
            it("Test2", function()  {
                cy.get('@ctx').then(ctx=> {
                    console.log(ctx)
                })
            })
        })
    })
    

    enter image description here

    Also, if you are not planning to have multiple test in a spec file, or pass different value of ctx for each test under 1 spec file, then just ignore the Before hook. You can declare a variable inside your test and then wrap it up and call it anywhere you want in that test. For the next test, do the same. Its the same approach i have used in my project. fixtures help a lot in defining and passing test data, rather than variables.