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