9
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?

user1
  • 121
  • 1
  • 1
  • 6
  • What is the problem you're trying to solve? The solution is specific to it. Jest doesn't have the concept of test contexts, proceed from this fact. You cannot pass a variable from a test to beforeEach because beforeEach is evaluated before it. – Estus Flask Feb 23 '21 at 15:15
  • I wanted to create a custom test report for each iteration of the test and there are some activity i have to do before each iteration, so I want that value so that I can publish result based on iteration – user1 Feb 24 '21 at 06:47
  • It's likely a move in wrong direction, there are custom reports and environments in Jest that allow to hijack there. Any way, what you're trying to do is usually solved by creating wrapper functions around test API. If you need test name, you can obtain a string from yourself. – Estus Flask Feb 24 '21 at 09:03

2 Answers2

4

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)

remix23
  • 2,632
  • 2
  • 11
  • 21
1

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);
  });
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • When I think about it, the question asked may actually be: "how do I chain async functions", which is "free" with beforeEach (beforeEach is used async above) – remix23 Feb 23 '21 at 15:41
  • I'm not entirely sure that jest doesn't provide test-scoped context by looking at that: https://github.com/facebook/jest/blob/0e50f7313837bd005a560cb2161423ab06845733/packages/jest-circus/src/run.ts#L93 – remix23 Feb 23 '21 at 15:44
  • But it's not obvious if it could be used this way and I agree thats it's preferable to implement such a context yourself – remix23 Feb 23 '21 at 15:51
  • It's internal and undocumented, so it may break with time. Initially Jest used Jasmine's `this` context but then it was abandoned and stopped working as intended. I don't see much problems with chaining since everything can be awaited the same way in a test itself. – Estus Flask Feb 23 '21 at 15:55
  • Yes it looks like a remnant of the `this` from jasmine. I don't see any difficulty either with chaining, but my point was that the person asking may have problems with this – remix23 Feb 23 '21 at 16:10