capybara 2.5.0 → 2.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (205) hide show
  1. checksums.yaml +5 -5
  2. data/.yard/templates_custom/default/class/html/selectors.erb +38 -0
  3. data/.yard/templates_custom/default/class/html/setup.rb +17 -0
  4. data/.yard/yard_extensions.rb +78 -0
  5. data/.yardopts +1 -0
  6. data/History.md +413 -10
  7. data/License.txt +1 -1
  8. data/README.md +237 -130
  9. data/lib/capybara/config.rb +132 -0
  10. data/lib/capybara/cucumber.rb +3 -1
  11. data/lib/capybara/driver/base.rb +27 -6
  12. data/lib/capybara/driver/node.rb +14 -5
  13. data/lib/capybara/dsl.rb +2 -3
  14. data/lib/capybara/helpers.rb +13 -65
  15. data/lib/capybara/minitest/spec.rb +177 -0
  16. data/lib/capybara/minitest.rb +278 -0
  17. data/lib/capybara/node/actions.rb +180 -24
  18. data/lib/capybara/node/base.rb +17 -5
  19. data/lib/capybara/node/document.rb +5 -0
  20. data/lib/capybara/node/document_matchers.rb +15 -14
  21. data/lib/capybara/node/element.rb +55 -7
  22. data/lib/capybara/node/finders.rb +179 -67
  23. data/lib/capybara/node/matchers.rb +301 -105
  24. data/lib/capybara/node/simple.rb +15 -4
  25. data/lib/capybara/queries/ancestor_query.rb +25 -0
  26. data/lib/capybara/queries/base_query.rb +69 -3
  27. data/lib/capybara/queries/current_path_query.rb +17 -8
  28. data/lib/capybara/queries/match_query.rb +19 -0
  29. data/lib/capybara/queries/selector_query.rb +251 -0
  30. data/lib/capybara/queries/sibling_query.rb +25 -0
  31. data/lib/capybara/queries/text_query.rb +67 -16
  32. data/lib/capybara/queries/title_query.rb +4 -2
  33. data/lib/capybara/query.rb +3 -131
  34. data/lib/capybara/rack_test/browser.rb +14 -5
  35. data/lib/capybara/rack_test/css_handlers.rb +1 -0
  36. data/lib/capybara/rack_test/driver.rb +15 -8
  37. data/lib/capybara/rack_test/form.rb +34 -12
  38. data/lib/capybara/rack_test/node.rb +29 -12
  39. data/lib/capybara/rails.rb +3 -3
  40. data/lib/capybara/result.rb +104 -9
  41. data/lib/capybara/rspec/compound.rb +95 -0
  42. data/lib/capybara/rspec/features.rb +17 -6
  43. data/lib/capybara/rspec/matcher_proxies.rb +45 -0
  44. data/lib/capybara/rspec/matchers.rb +199 -80
  45. data/lib/capybara/rspec.rb +4 -2
  46. data/lib/capybara/selector/css.rb +30 -0
  47. data/lib/capybara/selector/filter.rb +20 -0
  48. data/lib/capybara/selector/filter_set.rb +74 -0
  49. data/lib/capybara/selector/filters/base.rb +33 -0
  50. data/lib/capybara/selector/filters/expression_filter.rb +40 -0
  51. data/lib/capybara/selector/filters/node_filter.rb +27 -0
  52. data/lib/capybara/selector/selector.rb +276 -0
  53. data/lib/capybara/selector.rb +452 -157
  54. data/lib/capybara/selenium/driver.rb +282 -81
  55. data/lib/capybara/selenium/node.rb +144 -46
  56. data/lib/capybara/server.rb +59 -16
  57. data/lib/capybara/session/config.rb +114 -0
  58. data/lib/capybara/session/matchers.rb +29 -19
  59. data/lib/capybara/session.rb +378 -143
  60. data/lib/capybara/spec/fixtures/no_extension +1 -0
  61. data/lib/capybara/spec/public/jquery-ui.js +13 -791
  62. data/lib/capybara/spec/public/jquery.js +4 -9045
  63. data/lib/capybara/spec/public/test.js +45 -11
  64. data/lib/capybara/spec/session/accept_alert_spec.rb +30 -7
  65. data/lib/capybara/spec/session/accept_confirm_spec.rb +14 -2
  66. data/lib/capybara/spec/session/accept_prompt_spec.rb +35 -6
  67. data/lib/capybara/spec/session/all_spec.rb +45 -32
  68. data/lib/capybara/spec/session/ancestor_spec.rb +85 -0
  69. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +110 -0
  70. data/lib/capybara/spec/session/assert_current_path.rb +15 -2
  71. data/lib/capybara/spec/session/assert_selector.rb +29 -28
  72. data/lib/capybara/spec/session/assert_text.rb +59 -20
  73. data/lib/capybara/spec/session/assert_title.rb +25 -11
  74. data/lib/capybara/spec/session/attach_file_spec.rb +42 -4
  75. data/lib/capybara/spec/session/body_spec.rb +1 -0
  76. data/lib/capybara/spec/session/check_spec.rb +90 -14
  77. data/lib/capybara/spec/session/choose_spec.rb +31 -5
  78. data/lib/capybara/spec/session/click_button_spec.rb +20 -9
  79. data/lib/capybara/spec/session/click_link_or_button_spec.rb +15 -9
  80. data/lib/capybara/spec/session/click_link_spec.rb +39 -15
  81. data/lib/capybara/spec/session/current_scope_spec.rb +2 -1
  82. data/lib/capybara/spec/session/current_url_spec.rb +12 -3
  83. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +6 -5
  84. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +4 -3
  85. data/lib/capybara/spec/session/element/assert_match_selector.rb +36 -0
  86. data/lib/capybara/spec/session/element/match_css_spec.rb +23 -0
  87. data/lib/capybara/spec/session/element/match_xpath_spec.rb +23 -0
  88. data/lib/capybara/spec/session/element/matches_selector_spec.rb +106 -0
  89. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +22 -0
  90. data/lib/capybara/spec/session/evaluate_script_spec.rb +23 -1
  91. data/lib/capybara/spec/session/execute_script_spec.rb +22 -3
  92. data/lib/capybara/spec/session/fill_in_spec.rb +50 -32
  93. data/lib/capybara/spec/session/find_button_spec.rb +43 -2
  94. data/lib/capybara/spec/session/find_by_id_spec.rb +3 -2
  95. data/lib/capybara/spec/session/find_field_spec.rb +42 -6
  96. data/lib/capybara/spec/session/find_link_spec.rb +22 -3
  97. data/lib/capybara/spec/session/find_spec.rb +103 -57
  98. data/lib/capybara/spec/session/first_spec.rb +34 -18
  99. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +103 -0
  100. data/lib/capybara/spec/session/{within_frame_spec.rb → frame/within_frame_spec.rb} +44 -2
  101. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  102. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  103. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  104. data/lib/capybara/spec/session/has_button_spec.rb +17 -8
  105. data/lib/capybara/spec/session/has_css_spec.rb +85 -73
  106. data/lib/capybara/spec/session/has_current_path_spec.rb +91 -7
  107. data/lib/capybara/spec/session/has_field_spec.rb +93 -58
  108. data/lib/capybara/spec/session/has_link_spec.rb +9 -8
  109. data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
  110. data/lib/capybara/spec/session/has_select_spec.rb +159 -59
  111. data/lib/capybara/spec/session/has_selector_spec.rb +64 -28
  112. data/lib/capybara/spec/session/has_table_spec.rb +1 -0
  113. data/lib/capybara/spec/session/has_text_spec.rb +27 -12
  114. data/lib/capybara/spec/session/has_title_spec.rb +22 -4
  115. data/lib/capybara/spec/session/has_xpath_spec.rb +32 -29
  116. data/lib/capybara/spec/session/headers.rb +2 -1
  117. data/lib/capybara/spec/session/html_spec.rb +4 -3
  118. data/lib/capybara/spec/session/node_spec.rb +198 -38
  119. data/lib/capybara/spec/session/refresh_spec.rb +28 -0
  120. data/lib/capybara/spec/session/reset_session_spec.rb +46 -5
  121. data/lib/capybara/spec/session/response_code.rb +2 -1
  122. data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
  123. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -5
  124. data/lib/capybara/spec/session/save_page_spec.rb +34 -2
  125. data/lib/capybara/spec/session/save_screenshot_spec.rb +31 -1
  126. data/lib/capybara/spec/session/screenshot_spec.rb +4 -2
  127. data/lib/capybara/spec/session/select_spec.rb +34 -32
  128. data/lib/capybara/spec/session/selectors_spec.rb +65 -0
  129. data/lib/capybara/spec/session/sibling_spec.rb +52 -0
  130. data/lib/capybara/spec/session/text_spec.rb +4 -4
  131. data/lib/capybara/spec/session/title_spec.rb +2 -1
  132. data/lib/capybara/spec/session/uncheck_spec.rb +42 -2
  133. data/lib/capybara/spec/session/unselect_spec.rb +17 -16
  134. data/lib/capybara/spec/session/visit_spec.rb +77 -2
  135. data/lib/capybara/spec/session/window/become_closed_spec.rb +12 -11
  136. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  137. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  138. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +16 -11
  139. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +7 -4
  140. data/lib/capybara/spec/session/window/window_spec.rb +36 -29
  141. data/lib/capybara/spec/session/window/windows_spec.rb +1 -0
  142. data/lib/capybara/spec/session/window/within_window_spec.rb +31 -7
  143. data/lib/capybara/spec/session/within_spec.rb +14 -6
  144. data/lib/capybara/spec/spec_helper.rb +37 -4
  145. data/lib/capybara/spec/test_app.rb +15 -3
  146. data/lib/capybara/spec/views/buttons.erb +1 -0
  147. data/lib/capybara/spec/views/fieldsets.erb +2 -1
  148. data/lib/capybara/spec/views/form.erb +169 -9
  149. data/lib/capybara/spec/views/frame_child.erb +10 -2
  150. data/lib/capybara/spec/views/frame_one.erb +2 -1
  151. data/lib/capybara/spec/views/frame_parent.erb +3 -2
  152. data/lib/capybara/spec/views/frame_two.erb +2 -1
  153. data/lib/capybara/spec/views/header_links.erb +1 -0
  154. data/lib/capybara/spec/views/host_links.erb +1 -0
  155. data/lib/capybara/spec/views/initial_alert.erb +10 -0
  156. data/lib/capybara/spec/views/path.erb +1 -0
  157. data/lib/capybara/spec/views/popup_one.erb +1 -0
  158. data/lib/capybara/spec/views/popup_two.erb +1 -0
  159. data/lib/capybara/spec/views/postback.erb +2 -1
  160. data/lib/capybara/spec/views/tables.erb +1 -0
  161. data/lib/capybara/spec/views/with_base_tag.erb +1 -0
  162. data/lib/capybara/spec/views/with_count.erb +2 -1
  163. data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
  164. data/lib/capybara/spec/views/with_hover.erb +7 -1
  165. data/lib/capybara/spec/views/with_html.erb +40 -2
  166. data/lib/capybara/spec/views/with_html_entities.erb +1 -0
  167. data/lib/capybara/spec/views/with_js.erb +32 -1
  168. data/lib/capybara/spec/views/with_scope.erb +1 -0
  169. data/lib/capybara/spec/views/with_simple_html.erb +2 -1
  170. data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
  171. data/lib/capybara/spec/views/with_title.erb +2 -1
  172. data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
  173. data/lib/capybara/spec/views/with_windows.erb +7 -0
  174. data/lib/capybara/spec/views/within_frames.erb +3 -2
  175. data/lib/capybara/version.rb +2 -1
  176. data/lib/capybara/window.rb +20 -3
  177. data/lib/capybara.rb +189 -93
  178. data/spec/basic_node_spec.rb +7 -6
  179. data/spec/capybara_spec.rb +90 -4
  180. data/spec/dsl_spec.rb +3 -1
  181. data/spec/filter_set_spec.rb +28 -0
  182. data/spec/fixtures/capybara.csv +1 -0
  183. data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -1
  184. data/spec/fixtures/selenium_driver_rspec_success.rb +5 -1
  185. data/spec/minitest_spec.rb +130 -0
  186. data/spec/minitest_spec_spec.rb +135 -0
  187. data/spec/per_session_config_spec.rb +67 -0
  188. data/spec/rack_test_spec.rb +50 -7
  189. data/spec/result_spec.rb +76 -0
  190. data/spec/rspec/features_spec.rb +21 -8
  191. data/spec/rspec/scenarios_spec.rb +21 -0
  192. data/spec/rspec/{matchers_spec.rb → shared_spec_matchers.rb} +160 -54
  193. data/spec/rspec/views_spec.rb +5 -0
  194. data/spec/rspec_matchers_spec.rb +46 -0
  195. data/spec/rspec_spec.rb +79 -1
  196. data/spec/selector_spec.rb +199 -0
  197. data/spec/selenium_spec_chrome.rb +54 -9
  198. data/spec/selenium_spec_firefox.rb +68 -0
  199. data/spec/selenium_spec_marionette.rb +127 -0
  200. data/spec/server_spec.rb +102 -14
  201. data/spec/session_spec.rb +54 -0
  202. data/spec/shared_selenium_session.rb +215 -0
  203. data/spec/spec_helper.rb +7 -0
  204. metadata +140 -15
  205. data/spec/selenium_spec.rb +0 -128
