How to pass variable from test to beforeEach hook?

Viewed 4809
describe("SuiteName", () => {
  var numberArray =[1,2,3];

  beforeEach(async () => {
    //I want 'n' from test in this before each method
    console.log("Before Each" + expect.getState().currentTestName + 'number ' + n);
    
  });


    test.each(numberArray)("Tesst Name" , async (n) => {
    console.log("Current parameter is-> " + n);

  });
});

Hi, I am new to Jest and want to understand that how can i get the number value in beforeeach block?

2 Answers

By looking at jest code (the doc didn't help much) it seems the callback passed to beforeEach is called with the done callback argument, which wont help. (source https://github.com/facebook/jest/blob/0e50f7313837bd005a560cb2161423ab06845733/packages/jest-circus/src/run.ts and https://github.com/facebook/jest/blob/66629be6194f5e107a26f406180a6ed597fb3c55/packages/jest-circus/src/utils.ts)

But it doesn't matter as within a describe the beforeEach and the test share the same scope, and within a test suite, tests run sequentially (no overlapping "concurrent" access to testState), so it's perfectly fine to do this:

describe("SuiteName", () => {
  const testState = { n: undefined };
  var numberArray =[1,2,3];

  beforeEach(async () => {
    //I want 'n' from test in this before each method
    console.log("Before Each" + expect.getState().currentTestName + 'number ' + testState.n);
    
  });

  numberArray.forEach(n => {
    console.log("Current parameter is-> " + n);
    testState.n = n;
    test('Tesst Name for n: ' + n, async () => {
      console.log("Current parameter is-> " + n);
    })
  });
});

Problem, you lost some of the benefit of test.each by splitting it into multiple tests sharing the same code. But it seems there's no way around it using test.each.

Alternatively, since the use case of both test.each and beforeEach is preventing duplicating code and making the test more readable, why don't you just chain the beforeEach (async) hook code with the actual test:

describe("SuiteName", () => {
  var numberArray =[1,2,3];

  const forgetBeforeEachWeAreDoingTestEach = (n) => {
    return new Promise((resolve) => {
      //I want 'n' from test in this before each method
      console.log("Before Each" + expect.getState().currentTestName + 'number ' + n);
      resolve();
    });
  });

  test.each(numberArray)('Tesst Name', async (n) => {
    forgetBeforeEachWeAreDoingTestEach(n).then(() => {
        console.log("Current parameter is-> " + n);
    });
  });
});

I did the above with a Promise because I'm old school but converting from one to the other is pretty straightforward most of the time

May be just:

await forgetBeforeEachWeAreDoingTestEach(n);
console.log("Current parameter is-> " + n);

Note: This previous stackoverflow answer here provides a solution similar to the first one (testState) with sinon.sandbox, but does not address the test.each problem (having 1 test with multiple params VS having multiple tests with the same code)

expect.getState() is internal API. Jest doesn't have test-scoped context, it should be handled by a developer.

beforeEach functions are evaluated before respective tests and are unaware of what happens after. Notice that beforeEach are hierarchical and may be applied to tests that don't derive from numberArray.

In this case beforeEach doesn't have benefits as reusable piece of code. Since each function is common for all these tests, it can be:

  test.each(numberArray)("Tesst Name" , async (n) => {
    console.log("Before Each number ' + n);

    console.log("Current parameter is-> " + n);
  });
Related