capybara 0.4.1.2 → 1.0.0.beta1

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 (69) hide show
  1. data/History.txt +46 -0
  2. data/README.rdoc +211 -64
  3. data/lib/capybara.rb +31 -15
  4. data/lib/capybara/cucumber.rb +12 -16
  5. data/lib/capybara/dsl.rb +65 -28
  6. data/lib/capybara/node/actions.rb +7 -5
  7. data/lib/capybara/node/document.rb +8 -0
  8. data/lib/capybara/node/finders.rb +11 -7
  9. data/lib/capybara/node/matchers.rb +32 -6
  10. data/lib/capybara/node/simple.rb +20 -0
  11. data/lib/capybara/rack_test/browser.rb +115 -0
  12. data/lib/capybara/rack_test/driver.rb +77 -0
  13. data/lib/capybara/rack_test/form.rb +80 -0
  14. data/lib/capybara/rack_test/node.rb +101 -0
  15. data/lib/capybara/rspec.rb +11 -3
  16. data/lib/capybara/rspec/features.rb +22 -0
  17. data/lib/capybara/rspec/matchers.rb +146 -0
  18. data/lib/capybara/selector.rb +27 -8
  19. data/lib/capybara/selenium/driver.rb +148 -0
  20. data/lib/capybara/selenium/node.rb +91 -0
  21. data/lib/capybara/session.rb +42 -15
  22. data/lib/capybara/spec/driver.rb +55 -1
  23. data/lib/capybara/spec/fixtures/capybara.jpg +0 -0
  24. data/lib/capybara/spec/public/test.js +7 -2
  25. data/lib/capybara/spec/session.rb +51 -7
  26. data/lib/capybara/spec/session/attach_file_spec.rb +9 -6
  27. data/lib/capybara/spec/session/click_button_spec.rb +35 -0
  28. data/lib/capybara/spec/session/current_host_spec.rb +62 -0
  29. data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
  30. data/lib/capybara/spec/session/find_spec.rb +23 -1
  31. data/lib/capybara/spec/session/first_spec.rb +39 -6
  32. data/lib/capybara/spec/session/has_css_spec.rb +30 -0
  33. data/lib/capybara/spec/session/has_field_spec.rb +47 -11
  34. data/lib/capybara/spec/session/javascript.rb +0 -1
  35. data/lib/capybara/spec/session/text_spec.rb +19 -0
  36. data/lib/capybara/spec/test_app.rb +9 -0
  37. data/lib/capybara/spec/views/form.erb +8 -3
  38. data/lib/capybara/spec/views/header_links.erb +7 -0
  39. data/lib/capybara/spec/views/host_links.erb +12 -0
  40. data/lib/capybara/spec/views/with_html.erb +6 -2
  41. data/lib/capybara/spec/views/with_html_entities.erb +1 -0
  42. data/lib/capybara/spec/views/with_js.erb +4 -0
  43. data/lib/capybara/util/save_and_open_page.rb +7 -3
  44. data/lib/capybara/util/timeout.rb +2 -2
  45. data/lib/capybara/version.rb +1 -1
  46. data/spec/capybara_spec.rb +1 -1
  47. data/spec/driver/rack_test_driver_spec.rb +24 -2
  48. data/spec/driver/selenium_driver_spec.rb +2 -1
  49. data/spec/dsl_spec.rb +56 -4
  50. data/spec/rspec/features_spec.rb +45 -0
  51. data/spec/rspec/matchers_spec.rb +451 -0
  52. data/spec/rspec_spec.rb +9 -2
  53. data/spec/save_and_open_page_spec.rb +9 -13
  54. data/spec/server_spec.rb +4 -0
  55. data/spec/session/rack_test_session_spec.rb +2 -2
  56. data/spec/session/selenium_session_spec.rb +1 -1
  57. data/spec/spec_helper.rb +0 -14
  58. data/spec/string_spec.rb +1 -1
  59. metadata +60 -69
  60. data/lib/capybara/driver/celerity_driver.rb +0 -164
  61. data/lib/capybara/driver/culerity_driver.rb +0 -26
  62. data/lib/capybara/driver/rack_test_driver.rb +0 -303
  63. data/lib/capybara/driver/selenium_driver.rb +0 -161
  64. data/spec/driver/celerity_driver_spec.rb +0 -13
  65. data/spec/driver/culerity_driver_spec.rb +0 -14
  66. data/spec/driver/remote_culerity_driver_spec.rb +0 -22
  67. data/spec/driver/remote_selenium_driver_spec.rb +0 -16
  68. data/spec/session/celerity_session_spec.rb +0 -24
  69. data/spec/session/culerity_session_spec.rb +0 -26