data/lib/capybara.rb CHANGED
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  require 'timeout'
2
3
  require 'nokogiri'
3
4
  require 'xpath'
5
+ require 'forwardable'
6
+ require 'capybara/config'
4
7
 
5
8
  module Capybara
6
9
  class CapybaraError < StandardError; end
@@ -18,13 +21,41 @@ module Capybara
18
21
  class WindowError < CapybaraError; end
19
22
  class ReadOnlyElementError < CapybaraError; end
20
23
 
24
+
21
25
  class << self
22
- attr_accessor :asset_host, :app_host, :run_server, :default_host, :always_include_port
23
- attr_accessor :server_port, :exact, :match, :exact_options, :visible_text_only
24
- attr_accessor :default_selector, :default_max_wait_time, :ignore_hidden_elements
25
- attr_accessor :save_and_open_page_path, :wait_on_first_by_default, :automatic_reload, :raise_server_errors, :server_errors
26
- attr_writer :default_driver, :current_driver, :javascript_driver, :session_name, :server_host
27
- attr_accessor :app
26
+ extend Forwardable
27
+
28
+ # DelegateCapybara global configurations
29
+ # @!method app
30
+ # See {Capybara.configure}
31
+ # @!method reuse_server
32
+ # See {Capybara.configure}
33
+ # @!method threadsafe
34
+ # See {Capybara.configure}
35
+ # @!method server
36
+ # See {Capybara.configure}
37
+ # @!method default_driver
38
+ # See {Capybara.configure}
39
+ # @!method javascript_driver
40
+ # See {Capybara.configure}
41
+ Config::OPTIONS.each do |method|
42
+ def_delegators :config, method, "#{method}="
43
+ end
44
+
45
+ # Delegate Capybara global configurations
46
+ # @!method default_selector
47
+ # See {Capybara.configure}
48
+ # @!method default_max_wait_time
49
+ # See {Capybara.configure}
50
+ # @!method app_host
51
+ # See {Capybara.configure}
52
+ # @!method always_include_port
53
+ # See {Capybara.configure}
54
+ # @!method wait_on_first_by_default
55
+ # See {Capybara.configure}
56
+ SessionConfig::OPTIONS.each do |method|
57
+ def_delegators :config, method, "#{method}="
58
+ end
28
59
 
