futuresinc-webrat 0.4.4.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. data/History.txt +333 -0
  2. data/MIT-LICENSE.txt +19 -0
  3. data/README.rdoc +85 -0
  4. data/Rakefile +156 -0
  5. data/install.rb +1 -0
  6. data/lib/webrat/core/configuration.rb +98 -0
  7. data/lib/webrat/core/elements/area.rb +31 -0
  8. data/lib/webrat/core/elements/element.rb +33 -0
  9. data/lib/webrat/core/elements/field.rb +403 -0
  10. data/lib/webrat/core/elements/form.rb +103 -0
  11. data/lib/webrat/core/elements/label.rb +31 -0
  12. data/lib/webrat/core/elements/link.rb +92 -0
  13. data/lib/webrat/core/elements/select_option.rb +35 -0
  14. data/lib/webrat/core/locators/area_locator.rb +38 -0
  15. data/lib/webrat/core/locators/button_locator.rb +54 -0
  16. data/lib/webrat/core/locators/field_by_id_locator.rb +37 -0
  17. data/lib/webrat/core/locators/field_labeled_locator.rb +56 -0
  18. data/lib/webrat/core/locators/field_locator.rb +25 -0
  19. data/lib/webrat/core/locators/field_named_locator.rb +41 -0
  20. data/lib/webrat/core/locators/form_locator.rb +19 -0
  21. data/lib/webrat/core/locators/label_locator.rb +34 -0
  22. data/lib/webrat/core/locators/link_locator.rb +66 -0
  23. data/lib/webrat/core/locators/locator.rb +20 -0
  24. data/lib/webrat/core/locators/select_option_locator.rb +59 -0
  25. data/lib/webrat/core/locators.rb +20 -0
  26. data/lib/webrat/core/logging.rb +21 -0
  27. data/lib/webrat/core/matchers/have_content.rb +73 -0
  28. data/lib/webrat/core/matchers/have_selector.rb +74 -0
  29. data/lib/webrat/core/matchers/have_tag.rb +21 -0
  30. data/lib/webrat/core/matchers/have_xpath.rb +147 -0
  31. data/lib/webrat/core/matchers.rb +4 -0
  32. data/lib/webrat/core/methods.rb +61 -0
  33. data/lib/webrat/core/mime.rb +29 -0
  34. data/lib/webrat/core/save_and_open_page.rb +50 -0
  35. data/lib/webrat/core/scope.rb +350 -0
  36. data/lib/webrat/core/session.rb +281 -0
  37. data/lib/webrat/core/xml/hpricot.rb +19 -0
  38. data/lib/webrat/core/xml/nokogiri.rb +76 -0
  39. data/lib/webrat/core/xml/rexml.rb +24 -0
  40. data/lib/webrat/core/xml.rb +115 -0
  41. data/lib/webrat/core.rb +14 -0
  42. data/lib/webrat/core_extensions/blank.rb +58 -0
  43. data/lib/webrat/core_extensions/deprecate.rb +8 -0
  44. data/lib/webrat/core_extensions/detect_mapped.rb +12 -0
  45. data/lib/webrat/core_extensions/meta_class.rb +6 -0
  46. data/lib/webrat/core_extensions/nil_to_param.rb +5 -0
  47. data/lib/webrat/core_extensions/tcp_socket.rb +27 -0
  48. data/lib/webrat/mechanize.rb +74 -0
  49. data/lib/webrat/merb.rb +9 -0
  50. data/lib/webrat/merb_session.rb +65 -0
  51. data/lib/webrat/rack.rb +24 -0
  52. data/lib/webrat/rails.rb +105 -0
  53. data/lib/webrat/rspec-rails.rb +13 -0
  54. data/lib/webrat/selenium/application_server.rb +71 -0
  55. data/lib/webrat/selenium/location_strategy_javascript/button.js +12 -0
  56. data/lib/webrat/selenium/location_strategy_javascript/label.js +16 -0
  57. data/lib/webrat/selenium/location_strategy_javascript/webrat.js +5 -0
  58. data/lib/webrat/selenium/location_strategy_javascript/webratlink.js +9 -0
  59. data/lib/webrat/selenium/location_strategy_javascript/webratlinkwithin.js +15 -0
  60. data/lib/webrat/selenium/location_strategy_javascript/webratselectwithoption.js +5 -0
  61. data/lib/webrat/selenium/matchers/have_content.rb +66 -0
  62. data/lib/webrat/selenium/matchers/have_selector.rb +49 -0
  63. data/lib/webrat/selenium/matchers/have_tag.rb +72 -0
  64. data/lib/webrat/selenium/matchers/have_xpath.rb +45 -0
  65. data/lib/webrat/selenium/matchers.rb +4 -0
  66. data/lib/webrat/selenium/merb_application_server.rb +48 -0
  67. data/lib/webrat/selenium/rails_application_server.rb +42 -0
  68. data/lib/webrat/selenium/selenium_extensions.js +6 -0
  69. data/lib/webrat/selenium/selenium_rc_server.rb +80 -0
  70. data/lib/webrat/selenium/selenium_session.rb +241 -0
  71. data/lib/webrat/selenium/sinatra_application_server.rb +35 -0
  72. data/lib/webrat/selenium.rb +80 -0
  73. data/lib/webrat/sinatra.rb +44 -0
  74. data/lib/webrat.rb +34 -0
  75. data/vendor/selenium-server.jar +0 -0
  76. metadata +147 -0
