capybara 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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