pr0d1r2-capybara 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/History.txt +71 -0
  2. data/README.rdoc +388 -0
  3. data/lib/capybara.rb +57 -0
  4. data/lib/capybara/cucumber.rb +32 -0
  5. data/lib/capybara/driver/base.rb +48 -0
  6. data/lib/capybara/driver/celerity_driver.rb +143 -0
  7. data/lib/capybara/driver/culerity_driver.rb +25 -0
  8. data/lib/capybara/driver/rack_test_driver.rb +271 -0
  9. data/lib/capybara/driver/selenium_driver.rb +161 -0
  10. data/lib/capybara/dsl.rb +60 -0
  11. data/lib/capybara/node.rb +60 -0
  12. data/lib/capybara/rails.rb +17 -0
  13. data/lib/capybara/save_and_open_page.rb +33 -0
  14. data/lib/capybara/searchable.rb +54 -0
  15. data/lib/capybara/server.rb +114 -0
  16. data/lib/capybara/session.rb +262 -0
  17. data/lib/capybara/spec/driver.rb +162 -0
  18. data/lib/capybara/spec/fixtures/capybara.jpg +0 -0
  19. data/lib/capybara/spec/fixtures/test_file.txt +1 -0
  20. data/lib/capybara/spec/public/jquery-ui.js +35 -0
  21. data/lib/capybara/spec/public/jquery.js +19 -0
  22. data/lib/capybara/spec/public/test.js +33 -0
  23. data/lib/capybara/spec/session.rb +81 -0
  24. data/lib/capybara/spec/session/all_spec.rb +69 -0
  25. data/lib/capybara/spec/session/attach_file_spec.rb +64 -0
  26. data/lib/capybara/spec/session/check_spec.rb +67 -0
  27. data/lib/capybara/spec/session/choose_spec.rb +26 -0
  28. data/lib/capybara/spec/session/click_button_spec.rb +236 -0
  29. data/lib/capybara/spec/session/click_link_spec.rb +108 -0
  30. data/lib/capybara/spec/session/click_spec.rb +24 -0
  31. data/lib/capybara/spec/session/current_url_spec.rb +8 -0
  32. data/lib/capybara/spec/session/fill_in_spec.rb +108 -0
  33. data/lib/capybara/spec/session/find_button_spec.rb +16 -0
  34. data/lib/capybara/spec/session/find_by_id_spec.rb +16 -0
  35. data/lib/capybara/spec/session/find_field_spec.rb +22 -0
  36. data/lib/capybara/spec/session/find_link_spec.rb +17 -0
  37. data/lib/capybara/spec/session/find_spec.rb +57 -0
  38. data/lib/capybara/spec/session/has_button_spec.rb +32 -0
  39. data/lib/capybara/spec/session/has_content_spec.rb +106 -0
  40. data/lib/capybara/spec/session/has_css_spec.rb +107 -0
  41. data/lib/capybara/spec/session/has_field_spec.rb +96 -0
  42. data/lib/capybara/spec/session/has_link_spec.rb +33 -0
  43. data/lib/capybara/spec/session/has_select_spec.rb +89 -0
  44. data/lib/capybara/spec/session/has_table_spec.rb +96 -0
  45. data/lib/capybara/spec/session/has_xpath_spec.rb +123 -0
  46. data/lib/capybara/spec/session/headers.rb +19 -0
  47. data/lib/capybara/spec/session/javascript.rb +204 -0
  48. data/lib/capybara/spec/session/locate_spec.rb +59 -0
  49. data/lib/capybara/spec/session/select_spec.rb +77 -0
  50. data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
  51. data/lib/capybara/spec/session/unselect_spec.rb +54 -0
  52. data/lib/capybara/spec/session/within_spec.rb +153 -0
  53. data/lib/capybara/spec/test_app.rb +75 -0
  54. data/lib/capybara/spec/views/buttons.erb +4 -0
  55. data/lib/capybara/spec/views/fieldsets.erb +29 -0
  56. data/lib/capybara/spec/views/form.erb +234 -0
  57. data/lib/capybara/spec/views/frame_one.erb +8 -0
  58. data/lib/capybara/spec/views/frame_two.erb +8 -0
  59. data/lib/capybara/spec/views/postback.erb +13 -0
  60. data/lib/capybara/spec/views/tables.erb +122 -0
  61. data/lib/capybara/spec/views/with_html.erb +42 -0
  62. data/lib/capybara/spec/views/with_js.erb +39 -0
  63. data/lib/capybara/spec/views/with_scope.erb +36 -0
  64. data/lib/capybara/spec/views/with_simple_html.erb +1 -0
  65. data/lib/capybara/spec/views/within_frames.erb +10 -0
  66. data/lib/capybara/version.rb +3 -0
  67. data/lib/capybara/wait_until.rb +28 -0
  68. data/lib/capybara/xpath.rb +179 -0
  69. data/spec/capybara_spec.rb +18 -0
  70. data/spec/driver/celerity_driver_spec.rb +16 -0
  71. data/spec/driver/culerity_driver_spec.rb +12 -0
  72. data/spec/driver/rack_test_driver_spec.rb +11 -0
  73. data/spec/driver/remote_culerity_driver_spec.rb +23 -0
  74. data/spec/driver/remote_selenium_driver_spec.rb +18 -0
  75. data/spec/driver/selenium_driver_spec.rb +11 -0
  76. data/spec/dsl_spec.rb +140 -0
  77. data/spec/save_and_open_page_spec.rb +43 -0
  78. data/spec/searchable_spec.rb +66 -0
  79. data/spec/server_spec.rb +53 -0
  80. data/spec/session/celerity_session_spec.rb +27 -0
  81. data/spec/session/culerity_session_spec.rb +25 -0
  82. data/spec/session/rack_test_session_spec.rb +33 -0
  83. data/spec/session/selenium_session_spec.rb +25 -0
  84. data/spec/spec_helper.rb +19 -0
  85. data/spec/wait_until_spec.rb +28 -0
  86. data/spec/xpath_spec.rb +180 -0
  87. metadata +259 -0
