Use Capybara On Any HTML Fragment Or Page

Nick Quaranto

capybaras are pretty classy

I was upgrading Gemcutter to Cucumber and Capybara 1.0 yesterday from Webrat (a change long overdue!), and I discovered a neat little class within Capybara that is worth sharing. Basically, since I was moving the app from Webrat, matchers like assert_contain and assert_have_selector are no longer available. Capybara’s Node class has a great Matchers mixin with tons of goodies that can be used like so, in RSpec:

page.should have_content("This should be on the page")
page.should have_selector("a[href='http://thoughtbot.com']")

Great, but how does one use that in functional/controller tests?

Enter Capybara::Node::Simple, which I found purely by chance when source diving. This class’ docs proclaim its usefulness:

It is useful in that it does not require a session, an application or a driver, but can still use Capybara’s finders and matchers on any string that contains HTML

Bingo! Now, how to use in our test suite? We’re still on Test::Unit for Gemcutter, so I had to do the following in test/test_helper.rb:

class Test::Unit::TestCase
  def page
    Capybara::Node::Simple.new(@response.body)
  end
end

Now the Gemcutter test suite can do assertions like so:

assert page.has_content?("Rails (3.0.9)")
assert page.has_selector?("a[href='/gems/rails/versions/3.0.9']")

The whole diff is on GitHub if you’d like to see all of the changes of moving our functional tests from Webrat to Capybara.

Gabe also found out that there’s also a shortcut in Capybara for creating a Simple: Capybara.string. The docs for this show that it’s basically sugar on top of the Simple initializer:

node = Capybara.string <<-HTML
  <ul>
    <li id="home">Home</li>
    <li id="projects">Projects</li>
  </ul>
HTML

node.find('#projects').text # => 'Projects'

I think this pattern is really useful not just for upgrading suites from Webrat, but really anywhere you have an HTML fragment or string that you’d like to use Capybara’s matchers on.