Module: AssertXPath
- Included in:
- AssertJavaScript
- Defined in:
- lib/assert_xpath.rb,
lib/assert_xpath.rb
Defined Under Namespace
Modules: CommonXPathExtensions Classes: HpricotHelper, LibxmlHelper, RexmlHelper, XmlHelper
Constant Summary collapse
- Element =
:nodoc:
::REXML::Element
Instance Method Summary collapse
-
#assert_any_xpath(xpath, matcher = nil, diagnostic = nil, &block) ⇒ Object
Search nodes for a matching XPath whose
AssertXPath::Element#inner_text
matches a Regular Expression. -
#assert_hpricot(*args, &block) ⇒ Object
%html <a name=‘assert_hpricot’></a>.
- #assert_libxml(*args, &block) ⇒ Object
-
#assert_rexml(*args, &block) ⇒ Object
Processes a string of text, or the hidden
@response.body
, using REXML, and sets the hidden@xdoc
node. -
#assert_tag_id(tag, id, diagnostic = nil, &block) ⇒ Object
Wraps the common idiom
assert_xpath('descendant-or-self::./my_tag[ @id = "my_id" ]')
. -
#assert_tidy(messy = @response.body, verbosity = :noisy) ⇒ Object
%html <a name=‘assert_tidy’></a> Thin wrapper on the Tidy command line program (the one released 2005 September) *
messy
- optional string containing messy HTML. -
#assert_xml(*args, &block) ⇒ Object
%html <a name=‘assert_xml’></a>.
-
#assert_xpath(xpath, diagnostic = nil, &block) ⇒ Object
%html <a name=‘assert_xpath’></a>.
-
#deny_any_xpath(xpath, matcher, diagnostic = nil) ⇒ Object
Negates
assert_any_xpath
. -
#deny_tag_id(tag, id, diagnostic = nil) ⇒ Object
Negates
assert_tag_id
. -
#deny_xpath(xpath, diagnostic = nil) ⇒ Object
Negates
assert_xpath
. -
#drill(&block) ⇒ Object
ERGO document me.
-
#indent_xml(doc = @xdoc || assert_xml) ⇒ Object
Pretty-print a REXML::Element or Hpricot::Elem *
doc
- optional element. -
#invoke_hpricot ⇒ Object
Subsequent
assert_xml
calls will use Hpricot. -
#invoke_libxml(favorite_flavor = :html) ⇒ Object
Subsequent
assert_xml
calls will use LibXML. -
#invoke_rexml ⇒ Object
Subsequent
assert_xml
calls will use REXML. - #using(kode) ⇒ Object
Instance Method Details
#assert_any_xpath(xpath, matcher = nil, diagnostic = nil, &block) ⇒ Object
Search nodes for a matching XPath whose AssertXPath::Element#inner_text
matches a Regular Expression. Depends on assert_xml
-
xpath
- a query string describing a path among XML nodes. See: XPath Tutorial Roundup -
matcher
- optional Regular Expression to test node contents -
diagnostic
- optional string to add to failure message -
block|node|
- optional block called once per match. If this block returns a value other thanfalse
ornil
, assert_any_xpath stops looping and returns the currentnode
Example: %transclude AssertXPathSuite#test_assert_any_xpath
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 |
# File 'lib/assert_xpath.rb', line 462 def assert_any_xpath(xpath, matcher = nil, diagnostic = nil, &block) matcher ||= // block ||= lambda{ true } found_any = false found_match = false xpath = symbol_to_xpath(xpath) stash_xdoc do #assert_xpath xpath, diagnostic if !using(:rexml?) @xdoc.search(xpath) do |@xdoc| found_any = true if @xdoc.inner_text =~ matcher found_match = true _bequeath_attributes(@xdoc) return @xdoc if block.call(@xdoc) # note we only exit block if block.nil? or call returns false end end else # ERGO merge! @xdoc.each_element(xpath) do |@xdoc| found_any = true if @xdoc.inner_text =~ matcher found_match = true _bequeath_attributes(@xdoc) return @xdoc if block.call(@xdoc) # note we only exit block if block.nil? or call returns false end end end end found_any or flunk_xpath(diagnostic, "should find xpath <#{_esc xpath}>") found_match or flunk_xpath( diagnostic, "can find xpath <#{_esc xpath}> but can't find pattern <?>", matcher ) end |
#assert_hpricot(*args, &block) ⇒ Object
%html <a name=‘assert_hpricot’></a>
This parses one XML string using Hpricot, so subsequent calls to assert_xpath
will use Hpricot expressions. This method does not depend on invoke_hpricot
, and subsequent test cases will run in their suite’s mode.
Example: %transclude AssertXPathSuite#test_assert_hpricot
See also: assert_hpricot
375 376 377 378 379 380 381 382 |
# File 'lib/assert_xpath.rb', line 375 def assert_hpricot(*args, &block) xml = args.shift || @xdoc || @response.body ## ERGO why @xdoc?? # ERGO document that callseq! require 'hpricot' @xdoc = Hpricot(xml.to_s) # ERGO take that to_s out of all callers return assert_xpath(*args, &block) if args.length > 0 return @xdoc end |
#assert_libxml(*args, &block) ⇒ Object
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/assert_xpath.rb', line 326 def assert_libxml(*args, &block) xml = args.shift || @xdoc || @response.body require 'xml/libxml' xp = XML::Parser.new() xhtml = xml.to_s if xhtml !~ /^\<\!DOCTYPE\b/ and xhtml !~ /\<\?xml\b/ xhtml = _doc_type[@_favorite_flavor || :html] + "\n" + xhtml end # ERGO document we pass HTML level into invoker # # FIXME blog that libxml will fully validate your ass... xp.string = xhtml # FIXME blog we don't work with libxml-ruby 3.8.4 # XML::Parser.default_load_external_dtd = false XML::Parser.default_pedantic_parser = false # FIXME optionalize that #what? xp doc = xp.parse #what? doc #puts doc.debug_dump @xdoc = doc.root # @xdoc.namespace ||= XML::NS.new('') #pp (@xdoc.root.public_methods - public_methods).sort return assert_xpath(*args, &block) if args.length > 0 return @xdoc end |
#assert_rexml(*args, &block) ⇒ Object
Processes a string of text, or the hidden @response.body
, using REXML, and sets the hidden @xdoc
node. Does not depend on, or change, the values of invoke_hpricot
, invoke_libxml
, or invoke_rexml
Example: %transclude AssertXPathSuite#test_assert_rexml
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/assert_xpath.rb', line 304 def assert_rexml(*args, &block) contents = (args.shift || @response.body).to_s # ERGO benchmark these things contents.gsub!('\\\'', ''') contents.gsub!('//<![CDATA[<![CDATA[', '') contents.gsub!('//<![CDATA[', '') contents.gsub!('//]]>', '') contents.gsub!('//]>', '') begin @xdoc = REXML::Document.new(contents) rescue REXML::ParseException => e raise e unless e. =~ /attempted adding second root element to document/ @xdoc = REXML::Document.new("<xhtml>#{ contents }</xhtml>") end _bequeath_attributes(@xdoc) assert_xpath(*args, &block) if args != [] return (assert_xpath('/*') rescue nil) if @xdoc end |
#assert_tag_id(tag, id, diagnostic = nil, &block) ⇒ Object
Wraps the common idiom assert_xpath('descendant-or-self::./my_tag[ @id = "my_id" ]')
. Depends on assert_xml
-
tag
- an XML node name, such asdiv
orinput
. If this is a:symbol
, we prefix “.//
” -
id
- string or symbol uniquely identifying the node. This must not contain punctuation -
diagnostic
- optional string to add to failure message -
block|node|
- optional block containing assertions, based onassert_xpath
, which operate on this node as the XPath ‘.’ current node.
Returns the obtained REXML::Element node
Examples:
assert_tag_id '/span/div', "audience_#{ring.id}" do
assert_xpath 'table/tr/td[1]' do |td|
#...
assert_tag_id :form, :for_sale
end
end
%transclude AssertXPathSuite#test_assert_tag_id_and_tidy
%transclude AssertXPathSuite#test_assert_tag_id
566 567 568 569 |
# File 'lib/assert_xpath.rb', line 566 def assert_tag_id(tag, id, diagnostic = nil, &block) # CONSIDER upgrade assert_tag_id to use each_element_with_attribute assert_xpath build_xpath(tag, id), diagnostic, &block end |
#assert_tidy(messy = @response.body, verbosity = :noisy) ⇒ Object
%html <a name=‘assert_tidy’></a> Thin wrapper on the Tidy command line program (the one released 2005 September)
-
messy
- optional string containing messy HTML. Defaults to@response.body
. -
verbosity
- optional noise level. Defaults to:noisy
, which reports most errors. :verbose reports all information, and other value will repress all of Tidy’s screams of horror regarding the quality of your HTML.
The resulting XHTML loads into assert_xml
. Use this to retrofit assert_xpath
tests to less-than-pristine HTML.
assert_tidy
obeys invoke_rexml
and invoke_hpricot
, to select its HTML parser
Examples:
get :adjust, :id => transaction.id # <-- fetches ill-formed HTML
assert_tidy @response.body, :quiet # <-- upgrades it to well-formed
assert_tag_id '//table', :payment_history do # <-- sees good XML
#...
end
%transclude AssertXPathSuite#test_assert_tag_id_and_tidy
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 |
# File 'lib/assert_xpath.rb', line 642 def assert_tidy(messy = @response.body, verbosity = :noisy) scratch_html = RAILS_ROOT + '/tmp/scratch.html' # CONSIDER a railsoid tmp file system? # CONSIDER yield to something to respond to errors? File.open(scratch_html, 'w'){|f| f.write(messy) } gripes = `tidy -eq #{scratch_html} 2>&1` gripes.split("\n") # TODO kvetch about client_input_channel_req: channel 0 rtype [email protected] reply 1 puts gripes if verbosity == :verbose puts gripes.reject{|g| g =~ / - Info\: / or g =~ /Warning\: missing \<\!DOCTYPE\> declaration/ or g =~ /proprietary attribute/ or g =~ /lacks "(summary|alt)" attribute/ } if verbosity == :noisy assert_xml `tidy -wrap 1001 -asxhtml #{ scratch_html } 2>/dev/null` # CONSIDER that should report serious HTML deformities end |
#assert_xml(*args, &block) ⇒ Object
%html <a name=‘assert_xml’></a>
Prepare XML for assert_xpath et al
-
xml
- optional string containing XML. Without it, we read@response.body
-
xpath, diagnostic, block
- optional arguments passed toassert_xpath
Sets and returns the new secret @xdoc
REXML::Element root call-seq:
assert_xml(xml = @response.body <em>[, assert_xpath arguments]</em>) -> @xdoc, or assert_xpath's return value
Assertions based on assert_xpath
will call this automatically if the secret @xdoc
is nil
. This implies we may freely call assert_xpath
after any method that populates @response.body
– if @xdoc
is nil
. When in doubt, call assert_xml
explicitly
assert_xml
also translates the contents of assert_select
nodes. Use this to bridge assertions from one system to another. For example:
Returns the first node in the XML
Examples:
assert_select 'div#home_page' do |home_page|
assert_xml home_page # <-- calls home_page.to_s
assert_xpath ".//img[ @src = '#{newb.image_uri(self)}' ]"
deny_tag_id :form, :edit_user
end
%transclude AssertXPathSuite#test_assert_long_sick_expression See: AssertXPathSuite#test_assert_xml_drill
291 292 293 294 |
# File 'lib/assert_xpath.rb', line 291 def assert_xml(*args, &block) using :libxml? # prop-ulates @helper return @helper.assert_xml(self, *args, &block) end |
#assert_xpath(xpath, diagnostic = nil, &block) ⇒ Object
%html <a name=‘assert_xpath’></a>
Return the first XML node matching a query string. Depends on assert_xml
to populate our secret internal REXML::Element, @xdoc
-
xpath
- a query string describing a path among XML nodes. See: XPath Tutorial Roundup -
diagnostic
- optional string to add to failure message -
block|node|
- optional block containing assertions, based onassert_xpath
, which operate on this node as the XPath ‘.’ currentnode
Returns the obtained REXML::Element node
Examples:
render :partial => 'my_partial'
assert_xpath '/table' do |table|
assert_xpath './/p[ @class = "brown_text" ]/a' do |a|
assert_equal user.login, a.text # <-- native <code>REXML::Element#text</code> method
assert_match /\/my_name$/, a[:href] # <-- attribute generated by +assert_xpath+
end
assert_equal "ring_#{ring.id}", table.id! # <-- attribute generated by +assert_xpath+, escaped with !
end
%transclude AssertXPathSuite#test_assert_xpath
See: AssertXPathSuite#test_indent_xml, XPath Checker
415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
# File 'lib/assert_xpath.rb', line 415 def assert_xpath(xpath, diagnostic = nil, &block) # return assert_any_xpath(xpath, diagnostic) { # block.call(@xdoc) if block # true # } stash_xdoc do xpath = symbol_to_xpath(xpath) node = @xdoc.search(xpath).first @xdoc = node || flunk_xpath(diagnostic, "should find xpath <#{_esc xpath}>") @xdoc = _bequeath_attributes(@xdoc) block.call(@xdoc) if block # ERGO tribute here? return @xdoc end end |
#deny_any_xpath(xpath, matcher, diagnostic = nil) ⇒ Object
Negates assert_any_xpath
. Depends on assert_xml
-
xpath
- a query string describing a path among XML nodes. This must succeed - usedeny_xpath
for simple queries that must fail -
matcher
- optional Regular Expression to test node contents. Ifxpath
locates multiple nodes, this pattern must fail to match each node to pass the assertion. -
diagnostic
- optional string to add to failure message
Contrived example:
assert_xml '<heathrow><terminal>5</terminal><lean>methods</lean></heathrow>'
Test::Unit::AssertionFailedError,
/all xpath.*\.\/\/lean.*not have.*methods/ do
deny_any_xpath :lean, /methods/
end
deny_any_xpath :lean, /denver/
See: AssertXPathSuite#test_deny_any_xpath, assert_raise (on Ruby) - Don’t Just Say “No”
529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
# File 'lib/assert_xpath.rb', line 529 def deny_any_xpath(xpath, matcher, diagnostic = nil) @xdoc or assert_xml xpath = symbol_to_xpath(xpath) assert_any_xpath xpath, nil, diagnostic do |node| if node.inner_text =~ matcher flunk_xpath( diagnostic, "all xpath <#{_esc xpath}> nodes should not have pattern <?>", matcher ) end end end |
#deny_tag_id(tag, id, diagnostic = nil) ⇒ Object
Negates assert_tag_id
. Depends on assert_xml
Example - see: assert_xml
See: assert_tag_id
577 578 579 |
# File 'lib/assert_xpath.rb', line 577 def deny_tag_id(tag, id, diagnostic = nil) deny_xpath build_xpath(tag, id), diagnostic end |
#deny_xpath(xpath, diagnostic = nil) ⇒ Object
Negates assert_xpath
. Depends on assert_xml
Examples:
assert_tag_id :td, :object_list do
assert_xpath "table[ position() = 1 and @id = 'object_#{object1.id}' ]"
deny_xpath "table[ position() = 2 and @id = 'object_#{object2.id}' ]"
end # find object1 is still displayed, but object2 is not in position 2
%transclude AssertXPathSuite#test_deny_xpath
442 443 444 445 446 447 448 |
# File 'lib/assert_xpath.rb', line 442 def deny_xpath(xpath, diagnostic = nil) @xdoc or assert_xml xpath = symbol_to_xpath(xpath) @xdoc.search(xpath).first and flunk_xpath(diagnostic, "should not find: <#{_esc xpath}>") end |
#drill(&block) ⇒ Object
ERGO document me
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/assert_xpath.rb', line 124 def drill(&block) if block # ERGO harmonize with bang! version # ERGO deal if the key ain't a valid variable unless tribute(block) # ERGO pass in self (node)? sib = self nil while (sib = sib.next_sibling) and sib.node_type != :element p sib # ERGO do tests ever get here? q = sib and _bequeath_attributes(sib).drill(&block) return sib if q raise Test::Unit::AssertionFailedError.new("can't find beyond <#{xpath}>") end end return self # ERGO if block returns false/nil, find siblings until it passes. # throw a test failure if it don't. # ERGO axis concept end |
#indent_xml(doc = @xdoc || assert_xml) ⇒ Object
Pretty-print a REXML::Element or Hpricot::Elem
-
doc
- optional element. Defaults to the currentassert_xml
document
returns: string with indented XML
Use this while developing a test case, to see what the current @xdoc
node contains (as populated by assert_xml
and manipulated by assert_xpath
et al)
For example:
assert_javascript 'if(x == 42) answer_great_question();'
assert_js_if /x.*42/ do
puts indent_xml # <-- temporary statement to see what to assert next!
end
See: AssertXPathSuite#test_indent_xml
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 |
# File 'lib/assert_xpath.rb', line 598 def indent_xml(doc = @xdoc || assert_xml) if doc.kind_of?(Hpricot::Elem) or doc.kind_of?(Hpricot::Doc) zdoc = doc doc = REXML::Document.new(doc.to_s.strip) rescue nil unless doc # Hpricot didn't well-formify the HTML! return zdoc.to_s # note: not indented, but good enough for error messages end end # require 'rexml/formatters/default' # bar = REXML::Formatters::Pretty.new # out = String.new # bar.write(doc, out) # return out return doc.to_s # ERGO reconcile with 1.8.6.111! x = StringIO.new doc.write(x, 2) return x.string # CONSIDER does REXML have a simpler way? end |
#invoke_hpricot ⇒ Object
Subsequent assert_xml
calls will use Hpricot. (Alternately, assert_hpricot
will run one assertion in Hpricot mode.) Put invoke_hpricot
into setup
() method, to run entire suites in this mode. These test cases explore some differences between the two assertion systems: %transclude AssertXPathSuite#test_assert_long_xpath
222 223 224 225 |
# File 'lib/assert_xpath.rb', line 222 def invoke_hpricot @xdoc = nil @helper = HpricotHelper.new end |
#invoke_libxml(favorite_flavor = :html) ⇒ Object
Subsequent assert_xml
calls will use LibXML. (Alternately, assert_libxml
will run one assertion in Hpricot mode.) Put invoke_libxml
into setup
() method, to run entire suites in this mode.
234 235 236 237 238 |
# File 'lib/assert_xpath.rb', line 234 def invoke_libxml(favorite_flavor = :html) @_favorite_flavor = favorite_flavor @xdoc = nil @helper = LibxmlHelper.new end |
#invoke_rexml ⇒ Object
Subsequent assert_xml
calls will use REXML. See invoke_hpricot
to learn the various differences between the two systems
257 258 259 260 |
# File 'lib/assert_xpath.rb', line 257 def invoke_rexml @xdoc = nil @helper = RexmlHelper.new end |
#using(kode) ⇒ Object
355 356 357 358 |
# File 'lib/assert_xpath.rb', line 355 def using(kode) @helper ||= RexmlHelper.new # ERGO escallate this! return @helper.send(kode) end |