![](/img/trans.png)
[英]UnhandledPromiseRejectionWarning during testing with mocha-chai using chai-http
[英]Getting a UnhandledPromiseRejectionWarning when testing using mocha/chai
所以,我正在测试一个依赖于事件发射器的组件。 为此,我想出了一个使用 Promises 和 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();
});
});
在控制台上,即使调用了拒绝函数,我也会收到“UnhandledPromiseRejectionWarning”,因为它立即显示消息“AssertionError: Promise error”
(节点:25754)UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝ID:2):AssertionError:承诺错误:预期{Object(message,showDiff,...)}为假
- 应该转换为正确的事件
然后,2秒后我得到
错误:超过 2000 毫秒的超时。 确保在此测试中调用 done() 回调。
这更奇怪,因为执行了 catch 回调(我认为由于某种原因,断言失败阻止了其余的执行)
现在有趣的是,如果我注释掉assert.isNotOk(error...)
测试运行良好,控制台中没有任何警告。 从它执行捕获的意义上说,它仍然“失败”。
但是,我仍然无法通过承诺来理解这些错误。 有人可以启发我吗?
问题是由以下原因引起的:
.catch((error) => {
assert.isNotOk(error,'Promise error');
done();
});
如果断言失败,它将抛出错误。 这个错误会导致done()
永远不会被调用,因为代码在它之前出错了。 这就是超时的原因。
“未处理的承诺拒绝”也是由失败的断言引起的,因为如果在catch()
处理程序中抛出错误,并且没有后续的catch()
处理程序,错误将被吞噬(如本文所述) )。 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');
});
});
我在用 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'));
还有一个 resolves 方法(注意末尾的 s)。
见http://clarkdave.net/2016/09/node-v6-6-and-asynchronously-handled-promise-rejections
如果断言不正确,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);
});
我将这篇文章归功于在 Mocha 中测试 promise 时使用 .then(done,done) 的想法。
对于那些在测试环境之外寻找错误/警告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 */ });
我遇到了这个问题:
(node:1131004) UnhandledPromiseRejectionWarning: 未处理的承诺拒绝 (rejection id: 1): TypeError: res.json is not a function (node:1131004) DeprecationWarning: 未处理的承诺拒绝被弃用。 将来,未处理的承诺拒绝将以非零退出代码终止 Node.js 进程。
这是我的错误,我在then(function(res)
替换了res
对象,因此将res
更改为 result ,现在它可以工作了。
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");
});
服务代码:
function update(data){
var id = new require('mongodb').ObjectID(data._id);
userData = {
name:data.name,
email:data.email,
phone: data.phone
};
return collection.findAndModify(
{_id:id}, // query
[['_id','asc']], // sort order
{$set: userData}, // replacement
{ "new": true }
).then(function(doc) {
if(!doc)
throw new Error('Record not updated.');
return doc.value;
});
}
module.exports = {
update:update
}
如果你有一个async helperFunction()
从你的测试中调用......(一个带有 ES7 async
关键字的明确,我的意思是)
→ 请确保,您将其称为await helperFunction(whateverParams)
(嗯,是的,自然,一旦您知道...)
为了使其工作(为了避免“等待是保留字”),您的测试函数必须有一个外部异步标记:
it('my test', async () => { ...
卸载webpack后我解决了这个问题(反应js问题)。
sudo uninstall webpack
我对 Selenium 的 Chai-Webdriver 也有类似的经验。 我在断言中添加了await
并解决了这个问题:
使用 Cucumberjs 的示例:
Then(/I see heading with the text of Tasks/, async function() {
await chai.expect('h1').dom.to.contain.text('Tasks');
});
请注意,如果您不小心将测试代码放在 it 函数之外,您可能会收到UnhandledPromiseRejectionWarning
。 😬
describe('My Test', () => {
context('My Context', () => {
it('should test something', () => {})
const result = testSomething()
assert.isOk(result)
})
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.