w3resource

Setup and Teardown


Most times you have setup work that has to happen before the tests run, and there are some finishing works that has to happen after the tests run. Jest will provide helper functions to handle this.

Repeating Setup For Many Tests

If there are some work you need to do repeatedly for many tests, you can make use of beforeEach and afterEach.

For instance, consider when you have several tests interact with a database of cities. You have a method initializeCityDatabase() that has to be called before each of these tests, and a method clearCityDatabase() that has to be called after each of these tests. You can achieve this with:

beforeEach(() => {
  initializeCityDatabase();
});

afterEach(() => {
  clearCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

beforeEach and afterEach can also handle asynchronous code in the same ways that tests can handle asynchronous code - they either take a done parameter or they return a promise. For instance, in the case where initializeCityDatabase() returned a promise that resolved when the database was initialized, we would love to return that promise:

beforeEach(() => {
  return initializeCityDatabase();
});

One-Time Setup

In some cases, you need to do setup only once, and that is at the beginning of a file. When the setup is asynchronous, this can be especially bothersome, so you just can't do it inline. Jest provides beforeAll and afterAll to help you handle this situation.

For instance, in the case where both initializeCityDatabase and clearCityDatabase returned promises, and the city database can be reused between tests, we could decide to change our test code to:

beforeAll(() => {
  return initializeCityDatabase();
});

afterAll(() => {
  return clearCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

Scoping

By default, the before and after blocks will apply to every test in a file. A describe block can be used to group tests together. When tests are inside a describe block, the before and after blocks will only apply to the tests that are within that describe block.

For instance, let's say we don't only have a city database, but a food database also. We could create different setup for different tests:

//This applies to all tests in this file
beforeEach(() => {
  return initializeCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

describe('matching cities to foods', () => {
  // This applies only to tests in this describe block
  beforeEach(() => {
    return initializeFoodDatabase();
  });

  test('Vienna <3 sausage', () => {
    expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
  });

  test('San Juan <3 plantains', () => {
    expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
  });
});

Note that the top-level beforeEach will be executed before the beforeEach that is inside the describe block. Let's us illustrate the order of execution of all hooks.

beforeAll(() => console.log('1 - beforeAll'));
afterAll(() => console.log('1 - afterAll'));
beforeEach(() => console.log('1 - beforeEach'));
afterEach(() => console.log('1 - afterEach'));
test('', () => console.log('1 - test'));
describe('Scoped / Nested block', () => {
  beforeAll(() => console.log('2 - beforeAll'));
  afterAll(() => console.log('2 - afterAll'));
  beforeEach(() => console.log('2 - beforeEach'));
  afterEach(() => console.log('2 - afterEach'));
  test('', () => console.log('2 - test'));
});

// 1 - beforeAll
// 1 - beforeEach
// 1 - test
// 1 - afterEach
// 2 - beforeAll
// 1 - beforeEach
// 2 - beforeEach
// 2 - test
// 2 - afterEach
// 1 - afterEach
// 2 - afterAll
// 1 ? afterAll

Order of execution of describe and test blocks

Jest will execute all describe handlers in a test file before it executes any of the actual tests. This is also why you need to do setup and teardown inside before* and after* handlers instead of inside the describe blocks. when the describe blocks are complete, by default Jest will run all the tests serially in the order they were encountered in the collection phase, it waits for each to finish and get tidied up before moving on.

Take for example, the following illustrative test file and output:

describe('outer', () => {
  console.log('describe outer-a');

  describe('describe inner 1', () => {
    console.log('describe inner 1');
    test('test 1', () => {
      console.log('test for describe inner 1');
      expect(true).toEqual(true);
    });
  });

  console.log('describe outer-b');

  test('test 1', () => {
    console.log('test for describe outer');
    expect(true).toEqual(true);
  });

  describe('describe inner 2', () => {
    console.log('describe inner 2');
    test('test for describe inner 2', () => {
      console.log('test for describe inner 2');
      expect(false).toEqual(false);
    });
  });

  console.log('describe outer-c');
});

// describe outer-a
// describe inner 1
// describe outer-b
// describe inner 2
// describe outer-c
// test for describe inner 1
// test for describe outer
// test for describe inner 2

General Advice

In the case where a test is failing, one of the first things you need to check should be whether the test is failing when it's the only test that runs. It's simple to run only one test in Jest - all you need to do is temporarily change that test command to a test.only:

test.only('this will be the only test that runs', () => {
  expect(true).toBe(false);
});

test('this test will not run', () => {
  expect('A').toBe('A');
});

If you have an individual test that often fails when it's run as part of a larger suite, but runs successfully when you run it alone, then something in the other tests is interfering with the test. Most often you can fix this by clearing some shared state with beforeEach. If you're however not sure whether some shared state is being modified, you can as well try a beforeEach that just logs data.



Inviting useful, relevant, well-written and unique guest posts