OmniAuthでログインを失敗したときのテストでエラーが出たときの対処法

OmniAuthを利用したログインのsystem specで、ログインに失敗した場合のテストが次のようなエラーになった。

  1) ユーザがログインする ログインに失敗したとき "ログインに失敗しました"と表示されること
     Failure/Error: click_link 'Twitterでログイン'
     
     OmniAuth::Error:
       invalid_credentials
     # ./spec/system/login_spec.rb:98:in `block (3 levels) in <top (required)>'

もとになったspecはこちら。

  context 'ログインに失敗したとき' do
    around do |example|
      original_mock_auth = OmniAuth.config.mock_auth[:twitter]
      OmniAuth.config.mock_auth[:twitter] = :invalid_credentials
      visit root_path
      click_link 'Twitterでログイン'
      example.run
      OmniAuth.config.mock_auth[:twitter] = original_mock_auth
    end

    it '"ログインに失敗しました"と表示されること' do
      expect(page).to have_content 'ログインに失敗しました'
    end
  end

これまでは普通にテストが通っていたのでなんだろうと思って調べた。

原因

つまりテストの実行順序の問題で、pumaの起動がOmniAuthのテストより前に来てしまうとRACK_ENVがdevelopmentになり期待していた挙動と異なる振る舞いをするようになってしまっていた。

とりあえず明示的に、次の行をconfig/rails_helper.rbに追加したところうまく動くようになった。

ENV['RACK_ENV'] ||= 'test'

所感

これ、自分と同じようにハマる人が出てくると思うのでライブラリ側でどうにかしたいのだけど、どのライブラリにどのようにPR投げるか悩ましいですね…

  • rspec-rails
  • puma
  • capybara
  • omniauth

のどれか。rspec-railsでrails_helper.rbのテンプレートをいじってRACK_ENVもRAILS_ENVと同様に設定するようにする、というのがいいだろうか。

おまけ

どこでRACK_ENVが設定されているか調べるのに使った雑なスクリプトを置いておきます

module DebugEnv
  def []=(*args)
    key = args.first
    if key == 'RAILS_ENV' || key == 'RACK_ENV'
      p args
      p caller
    end
    super
  end
end

ENV.singleton_class.prepend DebugEnv

あと、この手の環境変数関連のデバッグではspringは切っておいたほうが良さそう(ちゃんと調べきれてないけど、設定されていないはずのタイミングでRACK_ENVが設定されていて、これでかなり時間を奪われた><)

また、rake specrakeでテストを実行しているときにはこの問題は発生しなさそう。

rspec-rails/rspec.rake at master · rspec/rspec-rails