dbrady-webrat 0.4.4

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 (70) hide show
  1. data/History.txt +325 -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.rb +34 -0
  7. data/lib/webrat/core.rb +14 -0
  8. data/lib/webrat/core/configuration.rb +98 -0
  9. data/lib/webrat/core/elements/area.rb +31 -0
  10. data/lib/webrat/core/elements/element.rb +33 -0
  11. data/lib/webrat/core/elements/field.rb +403 -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 +92 -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 +56 -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 +73 -0
  31. data/lib/webrat/core/matchers/have_selector.rb +74 -0
  32. data/lib/webrat/core/matchers/have_tag.rb +21 -0
  33. data/lib/webrat/core/matchers/have_xpath.rb +147 -0
  34. data/lib/webrat/core/methods.rb +61 -0
  35. data/lib/webrat/core/mime.rb +29 -0
  36. data/lib/webrat/core/save_and_open_page.rb +50 -0
  37. data/lib/webrat/core/scope.rb +350 -0
  38. data/lib/webrat/core/session.rb +281 -0
  39. data/lib/webrat/core/xml.rb +115 -0
  40. data/lib/webrat/core/xml/hpricot.rb +19 -0
  41. data/lib/webrat/core/xml/nokogiri.rb +76 -0
  42. data/lib/webrat/core/xml/rexml.rb +24 -0
  43. data/lib/webrat/core_extensions/blank.rb +58 -0
  44. data/lib/webrat/core_extensions/deprecate.rb +8 -0
  45. data/lib/webrat/core_extensions/detect_mapped.rb +12 -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 +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.rb +80 -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.rb +4 -0
  62. data/lib/webrat/selenium/matchers/have_content.rb +66 -0
  63. data/lib/webrat/selenium/matchers/have_selector.rb +49 -0
  64. data/lib/webrat/selenium/matchers/have_tag.rb +72 -0
  65. data/lib/webrat/selenium/matchers/have_xpath.rb +45 -0
  66. data/lib/webrat/selenium/selenium_extensions.js +6 -0
  67. data/lib/webrat/selenium/selenium_session.rb +241 -0
  68. data/lib/webrat/sinatra.rb +53 -0
  69. data/vendor/selenium-server.jar +0 -0
  70. metadata +141 -0