29
60
  ##
30
61
  #
@@ -37,27 +68,33 @@ module Capybara
37
68
  #
38
69
  # === Configurable options
39
70
  #
40
- # [app_host = String] The default host to use when giving a relative URL to visit
41
- # [always_include_port = Boolean] Whether the Rack server's port should automatically be inserted into every visited URL (Default: false)
42
- # [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil)
43
- # [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true)
44
- # [raise_server_errors = Boolean] Should errors raised in the server be raised in the tests? (Default: true)
45
- # [server_errors = Array\<Class\>] Error classes that should be raised in the tests if they are raised in the server and Capybara.raise_server_errors is true (Default: [StandardError])
46
- # [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: :css)
47
- # [default_max_wait_time = Numeric] The maximum number of seconds to wait for asynchronous processes to finish (Default: 2)
48
- # [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: true)
49
- # [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
50
- # [save_and_open_page_path = String] Where to put pages saved through save_and_open_page (Default: Dir.pwd)
51
- # [wait_on_first_by_default = Boolean] Whether Node#first defaults to Capybara waiting behavior for at least 1 element to match (Default: false)
71
+ # [app_host = String/nil] The default host to use when giving a relative URL to visit, must be a valid URL e.g. http://www.example.com
72
+ # [always_include_port = Boolean] Whether the Rack server's port should automatically be inserted into every visited URL unless another port is explicitly specified (Default: false)
73
+ # [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil)
74
+ # [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true)
75
+ # [raise_server_errors = Boolean] Should errors raised in the server be raised in the tests? (Default: true)
76
+ # [server_errors = Array\<Class\>] Error classes that should be raised in the tests if they are raised in the server and Capybara.raise_server_errors is true (Default: [StandardError])
77
+ # [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: :css)
78
+ # [default_max_wait_time = Numeric] The maximum number of seconds to wait for asynchronous processes to finish (Default: 2)
79
+ # [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: true)
80
+ # [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
81
+ # [save_path = String] Where to put pages saved through save_(page|screenshot), save_and_open_(page|screenshot) (Default: Dir.pwd)
82
+ # [wait_on_first_by_default = Boolean] Whether Node#first defaults to Capybara waiting behavior for at least 1 element to match (Default: false)
83
+ # [automatic_label_click = Boolean] Whether Node#choose, Node#check, Node#uncheck will attempt to click the associated label element if the checkbox/radio button are non-visible (Default: false)
84
+ # [enable_aria_label = Boolean] Whether fields, links, and buttons will match against aria-label attribute (Default: false)
85
+ # [reuse_server = Boolean] Reuse the server thread between multiple sessions using the same app object (Default: true)
86
+ # [threadsafe = Boolean] Whether sessions can be configured individually (Default: false)
87
+ # [server = Symbol] The name of the registered server to use when running the app under test (Default: :webrick)
88
+ #
52
89
  # === DSL Options
