【问题标题】:wait for sinon stubbed promise to resolve before making assertion on sinon spy在对 sinon spy 进行断言之前,等待 sinon stubbed promise 解决
【发布时间】:2017-10-24 13:15:04
【问题描述】:

我有一个中间件功能,它检查会话令牌以查看用户是否是管理员用户。如果所有检查都通过,该函数不会返回任何内容,而只是调用 next()。

在对作为 Sinon 间谍的 next() 回调进行断言之前,我如何才能等待内部异步 Promise (adminPromise) 解决?测试当前将失败,因为测试中的断言是在 AdminMiddleware.prototype.run 中的承诺解析之前做出的。

函数是:

AdminMiddleware.prototype.run = function (req, res, next) {
  let token        = req.header(sessionTokenHeader);
  let adminPromise = new admin().send()

  adminPromise.then(function (authResponse) {
    let adminBoolean = JSON.parse(authResponse).payload.admin;

    if (adminBoolean !== true) {
      return new responseTypes().clientError(res, {
          'user': 'validation.admin'
      }, 403);
    };

    next();
  });
};

还有测试:

it('should call next once if admin', function (done) {
    stub = sinon.stub(admin.prototype, 'send');
    stub.resolves(JSON.stringify({success : true, payload : {admin : true}}));
    let nextSpy = sinon.spy();

    AdminMiddleware.prototype.run({header: function () {}}, {}, nextSpy);
    expect(nextSpy.calledOnce).to.be.true;
    done();
});

目前我正在包装下面的期望,这将导致测试通过,但似乎是一个 hack。此外,如果它失败,将导致未处理的 promise 拒绝错误和超时,因为 done() 没有被调用。

    it('should call next once if admin', function (done) {
    stub = sinon.stub(admin.prototype, 'send');
    stub.resolves(JSON.stringify({success : true, payload : {admin : true}}));
    let nextSpy = sinon.spy();

    AdminMiddleware.prototype.run({header: function () {}}, {}, nextSpy);
    stub().then(function () {
        expect(nextSpy.calledOnce).to.be.true;
        done();
    });
});

【问题讨论】:

    标签: javascript mocha.js sinon sinon-chai


    【解决方案1】:

    一种解决方案是使用存根代替间谍。尽管它们是两个不同的东西,但我认为您在这种情况下不会丢失任何功能,因为您使用的是匿名间谍。

    AdminMiddleware.prototype.run = function (req, res, next) {
        const adminPromise = Promise.resolve()
    
        adminPromise.then(function (authResponse) {
            next()
        })
    }
    
    it('should call next once if admin', function (done) {
        const nextSpy = sinon.stub()
        nextSpy.callsFake(() => {
            expect(nextSpy.called).to.be.true
            done()
        })
        AdminMiddleware.prototype.run({header: function () {}}, {}, nextSpy);
    });
    

    此外,您可以避免在此断言中完全使用 sinon,并执行以下操作:

    it('should call next once if admin', function (done) {
        let called
        const nextSpy = function() {
            called = true
            expect(called).to.be.true
            done()
        }
        AdminMiddleware.prototype.run({header: function () {}}, {}, nextSpy);
    });
    

    在这两个示例中,如果未调用 nextSpy,您仍然会收到超时错误,想不出任何合理的解决方法。如果避免未处理的承诺拒绝非常重要,我想你可以这样做:

    nextSpy.callsFake(() => {
        try {
            expect(nextSpy.called).to.be.false
            done()
        } catch (e) {
            console.log(e)
        }
    })
    

    由于超时,它仍然会导致测试失败,但是它不会抛出未处理的 Promise 拒绝错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-13
      • 2018-07-19
      • 1970-01-01
      • 1970-01-01
      • 2020-11-17
      • 2021-11-16
      • 2020-10-21
      相关资源
      最近更新 更多