rcarvalho-capybara 0.4.1.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 (100) hide show
  1. data/History.txt +202 -0
  2. data/README.rdoc +540 -0
  3. data/lib/capybara.rb +231 -0
  4. data/lib/capybara/cucumber.rb +32 -0
  5. data/lib/capybara/driver/base.rb +60 -0
  6. data/lib/capybara/driver/celerity_driver.rb +164 -0
  7. data/lib/capybara/driver/culerity_driver.rb +26 -0
  8. data/lib/capybara/driver/node.rb +78 -0
  9. data/lib/capybara/driver/rack_test_driver.rb +303 -0
  10. data/lib/capybara/driver/selenium_driver.rb +165 -0
  11. data/lib/capybara/dsl.rb +109 -0
  12. data/lib/capybara/node/actions.rb +160 -0
  13. data/lib/capybara/node/base.rb +47 -0
  14. data/lib/capybara/node/document.rb +17 -0
  15. data/lib/capybara/node/element.rb +182 -0
  16. data/lib/capybara/node/finders.rb +201 -0
  17. data/lib/capybara/node/matchers.rb +391 -0
  18. data/lib/capybara/node/simple.rb +116 -0
  19. data/lib/capybara/rails.rb +17 -0
  20. data/lib/capybara/rspec.rb +18 -0
  21. data/lib/capybara/selector.rb +70 -0
  22. data/lib/capybara/server.rb +90 -0
  23. data/lib/capybara/session.rb +281 -0
  24. data/lib/capybara/spec/driver.rb +243 -0
  25. data/lib/capybara/spec/fixtures/capybara.jpg +0 -0
  26. data/lib/capybara/spec/fixtures/test_file.txt +1 -0
  27. data/lib/capybara/spec/public/jquery-ui.js +35 -0
  28. data/lib/capybara/spec/public/jquery.js +19 -0
  29. data/lib/capybara/spec/public/test.js +33 -0
  30. data/lib/capybara/spec/session.rb +110 -0
  31. data/lib/capybara/spec/session/all_spec.rb +78 -0
  32. data/lib/capybara/spec/session/attach_file_spec.rb +70 -0
  33. data/lib/capybara/spec/session/check_spec.rb +65 -0
  34. data/lib/capybara/spec/session/choose_spec.rb +26 -0
  35. data/lib/capybara/spec/session/click_button_spec.rb +252 -0
  36. data/lib/capybara/spec/session/click_link_or_button_spec.rb +36 -0
  37. data/lib/capybara/spec/session/click_link_spec.rb +113 -0
  38. data/lib/capybara/spec/session/current_url_spec.rb +15 -0
  39. data/lib/capybara/spec/session/fill_in_spec.rb +119 -0
  40. data/lib/capybara/spec/session/find_button_spec.rb +18 -0
  41. data/lib/capybara/spec/session/find_by_id_spec.rb +18 -0
  42. data/lib/capybara/spec/session/find_field_spec.rb +26 -0
  43. data/lib/capybara/spec/session/find_link_spec.rb +19 -0
  44. data/lib/capybara/spec/session/find_spec.rb +121 -0
  45. data/lib/capybara/spec/session/first_spec.rb +72 -0
  46. data/lib/capybara/spec/session/has_button_spec.rb +32 -0
  47. data/lib/capybara/spec/session/has_content_spec.rb +106 -0
  48. data/lib/capybara/spec/session/has_css_spec.rb +213 -0
  49. data/lib/capybara/spec/session/has_field_spec.rb +156 -0
  50. data/lib/capybara/spec/session/has_link_spec.rb +37 -0
  51. data/lib/capybara/spec/session/has_select_spec.rb +129 -0
  52. data/lib/capybara/spec/session/has_selector_spec.rb +129 -0
  53. data/lib/capybara/spec/session/has_table_spec.rb +96 -0
  54. data/lib/capybara/spec/session/has_xpath_spec.rb +123 -0
  55. data/lib/capybara/spec/session/headers.rb +19 -0
  56. data/lib/capybara/spec/session/javascript.rb +223 -0
  57. data/lib/capybara/spec/session/response_code.rb +19 -0
  58. data/lib/capybara/spec/session/select_spec.rb +105 -0
  59. data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
  60. data/lib/capybara/spec/session/unselect_spec.rb +61 -0
  61. data/lib/capybara/spec/session/within_spec.rb +160 -0
  62. data/lib/capybara/spec/test_app.rb +117 -0
  63. data/lib/capybara/spec/views/buttons.erb +4 -0
  64. data/lib/capybara/spec/views/fieldsets.erb +29 -0
  65. data/lib/capybara/spec/views/form.erb +348 -0
  66. data/lib/capybara/spec/views/frame_one.erb +8 -0
  67. data/lib/capybara/spec/views/frame_two.erb +8 -0
  68. data/lib/capybara/spec/views/popup_one.erb +8 -0
  69. data/lib/capybara/spec/views/popup_two.erb +8 -0
  70. data/lib/capybara/spec/views/postback.erb +13 -0
  71. data/lib/capybara/spec/views/tables.erb +122 -0
  72. data/lib/capybara/spec/views/with_html.erb +69 -0
  73. data/lib/capybara/spec/views/with_js.erb +39 -0
  74. data/lib/capybara/spec/views/with_scope.erb +36 -0
  75. data/lib/capybara/spec/views/with_simple_html.erb +1 -0
  76. data/lib/capybara/spec/views/within_frames.erb +10 -0
  77. data/lib/capybara/spec/views/within_popups.erb +25 -0
  78. data/lib/capybara/util/save_and_open_page.rb +40 -0
  79. data/lib/capybara/util/timeout.rb +27 -0
  80. data/lib/capybara/version.rb +3 -0
  81. data/spec/basic_node_spec.rb +77 -0
  82. data/spec/capybara_spec.rb +46 -0
  83. data/spec/driver/celerity_driver_spec.rb +13 -0
  84. data/spec/driver/culerity_driver_spec.rb +14 -0
  85. data/spec/driver/rack_test_driver_spec.rb +84 -0
  86. data/spec/driver/remote_culerity_driver_spec.rb +22 -0
  87. data/spec/driver/remote_selenium_driver_spec.rb +16 -0
  88. data/spec/driver/selenium_driver_spec.rb +14 -0
  89. data/spec/dsl_spec.rb +157 -0
  90. data/spec/rspec_spec.rb +47 -0
  91. data/spec/save_and_open_page_spec.rb +159 -0
  92. data/spec/server_spec.rb +85 -0
  93. data/spec/session/celerity_session_spec.rb +24 -0
  94. data/spec/session/culerity_session_spec.rb +26 -0
  95. data/spec/session/rack_test_session_spec.rb +44 -0
  96. data/spec/session/selenium_session_spec.rb +26 -0
  97. data/spec/spec_helper.rb +40 -0
  98. data/spec/string_spec.rb +77 -0
  99. data/spec/timeout_spec.rb +28 -0
  100. metadata +343 -0
