Search code examples
ruby-on-rails-3capybararspec-rails

How to test for non existing html tag in rspec/capybara


For a controller delivering some html snippet (used as ajax call), I have a view spec looking like that:

it "should not contain html element" do
    render
    rendered.should have_selector('div')
    rendered.should_not have_selector('html')
end

Since our ajax content loader doesn't allow a full html page to be rendered, I want to check that the result does not contain an html tag.

For now the result in rendered is a simple div tag:

puts rendered

leads to

"<div>Some text</div>"

However, the test fails:

Failure/Error: rendered.should_not have_selector('html')
  Capybara::ExpectationNotMet:
  expected not to find css "html", found 1 match: "Some text"

I also tried it with

rendered.should_not have_xpath('//html')
rendered.should_not have_css('html')
rendered.should have_no_xpath('//html')
rendered.should have_no_css('html')

but the result stays the same.

Why is a check for html matching the text inside the div? Even a test for body leads to the same result.


Solution

  • This should not be possible using the capybara matchers, because capybara is using Nokogiri::HTML to generate the internal DOM structure, and this always tries to create a valid HTML representation, which also includes an html and body tag, if there is none. See here in their source.

    If you want to do that, you could fork capybara and change that line into something like

    native = Nokogiri::HTML::Fragment(native) if native.is_a?(String)
    

    Nokogiri::HTML::Fragment will not try to enhance the code to have an completed html structure.

    Another solution would simply be doing a string match:

    rendered.match('<html').should be nil