yannp-capybara 0.3.9

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