mocha/chai を使用してテストするときに UnhandledPromiseRejectionWarning が発生する 質問する

mocha/chai を使用してテストするときに UnhandledPromiseRejectionWarning が発生する 質問する

そこで、イベント エミッターに依存するコンポーネントをテストしています。そのために、Mocha+Chai で Promises を使用するソリューションを思いつきました。

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」というメッセージが即座に表示されるため、「UnhandledPromiseRejectionWarning」が表示されます。

(ノード:25754) UnhandledPromiseRejectionWarning: 処理されていないプロミス拒否 (拒否 ID: 2): AssertionError: プロミス エラー: { Object (message, showDiff, ...) } が偽であることが予想されます

  1. 正しいイベントで遷移するべきである

そして2秒後に

エラー: 2000 ミリ秒のタイムアウトを超えました。このテストで done() コールバックが呼び出されていることを確認してください。

キャッチコールバックが実行されたので、これはさらに奇妙です(何らかの理由でアサートの失敗により残りの実行が妨げられたと思います)

面白いことに、コメントアウトすると、assert.isNotOk(error...)コンソールに警告が表示されずにテストが正常に実行されます。catch を実行するという意味では、まだ「失敗」しています。
しかし、Promise のこれらのエラーは理解できません。誰か教えてくれませんか?

ベストアンサー1

この問題の原因は次のとおりです:

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

アサーションが失敗すると、エラーがスローされます。このエラーによりdone()、その前にコードがエラーになったため、呼び出されなくなります。これがタイムアウトの原因です。

「未処理の約束の拒否」失敗したアサーションによっても発生します。ハンドラでエラーがスローされるとcatch()catch()後続のハンドラがない、エラーは吸収されます(この記事)。このUnhandledPromiseRejectionWarning警告はこの事実を警告しています。

一般的に、Mocha で Promise ベースのコードをテストする場合は、Mocha 自体がすでに Promise を処理できるという事実に頼る必要があります。 を使用するのではなくdone()、代わりにテストから Promise を返す必要があります。そうすれば、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');
  });
});

おすすめ記事