jest-each tests fail when using parameters set in beforeAll

Created on 4 Oct 2018  路  7Comments  路  Source: facebook/jest

馃悰 Bug Report

You cannot pass a variable set in the beforeAll block as a parameter to a parameterized test, as .each is run before beforeAll.

To Reproduce

let values
beforeAll(() => {
  values = ['hello', 'world']
})

describe('test setting variable in before all', () => {
  test('non-parameterized', () => {
    expect(values).toHaveLength(2) // passes
  })

  test.each(values)('parameterized', (value) => {
    expect(value).toBeDefined() // fails - values is undefined
  })

  let otherValues = [1, 2, 3]
  test.each(otherValues)('parameterized with variable set right before test', (value) => {
    expect(value).toBeDefined() // passes
  })
})

Expected behavior

The beforeAll block should run before a parameterized test, in order to match the behaviour in non-parameterized tests.

Link to repl or repo (highly encouraged)

N/A see block of code above

Run npx envinfo --preset jest

 System:
    OS: macOS High Sierra 10.13.6
    CPU: x64 Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
  Binaries:
    Node: 8.9.4 - ~/.nvm/versions/node/v8.9.4/bin/node
    npm: 6.1.0 - ~/.nvm/versions/node/v8.9.4/bin/npm
  npmPackages:
    jest: ^23.4.0 => 23.4.0 
Bug Needs Triage

Most helpful comment

If anyone needs to compute variables dynamically in beforeAll block, here is a way to do so: pass function references instead of values. Code example:

let values;

function getFirstValue() {
  return values[0];
}

function getSecondValue() {
  return values[1];
}

beforeAll(() => {
  // Values of the array are computed dynamically
  values = ['hello', 'world'];
});

describe('Test setting variables in beforeAll', () => {
  test.each([getFirstValue, getSecondValue])('parameterized', (valueFn) => {
    let value = valueFn();
    // the rest of the test code...
  })
});

If the data array is long, one could experiment with iterators like this:

let values;
let i = -1;

function getValue() {
  i++;
  return values[i];
}

beforeAll(() => {
  values = ['hello', 'world'];
});

describe('Test setting variables in beforeAll', () => {
  test.each([getValue, getValue])('parameterized', (valueFn) => {
    let value = valueFn();
    // the rest of the test code...
  })
});

All 7 comments

@mattphillips what do you think about this?

All tests tests and hooks are collected before we start executing any of them, so you cannot use dynamic data from a hook to define its or tests (which .each is sugar for)

Related issue: https://github.com/facebook/jest/issues/6888

As @SimenB said tests need to be defined synchronously. Perhaps we should add this to the docs?

Ah, we've added an error message now! Nice.

I'm fine with adding a note in the FAQ or something, a lot of people want to use stuff in beforeAll/Each when defining tests (mostly because of async work). Having it in the docs makes sense to me!

EDIT: We should probably throw on empty arrays as well, not just non-arrays

FWIW, I've also run into this and expected beforeAll() to actually complete before test.each().

The documentation on test.each doesn't say anything about this.

@dandv it's documented under troubleshooting - hope that helps

If anyone needs to compute variables dynamically in beforeAll block, here is a way to do so: pass function references instead of values. Code example:

let values;

function getFirstValue() {
  return values[0];
}

function getSecondValue() {
  return values[1];
}

beforeAll(() => {
  // Values of the array are computed dynamically
  values = ['hello', 'world'];
});

describe('Test setting variables in beforeAll', () => {
  test.each([getFirstValue, getSecondValue])('parameterized', (valueFn) => {
    let value = valueFn();
    // the rest of the test code...
  })
});

If the data array is long, one could experiment with iterators like this:

let values;
let i = -1;

function getValue() {
  i++;
  return values[i];
}

beforeAll(() => {
  values = ['hello', 'world'];
});

describe('Test setting variables in beforeAll', () => {
  test.each([getValue, getValue])('parameterized', (valueFn) => {
    let value = valueFn();
    // the rest of the test code...
  })
});
Was this page helpful?
0 / 5 - 0 ratings