直到超时 sinon chai 才解决承诺的测试

Testing that promise resolved not until timeout sinon chai

我们有一个简单的等待方法利用节点应用程序中的承诺

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

我们尝试使用 sinon 和 chai 测试此行为。

我们设法使用 chai-as-promised 获得了正确的断言,但它只检查承诺的解决,而我们无法测试真实的行为:

promise 与计时器的结合确实让我们头疼。

这是我们最后一次尝试的设置:

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: expected false to be true

然后如何将计时器与 chai - sinon 下的 promise 测试相结合,以正确地评估我们的定时解决方案?

您可以像这样测试问题中的代码:

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!
});

详情

Fake timers 将使用 setTimeout 安排的回调转换为同步调用。

另一方面,

Promise 回调在 Promise 解析时在 PromiseJobs queue 中排队,并且 运行 直到 在当前执行消息完成后.

在这种情况下,当前运行ning消息是测试,所以then回调将fulfilled设置为true 不会 运行 直到 测试完成后。

您可以使用 async 测试函数并在任何您想要暂停当前 运行ning 消息并允许任何排队的 Promise 回调的位置调用 await Promise.resolve();至 运行.

有关将假定时器与 Promises 一起使用的更多详细信息,请参阅使用 Jest,但概念是相同的。