benschwarz-webrat 0.3.2.1

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 (65) hide show
  1. data/History.txt +184 -0
  2. data/MIT-LICENSE.txt +19 -0
  3. data/README.rdoc +81 -0
  4. data/Rakefile +104 -0
  5. data/install.rb +1 -0
  6. data/lib/webrat.rb +34 -0
  7. data/lib/webrat/core.rb +13 -0
  8. data/lib/webrat/core/configuration.rb +44 -0
  9. data/lib/webrat/core/elements/area.rb +31 -0
  10. data/lib/webrat/core/elements/element.rb +29 -0
  11. data/lib/webrat/core/elements/field.rb +386 -0
  12. data/lib/webrat/core/elements/form.rb +103 -0
  13. data/lib/webrat/core/elements/label.rb +31 -0
  14. data/lib/webrat/core/elements/link.rb +94 -0
  15. data/lib/webrat/core/elements/select_option.rb +35 -0
  16. data/lib/webrat/core/locators.rb +20 -0
  17. data/lib/webrat/core/locators/area_locator.rb +38 -0
  18. data/lib/webrat/core/locators/button_locator.rb +54 -0
  19. data/lib/webrat/core/locators/field_by_id_locator.rb +37 -0
  20. data/lib/webrat/core/locators/field_labeled_locator.rb +50 -0
  21. data/lib/webrat/core/locators/field_locator.rb +25 -0
  22. data/lib/webrat/core/locators/field_named_locator.rb +41 -0
  23. data/lib/webrat/core/locators/form_locator.rb +19 -0
  24. data/lib/webrat/core/locators/label_locator.rb +34 -0
  25. data/lib/webrat/core/locators/link_locator.rb +66 -0
  26. data/lib/webrat/core/locators/locator.rb +20 -0
  27. data/lib/webrat/core/locators/select_option_locator.rb +59 -0
  28. data/lib/webrat/core/logging.rb +21 -0
  29. data/lib/webrat/core/matchers.rb +4 -0
  30. data/lib/webrat/core/matchers/have_content.rb +55 -0
  31. data/lib/webrat/core/matchers/have_selector.rb +37 -0
  32. data/lib/webrat/core/matchers/have_tag.rb +57 -0
  33. data/lib/webrat/core/matchers/have_xpath.rb +83 -0
  34. data/lib/webrat/core/methods.rb +54 -0
  35. data/lib/webrat/core/mime.rb +29 -0
  36. data/lib/webrat/core/scope.rb +318 -0
  37. data/lib/webrat/core/session.rb +241 -0
  38. data/lib/webrat/core/xml.rb +99 -0
  39. data/lib/webrat/core/xml/hpricot.rb +19 -0
  40. data/lib/webrat/core/xml/nokogiri.rb +44 -0
  41. data/lib/webrat/core/xml/rexml.rb +24 -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/hash_with_indifferent_access.rb +131 -0
  46. data/lib/webrat/core_extensions/meta_class.rb +6 -0
  47. data/lib/webrat/core_extensions/nil_to_param.rb +5 -0
  48. data/lib/webrat/mechanize.rb +43 -0
  49. data/lib/webrat/merb.rb +77 -0
  50. data/lib/webrat/rack.rb +26 -0
  51. data/lib/webrat/rails.rb +88 -0
  52. data/lib/webrat/rails/redirect_actions.rb +18 -0
  53. data/lib/webrat/rspec-rails.rb +13 -0
  54. data/lib/webrat/selenium.rb +58 -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/selenium_extensions.js +6 -0
  62. data/lib/webrat/selenium/selenium_session.rb +186 -0
  63. data/lib/webrat/sinatra.rb +21 -0
  64. data/vendor/selenium-server.jar +0 -0
  65. metadata +144 -0