@@ -0,0 +1,57 @@
1
+ require 'timeout'
2
+ require 'nokogiri'
3
+
4
+ module Capybara
5
+ class CapybaraError < StandardError; end
6
+ class DriverNotFoundError < CapybaraError; end
7
+ class ElementNotFound < CapybaraError; end
8
+ class OptionNotFound < ElementNotFound; end
9
+ class UnselectNotAllowed < CapybaraError; end
10
+ class NotSupportedByDriverError < CapybaraError; end
11
+ class TimeoutError < CapybaraError; end
12
+ class LocateHiddenElementError < CapybaraError; end
13
+ class InfiniteRedirectError < TimeoutError; end
14
+
15
+ class << self
16
+ attr_accessor :debug, :asset_root, :app_host, :run_server, :default_host
17
+ attr_accessor :default_selector, :default_wait_time, :default_timeout_in_follow_redirects, :ignore_hidden_elements
18
+
19
+ def default_selector
20
+ @default_selector ||= :xpath
21
+ end
22
+
23
+ def default_wait_time
24
+ @default_wait_time ||= 2
25
+ end
26
+
27
+ def default_timeout_in_follow_redirects
28
+ @default_timeout_in_follow_redirects ||= 4
29
+ end
30
+
31
+ def log(message)
32
+ puts "[capybara] #{message}" if debug
33
+ true
34
+ end
35
+ end
36
+
37
+ autoload :Server, 'capybara/server'
38
+ autoload :Session, 'capybara/session'
39
+ autoload :Node, 'capybara/node'
40
+ autoload :XPath, 'capybara/xpath'
41
+ autoload :Searchable, 'capybara/searchable'
42
+ autoload :VERSION, 'capybara/version'
43
+
44
+ module Driver
45
+ autoload :Base, 'capybara/driver/base'
46
+ autoload :RackTest, 'capybara/driver/rack_test_driver'
47
+ autoload :Celerity, 'capybara/driver/celerity_driver'
48
+ autoload :Culerity, 'capybara/driver/culerity_driver'
49
+ autoload :Selenium, 'capybara/driver/selenium_driver'
50
+ end
51
+ end
52
+
53
+ Capybara.run_server = true
54
+ Capybara.default_selector = :xpath
55
+ Capybara.default_wait_time = 2
56
+ Capybara.default_timeout_in_follow_redirects = 4
57
+ Capybara.ignore_hidden_elements = false
@@ -0,0 +1,32 @@
1
+ require 'capybara'
2
+ require 'capybara/dsl'
3
+
4
+ World(Capybara)
5
+
6
+ After do
7
+ Capybara.reset_sessions!
8
+ end
9
+
10
+ Before('@javascript') do
11
+ Capybara.current_driver = Capybara.javascript_driver
12
+ end
13
+
14
+ Before('@selenium') do
15
+ Capybara.current_driver = :selenium
16
+ end
17
+
18
+ Before('@celerity') do
19
+ Capybara.current_driver = :celerity
20
+ end
21
+
22
+ Before('@culerity') do
23
+ Capybara.current_driver = :culerity
24
+ end
25
+
26
+ Before('@rack_test') do
27
+ Capybara.current_driver = :rack_test
28
+ end
29
+
30
+ After do
31
+ Capybara.use_default_driver
32
+ end
@@ -0,0 +1,48 @@
1
+ class Capybara::Driver::Base
2
+ def current_url
3
+ raise NotImplementedError
4
+ end
5
+
6
+ def visit(path)
7
+ raise NotImplementedError
8
+ end
9
+
10
+ def find(query)
11
+ raise NotImplementedError
12
+ end
13
+
14
+ def evaluate_script(script)
15
+ raise Capybara::NotSupportedByDriverError
16
+ end
17
+
18
+ def wait?
19
+ false
20
+ end
21
+
22
+ def wait_until *args
23
+ end
24
+
25
+ def response_headers
26
+ raise Capybara::NotSupportedByDriverError
27
+ end
28
+
29
+ def body
30
+ raise NotImplementedError
31
+ end
32
+
33
+ def within_frame(frame_id)
34
+ raise Capybara::NotSupportedByDriverError
35
+ end
36
+
37
+ def source
38
+ raise NotImplementedError
39
+ end
40
+
41
+ def cleanup!
42
+ end
43
+
44
+ def has_shortcircuit_timeout?
45
+ false
46
+ end
47
+
48
+ end
@@ -0,0 +1,143 @@
1
+ class Capybara::Driver::Celerity < Capybara::Driver::Base
2
+ class Node < Capybara::Node
3
+ def text
4
+ node.text
5
+ end
6
+
7
+ def [](name)
8
+ value = if name.to_sym == :class
9
+ node.class_name
10
+ else
11
+ node.send(name.to_sym)
12
+ end
13
+ return value if value and not value.to_s.empty?
14
+ end
15
+
16
+ def value
17
+ if tag_name == "select" and node.multiple?
18
+ node.selected_options
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ def set(value)
25
+ node.set(value)
26
+ end
27
+
28
+ def select(option)
29
+ node.select(option)
30
+ rescue
31
+ options = all(:xpath, "//option").map { |o| "'#{o.text}'" }.join(', ')
32
+ raise Capybara::OptionNotFound, "No such option '#{option}' in this select box. Available options: #{options}"
33
+ end
34
+
35
+ def unselect(option)
36
+ unless node.multiple?
37
+ raise Capybara::UnselectNotAllowed, "Cannot unselect option '#{option}' from single select box."
38
+ end
39
+
40
+ # FIXME: couldn't find a clean way to unselect, so clear and reselect
41
+ selected_options = node.selected_options
42
+ if unselect_option = selected_options.detect { |value| value == option } ||
43
+ selected_options.detect { |value| value.index(option) }
44
+ node.clear
45
+ (selected_options - [unselect_option]).each { |value| node.select_value(value) }
46
+ else
47
+ options = all(:xpath, "//option").map { |o| "'#{o.text}'" }.join(', ')
48
+ raise Capybara::OptionNotFound, "No such option '#{option}' in this select box. Available options: #{options}"
49
+ end
50
+ end
51
+
52
+ def click
53
+ node.click
54
+ end
55
+
56
+ def drag_to(element)
57
+ node.fire_event('mousedown')
58
+ element.node.fire_event('mousemove')
59
+ element.node.fire_event('mouseup')
60
+ end
61
+
62
+ def tag_name
63
+ # FIXME: this might be the dumbest way ever of getting the tag name
64
+ # there has to be something better...
65
+ node.to_xml[/^\s*<([a-z0-9\-\:]+)/, 1]
66
+ end
67
+
68
+ def visible?
69
+ node.visible?
70
+ end
71
+
72
+ def path
73
+ node.xpath
74
+ end
75
+
76
+ def trigger(event)
77
+ node.fire_event(event.to_s)
78
+ end
79
+
80
+ private
81
+
82
+ def all_unfiltered(locator)
83
+ noko_node = Nokogiri::HTML(driver.body).xpath(node.xpath).first
84
+ all_nodes = noko_node.xpath(locator).map { |n| n.path }.join(' | ')
85
+ driver.find(all_nodes)
86
+ end
87
+
88
+ end
89
+
90
+ attr_reader :app, :rack_server
91
+
92
+ def initialize(app)
93
+ @app = app
94
+ @rack_server = Capybara::Server.new(@app)
95
+ @rack_server.boot if Capybara.run_server
96
+ end
97
+
98
+ def visit(path)
99
+ browser.goto(url(path))
100
+ end
101
+
102
+ def current_url
103
+ browser.url
104
+ end
105
+
106
+ def source
107
+ browser.html
108
+ end
109
+
110
+ def body
111
+ browser.document.as_xml
112
+ end
113
+
114
+ def response_headers
115
+ browser.response_headers
116
+ end
117
+
118
+ def find(selector)
119
+ browser.elements_by_xpath(selector).map { |node| Node.new(self, node) }
120
+ end
121
+
122
+ def wait?; true; end
123
+
124
+ def evaluate_script(script)
125
+ browser.execute_script "#{script}"
126
+ end
127
+
128
+ def browser
129
+ unless @_browser
130
+ require 'celerity'
131
+ @_browser = ::Celerity::Browser.new(:browser => :firefox, :log_level => :off)
132
+ end
133
+
134
+ @_browser
135
+ end
136
+
137
+ private
138
+
139
+ def url(path)
140
+ rack_server.url(path)
141
+ end
142
+
143
+ end
@@ -0,0 +1,25 @@
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, {:browser => :firefox, :log_level => :off}
18
+ at_exit do
19
+ @_browser.exit
20
+ end
21
+ end
22
+ @_browser
23
+ end
24
+
25
+ end
@@ -0,0 +1,271 @@
1
+ require 'rack/test'
2
+ require 'mime/types'
3
+ require 'nokogiri'
4
+ require 'cgi'
5
+
6
+ class Capybara::Driver::RackTest < Capybara::Driver::Base
7
+ class Node < Capybara::Node
8
+ def text
9
+ node.text
10
+ end
11
+
12
+ def [](name)
13
+ attr_name = name.to_s
14
+ case
15
+ when 'select' == tag_name && 'value' == attr_name
16
+ if node['multiple'] == 'multiple'
17
+ node.xpath(".//option[@selected='selected']").map { |option| option.content }
18
+ else
19
+ option = node.xpath(".//option[@selected='selected']").first || node.xpath(".//option").first
20
+ option.content if option
21
+ end
22
+ when 'input' == tag_name && 'checkbox' == type && 'checked' == attr_name
23
+ node[attr_name] == 'checked' ? true : false
24
+ else
25
+ node[attr_name]
26
+ end
27
+ end
28
+
29
+
30
+ def set(value)
31
+ if tag_name == 'input' and type == 'radio'
32
+ driver.html.xpath("//input[@name=#{Capybara::XPath.escape(self[:name])}]").each { |node| node.remove_attribute("checked") }
33
+ node['checked'] = 'checked'
34
+ elsif tag_name == 'input' and type == 'checkbox'
35
+ if value && !node['checked']
36
+ node['checked'] = 'checked'
37
+ elsif !value && node['checked']
38
+ node.remove_attribute('checked')
39
+ end
40
+ elsif tag_name == 'input'
41
+ node['value'] = value.to_s
42
+ elsif tag_name == "textarea"
43
+ node.content = value.to_s
44
+ end
45
+ end
46
+
47
+ def select(option)
48
+ if node['multiple'] != 'multiple'
49
+ node.xpath(".//option[@selected]").each { |node| node.remove_attribute("selected") }
50
+ end
51
+
52
+ if option_node = node.xpath(".//option[text()=#{Capybara::XPath.escape(option)}]").first ||
53
+ node.xpath(".//option[contains(.,#{Capybara::XPath.escape(option)})]").first
54
+ option_node["selected"] = 'selected'
55
+ else
56
+ options = node.xpath(".//option").map { |o| "'#{o.text}'" }.join(', ')
57
+ raise Capybara::OptionNotFound, "No such option '#{option}' in this select box. Available options: #{options}"
58
+ end
59
+ end
60
+
61
+ def unselect(option)
62
+ if node['multiple'] != 'multiple'
63
+ raise Capybara::UnselectNotAllowed, "Cannot unselect option '#{option}' from single select box."
64
+ end
65
+
66
+ if option_node = node.xpath(".//option[text()=#{Capybara::XPath.escape(option)}]").first ||
67
+ node.xpath(".//option[contains(.,#{Capybara::XPath.escape(option)})]").first
68
+ option_node.remove_attribute('selected')
69
+ else
70
+ options = node.xpath(".//option").map { |o| "'#{o.text}'" }.join(', ')
71
+ raise Capybara::OptionNotFound, "No such option '#{option}' in this select box. Available options: #{options}"
72
+ end
73
+ end
74
+
75
+ def click
76
+ if tag_name == 'a'
77
+ method = self["data-method"] || :get
78
+ driver.process(method, self[:href].to_s)
79
+ elsif (tag_name == 'input' or tag_name == 'button') and %w(submit image).include?(type)
80
+ Form.new(driver, form).submit(self)
81
+ end
82
+ end
83
+
84
+ def tag_name
85
+ node.node_name
86
+ end
87
+
88
+ def visible?
89
+ node.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none')]").size == 0
90
+ end
91
+
92
+ def path
93
+ node.path
94
+ end
95
+
96
+ private
97
+
98
+ def all_unfiltered(locator)
99
+ node.xpath(locator).map { |n| self.class.new(driver, n) }
100
+ end
101
+
102
+ def type
103
+ node[:type]
104
+ end
105
+
106
+ def form
107
+ node.ancestors('form').first
108
+ end
109
+ end
110
+
111
+ class Form < Node
112
+ def params(button)
113
+ params = {}
114
+
115
+ node.xpath(".//input[@type!='radio' and @type!='checkbox' and @type!='submit']").map do |input|
116
+ merge_param!(params, input['name'].to_s, input['value'].to_s)
117
+ end
118
+ node.xpath(".//textarea").map do |textarea|
119
+ merge_param!(params, textarea['name'].to_s, textarea.text.to_s)
120
+ end
121
+ node.xpath(".//input[@type='radio' or @type='checkbox']").map do |input|
122
+ merge_param!(params, input['name'].to_s, input['value'].to_s) if input['checked']
123
+ end
124
+ node.xpath(".//select").map do |select|
125
+ if select['multiple'] == 'multiple'
126
+ options = select.xpath(".//option[@selected]")
127
+ options.each do |option|
128
+ merge_param!(params, select['name'].to_s, (option['value'] || option.text).to_s)
129
+ end
130
+ else
131
+ option = select.xpath(".//option[@selected]").first
132
+ option ||= select.xpath('.//option').first
133
+ merge_param!(params, select['name'].to_s, (option['value'] || option.text).to_s) if option
134
+ end
135
+ end
136
+ node.xpath(".//input[@type='file']").map do |input|
137
+ unless input['value'].to_s.empty?
138
+ if multipart?
139
+ content_type = MIME::Types.type_for(input['value'].to_s).first.to_s
140
+ file = Rack::Test::UploadedFile.new(input['value'].to_s, content_type)
141
+ merge_param!(params, input['name'].to_s, file)
142
+ else
143
+ merge_param!(params, input['name'].to_s, File.basename(input['value'].to_s))
144
+ end
145
+ end
146
+ end
147
+ merge_param!(params, button[:name], button[:value] || "") if button[:name]
148
+ params
149
+ end
150
+
151
+ def submit(button)
152
+ driver.submit(method, node['action'].to_s, params(button))
153
+ end
154
+
155
+ def multipart?
156
+ self[:enctype] == "multipart/form-data"
157
+ end
158
+
159
+ private
160
+
161
+ def method
162
+ self[:method] =~ /post/i ? :post : :get
163
+ end
164
+
165
+ def merge_param!(params, key, value)
166
+ collection = key.sub!(/\[\]$/, '')
167
+ if collection
168
+ if params[key]
169
+ params[key] << value
170
+ else
171
+ params[key] = [value]
172
+ end
173
+ else
174
+ params[key] = value
175
+ end
176
+ end
177
+ end
178
+
179
+ include ::Rack::Test::Methods
180
+ attr_reader :app
181
+
182
+ alias_method :response, :last_response
183
+ alias_method :request, :last_request
184
+
185
+ def initialize(app)
186
+ @app = app
187
+ end
188
+
189
+ def visit(path, attributes = {})
190
+ process(:get, path, attributes)
191
+ end
192
+
193
+ def process(method, path, attributes = {})
194
+ return if path.gsub(/^#{current_path}/, '') =~ /^#/
195
+ send(method, path, attributes, env)
196
+ follow_redirects!
197
+ end
198
+
199
+ def current_url
200
+ request.url rescue ""
201
+ end
202
+
203
+ def response_headers
204
+ response.headers
205
+ end
206
+
207
+ def submit(method, path, attributes)
208
+ path = current_path if not path or path.empty?
209
+ send(method, path, attributes, env)
210
+ follow_redirects!
211
+ end
212
+
213
+ def find(selector)
214
+ html.xpath(selector).map { |node| Node.new(self, node) }
215
+ end
216
+
217
+ def body
218
+ @body ||= response.body
219
+ end
220
+
221
+ def html
222
+ @html ||= Nokogiri::HTML(body)
223
+ end
224
+ alias_method :source, :body
225
+
226
+ def get(*args, &block); reset_cache; super; end
227
+ def post(*args, &block); reset_cache; super; end
228
+ def put(*args, &block); reset_cache; super; end
229
+ def delete(*args, &block); reset_cache; super; end
230
+
231
+ private
232
+
233
+ def reset_cache
234
+ @body = nil
235
+ @html = nil
236
+ end
237
+
238
+ def build_rack_mock_session # :nodoc:
239
+ Rack::MockSession.new(app, Capybara.default_host || "www.example.com")
240
+ end
241
+
242
+ def current_path
243
+ request.path rescue ""
244
+ end
245
+
246
+ def follow_redirects!
247
+ Capybara::WaitUntil.timeout(Capybara.default_timeout_in_follow_redirects) do
248
+ redirect = response.redirect?
249
+ follow_redirect! if redirect
250
+ not redirect
251
+ end
252
+ rescue Capybara::TimeoutError
253
+ raise Capybara::InfiniteRedirectError, "infinite redirect detected!"
254
+ end
255
+
256
+ def env
257
+ env = {}
258
+ begin
259
+ env["HTTP_REFERER"] = request.url
260
+ rescue Rack::Test::Error
261
+ # no request yet
262
+ end
263
+ env
264
+ end
265
+
266
+ def reset_cache
267
+ @body = nil
268
+ @html = nil
269
+ end
270
+
271
+ end