Проверка того, что обещание выполнено не раньше, чем тайм-аут Sinon Chai - PullRequest
2 голосов
/ 31 марта 2019

У нас есть простой метод ожидания, использующий обещания в нашем приложении узла

exports.wait = (timeout) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve()
    }, timeout)
  });
};

Мы попытались проверить это поведение, используя sinon и chai.

Нам удалось получить правильное утверждение, используя chai-as-обещанное, но оно только проверило, что обещание разрешается, но мы не смогли проверить реальное поведение:

  • при передаче значения 100 мс в метод ожидания
  • мы ожидаем, что обещание не будет выполнено в 99мс
  • мы ожидаем, что обещание разрешится в 100мс

Сочетание обещания с таймерами действительно вызывает у нас головную боль.

Вот наша последняя попытка:

const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');
chai.use(require('sinon-chai'));
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);

const wait = require('./wait').wait;

var clock;

before(() => {
  clock = sinon.useFakeTimers();
});

after(() => {
  clock.restore();
})

it('should not resolve until given time', (done) => {
  const promise = wait(100);
  let fulfilled = false;

  promise.then(() => {
    fulfilled = true;
    done();
  });

  clock.tick(99);
  expect(fulfilled).to.be.false;
  clock.tick(2);
  expect(fulfilled).to.be.true;
});

Но fulfilled никогда не переходит на истину, или, по крайней мере, мы не можем его прочитать.

AssertionError: ожидается, что false будет true

Как тогда смешивать таймеры с тестированием обещаний в рамках Chai - Sinon, чтобы правильно использовать наше решение по времени?

1 Ответ

1 голос
/ 01 апреля 2019

Вы можете проверить код из вопроса следующим образом:

const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');

const wait = require('./wait').wait;

var clock;

before(() => {
  clock = sinon.useFakeTimers();
});

after(() => {
  clock.restore();
})

it('should not resolve until given time', async () => {  // <= async
  const promise = wait(100);
  let fulfilled = false;

  promise.then(() => {
    fulfilled = true;
    done();
  });

  clock.tick(99);
  await Promise.resolve();  // let any pending Promise callbacks run
  expect(fulfilled).to.be.false;  // Success!
  clock.tick(2);
  await Promise.resolve();  // let any pending Promise callbacks run
  expect(fulfilled).to.be.true;  // Success!
});

Подробности

Ложные таймеры Включение обратных вызовов по расписаниюс setTimeout в синхронные вызовы.

Promise обратные вызовы, с другой стороны, ставятся в очередь в очереди PromiseJobs , когда Promise разрешается, и не запускаются до после завершения текущего исполняемого сообщения .

В этом случае текущее запущенное сообщение - тест , поэтому обратный вызов then, устанавливающий fulfilled в true не запускается до после теста завершено.

Вы можете использовать тестовую функцию async и вызывать await Promise.resolve(); в любой точке, где вы хотите приостановить текущее выполнениесообщение и разрешить запуск любых обратных вызовов Promise в очереди.

Дополнительные сведения об использовании поддельных таймеров с Promises см. в этом ответе , в котором используется Jest, но концепции те же..

...