← Back to Upcase

Testing for specific link and its value


(Jon Seidel) #1

OK; I found a bug in my app wherein a link made an incorrect reference. Off I go to write a test but turns out this isn’t so easy. The code is simple:

<%= link_to 'mylist', '/wrong_place' %>

which of course generates:

<a href="/wrong_place">mylist</a>

What I want to do is find the link based on the contained text ‘mylist’ and then test for the href value that I expect to be there.

From what I can tell, there’s no way to do this with CSS selectors: ‘mylist’ is a text element contained in the ‘a’ tag and if I search for that element value, there’s no way to move “up” to its parent, which is where the href attribute lives that I want to test. There was a :contains selector proposed for CSS3 which was removed; various posts claim that it was actually implemented in most browsers, but it doesn’t work in rspec.

Unless I’ve fallen down a rabbit hole and can’t see the obvious solution (entirely possible :=), the only way I figure I can test this is by adding an attribute (class, id, …) to the link which I can then use to select the link and test for the desired href value.

What’s the obvious answer?


(Harlow Ward) #2

We can use the Capybara have_css matcher:

expect(page).to have_css "a[href='/wrong_place']", text: 'mylist' 

(Jon Seidel) #3

Thanks very much, @harlow… that works now in my feature spec. I know I tried that at some point, but I guess there were other problems with my test that prevented it from working.

Edit: So I got the selection with two items working by using the class of the items (one’s inside my nav/menus).

However, I’m running into more questions about have_css. On my home page, the user has to be logged in to view the ‘mylist’ page; if they’re not, they get a flash-error message and remain on the home page. The html on the page is:

<div class="error">You must be logged in to view this page</div>

This expectation works:

expect(page.html).to have_css('div.error', :text => 'You must be logged in to view this page')

while this one fails:

expect(page).to have_css('div.error', :text => 'You must be logged in to view this page')

Capybara docs say to use page.html only for testing, so I’m sure there’s a better way to get this to work without the page.html incantation…?


(Jon Seidel) #4

Here’s more detail about the spec, along with what worked (and didn’t work)…

  scenario "rejects mylist links if not logged in" do
    visit root_path
    ### All these commented-out versions failed
    #find('#nav li > a[href*="hoards"]').click_on
    #click_on find('#nav>ul>li>a[href*="hoards"]')
    #click_on find('#nav>a[href*="hoards"]')
    #click_on find('#nav a[href*="hoards"]')
    #find('#nav').find_link('[href*="hoards"]').click
    #find('#nav').find_link('ul a[href*="hoardss]').click
    #find('#nav').click_link('a[href*="hoards"]')
    #find('#nav').click_link('a[href="/hoards"]')
    within '#nav' do
      click_link 'mylist'
      expect(page.html).to have_css('div.error', :text => 'You must be logged in to view this page')
      ### Don't know why this fails and the above works...?
      #expect(page).to have_css('div.error', :text => 'You must be logged in to view this page')
    end
  end

(Chad Pytel) #5

@JESii what does save_and_open_page show you?


(Jon Seidel) #6

Here’s the pastie, @cyptel… I added the save_and_open page just before the “expect(page.hml)…” inside the “within” clause. I retested both expections just in case I missed something and (page) still fails while (page.html) passes.