@@ -0,0 +1,26 @@
1
+ require 'culerity'
2
+
3
+ class Capybara::Driver::Culerity < Capybara::Driver::Celerity
4
+
5
+ def self.server
6
+ unless @_server
7
+ @_server = ::Culerity::run_server
8
+ at_exit do
9
+ @_server.close
10
+ end
11
+ end
12
+ @_server
13
+ end
14
+
15
+ def browser
16
+ unless @_browser
17
+ @_browser = ::Culerity::RemoteBrowserProxy.new self.class.server, options
18
+ at_exit do
19
+ @_browser.close
20
+ @_browser.exit
21
+ end
22
+ end
23
+ @_browser
24
+ end
25
+
26
+ end
@@ -0,0 +1,78 @@
1
+ module Capybara
2
+ module Driver
3
+ class Node
4
+ attr_reader :driver, :native
5
+
6
+ def initialize(driver, native)
7
+ @driver = driver
8
+ @native = native
9
+ end
10
+
11
+ def text
12
+ raise NotImplementedError
13
+ end
14
+
15
+ def [](name)
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def value
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def set(value)
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def select_option
28
+ raise NotImplementedError
29
+ end
30
+
31
+ def unselect_option
32
+ raise NotImplementedError
33
+ end
34
+
35
+ def click
36
+ raise NotImplementedError
37
+ end
38
+
39
+ def drag_to(element)
40
+ raise NotImplementedError
41
+ end
42
+
43
+ def drag_to_location(right, down)
44
+ raise NotImplementedError
45
+ end
46
+
47
+ def tag_name
48
+ raise NotImplementedError
49
+ end
50
+
51
+ def visible?
52
+ raise NotImplementedError
53
+ end
54
+
55
+ def checked?
56
+ raise NotImplementedError
57
+ end
58
+
59
+ def selected?
60
+ raise NotImplementedError
61
+ end
62
+
63
+ def path
64
+ raise NotSupportedByDriverError
65
+ end
66
+
67
+ def trigger(event)
68
+ raise NotSupportedByDriverError
69
+ end
70
+
71
+ def inspect
72
+ %(#<Capybara::Driver::Node tag="#{tag_name}" path="#{path}">)
73
+ rescue NotSupportedByDriverError
74
+ %(#<Capybara::Driver::Node tag="#{tag_name}">)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,303 @@
1
+ require 'rack/test'
2
+ require 'rack/utils'
3
+ require 'mime/types'
4
+ require 'nokogiri'
5
+ require 'cgi'
6
+
7
+ class Capybara::Driver::RackTest < Capybara::Driver::Base
8
+ class Node < Capybara::Driver::Node
9
+ def text
10
+ native.text
11
+ end
12
+
13
+ def [](name)
14
+ string_node[name]
15
+ end
16
+
17
+ def value
18
+ string_node.value
19
+ end
20
+
21
+ def set(value)
22
+ if tag_name == 'input' and type == 'radio'
23
+ other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name).equals(self[:name])] }.to_s
24
+ driver.html.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") }
25
+ native['checked'] = 'checked'
26
+ elsif tag_name == 'input' and type == 'checkbox'
27
+ if value && !native['checked']
28
+ native['checked'] = 'checked'
29
+ elsif !value && native['checked']
30
+ native.remove_attribute('checked')
31
+ end
32
+ elsif tag_name == 'input'
33
+ native['value'] = value.to_s
34
+ elsif tag_name == "textarea"
35
+ native.content = value.to_s
36
+ end
37
+ end
38
+
39
+ def select_option
40
+ if select_node['multiple'] != 'multiple'
41
+ select_node.find(".//option[@selected]").each { |node| node.native.remove_attribute("selected") }
42
+ end
43
+ native["selected"] = 'selected'
44
+ end
45
+
46
+ def unselect_option
47
+ if select_node['multiple'] != 'multiple'
48
+ raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
49
+ end
50
+ native.remove_attribute('selected')
51
+ end
52
+
53
+ def click
54
+ if tag_name == 'a'
55
+ method = self["data-method"] || :get
56
+ driver.process(method, self[:href].to_s)
57
+ elsif (tag_name == 'input' and %w(submit image).include?(type)) or
58
+ ((tag_name == 'button') and type.nil? or type == "submit")
59
+ Form.new(driver, form).submit(self)
60
+ end
61
+ end
62
+
63
+ def tag_name
64
+ native.node_name
65
+ end
66
+
67
+ def visible?
68
+ string_node.visible?
69
+ end
70
+
71
+ def checked?
72
+ self[:checked]
73
+ end
74
+
75
+ def selected?
76
+ self[:selected]
77
+ end
78
+
79
+ def path
80
+ native.path
81
+ end
82
+
83
+ def find(locator)
84
+ native.xpath(locator).map { |n| self.class.new(driver, n) }
85
+ end
86
+
87
+ private
88
+
89
+ def string_node
90
+ @string_node ||= Capybara::Node::Simple.new(native)
91
+ end
92
+
93
+ # a reference to the select node if this is an option node
94
+ def select_node
95
+ find('./ancestor::select').first
96
+ end
97
+
98
+ def type
99
+ native[:type]
100
+ end
101
+
102
+ def form
103
+ native.ancestors('form').first
104
+ end
105
+ end
106
+
107
+ class Form < Node
108
+ # This only needs to inherit from Rack::Test::UploadedFile because Rack::Test checks for
109
+ # the class specifically when determing whether to consturct the request as multipart.
110
+ # That check should be based solely on the form element's 'enctype' attribute value,
111
+ # which should probably be provided to Rack::Test in its non-GET request methods.
112
+ class NilUploadedFile < Rack::Test::UploadedFile
113
+ def initialize
114
+ @empty_file = Tempfile.new("nil_uploaded_file")
115
+ @empty_file.close
116
+ end
117
+
118
+ def original_filename; ""; end
119
+ def content_type; "application/octet-stream"; end
120
+ def path; @empty_file.path; end
121
+ end
122
+
123
+ def params(button)
124
+ params = {}
125
+
126
+ native.xpath("(.//input|.//select|.//textarea)[not(@disabled)]").map do |field|
127
+ case field.name
128
+ when 'input'
129
+ if %w(radio checkbox).include? field['type']
130
+ merge_param!(params, field['name'].to_s, field['value'].to_s) if field['checked']
131
+ elsif %w(submit image).include? field['type']
132
+ # TO DO identify the click button here (in document order, rather
133
+ # than leaving until the end of the params)
134
+ elsif field['type'] =='file'
135
+ if multipart?
136
+ file = \
137
+ if (value = field['value']).to_s.empty?
138
+ NilUploadedFile.new
139
+ else
140
+ content_type = MIME::Types.type_for(value).first.to_s
141
+ Rack::Test::UploadedFile.new(value, content_type)
142
+ end
143
+ merge_param!(params, field['name'].to_s, file)
144
+ else
145
+ merge_param!(params, field['name'].to_s, File.basename(field['value'].to_s))
146
+ end
147
+ else
148
+ merge_param!(params, field['name'].to_s, field['value'].to_s)
149
+ end
150
+ when 'select'
151
+ if field['multiple'] == 'multiple'
152
+ options = field.xpath(".//option[@selected]")
153
+ options.each do |option|
154
+ merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s)
155
+ end
156
+ else
157
+ option = field.xpath(".//option[@selected]").first
158
+ option ||= field.xpath('.//option').first
159
+ merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) if option
160
+ end
161
+ when 'textarea'
162
+ merge_param!(params, field['name'].to_s, field.text.to_s)
163
+ end
164
+ end
165
+ merge_param!(params, button[:name], button[:value] || "") if button[:name]
166
+ params
167
+ end
168
+
169
+ def submit(button)
170
+ driver.submit(method, native['action'].to_s, params(button))
171
+ end
172
+
173
+ def multipart?
174
+ self[:enctype] == "multipart/form-data"
175
+ end
176
+
177
+ private
178
+
179
+ def method
180
+ self[:method] =~ /post/i ? :post : :get
181
+ end
182
+
183
+ def merge_param!(params, key, value)
184
+ Rack::Utils.normalize_params(params, key, value)
185
+ end
186
+ end
187
+
188
+ include ::Rack::Test::Methods
189
+ attr_reader :app
190
+
191
+ alias_method :response, :last_response
192
+ alias_method :request, :last_request
193
+
194
+ def initialize(app)
195
+ raise ArgumentError, "rack-test requires a rack application, but none was given" unless app
196
+ @app = app
197
+ end
198
+
199
+ def visit(path, attributes = {})
200
+ process(:get, path, attributes)
201
+ end
202
+
203
+ def process(method, path, attributes = {})
204
+ return if path.gsub(/^#{request_path}/, '') =~ /^#/
205
+ path = request_path + path if path =~ /^\?/
206
+ send(method, to_binary(path), to_binary( attributes ), env)
207
+ follow_redirects!
208
+ end
209
+
210
+ def current_url
211
+ request.url rescue ""
212
+ end
213
+
214
+ def response_headers
215
+ response.headers
216
+ end
217
+
218
+ def status_code
219
+ response.status
220
+ end
221
+
222
+ def to_binary(object)
223
+ return object unless Kernel.const_defined?(:Encoding)
224
+
225
+ if object.respond_to?(:force_encoding)
226
+ object.dup.force_encoding(Encoding::ASCII_8BIT)
227
+ elsif object.respond_to?(:each_pair) #Hash
228
+ {}.tap { |x| object.each_pair {|k,v| x[to_binary(k)] = to_binary(v) } }
229
+ elsif object.respond_to?(:each) #Array
230
+ object.map{|x| to_binary(x)}
231
+ else
232
+ object
233
+ end
234
+ end
235
+
236
+ def submit(method, path, attributes)
237
+ path = request_path if not path or path.empty?
238
+ send(method, to_binary(path), to_binary(attributes), env)
239
+ follow_redirects!
240
+ end
241
+
242
+ def find(selector)
243
+ html.xpath(selector).map { |node| Node.new(self, node) }
244
+ end
245
+
246
+ def body
247
+ @body ||= response.body
248
+ end
249
+
250
+ def html
251
+ @html ||= Nokogiri::HTML(body)
252
+ end
253
+ alias_method :source, :body
254
+
255
+ def reset!
256
+ clear_rack_mock_session
257
+ end
258
+
259
+ def get(*args, &block); reset_cache; super; end
260
+ def post(*args, &block); reset_cache; super; end
261
+ def put(*args, &block); reset_cache; super; end
262
+ def delete(*args, &block); reset_cache; super; end
263
+
264
+ def follow_redirects!
265
+ 5.times do
266
+ follow_redirect! if response.redirect?
267
+ end
268
+ raise Capybara::InfiniteRedirectError, "redirected more than 5 times, check for infinite redirects." if response.redirect?
269
+ end
270
+
271
+ private
272
+
273
+ def reset_cache
274
+ @body = nil
275
+ @html = nil
276
+ end
277
+
278
+ def build_rack_mock_session # :nodoc:
279
+ Rack::MockSession.new(app, Capybara.default_host || "www.example.com")
280
+ end
281
+
282
+ # Rack::Test::Methods does not provide methods for manipulating the session
283
+ # list so these must be manipulated directly.
284
+ def clear_rack_mock_session
285
+ @_rack_test_sessions = nil
286
+ @_rack_mock_sessions = nil
287
+ end
288
+
289
+ def request_path
290
+ request.path rescue ""
291
+ end
292
+
293
+ def env
294
+ env = {}
295
+ begin
296
+ env["HTTP_REFERER"] = request.url
297
+ rescue Rack::Test::Error
298
+ # no request yet
299
+ end
300
+ env
301
+ end
302
+
303
+ end
@@ -0,0 +1,165 @@
1
+ require 'selenium-webdriver'
2
+
3
+ class Capybara::Driver::Selenium < Capybara::Driver::Base
4
+ class Node < Capybara::Driver::Node
5
+ def text
6
+ native.text
7
+ end
8
+
9
+ def [](name)
10
+ if name == :value
11
+ value
12
+ else
13
+ native.attribute(name.to_s)
14
+ end
15
+ rescue Selenium::WebDriver::Error::WebDriverError
16
+ nil
17
+ end
18
+
19
+ def value
20
+ if tag_name == "select" and self[:multiple] and not self[:multiple] == "false"
21
+ native.find_elements(:xpath, ".//option").select { |n| n.selected? }.map { |n| n.value || n.text }
22
+ else
23
+ native.value
24
+ end
25
+ end
26
+
27
+ def set(value)
28
+ if tag_name == 'input' and type == 'radio'
29
+ native.click
30
+ elsif tag_name == 'input' and type == 'checkbox'
31
+ native.click if value ^ native.attribute('checked').to_s.eql?("true")
32
+ elsif tag_name == 'textarea' or tag_name == 'input'
33
+ native.clear
34
+ native.send_keys(value.to_s)
35
+ end
36
+ end
37
+
38
+ def select_option
39
+ native.select
40
+ end
41
+
42
+ def unselect_option
43
+ if select_node['multiple'] != 'multiple' and select_node['multiple'] != 'true'
44
+ raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
45
+ end
46
+ native.toggle if selected?
47
+ end
48
+
49
+ def click
50
+ native.click
51
+ end
52
+
53
+ def drag_to(element)
54
+ native.drag_and_drop_on(element.native)
55
+ end
56
+
57
+ def drag_to_location(right,down)
58
+ node.drag_and_drop_by(right,down)
59
+ end
60
+
61
+ def tag_name
62
+ native.tag_name
63
+ end
64
+
65
+ def visible?
66
+ displayed = native.displayed?
67
+ displayed and displayed != "false"
68
+ end
69
+
70
+ def selected?
71
+ selected = native.selected?
72
+ selected and selected != "false"
73
+ end
74
+
75
+ alias :checked? :selected?
76
+
77
+ def find(locator)
78
+ native.find_elements(:xpath, locator).map { |n| self.class.new(driver, n) }
79
+ end
80
+
81
+ private
82
+
83
+ # a reference to the select node if this is an option node
84
+ def select_node
85
+ find('./ancestor::select').first
86
+ end
87
+
88
+ def type
89
+ self[:type]
90
+ end
91
+
92
+ end
93
+
94
+ attr_reader :app, :rack_server, :options
95
+
96
+ def browser
97
+ unless @browser
98
+ @browser = Selenium::WebDriver.for(options[:browser] || :firefox, options)
99
+ at_exit do
100
+ @browser.quit
101
+ end
102
+ end
103
+ @browser
104
+ end
105
+
106
+ def initialize(app, options={})
107
+ @app = app
108
+ @options = options
109
+ @rack_server = Capybara::Server.new(@app)
110
+ @rack_server.boot if Capybara.run_server
111
+ end
112
+
113
+ def visit(path)
114
+ browser.navigate.to(url(path))
115
+ end
116
+
117
+ def source
118
+ browser.page_source
119
+ end
120
+
121
+ def body
122
+ browser.page_source
123
+ end
124
+
125
+ def current_url
126
+ browser.current_url
127
+ end
128
+
129
+ def find(selector)
130
+ browser.find_elements(:xpath, selector).map { |node| Node.new(self, node) }
131
+ end
132
+
133
+ def wait?; true; end
134
+
135
+ def execute_script(script)
136
+ browser.execute_script script
137
+ end
138
+
139
+ def evaluate_script(script)
140
+ browser.execute_script "return #{script}"
141
+ end
142
+
143
+ def reset!
144
+ # Use instance variable directly so we avoid starting the browser just to reset the session
145
+ @browser.manage.delete_all_cookies if @browser
146
+ end
147
+
148
+ def within_frame(frame_id)
149
+ old_window = browser.window_handle
150
+ browser.switch_to.frame(frame_id)
151
+ yield
152
+ browser.switch_to.window old_window
153
+ end
154
+
155
+ def within_window(handle, &blk)
156
+ browser.switch_to.window(handle, &blk)
157
+ end
158
+
159
+ private
160
+
161
+ def url(path)
162
+ rack_server.url(path)
163
+ end
164
+
165
+ end