Question

I'm new to ruby/rails and doing a turorial I was wondering how I could solve my little problem...

I have a describe "with valid information" which tests what should or should not happen when the user signs in with valid info. In this procedure, I want to be able to verify that some links exists on the new page. In the tuto, there are only 2 links so we do it like that:

it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Sign out', href: signout_path) }

But what if we have let's say 10 links? I think it would be easier to have a helper no? But I can't figure out how to write it. This is what I came with...

 lol = Hash[ 'Profile'  => 'user_path(user)',
             'Sign out' => 'signin_path']
 it { should have_list_of_links(lol) }

then in a $PROJECT/spec/support/utilities.rb file, I define the new *have_list_of_links* function:

RSpec::Matchers.define :have_list_of_links do |lol|
  match do |page|
    lol.each_pair do |label, link| 
                page.should have_link(label, href: link) 
    end
  end
end

I know it's not the right way to do it but I can't figure out how to do it...

Thanks.

Was it helpful?

Solution

There is two small problems I can see here. First use let syntax to define memoized variables inside rspec. Second drop the parentheses around *_path helpers when you build your hash.

So insted:

lol = Hash[ 'Profile'  => 'user_path(user)',
            'Sign out' => 'signin_path']

have:

let(:lol) { Hash[ 'Profile'  => user_path(user),
                  'Sign out' => signin_path] }

Your description block could be:

describe "with valid information" do
  let(:lol) { Hash[ 'Profile'  => user_path(user),
                    'Sign out' => signin_path] }

  it { should have_list_of_links(lol) }
end

As of a side effect I'll show you small example. Given you have matcher defined in $PROJECT/spec/support/utilities.rb file, application routes etc... are set up correctly and you have links in your view.

describe "Users pages" do
  before { visit root_path }
  let(:values) { Hash['Index' => users_path, 
                      'Sign out' => signout_path, 
                      'Sign in' => signin_path] }

  subject { page }

  describe "with valid informations" do
    it { should have_list_of_links(values) }
  end
end  

running rspec:

> rspec
.

Finished in 0.00267 seconds
1 example, 0 failures

Randomized with seed 67346

running rspec -f documentation

>rspec -f documentation
Users pages
  with valid informations
    should have link "Sign in"

Finished in 0.00049 seconds
1 example, 0 failures

Randomized with seed 53331

This is not clear and misleading, specially the documentation switch. Its a common practice to run a rspec -f documentation on new application You just put your hands on(if they use rspec ofc). To better understands what is going on.

If you instead have:

describe "Users pages" do
  before { visit root_path }

  subject { page }

  describe "with valid informations" do
    it { should have_link('Index', href: users_path) }
    it { should have_link('Sign out', href: signout_path) }
    it { should have_link('Sign in', href: signout_path) }
  end
end  

running rspec:

>rspec
...

Finished in 0.0097 seconds
3 examples, 0 failures

Randomized with seed 53347

running rspec -f documentation

>rspec -f documentation
Users pages
  with valid informations
    should have link "Index"
    should have link "Sign out"
    should have link "Sign in"

Finished in 0.00542 seconds
3 examples, 0 failures

Randomized with seed 40120

I personally like second case(more verbose one). Its value increasing when number of test are growing and test structures are getting more complicated. You can simply run rspec -f documentation to learn how to use application without even going to user manual/tutorial.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top