Jasmine は async/await と done() による callback の混合をサポートしない
Jasmine (version 3.8 で確認)では、以下のコードような、async(async/await の async)と done() による callback を混合した書き方はサポートしなくなったようです。
it("test", async (done) => { await somethingPromise(1000); done(); });
実際にこのテストを実行すると、成功扱いになりますが、以下のように警告が出力されます。
DEPRECATION: An asynchronous before/it/after function was defined with the async keyword but also took a done callback. This is not supported and will stop working in the future. Either remove the done callback (recommended) or remove the async keyword. (in spec: test test)
GitHub にて、該当のコミット者によるコメントがありました。
Jasmine doesn't support mixing callback-style and async/await in a single function.
Expectation when using both done and async functions? · Issue #1731 · jasmine/jasmine · GitHub
※サンプルのコードでは、async と done() を混合しなければいけない理由が不明かと思いますが、良いサンプルが思いつけませんでした。
なぜか
上記の GitHub のコメントを参考に、なぜこうなったのかは以下のように理解しました。
Jasmine は、2.7 から async/await をサポートしています。
async/await is supported by Jasmine 2.7 and later.
それまでは done() によって非同期のテストが書かれており、必然的に done() が実行されたかどうかでテストの完了を判断していたと思われます。
しかし、async/await をサポートすることによって、it("test", async (done) => {}
のようなテストコードの場合、Promise の完了をもってテスト完了と判断するのか、done() の実行をもってテスト完了と判断するのか、コードの読み手は混乱することになると思います。仮に挙動を定めたとしても Jasmine はそれを信頼すべき挙動とは断言したくなかったのでしょうか? そのために、混合をサポートせず冒頭のような警告が出力されるようになったのかと思います。
どうすればよいか
混合を避けて、done() だけで書くか、async/await だけで書くか、どちらかにコードを変更します。このコードは、こちら Continued support for async tests with done callbacks · Issue #1893 · jasmine/jasmine · GitHub を参考にしました。
done() だけを使う場合:
it("test2", (done) => { (async () => { await somethingPromise(1000); await somethingPromise(1000); done(); })(); });
async/await だけを使う場合:
it("test3", async () => { await somethingPromise(1000); await somethingPromise(1000); await expectAsync(somethingPromise(1000)).toBeResolved(); await expectAsync(somethingErrorPromise(1000)).toBeRejected(); });
このとき、toBeRejectedWith()
toBeRejectedWithError()
などのメソッドも役に立ちそうです。
今回のコード: Jasmine tests · GitHub