53
90
  #
54
91
  # when using capybara/dsl, the following options are also available:
55
92
  #
56
- # [default_driver = Symbol] The name of the driver to use by default. (Default: :rack_test)
57
- # [javascript_driver = Symbol] The name of a driver to use for JavaScript enabled tests. (Default: :selenium)
93
+ # [default_driver = Symbol] The name of the driver to use by default. (Default: :rack_test)
94
+ # [javascript_driver = Symbol] The name of a driver to use for JavaScript enabled tests. (Default: :selenium)
58
95
  #
59
96
  def configure
60
- yield self
97
+ yield ConfigureDeprecator.new(config)
61
98
  end
62
99
 
63
100
  ##
@@ -77,6 +114,26 @@ module Capybara
77
114
  drivers[name] = block
78
115
  end
79
116
 
117
+ ##
118
+ #
119
+ # Register a new server for Capybara.
120
+ #
121
+ # Capybara.register_server :webrick do |app, port, host|
122
+ # require 'rack/handler/webrick'
123
+ # Rack::Handler::WEBrick.run(app, ...)
124
+ # end
125
+ #
126
+ # @param [Symbol] name The name of the new driver
127
+ # @yield [app, port, host] This block takes a rack app and a port and returns a rack server listening on that port
128
+ # @yieldparam [<Rack>] app The rack application that this server will contain.
129
+ # @yieldparam port The port number the server should listen on
130
+ # @yieldparam host The host/ip to bind to
131
+ # @yieldreturn [Capybara::Driver::Base] A Capybara driver instance
132
+ #
133
+ def register_server(name, &block)
134
+ servers[name.to_sym] = block
135
+ end
136
+
80
137
  ##
81
138
  #
82
139
  # Add a new selector to Capybara. Selectors can be used by various methods in Capybara
@@ -109,29 +166,30 @@ module Capybara
109
166
  Capybara::Selector.add(name, &block)
110
167
  end
111
168
 
112
- def drivers
113
- @drivers ||= {}
114
- end
115
-
116
169
  ##