@@ -0,0 +1,77 @@
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
+ follow_redirect
46
+ end
47
+
48
+ def follow_redirect
49
+ self.get(@response.headers['Location'], nil, @response.headers) if @response.status == 302
50
+ end
51
+
52
+ end
53
+ end
54
+
55
+ module Merb #:nodoc:
56
+ module Test #:nodoc:
57
+ module RequestHelper #:nodoc:
58
+ def request(uri, env = {})
59
+ @_webrat_session ||= Webrat::MerbSession.new
60
+ @_webrat_session.response = @_webrat_session.request(uri, env)
61
+ end
62
+
63
+ def follow_redirect
64
+ @_webrat_session.follow_redirect
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ class Merb::Test::RspecStory #:nodoc:
71
+ def browser
72
+ @browser ||= Webrat::MerbSession.new
73
+ end
74
+ end
75
+
76
+ Webrat.configuration.mode = :merb
77
+
@@ -0,0 +1,26 @@
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
25
+
26
+ Webrat.configuration.mode = :rack
@@ -0,0 +1,88 @@
1
+ require "webrat"
2
+ require "action_controller/integration"
3
+
4
+ module Webrat
5
+ class RailsSession < Session #:nodoc:
6
+
7
+ def doc_root
8
+ File.expand_path(File.join(RAILS_ROOT, 'public'))
9
+ end
10
+
11
+ def saved_page_dir
12
+ File.expand_path(File.join(RAILS_ROOT, "tmp"))
13
+ end
14
+
15
+ def get(url, data, headers = nil)
16
+ do_request(:get, url, data, headers)
17
+ end
18
+
19
+ def post(url, data, headers = nil)
20
+ do_request(:post, url, data, headers)
21
+ end
22
+
23
+ def put(url, data, headers = nil)
24
+ do_request(:put, url, data, headers)
25
+ end
26
+
27
+ def delete(url, data, headers = nil)
28
+ do_request(:delete, url, data, headers)
29
+ end
30
+
31
+ def response_body
32
+ response.body
33
+ end
34
+
35
+ def response_code
36
+ response.code.to_i
37
+ end
38
+
39
+ protected
40
+
41
+ def integration_session
42
+ @context
43
+ end
44
+
45
+ def do_request(http_method, url, data, headers) #:nodoc:
46
+ update_protocol(url)
47
+ integration_session.request_via_redirect(http_method, remove_protocol(url), data, headers)
48
+ end
49
+
50
+ def remove_protocol(href) #:nodoc:
51
+ if href =~ %r{^https?://www.example.com(/.*)}
52
+ $LAST_MATCH_INFO.captures.first
53
+ else
54
+ href
55
+ end
56
+ end
57
+
58
+ def update_protocol(href) #:nodoc:
59
+ if href =~ /^https:/
60
+ integration_session.https!(true)
61
+ elsif href =~ /^http:/
62
+ integration_session.https!(false)
63
+ end
64
+ end
65
+
66
+ def response #:nodoc:
67
+ integration_session.response
68
+ end
69
+
70
+ end
71
+ end
72
+
73
+ module ActionController #:nodoc:
74
+ module Integration #:nodoc:
75
+ Session.class_eval do
76
+ unless instance_methods.include?("put_via_redirect")
77
+ require "webrat/rails/redirect_actions"
78
+ include Webrat::RedirectActions
79
+ end
80
+ end
81
+ end
82
+
83
+ IntegrationTest.class_eval do
84
+ include Webrat::Methods
85
+ end
86
+ end
87
+
88
+ Webrat.configuration.mode = :rails
@@ -0,0 +1,18 @@
1
+ # For Rails before http://dev.rubyonrails.org/ticket/10497 was committed
2
+ module Webrat
3
+ module RedirectActions #:nodoc:
4
+
5
+ def put_via_redirect(path, parameters = {}, headers = {})
6
+ put path, parameters, headers
7
+ follow_redirect! while redirect?
8
+ status
9
+ end
10
+
11
+ def delete_via_redirect(path, parameters = {}, headers = {})
12
+ delete path, parameters, headers
13
+ follow_redirect! while redirect?
14
+ status
15
+ end
16
+
17
+ end
18
+ 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:
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,58 @@
1
+ require "webrat"
2
+ gem "selenium-client", ">=1.2.9"
3
+ require "selenium/client"
4
+ require "webrat/selenium/selenium_session"
5
+
6
+ Webrat.configuration.mode = :selenium
7
+
8
+ module Webrat
9
+
10
+ def self.with_selenium_server #:nodoc:
11
+ start_selenium_server
12
+ yield
13
+ stop_selenium_server
14
+ end
15
+
16
+ def self.start_selenium_server #:nodoc:
17
+ @remote_control ||= ::Selenium::RemoteControl::RemoteControl.new("0.0.0.0", 4444, 5)
18
+ @remote_control.jar_file = File.expand_path(__FILE__ + "../../../../vendor/selenium-server.jar")
19
+ @remote_control.start :background => true
20
+ TCPSocket.wait_for_service :host => "0.0.0.0", :port => 4444
21
+ end
22
+
23
+ def self.stop_selenium_server #:nodoc:
24
+ @remote_control.stop
25
+ end
26
+
27
+ def self.start_app_server #:nodoc:
28
+ pid_file = File.expand_path(RAILS_ROOT + "/tmp/pids/mongrel_selenium.pid")
29
+ system("mongrel_rails start -d --chdir=#{RAILS_ROOT} --port=3001 --environment=selenium --pid #{pid_file} &")
30
+ TCPSocket.wait_for_service :host => "0.0.0.0", :port => 3001
31
+ end
32
+
33
+ def self.stop_app_server #:nodoc:
34
+ pid_file = File.expand_path(RAILS_ROOT + "/tmp/pids/mongrel_selenium.pid")
35
+ system "mongrel_rails stop -c #{RAILS_ROOT} --pid #{pid_file}"
36
+ end
37
+
38
+ module Selenium #:nodoc:
39
+ module Rails #:nodoc:
40
+ class World < ::ActionController::IntegrationTest
41
+
42
+ def initialize #:nodoc:
43
+ @_result = Test::Unit::TestResult.new
44
+ end
45
+
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ module ::ActionController #:nodoc:
53
+ module Integration #:nodoc:
54
+ class Session #:nodoc:
55
+ include Webrat::Methods
56
+ end
57
+ end
58
+ 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,6 @@
1
+ PatternMatcher.strategies['evalregex'] = function(regexpString) {
2
+ this.regexp = eval(regexpString);
3
+ this.matches = function(actual) {
4
+ return this.regexp.test(actual);
5
+ };
6
+ };
@@ -0,0 +1,186 @@
1
+ module Webrat
2
+ class SeleniumSession
3
+
4
+ def initialize(*args) # :nodoc:
5
+ extend_selenium
6
+ define_location_strategies
7
+ end
8
+
9
+ def visit(url)
10
+ selenium.open(url)
11
+ end
12
+
13
+ webrat_deprecate :visits, :visit
14
+
15
+ def fill_in(field_identifier, options)
16
+ locator = "webrat=#{Regexp.escape(field_identifier)}"
17
+ selenium.type(locator, "#{options[:with]}")
18
+ end
19
+
20
+ webrat_deprecate :fills_in, :fill_in
21
+
22
+ def response_body #:nodoc:
23
+ selenium.get_html_source
24
+ end
25
+
26
+ def click_button(button_text_or_regexp = nil, options = {})
27
+ if button_text_or_regexp.is_a?(Hash) && options == {}
28
+ pattern, options = nil, button_text_or_regexp
29
+ else
30
+ pattern = adjust_if_regexp(button_text_or_regexp)
31
+ end
32
+ pattern ||= '*'
33
+ selenium.click("button=#{pattern}")
34
+ wait_for_result(options[:wait])
35
+ end
36
+
37
+ webrat_deprecate :clicks_button, :click_button
38
+
39
+ def click_link(link_text_or_regexp, options = {})
40
+ pattern = adjust_if_regexp(link_text_or_regexp)
41
+ selenium.click("webratlink=#{pattern}")
42
+ wait_for_result(options[:wait])
43
+ end
44
+
45
+ webrat_deprecate :clicks_link, :click_link
46
+
47
+ def click_link_within(selector, link_text, options = {})
48
+ selenium.click("webratlinkwithin=#{selector}|#{link_text}")
49
+ wait_for_result(options[:wait])
50
+ end
51
+
52
+ webrat_deprecate :clicks_link_within, :click_link_within
53
+
54
+ def wait_for_result(wait_type)
55
+ if wait_type == :ajax
56
+ wait_for_ajax
57
+ elsif wait_type == :effects
58
+ wait_for_effects
59
+ else
60
+ wait_for_page_to_load
61
+ end
62
+ end
63
+
64
+ def wait_for_page_to_load(timeout = 15000)
65
+ selenium.wait_for_page_to_load(timeout)
66
+ end
67
+
68
+ def wait_for_ajax(timeout = 15000)
69
+ selenium.wait_for_condition "Ajax.activeRequestCount == 0", timeout
70
+ end
71
+
72
+ def wait_for_effects(timeout = 15000)
73
+ selenium.wait_for_condition "window.Effect.Queue.size() == 0", timeout
74
+ end
75
+
76
+ def wait_for_ajax_and_effects
77
+ wait_for_ajax
78
+ wait_for_effects
79
+ end
80
+
81
+ def select(option_text, options = {})
82
+ id_or_name_or_label = options[:from]
83
+
84
+ if id_or_name_or_label
85
+ select_locator = "webrat=#{id_or_name_or_label}"
86
+ else
87
+ select_locator = "webratselectwithoption=#{option_text}"
88
+ end
89
+ selenium.select(select_locator, option_text)
90
+ end
91
+
92
+ webrat_deprecate :selects, :select
93
+
94
+ def choose(label_text)
95
+ selenium.click("webrat=#{label_text}")
96
+ end
97
+
98
+ webrat_deprecate :chooses, :choose
99
+
100
+ def check(label_text)
101
+ selenium.check("webrat=#{label_text}")
102
+ end
103
+
104
+ webrat_deprecate :checks, :check
105
+
106
+ def is_ordered(*args) #:nodoc:
107
+ selenium.is_ordered(*args)
108
+ end
109
+
110
+ def dragdrop(*args) #:nodoc:
111
+ selenium.dragdrop(*args)
112
+ end
113
+
114
+ def fire_event(field_identifier, event)
115
+ locator = "webrat=#{Regexp.escape(field_identifier)}"
116
+ selenium.fire_event(locator, "#{event}")
117
+ end
118
+
119
+ def key_down(field_identifier, key_code)
120
+ locator = "webrat=#{Regexp.escape(field_identifier)}"
121
+ selenium.key_down(locator, key_code)
122
+ end
123
+
124
+ def key_up(field_identifier, key_code)
125
+ locator = "webrat=#{Regexp.escape(field_identifier)}"
126
+ selenium.key_up(locator, key_code)
127
+ end
128
+
129
+ def browser
130
+ return $browser if $browser
131
+ setup
132
+ $browser
133
+ end
134
+
135
+ protected
136
+
137
+ def setup #:nodoc:
138
+ silence_stream(STDOUT) do
139
+ Webrat.start_selenium_server
140
+ Webrat.start_app_server
141
+ end
142
+
143
+
144
+ $browser = ::Selenium::Client::Driver.new("localhost", 4444, "*firefox", "http://0.0.0.0:3001")
145
+ $browser.set_speed(0)
146
+ $browser.start
147
+ teardown_at_exit
148
+ end
149
+
150
+ def selenium #:nodoc:
151
+ browser
152
+ end
153
+
154
+ def teardown_at_exit #:nodoc:
155
+ at_exit do
156
+ silence_stream(STDOUT) do
157
+ $browser.stop
158
+ Webrat.stop_app_server
159
+ Webrat.stop_selenium_server
160
+ end
161
+ end
162
+ end
163
+
164
+ def adjust_if_regexp(text_or_regexp) #:nodoc:
165
+ if text_or_regexp.is_a?(Regexp)
166
+ "evalregex:#{text_or_regexp.inspect}"
167
+ else
168
+ text_or_regexp
169
+ end
170
+ end
171
+
172
+ def extend_selenium #:nodoc:
173
+ extensions_file = File.join(File.dirname(__FILE__), "selenium_extensions.js")
174
+ extenions_js = File.read(extensions_file)
175
+ selenium.get_eval(extenions_js)
176
+ end
177
+
178
+ def define_location_strategies #:nodoc:
179
+ Dir[File.join(File.dirname(__FILE__), "location_strategy_javascript", "*.js")].sort.each do |file|
180
+ strategy_js = File.read(file)
181
+ strategy_name = File.basename(file, '.js')
182
+ selenium.add_location_strategy(strategy_name, strategy_js)
183
+ end
184
+ end
185
+ end
186
+ end