@@ -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,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"
@@ -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,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,241 @@
1
+ require "webrat/core/save_and_open_page"
2
+ require "webrat/selenium/selenium_rc_server"
3
+ require "webrat/selenium/application_server"
4
+
5
+ module Webrat
6
+ class TimeoutError < WebratError
7
+ end
8
+
9
+ class SeleniumResponse
10
+ attr_reader :body
11
+ attr_reader :session
12
+
13
+ def initialize(session, body)
14
+ @session = session
15
+ @body = body
16
+ end
17
+
18
+ def selenium
19
+ session.selenium
20
+ end
21
+ end
22
+
23
+ class SeleniumSession
24
+ include Webrat::SaveAndOpenPage
25
+
26
+ def initialize(*args) # :nodoc:
27
+ end
28
+
29
+ def simulate
30
+ end
31
+
32
+ def automate
33
+ yield
34
+ end
35
+
36
+ def visit(url)
37
+ selenium.open(url)
38
+ end
39
+
40
+ webrat_deprecate :visits, :visit
41
+
42
+ def fill_in(field_identifier, options)
43
+ locator = "webrat=#{Regexp.escape(field_identifier)}"
44
+ selenium.wait_for_element locator, :timeout_in_seconds => 5
45
+ selenium.type(locator, "#{options[:with]}")
46
+ end
47
+
48
+ webrat_deprecate :fills_in, :fill_in
49
+
50
+ def response
51
+ SeleniumResponse.new(self, response_body)
52
+ end
53
+
54
+ def response_body #:nodoc:
55
+ selenium.get_html_source
56
+ end
57
+
58
+ def click_button(button_text_or_regexp = nil, options = {})
59
+ if button_text_or_regexp.is_a?(Hash) && options == {}
60
+ pattern, options = nil, button_text_or_regexp
61
+ elsif button_text_or_regexp
62
+ pattern = adjust_if_regexp(button_text_or_regexp)
63
+ end
64
+ pattern ||= '*'
65
+ locator = "button=#{pattern}"
66
+
67
+ selenium.wait_for_element locator, :timeout_in_seconds => 5
68
+ selenium.click locator
69
+ end
70
+
71
+ webrat_deprecate :clicks_button, :click_button
72
+
73
+ def click_link(link_text_or_regexp, options = {})
74
+ pattern = adjust_if_regexp(link_text_or_regexp)
75
+ locator = "webratlink=#{pattern}"
76
+ selenium.wait_for_element locator, :timeout_in_seconds => 5
77
+ selenium.click locator
78
+ end
79
+
80
+ webrat_deprecate :clicks_link, :click_link
81
+
82
+ def click_link_within(selector, link_text, options = {})
83
+ locator = "webratlinkwithin=#{selector}|#{link_text}"
84
+ selenium.wait_for_element locator, :timeout_in_seconds => 5
85
+ selenium.click locator
86
+ end
87
+
88
+ webrat_deprecate :clicks_link_within, :click_link_within
89
+
90
+ def select(option_text, options = {})
91
+ id_or_name_or_label = options[:from]
92
+
93
+ if id_or_name_or_label
94
+ select_locator = "webrat=#{id_or_name_or_label}"
95
+ else
96
+ select_locator = "webratselectwithoption=#{option_text}"
97
+ end
98
+
99
+ selenium.wait_for_element select_locator, :timeout_in_seconds => 5
100
+ selenium.select(select_locator, option_text)
101
+ end
102
+
103
+ webrat_deprecate :selects, :select
104
+
105
+ def choose(label_text)
106
+ locator = "webrat=#{label_text}"
107
+ selenium.wait_for_element locator, :timeout_in_seconds => 5
108
+ selenium.click locator
109
+ end
110
+
111
+ webrat_deprecate :chooses, :choose
112
+
113
+ def check(label_text)
114
+ locator = "webrat=#{label_text}"
115
+ selenium.wait_for_element locator, :timeout_in_seconds => 5
116
+ selenium.click locator
117
+ end
118
+ alias_method :uncheck, :check
119
+
120
+ webrat_deprecate :checks, :check
121
+
122
+ def fire_event(field_identifier, event)
123
+ locator = "webrat=#{Regexp.escape(field_identifier)}"
124
+ selenium.fire_event(locator, "#{event}")
125
+ end
126
+
127
+ def key_down(field_identifier, key_code)
128
+ locator = "webrat=#{Regexp.escape(field_identifier)}"
129
+ selenium.key_down(locator, key_code)
130
+ end
131
+
132
+ def key_up(field_identifier, key_code)
133
+ locator = "webrat=#{Regexp.escape(field_identifier)}"
134
+ selenium.key_up(locator, key_code)
135
+ end
136
+
137
+ def wait_for(params={})
138
+ timeout = params[:timeout] || 5
139
+ message = params[:message] || "Timeout exceeded"
140
+
141
+ begin_time = Time.now
142
+
143
+ while (Time.now - begin_time) < timeout
144
+ value = nil
145
+
146
+ begin
147
+ value = yield
148
+ rescue ::Spec::Expectations::ExpectationNotMetError, ::Selenium::CommandError, Webrat::WebratError
149
+ value = nil
150
+ end
151
+
152
+ return value if value
153
+
154
+ sleep 0.25
155
+ end
156
+
157
+ raise Webrat::TimeoutError.new(message + " (after #{timeout} sec)")
158
+ true
159
+ end
160
+
161
+ def selenium
162
+ return $browser if $browser
163
+ setup
164
+ $browser
165
+ end
166
+
167
+ webrat_deprecate :browser, :selenium
168
+
169
+
170
+ def save_and_open_screengrab
171
+ return unless File.exist?(saved_page_dir)
172
+
173
+ filename = "#{saved_page_dir}/webrat-#{Time.now.to_i}.png"
174
+
175
+ if $browser.chrome_backend?
176
+ $browser.capture_entire_page_screenshot(filename, '')
177
+ else
178
+ $browser.capture_screenshot(filename)
179
+ end
180
+ open_in_browser(filename)
181
+ end
182
+
183
+ protected
184
+
185
+ def silence_stream(stream)
186
+ old_stream = stream.dup
187
+ stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
188
+ stream.sync = true
189
+ yield
190
+ ensure
191
+ stream.reopen(old_stream)
192
+ end
193
+
194
+ def setup #:nodoc:
195
+ Webrat::Selenium::SeleniumRCServer.boot
196
+ Webrat::Selenium::ApplicationServer.boot
197
+
198
+ create_browser
199
+ $browser.start
200
+
201
+ extend_selenium
202
+ define_location_strategies
203
+ $browser.window_maximize
204
+ end
205
+
206
+
207
+ def create_browser
208
+ $browser = ::Selenium::Client::Driver.new(Webrat.configuration.selenium_server_address || "localhost",
209
+ Webrat.configuration.selenium_server_port, Webrat.configuration.selenium_browser_key, "http://#{Webrat.configuration.application_address}:#{Webrat.configuration.application_port}")
210
+ $browser.set_speed(0) unless Webrat.configuration.selenium_server_address
211
+
212
+ at_exit do
213
+ silence_stream(STDOUT) do
214
+ $browser.stop
215
+ end
216
+ end
217
+ end
218
+
219
+ def adjust_if_regexp(text_or_regexp) #:nodoc:
220
+ if text_or_regexp.is_a?(Regexp)
221
+ "evalregex:#{text_or_regexp.inspect}"
222
+ else
223
+ "evalregex:/#{text_or_regexp}/"
224
+ end
225
+ end
226
+
227
+ def extend_selenium #:nodoc:
228
+ extensions_file = File.join(File.dirname(__FILE__), "selenium_extensions.js")
229
+ extenions_js = File.read(extensions_file)
230
+ selenium.get_eval(extenions_js)
231
+ end
232
+
233
+ def define_location_strategies #:nodoc:
234
+ Dir[File.join(File.dirname(__FILE__), "location_strategy_javascript", "*.js")].sort.each do |file|
235
+ strategy_js = File.read(file)
236
+ strategy_name = File.basename(file, '.js')
237
+ selenium.add_location_strategy(strategy_name, strategy_js)
238
+ end
239
+ end
240
+ end
241
+ end