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.
- data/History.txt +202 -0
- data/README.rdoc +540 -0
- data/lib/capybara.rb +231 -0
- data/lib/capybara/cucumber.rb +32 -0
- data/lib/capybara/driver/base.rb +60 -0
- data/lib/capybara/driver/celerity_driver.rb +164 -0
- data/lib/capybara/driver/culerity_driver.rb +26 -0
- data/lib/capybara/driver/node.rb +78 -0
- data/lib/capybara/driver/rack_test_driver.rb +303 -0
- data/lib/capybara/driver/selenium_driver.rb +165 -0
- data/lib/capybara/dsl.rb +109 -0
- data/lib/capybara/node/actions.rb +160 -0
- data/lib/capybara/node/base.rb +47 -0
- data/lib/capybara/node/document.rb +17 -0
- data/lib/capybara/node/element.rb +182 -0
- data/lib/capybara/node/finders.rb +201 -0
- data/lib/capybara/node/matchers.rb +391 -0
- data/lib/capybara/node/simple.rb +116 -0
- data/lib/capybara/rails.rb +17 -0
- data/lib/capybara/rspec.rb +18 -0
- data/lib/capybara/selector.rb +70 -0
- data/lib/capybara/server.rb +90 -0
- data/lib/capybara/session.rb +281 -0
- data/lib/capybara/spec/driver.rb +243 -0
- data/lib/capybara/spec/fixtures/capybara.jpg +0 -0
- data/lib/capybara/spec/fixtures/test_file.txt +1 -0
- data/lib/capybara/spec/public/jquery-ui.js +35 -0
- data/lib/capybara/spec/public/jquery.js +19 -0
- data/lib/capybara/spec/public/test.js +33 -0
- data/lib/capybara/spec/session.rb +110 -0
- data/lib/capybara/spec/session/all_spec.rb +78 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +70 -0
- data/lib/capybara/spec/session/check_spec.rb +65 -0
- data/lib/capybara/spec/session/choose_spec.rb +26 -0
- data/lib/capybara/spec/session/click_button_spec.rb +252 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +36 -0
- data/lib/capybara/spec/session/click_link_spec.rb +113 -0
- data/lib/capybara/spec/session/current_url_spec.rb +15 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +119 -0
- data/lib/capybara/spec/session/find_button_spec.rb +18 -0
- data/lib/capybara/spec/session/find_by_id_spec.rb +18 -0
- data/lib/capybara/spec/session/find_field_spec.rb +26 -0
- data/lib/capybara/spec/session/find_link_spec.rb +19 -0
- data/lib/capybara/spec/session/find_spec.rb +121 -0
- data/lib/capybara/spec/session/first_spec.rb +72 -0
- data/lib/capybara/spec/session/has_button_spec.rb +32 -0
- data/lib/capybara/spec/session/has_content_spec.rb +106 -0
- data/lib/capybara/spec/session/has_css_spec.rb +213 -0
- data/lib/capybara/spec/session/has_field_spec.rb +156 -0
- data/lib/capybara/spec/session/has_link_spec.rb +37 -0
- data/lib/capybara/spec/session/has_select_spec.rb +129 -0
- data/lib/capybara/spec/session/has_selector_spec.rb +129 -0
- data/lib/capybara/spec/session/has_table_spec.rb +96 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +123 -0
- data/lib/capybara/spec/session/headers.rb +19 -0
- data/lib/capybara/spec/session/javascript.rb +223 -0
- data/lib/capybara/spec/session/response_code.rb +19 -0
- data/lib/capybara/spec/session/select_spec.rb +105 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
- data/lib/capybara/spec/session/unselect_spec.rb +61 -0
- data/lib/capybara/spec/session/within_spec.rb +160 -0
- data/lib/capybara/spec/test_app.rb +117 -0
- data/lib/capybara/spec/views/buttons.erb +4 -0
- data/lib/capybara/spec/views/fieldsets.erb +29 -0
- data/lib/capybara/spec/views/form.erb +348 -0
- data/lib/capybara/spec/views/frame_one.erb +8 -0
- data/lib/capybara/spec/views/frame_two.erb +8 -0
- data/lib/capybara/spec/views/popup_one.erb +8 -0
- data/lib/capybara/spec/views/popup_two.erb +8 -0
- data/lib/capybara/spec/views/postback.erb +13 -0
- data/lib/capybara/spec/views/tables.erb +122 -0
- data/lib/capybara/spec/views/with_html.erb +69 -0
- data/lib/capybara/spec/views/with_js.erb +39 -0
- data/lib/capybara/spec/views/with_scope.erb +36 -0
- data/lib/capybara/spec/views/with_simple_html.erb +1 -0
- data/lib/capybara/spec/views/within_frames.erb +10 -0
- data/lib/capybara/spec/views/within_popups.erb +25 -0
- data/lib/capybara/util/save_and_open_page.rb +40 -0
- data/lib/capybara/util/timeout.rb +27 -0
- data/lib/capybara/version.rb +3 -0
- data/spec/basic_node_spec.rb +77 -0
- data/spec/capybara_spec.rb +46 -0
- data/spec/driver/celerity_driver_spec.rb +13 -0
- data/spec/driver/culerity_driver_spec.rb +14 -0
- data/spec/driver/rack_test_driver_spec.rb +84 -0
- data/spec/driver/remote_culerity_driver_spec.rb +22 -0
- data/spec/driver/remote_selenium_driver_spec.rb +16 -0
- data/spec/driver/selenium_driver_spec.rb +14 -0
- data/spec/dsl_spec.rb +157 -0
- data/spec/rspec_spec.rb +47 -0
- data/spec/save_and_open_page_spec.rb +159 -0
- data/spec/server_spec.rb +85 -0
- data/spec/session/celerity_session_spec.rb +24 -0
- data/spec/session/culerity_session_spec.rb +26 -0
- data/spec/session/rack_test_session_spec.rb +44 -0
- data/spec/session/selenium_session_spec.rb +26 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/string_spec.rb +77 -0
- data/spec/timeout_spec.rb +28 -0
- 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
|