@@ -1,164 +0,0 @@
1
- class Capybara::Driver::Celerity < Capybara::Driver::Base
2
- class Node < Capybara::Driver::Node
3
- def text
4
- native.text
5
- end
6
-
7
- def [](name)
8
- value = native.attribute_value(name.to_sym)
9
- return value if value and not value.to_s.empty?
10
- end
11
-
12
- def value
13
- if tag_name == "select" and native.multiple?
14
- find(".//option[@selected]").map { |n| if n.has_value? then n.value else n.text end }
15
- else
16
- native.value
17
- end
18
- end
19
-
20
- def set(value)
21
- native.set(value)
22
- end
23
-
24
- def select_option
25
- native.click
26
- end
27
-
28
- def unselect_option
29
- unless select_node.native.multiple?
30
- raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
31
- end
32
-
33
- # FIXME: couldn't find a clean way to unselect, so clear and reselect
34
- selected_nodes = select_node.find('.//option[@selected]')
35
- select_node.native.clear
36
- selected_nodes.each { |n| n.click unless n.path == path }
37
- end
38
-
39
- def click
40
- native.click
41
- end
42
-
43
- def drag_to(element)
44
- native.fire_event('mousedown')
45
- element.native.fire_event('mousemove')
46
- element.native.fire_event('mouseup')
47
- end
48
-
49
- def tag_name
50
- # FIXME: this might be the dumbest way ever of getting the tag name
51
- # there has to be something better...
52
- native.to_xml[/^\s*<([a-z0-9\-\:]+)/, 1]
53
- end
54
-
55
- def visible?
56
- native.visible?
57
- end
58
-
59
- def checked?
60
- native.checked?
61
- rescue # https://github.com/langalex/culerity/issues/issue/33
62
- false
63
- end
64
-
65
- def selected?
66
- native.selected?
67
- rescue # https://github.com/langalex/culerity/issues/issue/33
68
- false
69
- end
70
-
71
- def path
72
- native.xpath
73
- end
74
-
75
- def trigger(event)
76
- native.fire_event(event.to_s)
77
- end
78
-
79
- def find(locator)
80
- noko_node = Nokogiri::HTML(driver.body).xpath(native.xpath).first
81
- all_nodes = noko_node.xpath(locator).map { |n| n.path }.join(' | ')
82
- if all_nodes.empty? then [] else driver.find(all_nodes) end
83
- end
84
-
85
- protected
86
-
87
- # a reference to the select node if this is an option node
88
- def select_node
89
- find('./ancestor::select').first
90
- end
91
-
92
- def has_value?
93
- native.object.hasAttribute('value')
94
- end
95
- end
96
-
97
- attr_reader :app, :rack_server, :options
98
-
99
- def initialize(app, options={})
100
- @app = app
101
- @options = options
102
- @rack_server = Capybara::Server.new(@app)
103
- @rack_server.boot if Capybara.run_server
104
- end
105
-
106
- def visit(path)
107
- browser.goto(url(path))
108
- end
109
-
110
- def current_url
111
- browser.url
112
- end
113
-
114
- def source
115
- browser.html
116
- end
117
-
118
- def body
119
- browser.document.as_xml
120
- end
121
-
122
- def response_headers
123
- browser.response_headers
124
- end
125
-
126
- def status_code
127
- browser.status_code
128
- end
129
-
130
- def find(selector)
131
- browser.elements_by_xpath(selector).map { |node| Node.new(self, node) }
132
- end
133
-
134
- def wait?; true; end
135
-
136
- def execute_script(script)
137
- browser.execute_script script
138
- nil
139
- end
140
-
141
- def evaluate_script(script)
142
- browser.execute_script "#{script}"
143
- end
144
-
145
- def browser
146
- unless @_browser
147
- require 'celerity'
148
- @_browser = ::Celerity::Browser.new(options)
149
- end
150
-
151
- @_browser
152
- end
153
-
154
- def reset!
155
- browser.clear_cookies
156
- end
157
-
158
- private
159
-
160
- def url(path)
161
- rack_server.url(path)
162
- end
163
-
164
- end
@@ -1,26 +0,0 @@
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
@@ -1,303 +0,0 @@
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