How to keep rspec tests DRY with lots of "have_link"

railstutorial.org, rspec, ruby-on-rails, ruby-on-rails-3, tdd

Solution

To define custom matchers you can read this feature and some inspiration.

And write something like that:

RSpec::Matchers.define :have_links do |expected|
  match do |actual|
    expected.all? do |name, options|
      have_link(name, options).matches?(actual)
    end
  end
end

But IMO, your first try is the best way to write it: clean and easy to read.

Problem

I'm new to Ruby on Rails and I'm doing http://ruby.railstutorial.org right now. From what I understand the language is supposed to follow this DRY standard wery strictly but it's so WET when it comes to test driven development in this tutorial. For example ``` it { should have_link('Users', href: users_path) } it { should have_link('Profile', href: user_path(user)) } it { should have_link('Settings', href: edit_user_path(user)) } it { should have_link('Sign out', href: signout_path) } ``` Here we have lots of rows that almost looks the same. I'we tried this ``` it "should have following links from this array" do [ ['Users', href: users_path], ['Profile', href: user_path(user)], ['Settings', href: edit_user_path(user)], ['Sign out', href: signout_path] ].each { |a| page.should have_link(a[0], a[1]) } end ``` This code works but it's looks ugly and it's more rows. So I want to know if it's an better way to add an array to have_link method. I now have a great idea but I don't know how to make it work. This is my helper (it does not look like it did when i created this question. It is edited after an answer from Michaël Witrant) ``` RSpec::Matchers.define :have_these_links do |*links| match do |actual| links.each do |link| have_link(link.first, link.extract_options!).matches?(actual) end end end ``` and this should now be my test ``` it { should have_these_links(['Users', href: users_path], ['Profile', href: user_path(user)], ['Settings', href: edit_user_path(user)], ['Sign out', href: signout_path]) } ``` So this works but it's not user friendly. When I run the test and I have an link does not exist on the page it tells me that I do not have these links. But I will be able to make the helper tell me which link I'm missing. This is my error code ``` expected #<Capybara::Session> to have these links ["Users", {:href=>"/users"}], ["Test Link", {:href=>"/Does_not_exist"}], and ["Profile", {:href=>"/users/991"}] # ./spec/requests/authentication_pages_spec.rb:42:in `block (4 levels) in <top (required)>' ```

Original source