Thoughts, links, pictures on music, food, wine, film, tech etc.


I wrote this:

Finding a Link by Its Text Using Cucumber and Nokogiri

A small project I've been working on recently requires linking to an external site, specified in the database.

Normally, when testing links in cucumber, I would do the following:

When I follow "more info"
Then I should see "More Info"

When "more info" is an external link, I don't really want to go clicking it as part of my integration testing: I mean, I could, but I don't like having a dependency on a net connection in my tests.

What I do want to test though is that the link is pointing to the right URL.

Webrat gives us a lovely way to click a link:

click_link("more info")

...but there's no easy way to get at the 'href' attribute of the 'a' element. I searched and searched the source code of webrat to find a convenience method, but the best I could get to was a couple of methods nested deep inside the webrat Link Locator.

Enter Capybara the new hotness in integration testing DSLs.

Capybara's "find_link" method is far more concise than webrat's and uses xpath to locate an 'a' tag by its contents. The Capybara xpath looks like this:

//a[@id='#{locator}' or contains(.,'#{locator}') or @title='#{locator}']

It's actually quite lovely.

Somewhere, at some stage along the chain, capybara passes that xpath down the chain to it's brother in new hotness arms, Nokogiri.

So anyway, using this bit of investigative source code browsing, I was able to come up with this step definition to solve my problem of check the 'href' of an 'a' tag with cucumber:

Then /^"([^\"]*)" should link to "([^\"]*)"$/ do |link, url|
  n = Nokogiri::HTML(response.body)
  n.xpath("//a[contains(.,'#{link}')]").first['href'].should == url

All I needed in this case was the 'contains' part of the xpath. It's pretty concise, and it's definitely something I'm going to use again in the future.

Made by Paul Campbell. paul@rushedsunlight.com. Twitter. Github.