How to save rspec DRY tests with a lot of "has_link",

I'm new to Ruby on Rails, and now I'm doing http://ruby.railstutorial.org .

From what I understand, the language should follow the strict DRY standard, but that's WET when it comes to test-based development in this tutorial.

for instance

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 many lines that almost look the same.

I 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 looks ugly and it has more lines.

So, I want to know if this is the best way to add an array to the has_link method.


I have a great idea now, but I don’t know how to make it work.

This is my assistant (this is not like when I created this question. It was edited after a response 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 now it will 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]) }

, , . , , , . , .

   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)>'
+5
2

, .

- :

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

, - : .

+4

, , DRY.

DRY . . , .

it { should have_link('Users', href: users_path) }

, , [text, url] , - .

.

+7

All Articles