Я пытаюсь проверить режим сбоя какого-либо почтового кода, который на самом низком уровне может выдать ошибку. Все слои между тестом и функцией, которые выдают, являются асинхронными и используют await для функций под ними. На верхнем уровне (также в асинхронной функции у меня есть блок try catch. Однако узел генерирует исключение необработанного обещания до того, как ошибка достигнет этого уровня.
Мой тестовый код выглядит так
beforeEach(function() {
//set default values - tests can change them
this.reasons = '';
this.reschedules = 0;
this.params.cid = 35124;
this.startTest = async () => {
/* this.confirmation is an async function under test,
this.mailer is a mock mailer with an async "send" method
which will throw an error in the correct test */
const doner = this.confirmation(this.mailer);
// ..other actions related to mocking database access made by confirmation
await doner;
return this.mailer.maildata; //provide info on parameters passed to this.mailer
};
});
it('Failure to send is reported', async function() {
this.mailer.sendResolve = false; //tell mock mailer to fail send request
try {
await this.startTest();
expect(true).to.be.false;
} catch(err) {
expect(err).to.be.instanceOf(Error);
}
});
макет немного похож на этот
class Mailer {
constructor(user,params){
...
}
...
async send(subject, to, cc, bcc) {
this.maildata.subject = subject;
if (to !== undefined) this.maildata.to = to;
if (cc !== undefined) this.maildata.cc = cc;
if (bcc !== undefined) this.maildata.bcc = bcc;
if (!this.sendResolve) throw new Error('Test Error');
}
...
}
и краткое содержание тестируемого кода
module.exports = async function(mailer) {
//get confirm data from database
const cData = await confirm(mailer.params.cid, mailer.db);
if (cData.count > 0) {
// ... format the email message and build it into maildata
await mailer.send(
subject,
emailAddress,
null,
process.env.PAS_MAIL_FROM,
{
pid:cData.pid,
type: 'confirmation',
extra: `Calendar ID ${mailer.params.cid} with procedure ${cData.procedure}`
}
);
debug('message sent, update the database');
await mailer.db.exec(async connection => {
...
});
debug('success');
} else {
debug('invalid calendarid');
throw new Error('Invalid Calendar ID');
}
};
Как видно, путь вызова из функции async send
, которая отбрасывает стек обратно в try {}catch(){}
, - все это асинхронные функции. Но когда я запускаю этот тестовый узел, выводится необработанное отклонение обещания.
Я попытался использовать отладчик кода Visual Studio для одного шага через это, я немного заблудился в механизме, который оборачивает асинхронные функции, превращая их в провайдеров обещаний. Насколько я вижу, один уровень ошибок обрабатывается правильно, а затем терпит неудачу на следующем уровне вверх.
Значит ли это, что каждая асинхронная функция должна иметь блок try catch, чтобы перехватывать и перебрасывать любую ошибку? Я не могу найти никакого объяснения, которое говорит, что я должен это сделать.