Often while writing tests you have some setup work that needs to happen before tests run, and you have some finishing work that needs to happen after tests run. Jest provides helper functions to handle this.

Repeating Setup For Many Tests

If you have some work you need to do repeatedly for many tests, you can use beforeEach and afterEach.

For example, let's say that several tests interact with a database of cities. You have a method initializeCityDatabase() that must be called before each of these tests, and a method clearCityDatabase() that must be called after each of these tests. You can do this with:

  1. beforeEach(() => {
  2. initializeCityDatabase();
  3. });
  4. afterEach(() => {
  5. clearCityDatabase();
  6. });
  7. test('city database has Vienna', () => {
  8. expect(isCity('Vienna')).toBeTruthy();
  9. });
  10. test('city database has San Juan', () => {
  11. expect(isCity('San Juan')).toBeTruthy();
  12. });

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

  1. beforeEach(() => {
  2. return initializeCityDatabase();
  3. });

One-Time Setup

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

For example, if both initializeCityDatabase and clearCityDatabase returned promises, and the city database could be reused between tests, we could change our test code to:

  1. beforeAll(() => {
  2. return initializeCityDatabase();
  3. });
  4. afterAll(() => {
  5. return clearCityDatabase();
  6. });
  7. test('city database has Vienna', () => {
  8. expect(isCity('Vienna')).toBeTruthy();
  9. });
  10. test('city database has San Juan', () => {
  11. expect(isCity('San Juan')).toBeTruthy();
  12. });

Scoping

By default, the before and after blocks apply to every test in a file. You can also group tests together using a describe block. When they are inside a describe block, the before and after blocks only apply to the tests within that describe block.

For example, let's say we had not just a city database, but also a food database. We could do different setup for different tests:

  1. // Applies to all tests in this file
  2. beforeEach(() => {
  3. return initializeCityDatabase();
  4. });
  5. test('city database has Vienna', () => {
  6. expect(isCity('Vienna')).toBeTruthy();
  7. });
  8. test('city database has San Juan', () => {
  9. expect(isCity('San Juan')).toBeTruthy();
  10. });
  11. describe('matching cities to foods', () => {
  12. // Applies only to tests in this describe block
  13. beforeEach(() => {
  14. return initializeFoodDatabase();
  15. });
  16. test('Vienna <3 sausage', () => {
  17. expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
  18. });
  19. test('San Juan <3 plantains', () => {
  20. expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
  21. });
  22. });

Note that the top-level beforeEach is executed before the beforeEach inside the describe block. It may help to illustrate the order of execution of all hooks.

  1. beforeAll(() => console.log('1 - beforeAll'));
  2. afterAll(() => console.log('1 - afterAll'));
  3. beforeEach(() => console.log('1 - beforeEach'));
  4. afterEach(() => console.log('1 - afterEach'));
  5. test('', () => console.log('1 - test'));
  6. describe('Scoped / Nested block', () => {
  7. beforeAll(() => console.log('2 - beforeAll'));
  8. afterAll(() => console.log('2 - afterAll'));
  9. beforeEach(() => console.log('2 - beforeEach'));
  10. afterEach(() => console.log('2 - afterEach'));
  11. test('', () => console.log('2 - test'));
  12. });
  13. // 1 - beforeAll
  14. // 1 - beforeEach
  15. // 1 - test
  16. // 1 - afterEach
  17. // 2 - beforeAll
  18. // 1 - beforeEach
  19. // 2 - beforeEach
  20. // 2 - test
  21. // 2 - afterEach
  22. // 1 - afterEach
  23. // 2 - afterAll
  24. // 1 - afterAll

Order of execution of describe and test blocks

Jest executes all describe handlers in a test file before it executes any of the actual tests. This is another reason to do setup and teardown in before and after handlers rather in the describe blocks. Once the describe blocks are complete, by default Jest runs all the tests serially in the order they were encountered in the collection phase, waiting for each to finish and be tidied up before moving on.

Consider the following illustrative test file and output:

  1. describe('outer', () => {
  2. console.log('describe outer-a');
  3. describe('describe inner 1', () => {
  4. console.log('describe inner 1');
  5. test('test 1', () => {
  6. console.log('test for describe inner 1');
  7. expect(true).toEqual(true);
  8. });
  9. });
  10. console.log('describe outer-b');
  11. test('test 1', () => {
  12. console.log('test for describe outer');
  13. expect(true).toEqual(true);
  14. });
  15. describe('describe inner 2', () => {
  16. console.log('describe inner 2');
  17. test('test for describe inner 2', () => {
  18. console.log('test for describe inner 2');
  19. expect(false).toEqual(false);
  20. });
  21. });
  22. console.log('describe outer-c');
  23. });
  24. // describe outer-a
  25. // describe inner 1
  26. // describe outer-b
  27. // describe inner 2
  28. // describe outer-c
  29. // test for describe inner 1
  30. // test for describe outer
  31. // test for describe inner 2

General Advice

If a test is failing, one of the first things to check should be whether the test is failing when it's the only test that runs. In Jest it's simple to run only one test - just temporarily change that test command to a test.only:

  1. test.only('this will be the only test that runs', () => {
  2. expect(true).toBe(false);
  3. });
  4. test('this test will not run', () => {
  5. expect('A').toBe('A');
  6. });

If you have a test that often fails when it's run as part of a larger suite, but doesn't fail when you run it alone, it's a good bet that something from a different test is interfering with this one. You can often fix this by clearing some shared state with beforeEach. If you're not sure whether some shared state is being modified, you can also try a beforeEach that just logs data.

原文: https://jestjs.io/docs/en/setup-teardown