Jest - Понимание порядка выполнения описаний () и его () - PullRequest
1 голос
/ 21 мая 2019

Я хотел бы понять, почему все блоки describe() запускаются до it() внутри каждого describe().

Вот пример CodeSandbox с журналом для каждого блока describe и it.

describe("sum A", () => {
  window.innerWidth = 100;
  console.log("describe A", window.innerWidth);

  beforeAll(() => {
    window.innerWidth = 105;
    console.log("describe A before", window.innerWidth);
  });

  it("1. should add 1 and 2", () => {
    console.log("it A1", window.innerWidth);
    expect(1 + 2).toBe(3);
  });
});

describe("sum B", () => {
  console.log("describe B", window.innerWidth, "why does it run before it A1?");

  beforeAll(() => {
    window.innerWidth = 205;
    console.log("describe B before", window.innerWidth);
  });

  it("1. should add 1 and 2", () => {
    console.log("it B1", window.innerWidth);
    expect(1 + 2).toBe(3);
  });
});

Вы заметите, что журнал из второго блока описания запускается до it() внутри первого блока описания.

Почему это происходит? Должны ли мы избегать выполнения каких-либо действий в этой части кода и предпочитать использовать beforeAll(), когда нам нужно совместно использовать данные в этом блоке описания?

1 Ответ

2 голосов
/ 22 мая 2019

Когда запускается Jest, он ищет все тестовые файлы и запускает каждый из них.

Каждый тестовый файл выполняется в среде, предоставляемой Jest, которая включает глобальные переменные, такие как describe, it, beforeAll и т. Д. Все эти глобальные переменные имеют параметр обратного вызова, который определяет их поведение.

Когда запускается тестовый файл, выполняется код верхнего уровня ... включая любые вызовы describe верхнего уровня.

Когда describe запускает его, регистрирует набор тестов , а затем его обратный вызов вызывается немедленно .

Это отличается от it, beforeAll, beforeEach и т. Д., Где обратный вызов записывается, но не сразу вызывается .

Это означает, что все функции обратного вызова describe вызываются в глубину в порядке их появления в тестовом файле, как видно из этого простого примера:

describe('1', () => {
  console.log('1');
  describe('2', () => { console.log('2'); });
  describe('3', () => {
    console.log('3');
    describe('4', () => { console.log('4'); })
    describe('5', () => { console.log('5'); })
  })
  describe('6', () => { console.log('6'); })
})
describe('7', () => {
  console.log('7');
  it('(since there has to be at least one test)', () => { });
})

... который регистрирует 1 - 7 по порядку.

Этот начальный запуск всех обратных вызовов describe называется этапом сбора , в течение которого определяются наборы тестов и все обратные вызовы для любых beforeAll, beforeEach, it, test и т. Д. Собираются

После завершения этапа сбора, Jest ...

запускает все тесты последовательно в порядке, в котором они встречались на этапе сбора, ожидая, пока каждый из них завершится и будет приведен в порядок, прежде чем двигаться дальше.

Для каждого теста (каждая функция обратного вызова, зарегистрированная с помощью глобальных функций it или test) Jest связывает воедино все перед обратными вызовами, сам тестовый обратный вызов и любые последующие обратные вызовы и запускает Результирующие функции в порядке.


Должны ли мы избегать выполнения каких-либо действий в этой части кода и предпочитать использовать beforeAll(), когда нам нужно совместно использовать данные в этом блоке описания?

Для простых вещей, которые не передаются, хорошо иметь их в describe:

describe('val', () => {
  const val = '1';

  it('should be 1', () => {
    expect(val).toBe('1');  // Success!
  });
});

... но код в describe может вызвать проблемы с общими данными:

describe('val', () => {
  let val;

  describe('1', () => {
    val = '1';
    it('should be 1', () => {
      expect(val).toBe('1');  // FAIL! (val gets set to 2 in the second describe)
    })
  })

  describe('2', () => {
    val = '2';
    it('should be 2', () => {
      expect(val).toBe('2');  // Success!
    })
  })

});

... это можно исправить с помощью before вызовов:

describe('val', () => {
  let val;

  describe('1', () => {
    beforeEach(() => {
      val = '1';
    });
    it('should be 1', () => {
      expect(val).toBe('1');  // Success!
    })
  })

  describe('2', () => {
    beforeEach(() => {
      val = '2';
    });
    it('should be 2', () => {
      expect(val).toBe('2');  // Success!
    })
  })

});

... или просто определить область данных до describe:

describe('val', () => {

  describe('1', () => {
    const val = '1';
    it('should be 1', () => {
      expect(val).toBe('1');  // Success!
    })
  })

  describe('2', () => {
    const val = '2';
    it('should be 2', () => {
      expect(val).toBe('2');  // Success!
    })
  })

});

В вашем примере вы используете window.innerWidth, который является общим глобальным, так что вы захотите использовать before функции, так как он не может быть ограничен до describe.


Также обратите внимание, что вы не можете ничего вернуть из describe, поэтому, если ваши тесты требуют какой-либо асинхронной настройки, вам нужно будет использовать функцию before, где вы можете вернуть Promise для Jest ждать:

const somethingAsync = () => Promise.resolve('1');

describe('val', () => {
  let val;

  beforeAll(async () => {
    val = await somethingAsync();
  });

  it('should be 1', () => {
    expect(val).toBe('1');  // Success!
  });
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...