単位試験の自動化。コーディングより時間かかる説
jest + supertestで単体試験を実行時にtestが完了してもjestのプロセスが終了しなかったのでその覚書。
(…まじで単体試験の自動化コードを書いてるときのほうが実製造作業より時間かかるのだけど。こんなもんなのだろうか。
Jestが終わんない
実際の状況は以下のエラーが表示されてjestのプロセスが終了しなくなった。エラー自体はjestの引数に--detectOpenHandles
を渡せばでなくなるような気もするけど、まぁ問題はそこじゃなくて。。。
jest did not exit one second after the test run has completed
日本語訳
テスト実行が完了した後、jestは1秒終了しませんでした
done(同期・非同期絡み)の記載と混同してしまって調べるのにえらく時間がかかったけど、結局supertestでrequest時に起動したWEBアプリケーションの処理が残ってるからjestが終了しないだろうという結論に至った。
余談
話は少しそれるけど、doneによる制御はjest v27からデフォルトのtestrunnerがjest-circus
に変更された煽りを受けて、最新版では「普通には」使えなくなっている。
参考:Use async-await with done does not work since v27. #11404
いままで通りdoneを使って、完了を待ちたい場合は、この記述を入れてtestRunnerをjest-jasmine2
に戻す必要があるけど、今後jest-jasmine2
のサポートをやめるとも書いてあったので、応急的で暫定的な処置として考えていたほうがよさそう。
module.exports = {
testRunner: 'jest-jasmine2'
};
ちなみに、testrunnerがjest-circus
でもstackoverflowの有識者のコードをかませば実行可能だった。itをラップしてる感じかな。
ちなみに元コードはTypescriptだったのでjavascriptに戻して、done.failがサポート外になったと記載があったのでdoneに変更してる。(この指摘をしている人はメソッド名もitにして既存コードと互換をとったみたい。)
function itAsyncDone(name, cb, timeout,) {
it(
name,
(done) => {
let doneCalled = false;
const wrappedDone = (...args) => {
if (doneCalled) {
return;
}
doneCalled = true;
done(...args);
};
wrappedDone.fail = (err) => {
if (doneCalled) {
return;
}
doneCalled = true;
done(err);
};
cb(wrappedDone).catch(wrappedDone);
},
timeout,
);
}
まぁ作ってみたももの結局使わなかったけど。。。
参考:[jest-circus] Support both done callback and async test simultaneously #10529
参考:Done.fail function is not working #11780
話を戻して
結局、じゃぁ何が原因なのかということで、調べてると大体出てくるのがDBコネクションの話。
参考:Jest did not exit one second after the test run has completed. #7287
うーん。それ関係あるのかなぁと思いながら、DBアクセスはsequelizeで統一していたので、sequelize.close()を
jestのafterAllで指定したらちゃんとプロセス終了するようになった。
??? 謎すぎる。
ってかsequelize.close()って自動で呼び出されるから明示的に呼び出す必要ないよって公式に書いてた気がするけど・・・。
あと、同一のit内で複数のrequest(app)を実行するのはできるけどitを分けてrequest(app)を実行すると相変わらずエラーが出るので、そもそものsupertestの使い方が間違ってるような気がしてならない。
あと、WEBアプリケーション(app)でミスってたらjestのプロセスが起動しっぱなしになったりするので、なんだかなー。な気もする。(そもそもそんなコード書くなというのは置いといて)
でも、まぁ、とりあえず、今はいいか・・・。と思った今日このごろ。
コメント