【问题标题】:Uncaught (in promise) error when testing promise with Mocha使用 Mocha 测试 Promise 时未捕获(承诺中)错误
【发布时间】:2018-05-10 09:40:37
【问题描述】:

我很难测试基于 Promise 的函数。我使用 Mocha 作为测试框架和 chai 库作为断言框架。我对摩卡和柴都是新手。我的问题很少,我不知道我的代码有问题。也许我的测试方法完全错误,也许有人帮助他们。

我得到了预期的 Uncaught (in promise) 错误,但实际上我不知道我的方法是否是测试这些函数的正确方法。

这是我的 returnResult 函数,它解析一个值 -> 一个字符串

var returnResult = function (stateParamName, stateParamValue) {

 return new Promise((resolve, reject) => {
   peer3.get({ path: { equals: 'todo/#0' } }).then(function (results) {
    console.log(stateParamName + ': ' + results[0].value[stateParamName])
    resolve(results[0].value[stateParamName]);
  });
});
}

这是我的摩卡咖啡测试

 describe("Call Tests Suite", function () {
  describe("Basic Call Test", function () {
  it("Call status for both side should be IN CALL", function () {
  peer3.call('login/add', ['testaccount1'])
    .then(() => peer3.call('todo/makeCall1', ['testaccount2@testdomain.com']))
    .then(() => checkResult('state_term', 'RINGING'))
    .then((interval) => { clearInterval(interval); peer3.call('todo/answerCall2', ['empty']) })
    .then(() => checkResult('state_term', 'IN_CALL'))
    .then((interval) => clearInterval(interval))
    //.then(console.log('test sonucu: ' + returnResult('state_term', 'IN_CALL')))
    .then(returnResult('state_term', 'IN_CALL'))
    .then((result) => expect(result).to.equal('IN_CALL'))        
   });

 });

如您所见,我只对最后一个结果使用断言。也许我应该将整个测试作为一个承诺函数进行测试。有人可以帮我吗?

【问题讨论】:

  • 您的.then((interval) => ...) 没有返回承诺,但应该返回。
  • 另外,您在第一个代码示例中提交了explicit promise construction antipattern。不要在那里使用new Promise()。直接return peer3.get()即可。
  • 不确定未捕获的错误来自何处,但您需要 return 承诺(在测试代码的第 4 行),以便 Mocha 可以等待它完成。您也未能在第三个then 中返回承诺。所以下一个then 不能等待peer3.call('todo/answerCall2', ['empty']) 完成。

标签: javascript promise mocha.js chai


【解决方案1】:

我不知道你的错误来自哪里。但是,您的代码中有很多地方可以改进,并且可能会引导您进行更好的调试,因此您可以找到错误:

1- 您应该在承诺链的末尾添加一个.catch 处理程序。 'uncaught 错误'指的是:您的then 处理程序之一中有错误,但未在catch 中捕获。您应该在火车末尾添加一个catch 呼叫:

describe("Call Tests Suite", function () {
describe("Basic Call Test", function () {
it("Call status for both side should be IN CALL", function () {
peer3.call('login/add', ['testaccount1'])
    .then(() => peer3.call('todo/makeCall1', ['testaccount2@testdomain.com']))
    .then(() => checkResult('state_term', 'RINGING'))
    .then((interval) => { clearInterval(interval); peer3.call('todo/answerCall2', ['empty']) })
    .then(() => checkResult('state_term', 'IN_CALL'))
    .then((interval) => clearInterval(interval))
    //.then(console.log('test sonucu: ' + returnResult('state_term', 'IN_CALL')))
    .then(returnResult('state_term', 'IN_CALL'))
    .then((result) => expect(result).to.equal('IN_CALL'))
    .catch(err => {
      console.log(err);//This will allow you better debugging.
    })       
});

});

好的,现在,我们必须记住您的代码是异步的。但是,mocha it 函数,默认情况下是同步的:它们不会等待您的异步代码执行。

为了告诉 mocha 您的测试是异步的,您必须向测试传递一个参数。此参数是一个函数,通常称为done,您必须在测试完成时显式调用该函数。否则,您的测试将在到达代码的异步部分之前完成,通常会给您带来误报。

describe("Call Tests Suite", function () {
describe("Basic Call Test", function () {
it("Call status for both side should be IN CALL", function (done) {
peer3.call('login/add', ['testaccount1'])
    .then(() => peer3.call('todo/makeCall1', ['testaccount2@testdomain.com']))
    .then(() => checkResult('state_term', 'RINGING'))
    .then((interval) => { clearInterval(interval); peer3.call('todo/answerCall2', ['empty']) })
    .then(() => checkResult('state_term', 'IN_CALL'))
    .then((interval) => clearInterval(interval))
    //.then(console.log('test sonucu: ' + returnResult('state_term', 'IN_CALL')))
    .then(returnResult('state_term', 'IN_CALL'))
    .then((result) => expect(result).to.equal('IN_CALL'))
    .then( () => {
        done(); //dont use .then(done) or things may break due to extra 
        parameter
    })
    .catch( err => {
         console.log(err);
         done(err); //passing a parameter to done makes the test fail.
    })       
});

});

不过,我们必须解决您的代码存在的问题。 then 方法需要一个 函数 作为参数。但是,在这一行中: .then(returnResult('state_term', 'IN_CALL'))

您将调用 returnResult('state_term', 'IN_CALL') 传递给它,它返回的不是一个函数,而是一个承诺。您应该改为传递一个函数-然后返回承诺-:

.then(() => returnResult('state_term', 'IN_CALL')) //now the parameter to 
       //then is a function that return a Promise, not a Promise itself.

此外,正如您在评论中被告知的那样,您明确地返回了一个新的 Promise,它在您的 return result 函数中包装了一个 Promise:这根本不需要,该函数可以这样编写:

var returnResult = function (stateParamName, stateParamValue) {
    return peer3.get({ path: { equals: 'todo/#0' } }).then(function (results) {
        console.log(stateParamName + ': ' + results[0].value[stateParamName]);
        return(results[0].value([stateParamName]));
    });
}

但是,您的代码中有很多看起来很奇怪的东西(我完全不确定为什么会有 setinterval 调用),所以我非常有信心测试不会像您期望的那样工作.你应该从熟悉 Promises 和异步 mocha 测试开始,不要尝试测试非常长的异步操作序列。祝你好运!

【讨论】:

  • 感谢 Sergeon 的详细回答,我会尝试的,但在此之前我想提一些东西。我发现即使不使用摩卡咖啡也有问题。当我放入按钮侦听器时,相同的代码按顺序运行,但当我将代码直接放入 js 页面并运行 mocha 时,即使我删除了预期部分,也不会按顺序运行。真的无法理解这一点->为什么同一段代码不在侦听器中时不起作用。即使我删除了与 mocha 相关的所有内容,但仍然以与按钮侦听器中相同的顺序运行相同的代码?真的很困惑。
  • Btw setinterval 调用是等待 bcos 我不知道什么时候会更新值。
  • 实际上,我已经尝试过一次又一次,我用您的代码对其进行了测试。我得到 Uncaught (in promise) ReferenceError: done is not defined
  • 您是否将done 作为参数添加到it 回调函数中?
  • 在函数调用中添加完成参数后(...行,我这次收到此错误。->错误:超过2000ms的超时。对于异步测试和挂钩,请确保“完成() " 被调用;如果返回一个 Promise,请确保它解析。
猜你喜欢
  • 1970-01-01
  • 2016-12-30
  • 2021-11-28
  • 1970-01-01
  • 2022-12-19
  • 1970-01-01
  • 2016-06-19
  • 2015-11-23
  • 2023-03-27
相关资源
最近更新 更多