capybara 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +39 -0
- data/README.rdoc +181 -57
- data/Rakefile +7 -16
- data/config.ru +6 -0
- data/lib/capybara.rb +19 -9
- data/lib/capybara/cucumber.rb +4 -0
- data/lib/capybara/driver/base.rb +25 -8
- data/lib/capybara/driver/celerity_driver.rb +108 -0
- data/lib/capybara/driver/culerity_driver.rb +1 -70
- data/lib/capybara/driver/rack_test_driver.rb +57 -25
- data/lib/capybara/driver/selenium_driver.rb +28 -10
- data/lib/capybara/dsl.rb +7 -4
- data/lib/capybara/node.rb +50 -29
- data/lib/capybara/rails.rb +1 -1
- data/lib/capybara/save_and_open_page.rb +1 -1
- data/lib/capybara/searchable.rb +45 -0
- data/lib/capybara/server.rb +11 -4
- data/lib/capybara/session.rb +94 -94
- data/lib/capybara/wait_until.rb +23 -0
- data/lib/capybara/xpath.rb +55 -41
- data/spec/capybara_spec.rb +18 -0
- data/spec/driver/celerity_driver_spec.rb +17 -0
- data/spec/driver/culerity_driver_spec.rb +3 -0
- data/spec/driver/rack_test_driver_spec.rb +3 -0
- data/spec/driver/remote_culerity_driver_spec.rb +19 -0
- data/spec/driver/remote_selenium_driver_spec.rb +18 -0
- data/spec/driver/selenium_driver_spec.rb +2 -0
- data/spec/drivers_spec.rb +51 -5
- data/spec/dsl/all_spec.rb +38 -0
- data/spec/dsl/attach_file_spec.rb +66 -0
- data/spec/dsl/check_spec.rb +28 -0
- data/spec/dsl/choose_spec.rb +28 -0
- data/spec/dsl/click_button_spec.rb +183 -0
- data/spec/dsl/click_link_spec.rb +88 -0
- data/spec/dsl/click_spec.rb +26 -0
- data/spec/dsl/current_url_spec.rb +10 -0
- data/spec/dsl/fill_in_spec.rb +83 -0
- data/spec/dsl/find_button_spec.rb +18 -0
- data/spec/dsl/find_field_spec.rb +24 -0
- data/spec/dsl/find_link_spec.rb +19 -0
- data/spec/dsl/find_spec.rb +36 -0
- data/spec/dsl/has_content_spec.rb +103 -0
- data/spec/dsl/has_css_spec.rb +109 -0
- data/spec/dsl/has_xpath_spec.rb +115 -0
- data/spec/dsl/locate_spec.rb +38 -0
- data/spec/dsl/select_spec.rb +27 -0
- data/spec/dsl/uncheck_spec.rb +29 -0
- data/spec/dsl/within_spec.rb +145 -0
- data/spec/fixtures/capybara.jpg +0 -0
- data/spec/public/test.js +27 -0
- data/spec/searchable_spec.rb +61 -0
- data/spec/server_spec.rb +47 -0
- data/spec/session/celerity_session_spec.rb +27 -0
- data/spec/session/culerity_session_spec.rb +1 -0
- data/spec/session/rack_test_session_spec.rb +1 -0
- data/spec/session/selenium_session_spec.rb +1 -0
- data/spec/session_spec.rb +32 -903
- data/spec/session_with_headers_support_spec.rb +13 -0
- data/spec/session_with_javascript_support_spec.rb +165 -0
- data/spec/session_without_headers_support_spec.rb +15 -0
- data/spec/session_without_javascript_support_spec.rb +15 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/test_app.rb +9 -1
- data/spec/views/form.erb +38 -0
- data/spec/views/postback.erb +13 -0
- data/spec/views/with_html.erb +13 -0
- data/spec/views/with_js.erb +9 -24
- data/spec/views/with_simple_html.erb +1 -1
- data/spec/wait_until_spec.rb +28 -0
- data/spec/xpath_spec.rb +34 -3
- metadata +54 -5
data/lib/capybara/cucumber.rb
CHANGED
data/lib/capybara/driver/base.rb
CHANGED
@@ -1,17 +1,34 @@
|
|
1
1
|
class Capybara::Driver::Base
|
2
|
+
def current_url
|
3
|
+
raise NotImplementedError
|
4
|
+
end
|
5
|
+
|
2
6
|
def visit(path)
|
3
|
-
raise
|
7
|
+
raise NotImplementedError
|
4
8
|
end
|
5
|
-
|
9
|
+
|
6
10
|
def find(query)
|
7
|
-
raise
|
11
|
+
raise NotImplementedError
|
8
12
|
end
|
9
|
-
|
10
|
-
def
|
11
|
-
raise
|
13
|
+
|
14
|
+
def evaluate_script(script)
|
15
|
+
raise Capybara::NotSupportedByDriverError
|
12
16
|
end
|
13
|
-
|
17
|
+
|
14
18
|
def wait?
|
15
19
|
false
|
16
20
|
end
|
17
|
-
|
21
|
+
|
22
|
+
def response_headers
|
23
|
+
raise Capybara::NotSupportedByDriverError
|
24
|
+
end
|
25
|
+
|
26
|
+
def body
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
|
30
|
+
def source
|
31
|
+
raise NotImplementedError
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,108 @@
|
|
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.empty?
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(value)
|
17
|
+
node.set(value)
|
18
|
+
end
|
19
|
+
|
20
|
+
def select(option)
|
21
|
+
node.select(option)
|
22
|
+
end
|
23
|
+
|
24
|
+
def click
|
25
|
+
node.click
|
26
|
+
end
|
27
|
+
|
28
|
+
def drag_to(element)
|
29
|
+
node.fire_event('mousedown')
|
30
|
+
element.node.fire_event('mousemove')
|
31
|
+
element.node.fire_event('mouseup')
|
32
|
+
end
|
33
|
+
|
34
|
+
def tag_name
|
35
|
+
# FIXME: this might be the dumbest way ever of getting the tag name
|
36
|
+
# there has to be something better...
|
37
|
+
node.to_xml[/^\s*<([a-z0-9\-\:]+)/, 1]
|
38
|
+
end
|
39
|
+
|
40
|
+
def visible?
|
41
|
+
node.visible?
|
42
|
+
end
|
43
|
+
|
44
|
+
def path
|
45
|
+
node.xpath
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_reader :app, :rack_server
|
51
|
+
|
52
|
+
def initialize(app)
|
53
|
+
@app = app
|
54
|
+
unless Capybara.app_host
|
55
|
+
@rack_server = Capybara::Server.new(@app)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def visit(path)
|
60
|
+
browser.goto(url(path))
|
61
|
+
end
|
62
|
+
|
63
|
+
def current_url
|
64
|
+
browser.url
|
65
|
+
end
|
66
|
+
|
67
|
+
def source
|
68
|
+
browser.html
|
69
|
+
end
|
70
|
+
|
71
|
+
def body
|
72
|
+
browser.document.as_xml
|
73
|
+
end
|
74
|
+
|
75
|
+
def response_headers
|
76
|
+
browser.response_headers
|
77
|
+
end
|
78
|
+
|
79
|
+
def find(selector)
|
80
|
+
browser.elements_by_xpath(selector).map { |node| Node.new(self, node) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def wait?; true; end
|
84
|
+
|
85
|
+
def evaluate_script(script)
|
86
|
+
browser.execute_script "#{script}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def browser
|
90
|
+
unless @_browser
|
91
|
+
require 'celerity'
|
92
|
+
@_browser = ::Celerity::Browser.new(:browser => :firefox, :log_level => :off)
|
93
|
+
end
|
94
|
+
|
95
|
+
@_browser
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def url(path)
|
101
|
+
if rack_server
|
102
|
+
rack_server.url(path)
|
103
|
+
else
|
104
|
+
Capybara.app_host.to_s + path
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -1,46 +1,6 @@
|
|
1
1
|
require 'culerity'
|
2
2
|
|
3
|
-
class Capybara::Driver::Culerity < Capybara::Driver::
|
4
|
-
class Node < Capybara::Node
|
5
|
-
def text
|
6
|
-
node.text
|
7
|
-
end
|
8
|
-
|
9
|
-
def [](name)
|
10
|
-
value = if name.to_sym == :class
|
11
|
-
node.class_name
|
12
|
-
else
|
13
|
-
node.send(name.to_sym)
|
14
|
-
end
|
15
|
-
return value if value and not value.empty?
|
16
|
-
end
|
17
|
-
|
18
|
-
def set(value)
|
19
|
-
node.set(value)
|
20
|
-
end
|
21
|
-
|
22
|
-
def select(option)
|
23
|
-
node.select(option)
|
24
|
-
end
|
25
|
-
|
26
|
-
def click
|
27
|
-
node.click
|
28
|
-
end
|
29
|
-
|
30
|
-
def drag_to(element)
|
31
|
-
node.fire_event('mousedown')
|
32
|
-
element.node.fire_event('mousemove')
|
33
|
-
element.node.fire_event('mouseup')
|
34
|
-
end
|
35
|
-
|
36
|
-
def tag_name
|
37
|
-
# FIXME: this might be the dumbest way ever of getting the tag name
|
38
|
-
# there has to be something better...
|
39
|
-
node.to_xml[/^\s*<([a-z0-9\-\:]+)/, 1]
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
attr_reader :app, :rack_server
|
3
|
+
class Capybara::Driver::Culerity < Capybara::Driver::Celerity
|
44
4
|
|
45
5
|
def self.server
|
46
6
|
unless @_server
|
@@ -52,35 +12,6 @@ class Capybara::Driver::Culerity < Capybara::Driver::Base
|
|
52
12
|
@_server
|
53
13
|
end
|
54
14
|
|
55
|
-
def initialize(app)
|
56
|
-
@app = app
|
57
|
-
@rack_server = Capybara::Server.new(@app)
|
58
|
-
end
|
59
|
-
|
60
|
-
def visit(path)
|
61
|
-
browser.goto(url(path))
|
62
|
-
end
|
63
|
-
|
64
|
-
def body
|
65
|
-
browser.html
|
66
|
-
end
|
67
|
-
|
68
|
-
def find(selector)
|
69
|
-
browser.elements_by_xpath(selector).map { |node| Node.new(self, node) }
|
70
|
-
end
|
71
|
-
|
72
|
-
def wait?; true; end
|
73
|
-
|
74
|
-
def evaluate_script(script)
|
75
|
-
browser.execute_script "#{script}"
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
def url(path)
|
81
|
-
rack_server.url(path)
|
82
|
-
end
|
83
|
-
|
84
15
|
def browser
|
85
16
|
unless @_browser
|
86
17
|
@_browser = ::Culerity::RemoteBrowserProxy.new self.class.server, {:browser => :firefox, :log_level => :off}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rack/test'
|
2
|
+
require 'mime/types'
|
2
3
|
require 'nokogiri'
|
3
4
|
require 'cgi'
|
4
5
|
|
@@ -7,7 +8,7 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
7
8
|
def text
|
8
9
|
node.text
|
9
10
|
end
|
10
|
-
|
11
|
+
|
11
12
|
def [](name)
|
12
13
|
value = node[name.to_s]
|
13
14
|
return value.to_s if value
|
@@ -29,7 +30,7 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
29
30
|
node.content = value.to_s
|
30
31
|
end
|
31
32
|
end
|
32
|
-
|
33
|
+
|
33
34
|
def select(option)
|
34
35
|
node.xpath(".//option").each { |node| node.remove_attribute("selected") }
|
35
36
|
node.xpath(".//option[contains(.,'#{option}')]").first["selected"] = 'selected'
|
@@ -37,18 +38,26 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
37
38
|
|
38
39
|
def click
|
39
40
|
if tag_name == 'a'
|
40
|
-
driver.visit(self[:href])
|
41
|
+
driver.visit(self[:href].to_s)
|
41
42
|
elsif (tag_name == 'input' or tag_name == 'button') and %w(submit image).include?(type)
|
42
43
|
Form.new(driver, form).submit(self)
|
43
44
|
end
|
44
45
|
end
|
45
|
-
|
46
|
+
|
46
47
|
def tag_name
|
47
48
|
node.node_name
|
48
49
|
end
|
49
50
|
|
51
|
+
def visible?
|
52
|
+
node.xpath("./ancestor-or-self::*[contains(@style, 'display:none')]").size == 0
|
53
|
+
end
|
54
|
+
|
55
|
+
def path
|
56
|
+
node.path
|
57
|
+
end
|
58
|
+
|
50
59
|
private
|
51
|
-
|
60
|
+
|
52
61
|
def type
|
53
62
|
self[:type]
|
54
63
|
end
|
@@ -76,9 +85,11 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
76
85
|
merge_param!(params, select['name'].to_s, (option['value'] || option.text).to_s) if option
|
77
86
|
end
|
78
87
|
node.xpath(".//input[@type='file']").map do |input|
|
79
|
-
|
88
|
+
unless input['value'].to_s.empty?
|
80
89
|
if multipart?
|
81
|
-
|
90
|
+
content_type = MIME::Types.type_for(input['value'].to_s).first.to_s
|
91
|
+
file = Rack::Test::UploadedFile.new(input['value'].to_s, content_type)
|
92
|
+
merge_param!(params, input['name'].to_s, file)
|
82
93
|
else
|
83
94
|
merge_param!(params, input['name'].to_s, File.basename(input['value'].to_s))
|
84
95
|
end
|
@@ -89,23 +100,19 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
89
100
|
end
|
90
101
|
|
91
102
|
def submit(button)
|
92
|
-
|
93
|
-
driver.submit(node['action'].to_s, params(button))
|
94
|
-
else
|
95
|
-
driver.visit(node['action'].to_s, params(button))
|
96
|
-
end
|
103
|
+
driver.submit(method, node['action'].to_s, params(button))
|
97
104
|
end
|
98
105
|
|
99
106
|
def multipart?
|
100
107
|
self[:enctype] == "multipart/form-data"
|
101
108
|
end
|
109
|
+
|
110
|
+
private
|
102
111
|
|
103
|
-
def
|
104
|
-
self[:method] =~ /post/i
|
112
|
+
def method
|
113
|
+
self[:method] =~ /post/i ? :post : :get
|
105
114
|
end
|
106
|
-
|
107
|
-
private
|
108
|
-
|
115
|
+
|
109
116
|
def merge_param!(params, key, value)
|
110
117
|
collection = key.sub!(/\[\]$/, '')
|
111
118
|
if collection
|
@@ -119,26 +126,37 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
119
126
|
end
|
120
127
|
end
|
121
128
|
end
|
122
|
-
|
129
|
+
|
123
130
|
include ::Rack::Test::Methods
|
124
131
|
attr_reader :app, :html, :body
|
125
132
|
|
126
133
|
alias_method :response, :last_response
|
127
134
|
alias_method :request, :last_request
|
128
|
-
|
135
|
+
alias_method :source, :body
|
136
|
+
|
129
137
|
def initialize(app)
|
130
138
|
@app = app
|
131
139
|
end
|
132
|
-
|
140
|
+
|
133
141
|
def visit(path, attributes = {})
|
142
|
+
return if path.gsub(/^#{current_path}/, '') =~ /^#/
|
134
143
|
get(path, attributes)
|
135
|
-
|
144
|
+
follow_redirects!
|
136
145
|
cache_body
|
137
146
|
end
|
138
147
|
|
139
|
-
def
|
140
|
-
|
141
|
-
|
148
|
+
def current_url
|
149
|
+
request.url rescue ""
|
150
|
+
end
|
151
|
+
|
152
|
+
def response_headers
|
153
|
+
response.headers
|
154
|
+
end
|
155
|
+
|
156
|
+
def submit(method, path, attributes)
|
157
|
+
path = current_path if not path or path.empty?
|
158
|
+
send(method, path, attributes)
|
159
|
+
follow_redirects!
|
142
160
|
cache_body
|
143
161
|
end
|
144
162
|
|
@@ -146,7 +164,21 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
146
164
|
html.xpath(selector).map { |node| Node.new(self, node) }
|
147
165
|
end
|
148
166
|
|
149
|
-
|
167
|
+
private
|
168
|
+
|
169
|
+
def current_path
|
170
|
+
request.path rescue ""
|
171
|
+
end
|
172
|
+
|
173
|
+
def follow_redirects!
|
174
|
+
Capybara::WaitUntil.timeout(4) do
|
175
|
+
redirect = response.redirect?
|
176
|
+
follow_redirect! if redirect
|
177
|
+
not redirect
|
178
|
+
end
|
179
|
+
rescue Capybara::TimeoutError
|
180
|
+
raise Capybara::InfiniteRedirectError, "infinite redirect detected!"
|
181
|
+
end
|
150
182
|
|
151
183
|
def cache_body
|
152
184
|
@body = response.body
|
@@ -43,6 +43,10 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|
43
43
|
node.tag_name
|
44
44
|
end
|
45
45
|
|
46
|
+
def visible?
|
47
|
+
node.displayed? and node.displayed? != "false"
|
48
|
+
end
|
49
|
+
|
46
50
|
private
|
47
51
|
|
48
52
|
def type
|
@@ -65,35 +69,49 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|
65
69
|
|
66
70
|
def initialize(app)
|
67
71
|
@app = app
|
68
|
-
|
72
|
+
unless Capybara.app_host
|
73
|
+
@rack_server = Capybara::Server.new(@app)
|
74
|
+
end
|
69
75
|
end
|
70
76
|
|
71
77
|
def visit(path)
|
72
|
-
|
78
|
+
browser.navigate.to(url(path))
|
79
|
+
end
|
80
|
+
|
81
|
+
def source
|
82
|
+
browser.page_source
|
73
83
|
end
|
74
84
|
|
75
85
|
def body
|
76
|
-
|
86
|
+
browser.page_source
|
87
|
+
end
|
88
|
+
|
89
|
+
def current_url
|
90
|
+
browser.current_url
|
77
91
|
end
|
78
92
|
|
79
93
|
def find(selector)
|
80
|
-
|
94
|
+
browser.find_elements(:xpath, selector).map { |node| Node.new(self, node) }
|
81
95
|
end
|
82
96
|
|
83
97
|
def wait?; true; end
|
84
98
|
|
85
99
|
def evaluate_script(script)
|
86
|
-
|
100
|
+
browser.execute_script "return #{script}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def browser
|
104
|
+
self.class.driver
|
87
105
|
end
|
88
106
|
|
89
107
|
private
|
90
108
|
|
91
109
|
def url(path)
|
92
|
-
rack_server
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
110
|
+
if rack_server
|
111
|
+
rack_server.url(path)
|
112
|
+
else
|
113
|
+
Capybara.app_host.to_s + path
|
114
|
+
end
|
97
115
|
end
|
98
116
|
|
99
117
|
end
|