1. ホーム
  2. javascript

[解決済み] Chaiを非同期Mochaテストで動作させる方法はありますか?

2023-07-08 10:46:11

質問

ブラウザランナーを使ってMochaでいくつかの非同期テストを実行していますが、Chaiのexpectスタイルのアサーションを使おうとしています。

window.expect = chai.expect;
describe('my test', function() {
  it('should do something', function (done) {
    setTimeout(function () {
      expect(true).to.equal(false);
    }, 100);
  }
}

これは通常のアサーション失敗のメッセージは出さず、代わりに

Error: the string "Uncaught AssertionError: expected true to equal false" was thrown, throw an Error :)
    at Runner.fail (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3475:11)
    at Runner.uncaught (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3748:8)
    at uncaught (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3778:10)

というわけで、明らかにエラーをキャッチしているのですが、ただ正しく表示されていません。これを行う方法について何かアイデアはありますか?私はエラーオブジェクトで "done" を呼び出すことができると思いますが、そうすると Chai のようなエレガントさが失われ、非常に不格好になります...。

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

非同期テストで例外が発生し、失敗すると expect() で捕捉できない例外が発生します。 it() の外で例外が発生するため it() のスコープ外で投げられたからです。

表示されているキャプチャされた例外は process.on('uncaughtException') を使うか window.onerror() を使ってください。

この問題を解決するためには、以下のようにして呼び出された非同期関数内で例外を捕捉する必要があります。 setTimeout() を呼び出すために done() を呼び出すために、最初のパラメータとして例外を指定します。また done() を呼び出す必要があります。そうしないと、テスト関数が完了したことを通知しないので、mochaはタイムアウトエラーを報告します。

window.expect = chai.expect;

describe( 'my test', function() {
  it( 'should do something', function ( done ) {
    // done() is provided by it() to indicate asynchronous completion
    // call done() with no parameter to indicate that it() is done() and successful
    // or with an error to indicate that it() failed
    setTimeout( function () {
      // Called from the event loop, not it()
      // So only the event loop could capture uncaught exceptions from here
      try {
        expect( true ).to.equal( false );
        done(); // success: call done with no parameter to indicate that it() is done()
      } catch( e ) {
        done( e ); // failure: call done with an error Object to indicate that it() failed
      }
    }, 100 );
    // returns immediately after setting timeout
    // so it() can no longer catch exception happening asynchronously
  }
}

すべてのテストケースでこれを行うのは面倒ですし、DRYではないので、これを行うための関数を提供したいと思うかもしれません。この関数を check() :

function check( done, f ) {
  try {
    f();
    done();
  } catch( e ) {
    done( e );
  }
}

とは check() を使えば、非同期テストを以下のように書き換えることができます。

window.expect = chai.expect;

describe( 'my test', function() {
  it( 'should do something', function( done ) {
    setTimeout( function () {
      check( done, function() {
        expect( true ).to.equal( false );
      } );
    }, 100 );
  }
}