RSpecで独自matcherを作成してみよう

RSpecを使っていて、minitestならできるmatcherが、RSpecにはないってことがあります。

例えば、統合テストでflashの有無を確認する場合

minitest

asset flash.empty?

RSpec

expect(page).to have_selector '.alert'

こんな感じになるかと思います。

flashの有無という、観点で考えるなら、minitestの方が伝わりやすいと思います。

原因は対応するmatcherがないからだと思いました。

そこで、matcherを作成してみましょう!

手順としては、matcherを定義するファイルを作成し、ファイルを読み込ませる設定にします。

まずは設定でmatcherを作成するファイルを読み込めるようにします。

spec/rails_helper.rb

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

コメントアウトになっていると思うので、コメントアウトをはずします。

次に、該当するフォルダとファイルを作成します。

mkdir spec/support
touch spec/support/macther_helper.rb

spec/support/matcher_helper.rb

RSpec::Matchers.define :have_flash do |type|
  match do |page|
    expect(page).to have_selector("div.alert.alert-#{type}")
  end
end

RSpec::Matchers.defineでmatcherを定義するという意味になります。

今回は、alertの状況により判断するようにしました。

こうすることで、次のようにできます。

RSpec

expect(page).to have_flash 'success'

直感的にわかりやすくなったのではないでしょうか。

意外に簡単にmatcher自体は定義できるので、自分でカスタマイズするのもいいですね。