117
170
  #
118
- # Register a proc that Capybara will call to run the Rack application.
171
+ # Modify a selector previously created by {Capybara.add_selector}.
172
+ # For example, adding a new filter to the :button selector to filter based on
173
+ # button style (a class) might look like this
119
174
  #
120
- # Capybara.server do |app, port|
121
- # require 'rack/handler/mongrel'
122
- # Rack::Handler::Mongrel.run(app, :Port => port)
175
+ # Capybara.modify_selector(:button) do
176
+ # filter (:style, valid_values: [:primary, :secondary]) { |node, style| node[:class].split.include? "btn-#{style}" }
123
177
  # end
124
178
  #
125
- # By default, Capybara will try to run webrick.
126
179
  #
127
- # @yield [app, port] This block receives a rack app and port and should run a Rack handler
180
+ # @param [Symbol] name The name of the selector to modify
181
+ # @yield A block executed in the context of the existing {Capybara::Selector}
128
182
  #
129
- def server(&block)
130
- if block_given?
131
- @server = block
132
- else
133
- @server
134
- end
183
+ def modify_selector(name, &block)
184
+ Capybara::Selector.update(name, &block)
185
+ end
186
+
187
+ def drivers
188
+ @drivers ||= {}
189
+ end
190
+
191
+ def servers
192
+ @servers ||= {}
135
193
  end
136
194
 
137
195
  ##
@@ -140,7 +198,16 @@ module Capybara
140
198
  # in a {Capybara::Node::Simple} which exposes all {Capybara::Node::Matchers},
141
199
  # {Capybara::Node::Finders} and {Capybara::Node::DocumentMatchers}. This allows you to query
142
200
  # any string containing HTML in the exact same way you would query the current document in a Capybara
143
- # session. For example:
201
+ # session.
202
+ #
203
+ # Example: A single element
204
+ #
205
+ # node = Capybara.string('<a href="foo">bar</a>')
206
+ # anchor = node.first('a')
207
+ # anchor[:href] #=> 'foo'
208
+ # anchor.text #=> 'bar'
209
+ #
210
+ # Example: Multiple elements
144
211
  #
145
212
  # node = Capybara.string <<-HTML
146
213
  # <ul>
@@ -150,7 +217,7 @@ module Capybara
150
217
  # HTML
151
218
  #
152
219
  # node.find('#projects').text # => 'Projects'
153
- # node.has_selector?('li#home', :text => 'Home')
220
+ # node.has_selector?('li#home', text: 'Home')
154
221
  # node.has_selector?('#projects')
155
222
  # node.find('ul').find('li:first-child').text # => 'Home'
156
223
  #
@@ -168,19 +235,10 @@ module Capybara
168
235
  # manually.
169
236
  #
170
237
  # @param [Rack Application] app The rack application to run
171
- # @param [Fixnum] port The port to run the application on
238
+ # @param [Integer] port The port to run the application on
172
239
  #
173
240
  def run_default_server(app, port)
174
- require 'rack/handler/webrick'
175
- Rack::Handler::WEBrick.run(app, :Host => server_host, :Port => port, :AccessLog => [], :Logger => WEBrick::Log::new(nil, 0))
176
- end
177
-
178
- ##
179
- #
180
- # @return [Symbol] The name of the driver to use by default
181
- #
182
- def default_driver
183
- @default_driver || :rack_test
241
+ servers[:webrick].call(app, port, server_host)
184
242
  end
185
243
 
186
244
  ##
@@ -188,16 +246,20 @@ module Capybara
188
246
  # @return [Symbol] The name of the driver currently in use
189
247
  #
190
248
  def current_driver
191
- @current_driver || default_driver
249
+ if threadsafe
250
+ Thread.current['capybara_current_driver']
251
+ else
252
+ @current_driver
253
+ end || default_driver
192
254
  end
193
255
  alias_method :mode, :current_driver
194
256
 
195
- ##
196
- #
197
- # @return [Symbol] The name of the driver used when JavaScript is needed
198
- #
199
- def javascript_driver
200
- @javascript_driver || :selenium
257
+ def current_driver=(name)
258
+ if threadsafe
259
+ Thread.current['capybara_current_driver'] = name
260
+ else
261
+ @current_driver = name
262
+ end
201
263
  end
202
264
 
203
265
  ##
@@ -205,7 +267,7 @@ module Capybara
205
267
  # Use the default driver as the current driver
206
268
  #
207
269
  def use_default_driver
208
- @current_driver = nil
270
+ self.current_driver = nil
209
271
  end
210
272
 
211
273
  ##
@@ -217,15 +279,7 @@ module Capybara
217
279
  Capybara.current_driver = driver
218
280
  yield
219
281
  ensure
220
- @current_driver = previous_driver
221
- end
222
-
223
- ##
224
- #
225
- # @return [String] The IP address bound by default server
226
- #
227
- def server_host
228
- @server_host || '127.0.0.1'
282
+ self.current_driver = previous_driver
229
283
  end
230
284
 
231
285
  ##
@@ -256,7 +310,8 @@ module Capybara
256
310
  # as cookies.
257
311
  #
258
312
  def reset_sessions!
