On Sun, Mar 8, 2009 at 2:03 PM, David Chelimsky <dchelim...@gmail.com> wrote: > On Sun, Mar 8, 2009 at 12:00 PM, Phlip <phlip2...@gmail.com> wrote: >> RSpecsters: >> >> I like nested XPath expressions, because the outer XPath assertion can clip >> the diagnostic of the inner XPath assertion. You don't get the whole page >> spewed into your face when you fault! >> >> This specification, for example, tests Yury Kotlyarov's user login page, >> from: >> >> http://github.com/yura/howto-rspec-custom-matchers/tree/master >> >> it 'should have xpathic tags' do >> render '/users/new' >> >> response.body.should be_xml_with{ >> 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 > > This is nice, but the abstractions are operating at different levels. > The keyword is "xpath" but the args passed to that look nothing like > xpath. How about something like: > > response.body.should be_xml_with do > form :action => '/users' do > fieldset do > legend "Personal Information" > label "First name" > input :type => 'text', :name => 'user[first_name]' > end > end > end >
I like this a lot. > > > >> >> That tests this (otherwise innocuous) new.html.erb: >> >> <form action="/users"> >> <fieldset> >> <legend>Personal Information</legend> >> <ol> >> <li id="control_user_first_name"> >> <label for="user_first_name">First name</label> >> <input type="text" name="user[first_name]" id="user_first_name" /> >> </li> >> </ol> >> </fieldset> >> </form> >> >> If that code had any major complex <%= erb %> activity, the tests^W >> specifications would keep it honest. >> >> Let's change the specification, to simulate a bug, and try it: >> >> xpath :input, :type => 'text', :name => 'user[first_nome]' # was _name >> >> That provides this mind-blast of errata: >> >> '/users/new should have xpathic tags' FAILED >> xpath: "descendant-or-self::inp...@type = $type and @name = $name]" >> arguments: {"name"=>"user[first_nome]", "type"=>"text"} >> >> xml context: >> >> <fieldset> >> <legend> >> Personal Information >> </legend> >> <ol> >> <li id='control_user_first_name'> >> <label for='user_first_name'> >> First name >> </label> >> <input name='user[first_name]' type='text' id='user_first_name'/> >> </li> >> </ol> >> </fieldset> >> >> assert{ ( ( xpath(:"legend[ contains(., \"Personal Information\") ]") ) and >> ( ( ( xpath(:"label[ contains(., \"First name\") ]") ) and >> ( xpath(:input, { :type => "text", :name => "user[first_nome]" }) ) ) ) ) >> } >> --> nil - should pass >> >> xpath(:"legend[ contains(., \"Personal Information\") ]") >> --> <legend> ... </> >> >> xpath(:"label[ contains(., \"First name\") ]") >> --> <label for='user_first_name'> ... </> >> >> xpath(:input, { :type => "text", :name => "user[first_nome]" }) >> --> nil >> >> ./spec/views/users/new.html.erb_spec.rb:63: >> script/spec:5: >> >> Finished in 0.116823 seconds >> >> 2 examples, 1 failure >> >> Note that the error message restricted itself to the XHTML inside the <form> >> tag. This is a major benefit when diagnosing a huge page that failed. (But >> also note that your HTML, like your code, should come in small reusable >> snippets, such as partials, and that these should get tested directly!) >> >> Soon I will upgrade this system to use Nokogiri instead of (>cough<) REXML. >> >> Now, while I go and put the "simple" matcher that does this onto Twitter, >> YouTube, Mingle, Facebook, Mindfuck, Reddit, Tumblog, LinkedIn, and Gist, >> you all can just read it below my sig. >> >> -- >> Phlip >> http://www.zeroplayer.com/ >> >> require File.dirname(__FILE__) + "/../../spec_helper" >> require 'assert2/xpath' >> require 'spec/matchers/wrap_expectation' >> >> Spec::Runner.configure do |c| >> c.include Test::Unit::Assertions >> end # TODO blog this >> >> describe "/users/new" do >> >> it "should have user form" do >> render '/users/new' >> response.should have_form('/users') do >> with_field_set 'Personal Information' do >> with_text_field 'First name', 'user', 'first_name' >> end >> end >> end >> >> class BeXmlWith >> >> def initialize(scope, &block) >> �...@scope, @block = scope, block >> end >> >> def matches?(stwing, &block) >> waz_xdoc = @xdoc >> >> �...@scope.wrap_expectation self do >> �...@scope.assert_xhtml stwing >> return (block || @block || proc{}).call >> end >> ensure >> �...@xdoc = waz_xdoc >> end >> >> attr_accessor :failure_message >> >> def negative_failure_message >> "yack yack yack" >> end >> end >> >> def be_xml_with(&block) >> BeXmlWith.new(self, &block) >> end >> >> def be_xml_with_(&block) >> waz_xdoc = @xdoc >> simple_matcher 'yo' do |given, matcher| >> wrap_expectation matcher do >> assert_xhtml given # this works >> block.call # crashes with a nil.first error! >> end >> end >> ensure >> �...@xdoc = waz_xdoc >> end >> >> it 'should have xpathic tags' do >> render '/users/new' >> >> response.body.should be_xml_with{ >> 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 >> >> _______________________________________________ >> rspec-users mailing list >> rspec-users@rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users >> > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users > -- Zach Dennis http://www.continuousthinking.com http://www.mutuallyhuman.com _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users