おもしろ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にする

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

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

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

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

前提として、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:僕はきっちりハマりました><