259
- session_pool.each { |mode, session| session.reset! }
313
+ #reset in reverse so sessions that started servers are reset last
314
+ session_pool.reverse_each { |_mode, session| session.reset! }
260
315
  end
261
316
  alias_method :reset!, :reset_sessions!
262
317
 
@@ -267,7 +322,19 @@ module Capybara
267
322
  # @return [Symbol] The name of the currently used session.
268
323
  #
269
324
  def session_name
270
- @session_name ||= :default
325
+ if threadsafe
326
+ Thread.current['capybara_session_name'] ||= :default
327
+ else
328
+ @session_name ||= :default
329
+ end
330
+ end
331
+
332
+ def session_name=(name)
333
+ if threadsafe
334
+ Thread.current['capybara_session_name'] = name
335
+ else
336
+ @session_name = name
337
+ end
271
338
  end
272
339
 
273
340
  ##
@@ -275,11 +342,19 @@ module Capybara
275
342
  # Yield a block using a specific session name.
276
343
  #
277
344
  def using_session(name)
278
- previous_session_name = self.session_name
345
+ previous_session_info = {
346
+ session_name: session_name,
347
+ current_driver: current_driver,
348
+ app: app
349
+ }
279
350
  self.session_name = name
280
351
  yield
281
352
  ensure
282
- self.session_name = previous_session_name
353
+ self.session_name = previous_session_info[:session_name]
354
+ if threadsafe
355
+ self.current_driver = previous_session_info[:current_driver]
356
+ self.app = previous_session_info[:app]
357
+ end
283
358
  end
284
359
 
285
360
  ##
@@ -292,21 +367,13 @@ module Capybara
292
367
  def HTML(html)
293
368
  Nokogiri::HTML(html).tap do |document|
294
369
  document.xpath('//textarea').each do |textarea|
295
- textarea.content=textarea.content.sub(/\A\n/,'')
370
+ textarea['_capybara_raw_value'] = textarea.content.sub(/\A\n/,'')
296
371
  end
297
372
  end
298
373
  end
299
-
300
- # @deprecated Use default_max_wait_time instead
301
- def default_wait_time
302
- deprecate('default_wait_time', 'default_max_wait_time', true)
303
- default_max_wait_time
304
- end
305
-
306
- # @deprecated Use default_max_wait_time= instead
307
- def default_wait_time=(t)
308
- deprecate('default_wait_time=', 'default_max_wait_time=')
309
- self.default_max_wait_time = t
374
+
375
+ def session_options
376
+ config.session_options
310
377
  end
311
378
 
312
379
  def included(base)
@@ -314,13 +381,10 @@ module Capybara
314
381
  warn "`include Capybara` is deprecated. Please use `include Capybara::DSL` instead."
315
382
  end
316
383
 
317
- def deprecate(method, alternate_method, once=false)
318
- @deprecation_notified ||= {}
319
- warn "DEPRECATED: ##{method} is deprecated, please use ##{alternate_method} instead" unless once and @deprecation_notified[method]
320
- @deprecation_notified[method]=true
321
- end
322
-
323
384
  private
385
+ def config
386
+ @config ||= Capybara::Config.new
387
+ end
324
388
 
325
389
  def session_pool
326
390
  @session_pool ||= {}
@@ -337,7 +401,6 @@ module Capybara
337
401
 
338
402
  require 'capybara/helpers'
339
403
  require 'capybara/session'
340
- require 'capybara/dsl'
341
404
  require 'capybara/window'
342
405
  require 'capybara/server'
343
406
  require 'capybara/selector'
@@ -345,11 +408,15 @@ module Capybara
345
408
  require 'capybara/version'
346
409
 
347
410
  require 'capybara/queries/base_query'
348
- require 'capybara/query'
411
+ require 'capybara/queries/selector_query'
349
412
  require 'capybara/queries/text_query'
350
413
  require 'capybara/queries/title_query'
351
414
  require 'capybara/queries/current_path_query'
352
-
415
+ require 'capybara/queries/match_query'
416
+ require 'capybara/queries/ancestor_query'
417
+ require 'capybara/queries/sibling_query'
418
+ require 'capybara/query'
419
+
353
420
  require 'capybara/node/finders'
354
421
  require 'capybara/node/matchers'
355
422
  require 'capybara/node/actions'
@@ -372,10 +439,24 @@ module Capybara
372
439
  require 'capybara/selenium/driver'
373
440
  end
374
441
 
442
+ Capybara.register_server :default do |app, port, _host|
443
+ Capybara.run_default_server(app, port)
444
+ end
445
+
446
+ Capybara.register_server :webrick do |app, port, host, options={}|
447
+ require 'rack/handler/webrick'
448
+ Rack::Handler::WEBrick.run(app, {Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log::new(nil, 0)}.merge(options))
449
+ end
450
+
451
+ Capybara.register_server :puma do |app, port, host, options={}|
452
+ require 'rack/handler/puma'
453
+ Rack::Handler::Puma.run(app, {Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false}.merge(options))
454
+ end
455
+
375
456
  Capybara.configure do |config|
376
457
  config.always_include_port = false
377
458
  config.run_server = true
378
- config.server {|app, port| Capybara.run_default_server(app, port)}
459
+ config.server = :default
379
460
  config.default_selector = :css
