#345 new
Andreas Krüger

assert_have_xpath messes up XML / XHTML input by parsing as HTML

Reported by Andreas Krüger | January 21st, 2010 @ 08:06 AM

Hello,

my RoR web application outputs correct XHTML. Specifically,

<option selected="selected" ...`

A Webrat assert_have_xpath on such output failed.

In the error output, Webrat made me believe my web application actually had output non-XHTML "attribute without value":

<option selected ...`

This sent me on a sizeable wild goose chase.

Hours later, I finally realized what Webrat had printed in the error message did not faithfully reflect what my application actually had provided.


Secondly, when a code block is provided to assert_have_xpath, I expect this code block to receive DOM nodes that faithfully reflect the input XML.

This also is not the case.


I have coded a couple of tests that expose these two problems. Those tests I enclose as a patch.

I think this may be related to #66 . More specifically, I have hunted it down to webrat-0.6.0/lib/webrat/core/xml.rb lines 14 and 16. To paraphrase:

If it is has a body, or else is something not easily recognized, it needs to be treated as HTML, never XHTML nor XML.

As a workaround, I'm using this home-grown version of assert_have_xpath:

  def self.assert_have_xpath(expected, &block) 
    xmldoc = Nokogiri::XML(response.body)
    xpathcontext = Nokogiri::XML::XPathContext.new(xmldoc)

    # Looking for a default namespace in the document root
    document_root = xmldoc.child.element? ? \
      xmldoc.child : xmldoc.child.next_element
    namespace = document_root.namespace
    if(namespace && ! namespace.prefix)
      # default namespace found, registering it with prefix "default"
      # The expected expression will probably need to make use of this prefix.
      xpathcontext.register_ns("default", namespace.href)
    end

    nodeset = xpathcontext.evaluate(expected).node_set
    if block
      # This is a bit different from what webrat normally does:
      # My block filters the nodes matched by XPath (one at a time).
      assert nodeset.any? {|x| block.call(x)}, <<-MESS
Filtering using the code block that was provided
nodes selected by the XPath \"#{expected}
no result was left, given the following XML:

#{response.body}

        MESS
    else
        assert nodeset.any?, <<-MESS
No nodes were selected by the XPath #{expected}, given the following XML:

#{response.body}

        MESS
    end
  end

Comments and changes to this ticket

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

Ruby Acceptance Testing for Web applications.

Shared Ticket Bins

People watching this ticket

Attachments

Pages