1. ホーム
  2. javascript

[解決済み] mocha/chaiを使用したテスト時にUnhandledPromiseRejectionWarningが発生する

2022-01-29 07:23:08

質問

イベントエミッターに依存するコンポーネントをテストしています。そのために、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();
  });
});

コンソールでは、拒否関数が呼ばれているにもかかわらず、「UnhandledPromiseRejectionWarning」が表示されます。これは、「AssertionError.Promise」というメッセージが即座に表示されるためです。Promise error' と表示されます。

(node:25754) UnhandledPromiseRejectionWarning: 未処理の約束 拒否されました (拒否 ID: 2)。AssertionError: プロミスエラー: 期待される {オブジェクト (メッセージ、showDiff、...) } が偽者であること。

  1. は正しいイベントで遷移する必要があります。

そして、2秒後に

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

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

さて、おかしなことに、もし私が assert.isNotOk(error...) を実行すると、コンソールに警告が表示されることなく、テストは正常に実行されます。しかし、catchを実行するという意味では、まだ「失敗」しています。
それにしても、このpromiseでのエラーは理解できません。どなたか教えていただけませんか?

どのように解決するのですか?

この問題が発生する原因はこれです。

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

アサーションに失敗した場合は、エラーをスローします。このエラーは done() なぜなら、その前にコードがエラーになったからです。これがタイムアウトの原因です。

その "Unhandled promise rejection" はアサーションに失敗したことも原因です。 catch() ハンドラを使用します。 がなく、その後に続く catch() ハンドラ で説明されているように)、エラーは飲み込まれます。 この記事 ). その UnhandledPromiseRejectionWarning の警告は、この事実を警告しているのです。

一般的に、Mocha でプロミスベースのコードをテストしたい場合、Mocha 自体がすでにプロミスを扱えるという事実に頼るべきです。を使うべきではありません。 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');
  });
});