所以,我正在测试一个依赖于事件发射器的组件。为此,我想出了一个使用Promise with Mocha + Chai的解决方案:
it('should transition with the correct event', (done) => {
const cFSM = new CharacterFSM({}, emitter, transitions);
let timeout = null;
let resolved = false;
new Promise((resolve, reject) => {
emitter.once('action', resolve);
emitter.emit('done', {});
timeout = setTimeout(() => {
if (!resolved) {
reject('Timedout!');
}
clearTimeout(timeout);
}, 100);
}).then(((state) => {
resolved = true;
assert(state.action === 'DONE', 'should change state');
done();
}))
.catch((error) => {
assert.isNotOk(error,'Promise error');
done();
});
});
});
在控制台上,我得到了一个未处理的提示撤消警告'即使拒绝函数被调用,因为它立即显示消息' AssertionError:Promise error'
(node:25754)UnhandledPromiseRejectionWarning:未处理的承诺 rejection(拒绝id:2):AssertionError:Promise错误:预期 {Object(message,showDiff,...)}是假的 1)应该使用正确的事件进行转换
然后,在2秒后我得到了
错误:超过2000毫秒的超时。确保done()回调是 在这次考试中被召唤。
自执行catch回调以来,这甚至更奇怪。(我认为由于某种原因,断言失败阻止了其余的执行)
现在有趣的是,如果我注释掉assert.isNotOk(error...)
,测试运行正常,控制台中没有任何警告。它仍然失败'从它执行捕获的意义上来说
但是,我仍然无法理解这些错误。有人可以开导我吗?
答案 0 :(得分:130)
问题是由此造成的:
.catch((error) => {
assert.isNotOk(error,'Promise error');
done();
});
如果断言失败,则会抛出错误。此错误将导致done()
永远不会被调用,因为代码在它之前出错了。这是导致超时的原因。
"未处理的承诺拒绝" 也是由失败的断言引起的,因为如果catch()
处理程序中出现错误,并且没有& #39;随后的catch()
处理程序,错误将被吞噬(如this article中所述)。 UnhandledPromiseRejectionWarning
警告提醒您注意这一事实。
一般来说,如果你想在Mocha中测试基于promise的代码,你应该依赖Mocha本身可以处理promise的事实。你不应该使用done()
,而是从你的测试中返回一个承诺。然后Mocha将自己捕获任何错误。
像这样:
it('should transition with the correct event', () => {
...
return new Promise((resolve, reject) => {
...
}).then((state) => {
assert(state.action === 'DONE', 'should change state');
})
.catch((error) => {
assert.isNotOk(error,'Promise error');
});
});
答案 1 :(得分:9)
当与sinon衔接时我得到了这个错误。
修复是在使用存根解析或拒绝承诺时使用npm包 sinon-as-promised 。
而不是......
sinon.stub(Database, 'connect').returns(Promise.reject( Error('oops') ))
使用......
require('sinon-as-promised');
sinon.stub(Database, 'connect').rejects(Error('oops'));
还有一种解决方法(注意结尾处的s)。
请参阅http://clarkdave.net/2016/09/node-v6-6-and-asynchronously-handled-promise-rejections
答案 2 :(得分:8)
如果断言不正确,Mocha中的断言库通过抛出错误来工作。抛出错误会导致拒绝承诺,即使在提供给catch
方法的执行程序函数中抛出也是如此。
.catch((error) => {
assert.isNotOk(error,'Promise error');
done();
});
在上面的代码中,error
反对求值为true
,因此断言库会抛出一个错误......它永远不会被捕获。由于该错误,永远不会调用done
方法。 Mocha的done
回调接受这些错误,因此您可以使用.then(done,done)
简单地结束Mocha中的所有承诺链。这样可以确保始终调用done方法,并且报告错误的方式与Mocha在同步代码中捕获断言错误的方式相同。
it('should transition with the correct event', (done) => {
const cFSM = new CharacterFSM({}, emitter, transitions);
let timeout = null;
let resolved = false;
new Promise((resolve, reject) => {
emitter.once('action', resolve);
emitter.emit('done', {});
timeout = setTimeout(() => {
if (!resolved) {
reject('Timedout!');
}
clearTimeout(timeout);
}, 100);
}).then(((state) => {
resolved = true;
assert(state.action === 'DONE', 'should change state');
})).then(done,done);
});
我赞赏this article在Mocha中测试承诺时使用.then(done,done)的想法。
答案 3 :(得分:4)
对于那些在测试环境之外寻找错误/警告UnhandledPromiseRejectionWarning
的人来说,可能是因为代码中的任何人都没有处理承诺中的最终错误:
例如,此代码将显示此问题中报告的警告:
new Promise((resolve, reject) => {
return reject('Error reason!');
});
(node:XXXX) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Error reason!
并添加.catch()
或处理错误应解决警告/错误
new Promise((resolve, reject) => {
return reject('Error reason!');
}).catch(() => { /* do whatever you want here */ });
或使用then
函数
new Promise((resolve, reject) => {
return reject('Error reason!');
}).then(null, () => { /* do whatever you want here */ });
答案 4 :(得分:1)
如果您的测试中调用了async helperFunction()
...(我的意思是ES7 async
关键字的一个明确的说明)
→确保,你称之为await helperFunction(whateverParams)
(嗯,是的,当然,一旦你知道......)
为了实现这一点(为了避免'await是一个保留字'),你的测试函数必须有一个外部异步标记:
it('my test', async () => { ...
答案 5 :(得分:0)
我遇到了这个问题:
(node:1131004)UnhandledPromiseRejectionWarning:未处理的承诺拒绝(re jection id:1):TypeError:res.json不是函数 (node:1131004)弃用警告:不推荐使用未处理的拒绝承诺。 将来,未处理的承诺拒绝将终止Node.j 使用非零退出代码的进程。
这是我的错误,我正在替换/
中的res
对象,因此将then(function(res)
更改为结果,现在它正在运行。
res
module.exports.update = function(req, res){
return Services.User.update(req.body)
.then(function(res){//issue was here, res overwrite
return res.json(res);
}, function(error){
return res.json({error:error.message});
}).catch(function () {
console.log("Promise Rejected");
});
服务代码:
module.exports.update = function(req, res){
return Services.User.update(req.body)
.then(function(result){//res replaced with result
return res.json(result);
}, function(error){
return res.json({error:error.message});
}).catch(function () {
console.log("Promise Rejected");
});
答案 6 :(得分:0)
我在卸载webpack后解决了这个问题(js问题)。
sudo uninstall webpack
答案 7 :(得分:0)
我在Cele-Webdriver for Selenium上也有类似的经历。
我在断言中添加了await
,并解决了该问题:
使用Cucumberjs的示例:
Then(/I see heading with the text of Tasks/, async function() {
await chai.expect('h1').dom.to.contain.text('Tasks');
});
答案 8 :(得分:0)
请注意,如果您不小心将测试代码放在 it 函数之外,您可能会得到 UnhandledPromiseRejectionWarning
。 ?
describe('My Test', () => {
context('My Context', () => {
it('should test something', () => {})
const result = testSomething()
assert.isOk(result)
})
})