380
461
  config.default_max_wait_time = 2
381
462
  config.ignore_hidden_elements = true
@@ -383,10 +464,14 @@ Capybara.configure do |config|
383
464
  config.automatic_reload = true
384
465
  config.match = :smart
385
466
  config.exact = false
467
+ config.exact_text = false
386
468
  config.raise_server_errors = true
387
469
  config.server_errors = [StandardError]
388
470
  config.visible_text_only = false
389
471
  config.wait_on_first_by_default = false
472
+ config.automatic_label_click = false
473
+ config.enable_aria_label = false
474
+ config.reuse_server = true
390
475
  end
391
476
 
392
477
  Capybara.register_driver :rack_test do |app|
@@ -396,3 +481,14 @@ end
396
481
  Capybara.register_driver :selenium do |app|
397
482
  Capybara::Selenium::Driver.new(app)
398
483
  end
484
+
485
+ Capybara.register_driver :selenium_chrome do |app|
486
+ Capybara::Selenium::Driver.new(app, :browser => :chrome)
487
+ end
488
+
489
+ Capybara.register_driver :selenium_chrome_headless do |app|
490
+ browser_options = ::Selenium::WebDriver::Chrome::Options.new()
491
+ browser_options.args << '--headless'
492
+ browser_options.args << '--disable-gpu'
493
+ Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
494
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  RSpec.describe Capybara do
@@ -51,7 +52,7 @@ RSpec.describe Capybara do
51
52
 
52
53
  it "allows using custom matchers" do
53
54
  Capybara.add_selector :lifeform do
54
- xpath { |name| "//option[contains(.,'#{name}')]" }
55
+ xpath { |name| ".//option[contains(.,'#{name}')]" }
55
56
  end
56
57
  expect(string).to have_selector(:id, "page")
57
58
  expect(string).not_to have_selector(:id, 'does-not-exist')
@@ -68,13 +69,13 @@ RSpec.describe Capybara do
68
69
  end
69
70
 
70
71
  it "allows using matchers with text option" do
71
- expect(string).to have_css('h1', :text => 'Totally awesome')
72
- expect(string).not_to have_css('h1', :text => 'Not so awesome')
72
+ expect(string).to have_css('h1', text: 'Totally awesome')
73
+ expect(string).not_to have_css('h1', text: 'Not so awesome')
73
74
  end
74
75
 
75
76
  it "allows finding only visible nodes" do
76
- expect(string.all(:css, '#secret', :visible => true)).to be_empty
77
- expect(string.all(:css, '#secret', :visible => false).size).to eq(1)
77
+ expect(string.all(:css, '#secret', visible: true)).to be_empty
78
+ expect(string.all(:css, '#secret', visible: false).size).to eq(1)
78
79
  end
79
80
 
80
81
  it "allows finding elements and extracting text from them" do
@@ -100,7 +101,7 @@ RSpec.describe Capybara do
100
101
 
101
102
  it "allows finding elements and checking if they are visible" do
102
103
  expect(string.find('//h1')).to be_visible
103
- expect(string.find(:css, "#secret", :visible => false)).not_to be_visible
104
+ expect(string.find(:css, "#secret", visible: false)).not_to be_visible
104
105
  end
105
106
 
106
107
  it "allows finding elements and checking if they are disabled" do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  RSpec.describe Capybara do
@@ -13,8 +14,8 @@ RSpec.describe Capybara do
13
14
  end
14
15
 
15
16
  it "should be accesible as the deprecated default_wait_time" do
16
- expect_any_instance_of(Kernel).to receive(:warn).once.with('DEPRECATED: #default_wait_time= is deprecated, please use #default_max_wait_time= instead')
17
- expect_any_instance_of(Kernel).to receive(:warn).once.with('DEPRECATED: #default_wait_time is deprecated, please use #default_max_wait_time instead')
17
+ expect(Capybara.send(:config)).to receive(:warn).ordered.with('DEPRECATED: #default_wait_time= is deprecated, please use #default_max_wait_time= instead')
18
+ expect(Capybara.send(:config)).to receive(:warn).ordered.with('DEPRECATED: #default_wait_time is deprecated, please use #default_max_wait_time instead')
18
19
  @previous_default_time = Capybara.default_max_wait_time
19
20
  Capybara.default_wait_time = 5
20
21
  expect(Capybara.default_wait_time).to eq(5)
@@ -33,9 +34,24 @@ RSpec.describe Capybara do
33
34
  end
34
35
  end
35
36
 
37
+ describe '.register_server' do
38
+ it "should add a new server" do
39
+ handler = double("handler")
40
+ Capybara.register_server :blob do |app, port, host|
41
+ handler.run
42
+ end
43
+
44
+ expect(Capybara.servers).to have_key(:blob)
45
+ end
46
+ end
47
+
36
48
  describe ".server" do
49
+ before do
50
+ @old_server = Capybara.server
51
+ end
52
+
37
53
  after do
38
- Capybara.server {|app, port| Capybara.run_default_server(app, port)}
54
+ Capybara.server(&@old_server)
39
55
  end
40
56
 
41
57
  it "should default to a proc that calls run_default_server" do