@@ -0,0 +1,74 @@
1
+ require "mechanize"
2
+
3
+ module Webrat #:nodoc:
4
+ class MechanizeSession < Session #:nodoc:
5
+
6
+ attr_accessor :response
7
+ alias :page :response
8
+
9
+ def request_page(url, http_method, data) #:nodoc:
10
+ super(absolute_url(url), http_method, data)
11
+ end
12
+
13
+ def get(url, data, headers_argument_not_used = nil)
14
+ @response = mechanize.get(url, data)
15
+ end
16
+
17
+ def post(url, data, headers_argument_not_used = nil)
18
+ post_data = data.inject({}) do |memo, param|
19
+ case param.last
20
+ when Hash
21
+ param.last.each {|attribute, value| memo["#{param.first}[#{attribute}]"] = value }
22
+ else
23
+ memo[param.first] = param.last
24
+ end
25
+ memo
26
+ end
27
+ @response = mechanize.post(url, post_data)
28
+ end
29
+
30
+ def response_body
31
+ @response.content
32
+ end
33
+
34
+ def response_code
35
+ @response.code.to_i
36
+ end
37
+
38
+ def mechanize
39
+ @mechanize ||= WWW::Mechanize.new
40
+ end
41
+
42
+ def_delegators :mechanize, :basic_auth
43
+
44
+ def absolute_url(url) #:nodoc:
45
+ current_host, current_path = split_current_url
46
+ if url =~ Regexp.new('^https?://')
47
+ url
48
+ elsif url =~ Regexp.new('^/')
49
+ current_host + url
50
+ elsif url =~ Regexp.new('^\.')
51
+ current_host + absolute_path(current_path, url)
52
+ else
53
+ url
54
+ end
55
+ end
56
+
57
+ private
58
+ def split_current_url
59
+ current_url =~ Regexp.new('^(https?://[^/]+)(/.*)?')
60
+ [Regexp.last_match(1), Regexp.last_match(2)]
61
+ end
62
+
63
+ def absolute_path(current_path, url)
64
+ levels_up = url.split('/').find_all { |x| x == '..' }.size
65
+ ancestor = if current_path.nil?
66
+ ""
67
+ else
68
+ current_path.split("/")[0..(-1 - levels_up)].join("/")
69
+ end
70
+ descendent = url.split("/")[levels_up..-1]
71
+ "#{ancestor}/#{descendent}"
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,9 @@
1
+ require "webrat"
2
+
3
+ # This is a temporary hack to support backwards compatibility
4
+ # with Merb 1.0.8 until it's updated to use the new Webrat.configure
5
+ # syntax
6
+
7
+ Webrat.configure do |config|
8
+ config.mode = :merb
9
+ end
@@ -0,0 +1,65 @@
1
+ require "webrat"
2
+
3
+ require "cgi"
4
+ gem "extlib"
5
+ require "extlib"
6
+ require "merb-core"
7
+
8
+ # HashWithIndifferentAccess = Mash
9
+
10
+ module Webrat
11
+ class MerbSession < Session #:nodoc:
12
+ include Merb::Test::MakeRequest
13
+
14
+ attr_accessor :response
15
+
16
+ def get(url, data, headers = nil)
17
+ do_request(url, data, headers, "GET")
18
+ end
19
+
20
+ def post(url, data, headers = nil)
21
+ do_request(url, data, headers, "POST")
22
+ end
23
+
24
+ def put(url, data, headers = nil)
25
+ do_request(url, data, headers, "PUT")
26
+ end
27
+
28
+ def delete(url, data, headers = nil)
29
+ do_request(url, data, headers, "DELETE")
30
+ end
31
+
32
+ def response_body
33
+ @response.body.to_s
34
+ end
35
+
36
+ def response_code
37
+ @response.status
38
+ end
39
+
40
+ def do_request(url, data, headers, method)
41
+ @response = request(url,
42
+ :params => (data && data.any?) ? data : nil,
43
+ :headers => headers,
44
+ :method => method)
45
+ end
46
+
47
+ end
48
+ end
49
+
50
+ module Merb #:nodoc:
51
+ module Test #:nodoc:
52
+ module RequestHelper #:nodoc:
53
+ def request(uri, env = {})
54
+ @_webrat_session ||= Webrat::MerbSession.new
55
+ @_webrat_session.response = @_webrat_session.request(uri, env)
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ class Merb::Test::RspecStory #:nodoc:
62
+ def browser
63
+ @browser ||= Webrat::MerbSession.new
64
+ end
65
+ end
@@ -0,0 +1,24 @@
1
+ require 'webrat'
2
+
3
+ class CGIMethods #:nodoc:
4
+ def self.parse_query_parameters(params)
5
+ hash = {}
6
+ params.split('&').each do |p|
7
+ pair = p.split('=')
8
+ hash[pair[0]] = pair[1]
9
+ end
10
+ hash
11
+ end
12
+ end
13
+
14
+ module Webrat
15
+ class RackSession < Session #:nodoc:
16
+ def response_body
17
+ @response.body
18
+ end
19
+
20
+ def response_code
21
+ @response.status
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,105 @@
1
+ require "webrat"
2
+
3
+ require "action_controller"
4
+ require "action_controller/integration"
5
+ require "action_controller/record_identifier"
6
+
7
+ module Webrat
8
+ class RailsSession < Session #:nodoc:
9
+ include ActionController::RecordIdentifier
10
+
11
+ # The Rails version of within supports passing in a model and Webrat
12
+ # will apply a scope based on Rails' dom_id for that model.
13
+ #
14
+ # Example:
15
+ # within User.last do
16
+ # click_link "Delete"
17
+ # end
18
+ def within(selector_or_object, &block)
19
+ if selector_or_object.is_a?(String)
20
+ super
21
+ else
22
+ super('#' + dom_id(selector_or_object), &block)
23
+ end
24
+ end
25
+
26
+ def doc_root
27
+ File.expand_path(File.join(RAILS_ROOT, 'public'))
28
+ end
29
+
30
+ def saved_page_dir
31
+ File.expand_path(File.join(RAILS_ROOT, "tmp"))
32
+ end
33
+
34
+ def get(url, data, headers = nil)
35
+ do_request(:get, url, data, headers)
36
+ end
37
+
38
+ def post(url, data, headers = nil)
39
+ do_request(:post, url, data, headers)
40
+ end
41
+
42
+ def put(url, data, headers = nil)
43
+ do_request(:put, url, data, headers)
44
+ end
45
+
46
+ def delete(url, data, headers = nil)
47
+ do_request(:delete, url, data, headers)
48
+ end
49
+
50
+ def response_body
51
+ response.body
52
+ end
53
+
54
+ def response_code
55
+ response.code.to_i
56
+ end
57
+
58
+ def xml_content_type?
59
+ response.headers["Content-Type"].to_s =~ /xml/
60
+ end
61
+
62
+ protected
63
+
64
+ def integration_session
65
+ @context
66
+ end
67
+
68
+ def do_request(http_method, url, data, headers) #:nodoc:
69
+ update_protocol(url)
70
+ integration_session.send(http_method, normalize_url(url), data, headers)
71
+ end
72
+
73
+ # remove protocol, host and anchor
74
+ def normalize_url(href) #:nodoc:
75
+ uri = URI.parse(href)
76
+ normalized_url = []
77
+ normalized_url << "#{uri.scheme}://" if uri.scheme
78
+ normalized_url << uri.host if uri.host
79
+ normalized_url << ":#{uri.port}" if uri.port && ![80,443].include?(uri.port)
80
+ normalized_url << uri.path if uri.path
81
+ normalized_url << "?#{uri.query}" if uri.query
82
+ normalized_url.join
83
+ end
84
+
85
+ def update_protocol(href) #:nodoc:
86
+ if href =~ /^https:/
87
+ integration_session.https!(true)
88
+ elsif href =~ /^http:/
89
+ integration_session.https!(false)
90
+ end
91
+ end
92
+
93
+ def response #:nodoc:
94
+ integration_session.response
95
+ end
96
+
97
+ end
98
+ end
99
+
100
+ module ActionController #:nodoc:
101
+ IntegrationTest.class_eval do
102
+ include Webrat::Methods
103
+ include Webrat::Matchers
104
+ end
105
+ end
@@ -0,0 +1,13 @@
1
+ # Supports using the matchers in controller, helper, and view specs if you're
2
+ # using rspec-rails. Just add a require statement to spec/spec_helper.rb or env.rb:
3
+ #
4
+ # require 'webrat/rspec-rails'
5
+ #
6
+ require "webrat/core/matchers"
7
+
8
+ Spec::Runner.configure do |config|
9
+ # rspec should support :type => [:controller, :helper, :view] - but until it does ...
10
+ config.include(Webrat::Matchers, :type => :controller)
11
+ config.include(Webrat::Matchers, :type => :helper)
12
+ config.include(Webrat::Matchers, :type => :view)
13
+ end
@@ -0,0 +1,71 @@
1
+ module Webrat
2
+ module Selenium
3
+
4
+ class ApplicationServer
5
+
6
+ def self.boot
7
+ case Webrat.configuration.application_framework
8
+ when :sinatra
9
+ require "webrat/selenium/sinatra_application_server"
10
+ SinatraApplicationServer.new.boot
11
+ when :merb
12
+ require "webrat/selenium/merb_application_server"
13
+ MerbApplicationServer.new.boot
14
+ when :rails
15
+ require "webrat/selenium/rails_application_server"
16
+ RailsApplicationServer.new.boot
17
+ else
18
+ raise WebratError.new(<<-STR)
19
+ Unknown Webrat application_framework: #{Webrat.configuration.application_framework.inspect}
20
+
21
+ Please ensure you have a Webrat configuration block that specifies an application_framework
22
+ in your test_helper.rb, spec_helper.rb, or env.rb (for Cucumber).
23
+
24
+ For example:
25
+
26
+ Webrat.configure do |config|
27
+ # ...
28
+ config.application_framework = :rails
29
+ end
30
+ STR
31
+ end
32
+ end
33
+
34
+ def boot
35
+ start
36
+ wait
37
+ stop_at_exit
38
+ end
39
+
40
+ def stop_at_exit
41
+ at_exit do
42
+ stop
43
+ end
44
+ end
45
+
46
+ def wait
47
+ $stderr.print "==> Waiting for #{Webrat.configuration.application_framework} application server on port #{Webrat.configuration.application_port}... "
48
+ wait_for_socket
49
+ $stderr.print "Ready!\n"
50
+ end
51
+
52
+ def wait_for_socket
53
+ silence_stream(STDOUT) do
54
+ TCPSocket.wait_for_service_with_timeout \
55
+ :host => Webrat.configuration.application_address,
56
+ :port => Webrat.configuration.application_port.to_i,
57
+ :timeout => 30 # seconds
58
+ end
59
+ rescue SocketError
60
+ fail
61
+ end
62
+
63
+ def prepare_pid_file(file_path, pid_file_name)
64
+ FileUtils.mkdir_p File.expand_path(file_path)
65
+ File.expand_path("#{file_path}/#{pid_file_name}")
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,12 @@
1
+ if (locator == '*') {
2
+ return selenium.browserbot.locationStrategies['xpath'].call(this, "//input[@type='submit']", inDocument, inWindow)
3
+ }
4
+ var inputs = inDocument.getElementsByTagName('input');
5
+ return $A(inputs).find(function(candidate){
6
+ inputType = candidate.getAttribute('type');
7
+ if (inputType == 'submit' || inputType == 'image') {
8
+ var buttonText = $F(candidate);
9
+ return (PatternMatcher.matches(locator, buttonText));
10
+ }
11
+ return false;
12
+ });
@@ -0,0 +1,16 @@
1
+ var allLabels = inDocument.getElementsByTagName("label");
2
+ var candidateLabels = $A(allLabels).select(function(candidateLabel){
3
+ var regExp = new RegExp('^' + locator + '\\b', 'i');
4
+ var labelText = getText(candidateLabel).strip();
5
+ return (labelText.search(regExp) >= 0);
6
+ });
7
+ if (candidateLabels.length == 0) {
8
+ return null;
9
+ }
10
+ candidateLabels = candidateLabels.sortBy(function(s) { return s.length * -1; }); //reverse length sort
11
+ var locatedLabel = candidateLabels.first();
12
+ var labelFor = locatedLabel.getAttribute('for');
13
+ if ((labelFor == null) && (locatedLabel.hasChildNodes())) {
14
+ return locatedLabel.firstChild; //TODO: should find the first form field, not just any node
15
+ }
16
+ return selenium.browserbot.locationStrategies['id'].call(this, labelFor, inDocument, inWindow);
@@ -0,0 +1,5 @@
1
+ var locationStrategies = selenium.browserbot.locationStrategies;
2
+ return locationStrategies['id'].call(this, locator, inDocument, inWindow)
3
+ || locationStrategies['name'].call(this, locator, inDocument, inWindow)
4
+ || locationStrategies['label'].call(this, locator, inDocument, inWindow)
5
+ || null;
@@ -0,0 +1,9 @@
1
+ var links = inDocument.getElementsByTagName('a');
2
+ var candidateLinks = $A(links).select(function(candidateLink) {
3
+ return PatternMatcher.matches(locator, getText(candidateLink));
4
+ });
5
+ if (candidateLinks.length == 0) {
6
+ return null;
7
+ }
8
+ candidateLinks = candidateLinks.sortBy(function(s) { return s.length * -1; }); //reverse length sort
9
+ return candidateLinks.first();
@@ -0,0 +1,15 @@
1
+ var locatorParts = locator.split('|');
2
+ var cssAncestor = locatorParts[0];
3
+ var linkText = locatorParts[1];
4
+ var matchingElements = cssQuery(cssAncestor, inDocument);
5
+ var candidateLinks = matchingElements.collect(function(ancestor){
6
+ var links = ancestor.getElementsByTagName('a');
7
+ return $A(links).select(function(candidateLink) {
8
+ return PatternMatcher.matches(linkText, getText(candidateLink));
9
+ });
10
+ }).flatten().compact();
11
+ if (candidateLinks.length == 0) {
12
+ return null;
13
+ }
14
+ candidateLinks = candidateLinks.sortBy(function(s) { return s.length * -1; }); //reverse length sort
15
+ return candidateLinks.first();
@@ -0,0 +1,5 @@
1
+ var optionElements = inDocument.getElementsByTagName('option');
2
+ var locatedOption = $A(optionElements).find(function(candidate){
3
+ return (PatternMatcher.matches(locator, getText(candidate)));
4
+ });
5
+ return locatedOption ? locatedOption.parentNode : null;
@@ -0,0 +1,66 @@
1
+ module Webrat
2
+ module Selenium
3
+ module Matchers
4
+ class HasContent #:nodoc:
5
+ def initialize(content)
6
+ @content = content
7
+ end
8
+
9
+ def matches?(response)
10
+ if @content.is_a?(Regexp)
11
+ text_finder = "regexp:#{@content.source}"
12
+ else
13
+ text_finder = @content
14
+ end
15
+
16
+ response.session.wait_for do
17
+ response.selenium.is_text_present(text_finder)
18
+ end
19
+ rescue Webrat::TimeoutError
20
+ false
21
+ end
22
+
23
+ # ==== Returns
24
+ # String:: The failure message.
25
+ def failure_message
26
+ "expected the following element's content to #{content_message}:\n#{@element}"
27
+ end
28
+
29
+ # ==== Returns
30
+ # String:: The failure message to be displayed in negative matches.
31
+ def negative_failure_message
32
+ "expected the following element's content to not #{content_message}:\n#{@element}"
33
+ end
34
+
35
+ def content_message
36
+ case @content
37
+ when String
38
+ "include \"#{@content}\""
39
+ when Regexp
40
+ "match #{@content.inspect}"
41
+ end
42
+ end
43
+ end
44
+
45
+ # Matches the contents of an HTML document with
46
+ # whatever string is supplied
47
+ def contain(content)
48
+ HasContent.new(content)
49
+ end
50
+
51
+ # Asserts that the body of the response contain
52
+ # the supplied string or regexp
53
+ def assert_contain(content)
54
+ hc = HasContent.new(content)
55
+ assert hc.matches?(response), hc.failure_message
56
+ end
57
+
58
+ # Asserts that the body of the response
59
+ # does not contain the supplied string or regepx
60
+ def assert_not_contain(content)
61
+ hc = HasContent.new(content)
62
+ assert !hc.matches?(response), hc.negative_failure_message
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,49 @@
1
+ module Webrat
2
+ module Selenium
3
+ module Matchers
4
+ class HaveSelector
5
+ def initialize(expected)
6
+ @expected = expected
7
+ end
8
+
9
+ def matches?(response)
10
+ response.session.wait_for do
11
+ response.selenium.is_element_present("css=#{@expected}")
12
+ end
13
+ rescue Webrat::TimeoutError
14
+ false
15
+ end
16
+
17
+ # ==== Returns
18
+ # String:: The failure message.
19
+ def failure_message
20
+ "expected following text to match selector #{@expected}:\n#{@document}"
21
+ end
22
+
23
+ # ==== Returns
24
+ # String:: The failure message to be displayed in negative matches.
25
+ def negative_failure_message
26
+ "expected following text to not match selector #{@expected}:\n#{@document}"
27
+ end
28
+ end
29
+
30
+ def have_selector(content)
31
+ HaveSelector.new(content)
32
+ end
33
+
34
+ # Asserts that the body of the response contains
35
+ # the supplied selector
36
+ def assert_have_selector(expected)
37
+ hs = HaveSelector.new(expected)
38
+ assert hs.matches?(response), hs.failure_message
39
+ end
40
+
41
+ # Asserts that the body of the response
42
+ # does not contain the supplied string or regepx
43
+ def assert_have_no_selector(expected)
44
+ hs = HaveSelector.new(expected)
45
+ assert !hs.matches?(response), hs.negative_failure_message
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,72 @@
1
+ module Webrat
2
+ module Selenium
3
+ module Matchers
4
+
5
+ class HaveTag < HaveSelector #:nodoc:
6
+ # ==== Returns
7
+ # String:: The failure message.
8
+ def failure_message
9
+ "expected following output to contain a #{tag_inspect} tag:\n#{@document}"
10
+ end
11
+
12
+ # ==== Returns
13
+ # String:: The failure message to be displayed in negative matches.
14
+ def negative_failure_message
15
+ "expected following output to omit a #{tag_inspect}:\n#{@document}"
16
+ end
17
+
18
+ def tag_inspect
19
+ options = @expected.last.dup
20
+ content = options.delete(:content)
21
+
22
+ html = "<#{@expected.first}"
23
+ options.each do |k,v|
24
+ html << " #{k}='#{v}'"
25
+ end
26
+
27
+ if content
28
+ html << ">#{content}</#{@expected.first}>"
29
+ else
30
+ html << "/>"
31
+ end
32
+
33
+ html
34
+ end
35
+
36
+ def query
37
+ options = @expected.last.dup
38
+ selector = @expected.first.to_s
39
+
40
+ selector << ":contains('#{options.delete(:content)}')" if options[:content]
41
+
42
+ options.each do |key, value|
43
+ selector << "[#{key}='#{value}']"
44
+ end
45
+
46
+ Nokogiri::CSS.parse(selector).map { |ast| ast.to_xpath }
47
+ end
48
+ end
49
+
50
+ def have_tag(name, attributes = {}, &block)
51
+ HaveTag.new([name, attributes], &block)
52
+ end
53
+
54
+ alias_method :match_tag, :have_tag
55
+
56
+ # Asserts that the body of the response contains
57
+ # the supplied tag with the associated selectors
58
+ def assert_have_tag(name, attributes = {})
59
+ ht = HaveTag.new([name, attributes])
60
+ assert ht.matches?(response), ht.failure_message
61
+ end
62
+
63
+ # Asserts that the body of the response
64
+ # does not contain the supplied string or regepx
65
+ def assert_have_no_tag(name, attributes = {})
66
+ ht = HaveTag.new([name, attributes])
67
+ assert !ht.matches?(response), ht.negative_failure_message
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,45 @@
1
+ module Webrat
2
+ module Selenium
3
+ module Matchers
4
+ class HaveXpath
5
+ def initialize(expected)
6
+ @expected = expected
7
+ end
8
+
9
+ def matches?(response)
10
+ response.session.wait_for do
11
+ response.selenium.is_element_present("xpath=#{@expected}")
12
+ end
13
+ rescue Webrat::TimeoutError
14
+ false
15
+ end
16
+
17
+ # ==== Returns
18
+ # String:: The failure message.
19
+ def failure_message
20
+ "expected following text to match xpath #{@expected}:\n#{@document}"
21
+ end
22
+
23
+ # ==== Returns
24
+ # String:: The failure message to be displayed in negative matches.
25
+ def negative_failure_message
26
+ "expected following text to not match xpath #{@expected}:\n#{@document}"
27
+ end
28
+ end
29
+
30
+ def have_xpath(xpath)
31
+ HaveXpath.new(xpath)
32
+ end
33
+
34
+ def assert_have_xpath(expected)
35
+ hs = HaveXpath.new(expected)
36
+ assert hs.matches?(response), hs.failure_message
37
+ end
38
+
39
+ def assert_have_no_xpath(expected)
40
+ hs = HaveXpath.new(expected)
41
+ assert !hs.matches?(response), hs.negative_failure_message
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,4 @@
1
+ require "webrat/selenium/matchers/have_xpath"
2
+ require "webrat/selenium/matchers/have_selector"
3
+ # require "webrat/selenium/matchers/have_tag"
4
+ require "webrat/selenium/matchers/have_content"