capybara 0.2.0 → 0.3.0

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 (71) hide show
  1. data/Manifest.txt +39 -0
  2. data/README.rdoc +181 -57
  3. data/Rakefile +7 -16
  4. data/config.ru +6 -0
  5. data/lib/capybara.rb +19 -9
  6. data/lib/capybara/cucumber.rb +4 -0
  7. data/lib/capybara/driver/base.rb +25 -8
  8. data/lib/capybara/driver/celerity_driver.rb +108 -0
  9. data/lib/capybara/driver/culerity_driver.rb +1 -70
  10. data/lib/capybara/driver/rack_test_driver.rb +57 -25
  11. data/lib/capybara/driver/selenium_driver.rb +28 -10
  12. data/lib/capybara/dsl.rb +7 -4
  13. data/lib/capybara/node.rb +50 -29
  14. data/lib/capybara/rails.rb +1 -1
  15. data/lib/capybara/save_and_open_page.rb +1 -1
  16. data/lib/capybara/searchable.rb +45 -0
  17. data/lib/capybara/server.rb +11 -4
  18. data/lib/capybara/session.rb +94 -94
  19. data/lib/capybara/wait_until.rb +23 -0
  20. data/lib/capybara/xpath.rb +55 -41
  21. data/spec/capybara_spec.rb +18 -0
  22. data/spec/driver/celerity_driver_spec.rb +17 -0
  23. data/spec/driver/culerity_driver_spec.rb +3 -0
  24. data/spec/driver/rack_test_driver_spec.rb +3 -0
  25. data/spec/driver/remote_culerity_driver_spec.rb +19 -0
  26. data/spec/driver/remote_selenium_driver_spec.rb +18 -0
  27. data/spec/driver/selenium_driver_spec.rb +2 -0
  28. data/spec/drivers_spec.rb +51 -5
  29. data/spec/dsl/all_spec.rb +38 -0
  30. data/spec/dsl/attach_file_spec.rb +66 -0
  31. data/spec/dsl/check_spec.rb +28 -0
  32. data/spec/dsl/choose_spec.rb +28 -0
  33. data/spec/dsl/click_button_spec.rb +183 -0
  34. data/spec/dsl/click_link_spec.rb +88 -0
  35. data/spec/dsl/click_spec.rb +26 -0
  36. data/spec/dsl/current_url_spec.rb +10 -0
  37. data/spec/dsl/fill_in_spec.rb +83 -0
  38. data/spec/dsl/find_button_spec.rb +18 -0
  39. data/spec/dsl/find_field_spec.rb +24 -0
  40. data/spec/dsl/find_link_spec.rb +19 -0
  41. data/spec/dsl/find_spec.rb +36 -0
  42. data/spec/dsl/has_content_spec.rb +103 -0
  43. data/spec/dsl/has_css_spec.rb +109 -0
  44. data/spec/dsl/has_xpath_spec.rb +115 -0
  45. data/spec/dsl/locate_spec.rb +38 -0
  46. data/spec/dsl/select_spec.rb +27 -0
  47. data/spec/dsl/uncheck_spec.rb +29 -0
  48. data/spec/dsl/within_spec.rb +145 -0
  49. data/spec/fixtures/capybara.jpg +0 -0
  50. data/spec/public/test.js +27 -0
  51. data/spec/searchable_spec.rb +61 -0
  52. data/spec/server_spec.rb +47 -0
  53. data/spec/session/celerity_session_spec.rb +27 -0
  54. data/spec/session/culerity_session_spec.rb +1 -0
  55. data/spec/session/rack_test_session_spec.rb +1 -0
  56. data/spec/session/selenium_session_spec.rb +1 -0
  57. data/spec/session_spec.rb +32 -903
  58. data/spec/session_with_headers_support_spec.rb +13 -0
  59. data/spec/session_with_javascript_support_spec.rb +165 -0
  60. data/spec/session_without_headers_support_spec.rb +15 -0
  61. data/spec/session_without_javascript_support_spec.rb +15 -0
  62. data/spec/spec_helper.rb +12 -0
  63. data/spec/test_app.rb +9 -1
  64. data/spec/views/form.erb +38 -0
  65. data/spec/views/postback.erb +13 -0
  66. data/spec/views/with_html.erb +13 -0
  67. data/spec/views/with_js.erb +9 -24
  68. data/spec/views/with_simple_html.erb +1 -1
  69. data/spec/wait_until_spec.rb +28 -0
  70. data/spec/xpath_spec.rb +34 -3
  71. metadata +54 -5
@@ -15,6 +15,10 @@ Before('@selenium') do
15
15
  Capybara.current_driver = :selenium
16
16
  end
17
17
 
18
+ Before('@celerity') do
19
+ Capybara.current_driver = :celerity
20
+ end
21
+
18
22
  Before('@culerity') do
19
23
  Capybara.current_driver = :culerity
20
24
  end
@@ -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 "Not implemented"
7
+ raise NotImplementedError
4
8
  end
5
-
9
+
6
10
  def find(query)
7
- raise "Not implemented"
11
+ raise NotImplementedError
8
12
  end
9
-
10
- def body
11
- raise "Not implemented"
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
- end
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::Base
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
- if input['value'].to_s.any?
88
+ unless input['value'].to_s.empty?
80
89
  if multipart?
81
- merge_param!(params, input['name'].to_s, Rack::Test::UploadedFile.new(input['value'].to_s))
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
- if post?
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 post?
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
- follow_redirect! while response.redirect?
144
+ follow_redirects!
136
145
  cache_body
137
146
  end
138
147
 
139
- def submit(path, attributes)
140
- post(path, attributes)
141
- follow_redirect! while response.redirect?
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
- private
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
- @rack_server = Capybara::Server.new(@app)
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
- driver.navigate.to(url(path))
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
- driver.page_source
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
- driver.find_elements(:xpath, selector).map { |node| Node.new(self, node) }
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
- driver.execute_script "return #{script}"
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.url(path)
93
- end
94
-
95
- def driver
96
- self.class.driver
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