@@ -49,11 +65,81 @@ RSpec.describe Capybara do
49
65
  Capybara.server(&server)
50
66
  expect(Capybara.server).to eq(server)
51
67
  end
68
+
69
+ it "should have :webrick registered" do
70
+ require 'rack/handler/webrick'
71
+ mock_app = double('app')
72
+ Capybara.server = :webrick
73
+ expect(Rack::Handler::WEBrick).to receive(:run)
74
+ Capybara.server.call(mock_app, 8000)
75
+ end
76
+
77
+ it "should have :puma registered" do
78
+ require 'rack/handler/puma'
79
+ mock_app = double('app')
80
+ Capybara.server = :puma
81
+ expect(Rack::Handler::Puma).to receive(:run).with(mock_app, hash_including(Host: nil, Port: 8000))
82
+ Capybara.server.call(mock_app, 8000)
83
+ end
84
+
85
+ it "should pass options to server" do
86
+ require 'rack/handler/puma'
87
+ mock_app = double('app')
88
+ Capybara.server = :puma, { Silent: true }
89
+ expect(Rack::Handler::Puma).to receive(:run).with(mock_app, hash_including(Host: nil, Port: 9000, Silent: true))
90
+ Capybara.server.call(mock_app, 9000)
91
+ end
92
+ end
93
+
94
+ describe 'app_host' do
95
+ after do
96
+ Capybara.app_host = nil
97
+ end
98
+
99
+ it "should warn if not a valid URL" do
100
+ expect { Capybara.app_host = "www.example.com" }.to raise_error(ArgumentError, /Capybara\.app_host should be set to a url/)
101
+ end
102
+
103
+ it "should not warn if a valid URL" do
104
+ expect { Capybara.app_host = "http://www.example.com" }.not_to raise_error
105
+ end
106
+
107
+ it "should not warn if nil" do
108
+ expect { Capybara.app_host = nil }.not_to raise_error
109
+ end
110
+ end
111
+
112
+ describe 'default_host' do
113
+ around do |test|
114
+ old_default = Capybara.default_host
115
+ test.run
116
+ Capybara.default_host = old_default
117
+ end
118
+
119
+ it "should warn if not a valid URL" do
120
+ expect { Capybara.default_host = "www.example.com" }.to raise_error(ArgumentError, /Capybara\.default_host should be set to a url/)
121
+ end
122
+
123
+ it "should not warn if a valid URL" do
124
+ expect { Capybara.default_host = "http://www.example.com" }.not_to raise_error
125
+ end
126
+ end
127
+
128
+ describe "configure" do
129
+ it 'deprecates calling non configuration option methods in configure' do
130
+ expect_any_instance_of(Kernel).to receive(:warn).
131
+ with('Calling register_driver from Capybara.configure is deprecated - please call it on Capybara directly ( Capybara.register_driver(...) )')
132
+ Capybara.configure do |config|
133
+ config.register_driver(:random_name) do
134
+ #just a random block
135
+ end
136
+ end
137
+ end
52
138
  end
53
139
  end
54
140
 
55
141
  RSpec.describe Capybara::Session do
56
- context 'with non-existant driver' do
142
+ context 'with nonexistent driver' do
57
143
  it "should raise an error" do
58
144
  expect {
59
145
  Capybara::Session.new(:quox, TestApp).driver
data/spec/dsl_spec.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
  require 'capybara/dsl'
3
4
 
@@ -5,7 +6,7 @@ class TestClass
5
6
  include Capybara::DSL
6
7
  end
7
8
 
8
- Capybara::SpecHelper.run_specs TestClass.new, "DSL", :capybara_skip => [
9
+ Capybara::SpecHelper.run_specs TestClass.new, "DSL", capybara_skip: [
9
10
  :js,
10
11
  :modals,
11
12
  :screenshot,
@@ -15,6 +16,7 @@ Capybara::SpecHelper.run_specs TestClass.new, "DSL", :capybara_skip => [
15
16
  :server,
16
17
  :hover,
17
18
  :about_scheme,
19
+ :psc
18
20
  ]
19
21
 
20
22
  RSpec.describe Capybara::DSL do
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ RSpec.describe Capybara::Selector::FilterSet do
5
+ after do
6
+ Capybara::Selector::FilterSet.remove(:test)
7
+ end
8
+
9
+ it "allows node filters" do
10
+ fs = Capybara::Selector::FilterSet.add(:test) do
11
+ filter(:node_test, :boolean) { |node, value| true }
12
+ expression_filter(:expression_test, :boolean) { |expr, value| true }
13
+ end
14
+
15
+ expect(fs.node_filters.keys).to include(:node_test)
16
+ expect(fs.node_filters.keys).not_to include(:expression_test)
17
+ end
18
+
19
+ it "allows expression filters" do
20
+ fs = Capybara::Selector::FilterSet.add(:test) do
21
+ filter(:node_test, :boolean) { |node, value| true }
22
+ expression_filter(:expression_test, :boolean) { |expr, value| true }
23
+ end
24
+
25
+ expect(fs.expression_filters.keys).to include(:expression_test)
26
+ expect(fs.expression_filters.keys).not_to include(:node_test)
27
+ end
28
+ end
@@ -0,0 +1 @@
1
+ test, mime-type, file