これは、以下の記事を参考にしていたときの副産物ですが、ちょいちょいハマったところがあるので記事にしておきます。
ローカルでついうっかりsystem specを行うと、初回アクセス時にwebpacker:compileが実行され、最初のテストがほぼ、タイムアウトに引っかかって失敗するという現象に悩んでいました。 それが上記の記事の途中で出てくる、system specを検出したらテスト実行前にwebpacker:compileが行われるコードを導入しました。
このprecompile_assets.rbを丸っとコピーして取り込んだところ、初回テストも失敗しないようなりました。快適!!😀 早速PRを作ってpushしたところ、CIでrake taskのテストが落ちました😩どうして…どうして…🐱
現象
標準出力に出てくる文字列の検証を行なっている箇所で二重に出力が行われていました。
テストが落ちる原因
原因は、先ほどのprecompile_assets.rbで行っているRails.application.load_tasks
であることは突き止めましたが、これを行わないとRake::Task["webpacker:compile"].execute
ができないので、これはなんとしてもやりたい…。ちなみにRails.application.load_tasks
を何度も呼んでみたところ、標準出力に出てくる文字列が読み込んだ回数だけ増えたので、どうもテストしているrake taskをどこかで重複して読み込んでいるな、というところまでは想像できました。
rake_shared_contextが怪しそう
rake_shared_contextという、rake taskのテストを簡単に書けるようになるgemがあります。
これを読むと、before(:suite)でプロジェクトのrake taskのファイルを読み込んでいるので、当たってた模様。まぁこれはrake_shared_contextが悪いわけではなくて、私がRails.application.load_tasks
を読んでいるのが原因です。ならば、どうすればいいのか?
解決策
Rails.application.load_tasks
を行う前に、Rake.Task.clear
を呼びます。こうすることで、rake_shared_contextによって登録されたプロジェクトのタスクを一旦破棄します。その後のRails.application.load_tasks
で再びrake taskとして登録されるので問題ありません👍
Rake::Task.clear Rails.application.load_tasks Rake::Task["webpacker:compile"].execute
まだCIで落ちる
今度は、CIで不可解な現象が起きました。テストは全部通っているのに、終了コードが1になって落ちていました😢しかも、parallel_testsを使っているはずなのに、並列で行われていない…。
以下はCircleCIのログ。
🐢 Precompiling assets. Finished in 0.27 seconds .......... 🐢 Precompiling assets. Finished in 0.25 seconds .......... 🐢 Precompiling assets. Finished in 0.25 seconds ........... 🐢 Precompiling assets. Finished in 0.26 seconds ...... // 省略。何度も呼ばれる🐢… 🐢 Precompiling assets. Finished in 0.26 seconds ................... Finished in 18 minutes 31 seconds 842 examples, 0 failures, 2 pending --------------------After Queue Hook - run after test suite-------------------- Coverage report generated for rspec_ci_node_1 to /home/circleci/project/tmp/coverage. 6624 / 13479 LOC (49.14%) covered. Exited with code exit status 1 CircleCI received exit code 1
なんで何度もbefore(:suite)が呼ばれてるのかも不可解だし、2並列で動いてないのもおかしい。
原因
原因は、CIで2並列でprecompile_assets.rbの処理が行われて、webpacker:compile
が同時に2並列で動いて、片方がなんらかの原因で落ちていたせいでした。
何度も呼ばれる🐢は、knapsack_proを使っている影響でテストケースを取得しにいってテストを実行するたびにbefore(:suite)が実行されているからでした。そうだったのか…。
対策
CIでは、元々事前にassets:precompile
を実行させていたので、そもそも並列でこの処理実行させたくなかったので、CIの時はprecompile_assets.rbの処理をスキップさせるようにしました。
RSpec.configure do |config| config.before(:suite) do unless ENV['CI'] # 元々のprecompile_assets.rbの処理をこの中に移動させる end end end
これで、ローカルでsystem specを実行する場合は事前にwebpacker:compileを実行してくれるようになり、CIでは何もしないようになりました。