[rspec-users] how to write nested XPath matchers

Phlip phlip2005 at gmail.com
Mon Feb 16 10:36:32 EST 2009


> This looks pretty cool. I wonder if you'd have any interest in making
> this a bit more rspec-friendly? Something like an option to run it
> like this:

Here's the spec. The sauce is below my signature.

   it 'should have a user form with the first name' do
     render '/users/new'
     response.body.should be_xml_with do
       xpath :form, :action => '/users' do
         xpath :fieldset do
           xpath :'legend[ contains(., "Personal Information") ]' and
           xpath :'label[ contains(., "First name") ]' and
           xpath :input, :type => 'text', :name => 'user[first_name]'
         end
       end
     end
   end

Now, two issues. Firstly, what is the point of writing verbiage, designed for 
review by the customer team, if they should not be expected to understand 
hardcore engineering gibberish beginning with "body.should be_xml_with do"? A 
sentence that is only partly English does more harm than good!

Secondly, when an xpath() fails, it prepares an elaborate and detailed analysis 
of the entire situation, packs this into a flunk(), and raises it in a 
Test::Unit::AssertionFailedError.

Then RSpec then throws all that stuff away, and provides an incorrect stack 
trace to an internal error. Switching my 'user[first_name]' to 
'user[first_nome]' provides this:

NoMethodError in '/users/new should have xpathic tags'
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.first
./spec/views/users/new.html.erb_spec.rb:50:

So if I were to rescue my own AssertionFailedError, and pack it into a 
failure_message, wouldn't that effort be redundant?

-- 
   Phlip

require 'assert2/xpath'

Spec::Runner.configure do |c|
   c.include Test::Unit::Assertions
end  #  TODO blog this

   class BeXmlWith

     def initialize(scope, &block)
       @scope, @block = scope, block
     end

     def matches?(stwing, &block)
       waz_xdoc = @xdoc
       @block = block if block
       @scope.assert_xhtml stwing
       return (block || @block || proc{}).call
     ensure
       @xdoc = waz_xdoc
     end

     def failure_message
       "yack yack yack"
     end

     def negative_failure_message
       "yack yack yack"
     end
   end

   def be_xml_with(&block)
     BeXmlWith.new(self, &block)
   end



More information about the rspec-users mailing list