Подтвердить что ты не робот

NodeJS UnhandledPromiseRejectionWarning

Итак, я тестирую компонент, который опирается на источник событий. Для этого я предложил решение, использующее 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: Ошибка обещания"

(узел: 25754) UnhandledPromiseRejectionWarning: необработанное обещание отклонение (id отклонения: 2): AssertionError: ошибка обещания: ожидается {Object (message, showDiff,...)} быть ложным 1) должен перейти с правильным событием

И затем, через 2 секунды, я получаю

Ошибка: превышено время ожидания 2000 мс. Убедитесь, что обратный вызов done() вызывается в этом тесте.

Что еще более странно, поскольку был выполнен обратный вызов catch (я думаю, что по какой-то причине ошибка assert помешала завершению выполнения)

Самое смешное, если я закомментирую assert.isNotOk(error...), тест будет работать без всякого предупреждения в консоли. Он по-прежнему "терпит неудачу" в том смысле, что выполняет задание.
Но все же я не могу понять эти ошибки с обещанием. Может ли кто-нибудь просветить меня?

4b9b3361

Ответ 1

Проблема вызвана следующим:

.catch((error) => {
  assert.isNotOk(error,'Promise error');
  done();
});

Если утверждение не выполняется, оно выдает ошибку. Эта ошибка приведет к тому, что done() никогда не будет вызван, потому что код был ошибочен перед этим. Это то, что вызывает таймаут.

"Отказ от необработанного обещания" также вызван неудавшимся утверждением, потому что если в обработчике catch() возникает ошибка, и нет последующего обработчика catch(), ошибка будет проглатываться (как объясняется в этой статье). Предупреждение UnhandledPromiseRejectionWarning предупреждает вас об этом факте.

В общем, если вы хотите проверить код на основе обещаний в Mocha, вы должны полагаться на то, что сам Mocha может обрабатывать promises уже. Вы не должны использовать 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');
  });
});

Ответ 2

Я получил эту ошибку при заглушении с помощью sinon.

Исправление заключается в использовании пакета npm sinon-as-обещано при разрешении или отклонении обещаний с заглушками.

Вместо...

sinon.stub(Database, 'connect').returns(Promise.reject( Error('oops') ))

Используйте...

require('sinon-as-promised');
sinon.stub(Database, 'connect').rejects(Error('oops'));

Существует также метод resolves (обратите внимание на конец).

См. Http://clarkdave.net/2016/09/node-v6-6-and-asynchronously-handled-promise-rejected

Ответ 3

Библиотеки утверждений в Mocha работают, выдавая ошибку, если утверждение было неверным. Возникновение ошибки приводит к отклонению обещания, даже если оно было выдано в функции executor, предоставленной методу catch.

.catch((error) => {
  assert.isNotOk(error,'Promise error');
  done();
});

В приведенном выше коде возражаемая error оценивается как true поэтому библиотека утверждений выдает ошибку... которая никогда не перехватывается. В результате ошибки метод done никогда не вызывается. Обратный вызов Mocha done принимает эти ошибки, поэтому вы можете просто завершить все цепочки обещаний в Mocha с помощью .then(done,done). Это гарантирует, что метод 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);
});

Я воздаю должное этой статье за идею использования .then (сделано, сделано) при тестировании обещаний в Mocha.

Ответ 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 */ });

Ответ 5

Здесь мой опыт работы с E7 async/await:

Если у вас есть async helperFunction(), вызванный из вашего теста... (один из объяснений с ключевым словом ES7 async, я имею в виду)

→ убедитесь, что вы называете это await helperFunction(whateverParams) (ну да, естественно, как только вы знаете...)

И для этого для работы (чтобы избежать "ожидания - это зарезервированное слово), ваша тестовая функция должна иметь внешний асинхронный маркер:

it('my test', async () => { ...

Ответ 6

Я решил эту проблему после удаления веб-пакета (реагирует на проблему с js).

sudo uninstall webpack

Ответ 7

Я столкнулся с этой проблемой:

(node: 1131004) UnhandledPromiseRejectionWarning: отказ от необработанного обещания (re jection id: 1): TypeError: res.json не является функцией (node: 1131004) Отказ. Предупреждение. Отклонения от необработанного обещания устарели. В будущем обещание отклонения, которое не обрабатывается, приведет к завершению Node.j s с ненулевым кодом выхода.

Это была моя ошибка, я заменил res объект в then(function(res), поэтому изменил res на результат, и теперь он работает.

Wrong

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
}