おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

ActionCableでフィーチャスペックを書く

最近自分の作っているサービスにActionCableを導入しました。そこでフィーチャスペックを書いていくつかハマったので内容を共有します。

使っているのはcapybara & poltergeistです。

Capybara.serverをpumaにする

Capybaraのデフォルトのサーバは、ざっと見た感じRailsアプリを別スレッドで動かしているだけのようです。これではActionCableを動かすことはできません。ActionCableを利用するにはpumaを使う必要があります。

次のようにすれば Capybara はpumaをサーバとして使ってくれます。

Capybara.server = :puma

これでオーケー…と言いたいところですが、まだ落とし穴が2つほどあります*1

puma のデフォルトワーカ数(プロセス数)を1にする

(追記)最近のcapybara(2.15.1以上?)を使っている場合、config/puma.rbの設定に関わらずワーカ数は1に設定されるようになったみたいです。

pumaはconfig/puma.rb があると、テスト時でもそれを設定に利用します。developmentやtestの環境ではActionCableのアダプタはasyncが設定されているため、pumaのプロセス数が2以上だとうまく動かないケースがあります。

次のように環境変数が設定されていない場合は1になるようにしておきましょう。

workers ENV.fetch("WEB_CONCURRENCY") { 1 }

ActiveJobのテストと環境を分ける

(追記)コード見た感じ、同一プロセス内の別スレッドでサーバ起動しているように見える&&実際にpumaで問題なく動くようだったのでこの節は読み飛ばしてください><

capybara/server.rb at master · teamcapybara/capybara · GitHub

前提として、ActiveJobのテスト用のアダプタはデフォルトの:testです。

Capybaraデフォルトのサーバを利用する場合は同一プロセス内でサーバが動くので、サーバ内でキューにジョブを詰めたとき、テストコード内でassert_enqueued_jobsなどのメソッドで実際にキューにジョブが入ったかを確認することができます。しかし、サーバをpumaにした場合は別プロセスになり、サーバ内でキューにジョブを詰めても、テストコード内では確認することができません。

ではActionCableを利用した場合だけサーバをpumaに変えればいいのでは?と思い次のようにしたのですが、フィーチャスペックが不安定になったのでやめました。どうやらserverはdriverのように頻繁に変更するようにはできていないようです(深掘りはしていません)。

config.around(:example, websocket: true) do |example|
  default_server = Capybara.server
  Capybara.server = :puma
  example.run
  Capybara.server = default_server
end

とりあえず次のように、通常のテストはActionCable以外をテストし、ActionCableを使ったテストだけを実行したい場合は環境変数をつけるようにしました。

if ENV['WEBSOCKET'].present?
  config.filter_run_including :websocket
else
  config.filter_run_excluding :websocket
end

これでテストが通るようになりました🍏

*1:僕はきっちりハマりました><