capybara 3.6.0 → 3.7.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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +16 -0
  3. data/README.md +5 -1
  4. data/lib/capybara.rb +2 -0
  5. data/lib/capybara/minitest/spec.rb +1 -1
  6. data/lib/capybara/node/actions.rb +34 -25
  7. data/lib/capybara/node/base.rb +15 -17
  8. data/lib/capybara/node/document_matchers.rb +1 -3
  9. data/lib/capybara/node/element.rb +11 -12
  10. data/lib/capybara/node/finders.rb +2 -1
  11. data/lib/capybara/node/simple.rb +13 -6
  12. data/lib/capybara/queries/base_query.rb +4 -4
  13. data/lib/capybara/queries/selector_query.rb +119 -94
  14. data/lib/capybara/queries/text_query.rb +2 -1
  15. data/lib/capybara/rack_test/form.rb +4 -4
  16. data/lib/capybara/rack_test/node.rb +5 -5
  17. data/lib/capybara/result.rb +23 -32
  18. data/lib/capybara/rspec/compound.rb +1 -1
  19. data/lib/capybara/rspec/matchers.rb +63 -61
  20. data/lib/capybara/selector.rb +28 -10
  21. data/lib/capybara/selector/css.rb +17 -17
  22. data/lib/capybara/selector/filter_set.rb +9 -9
  23. data/lib/capybara/selector/selector.rb +3 -4
  24. data/lib/capybara/selenium/driver.rb +73 -95
  25. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +4 -4
  26. data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +9 -0
  27. data/lib/capybara/selenium/node.rb +127 -67
  28. data/lib/capybara/selenium/nodes/chrome_node.rb +3 -3
  29. data/lib/capybara/selenium/nodes/marionette_node.rb +14 -8
  30. data/lib/capybara/server.rb +2 -2
  31. data/lib/capybara/server/animation_disabler.rb +17 -3
  32. data/lib/capybara/server/middleware.rb +8 -4
  33. data/lib/capybara/session.rb +43 -37
  34. data/lib/capybara/session/config.rb +8 -6
  35. data/lib/capybara/spec/session/assert_text_spec.rb +14 -0
  36. data/lib/capybara/spec/session/attach_file_spec.rb +7 -0
  37. data/lib/capybara/spec/session/check_spec.rb +21 -0
  38. data/lib/capybara/spec/session/choose_spec.rb +15 -1
  39. data/lib/capybara/spec/session/fill_in_spec.rb +7 -0
  40. data/lib/capybara/spec/session/find_spec.rb +2 -1
  41. data/lib/capybara/spec/session/has_selector_spec.rb +18 -0
  42. data/lib/capybara/spec/session/has_text_spec.rb +14 -0
  43. data/lib/capybara/spec/session/node_spec.rb +2 -1
  44. data/lib/capybara/spec/session/reset_session_spec.rb +4 -4
  45. data/lib/capybara/spec/session/text_spec.rb +2 -1
  46. data/lib/capybara/spec/session/title_spec.rb +2 -1
  47. data/lib/capybara/spec/session/uncheck_spec.rb +8 -0
  48. data/lib/capybara/spec/session/within_spec.rb +2 -1
  49. data/lib/capybara/spec/spec_helper.rb +1 -32
  50. data/lib/capybara/spec/views/with_js.erb +3 -4
  51. data/lib/capybara/version.rb +1 -1
  52. data/spec/minitest_spec.rb +4 -0
  53. data/spec/minitest_spec_spec.rb +4 -0
  54. data/spec/rack_test_spec.rb +4 -4
  55. data/spec/rspec/shared_spec_matchers.rb +4 -2
  56. data/spec/selector_spec.rb +15 -1
  57. data/spec/selenium_spec_chrome.rb +1 -6
  58. data/spec/selenium_spec_chrome_remote.rb +1 -1
  59. data/spec/selenium_spec_firefox_remote.rb +2 -5
  60. data/spec/selenium_spec_ie.rb +41 -4
  61. data/spec/selenium_spec_marionette.rb +1 -25
  62. data/spec/shared_selenium_session.rb +74 -16
  63. data/spec/spec_helper.rb +41 -0
  64. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f61329ea428004635c5d6768afcdc61fcc22a2dd3a4cb0f14bde2d3b05102cb
4
- data.tar.gz: d9d3de632455c5a3a8eecbef2c2fccc7b8d301bb589dcd7a5a21c719e639a5f5
3
+ metadata.gz: e081025be98ae57e3e43ef0fb2a156b3bfb3ff4d54f8f25bfc09a4bcff2fc59c
4
+ data.tar.gz: 95e8d6fffe004d4802cd0f97d3bddeae5394041dc774d341c3ad10a60d0b04eb
5
5
  SHA512:
6
- metadata.gz: 79e61c8494174a8006f158dc0b26d143a14525e4c0e77b4a1b5148f7f46c79207d4d5d89d0f5ef6f3ed3a8374bf2b54e915160770c6c254147c9aea52da48bf1
7
- data.tar.gz: b329ae727a2c0d47903f9c992e8acd9e7e26e3bb280751fb8f681cb67c29650ad11d002ad9bfae627c1e767a00483e97a74667e564d4cec0bae2c529afc27452
6
+ metadata.gz: 93e42ca9e9ad0bde5911fe2c7e86ad2d0ac1c40428dfcd256aa01b21b6a8c2e1755df018a272f1917e0628c5c7e1a68b35eb930c3abdb5ffec4e9079187ca5b8
7
+ data.tar.gz: c7faa43983241d170cf725c22fcc595d2fde4572a71abcf3271d32993bbb6e2874a96c74b850090089598d277b8793b072315fc1e34c9e7a876daeb64a007f7e
data/History.md CHANGED
@@ -1,3 +1,19 @@
1
+ # Version 3.7.0
2
+ Release date: 2018-09-02
3
+
4
+ ### Added
5
+
6
+ * `Capybara.disable_animation` can be set to a CSS selector to identify which elements will have animation disabled [Michael Glass]
7
+ * `Capybara.default_normalize_ws` option which sets whether or not text predicates and matchers (`has_text?`, `has_content?`, `assert_text`, etc) use `normalize_ws` option by default. Defaults to false. [Stegalin Ivan]
8
+ * Selector based predicates, matchers, and finders now support the `:normalize_ws` option for the `:text`/`:exact_text` filters. Defaults to the `Capybara.default_normalize_ws`setting above.
9
+ * Element `choose`/`check`/`uncheck`/`attach_file`/`fill_in` can now operate on the element they're called on or a descendant if no locator is passed.
10
+
11
+ ### Fixed
12
+
13
+ * All CSS styles applied by the `Element#attach_file` `:make_visible` option will now have `!important` priority set to ensure they override any other specified style.
14
+ * Firefox file inputs are only manually cleared when necessary.
15
+ *
16
+
1
17
  # Version 3.6.0
2
18
  Release date: 2018-08-14
3
19
 
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=capybara&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=capybara&package-manager=bundler&version-scheme=semver)
8
8
 
9
9
  **Note** You are viewing the README for the development version of Capybara. If you are using the current release version
10
- you can find the README at https://github.com/teamcapybara/capybara/blob/3.6_stable/README.md
10
+ you can find the README at https://github.com/teamcapybara/capybara/blob/3.7_stable/README.md
11
11
 
12
12
 
13
13
  Capybara helps you test web applications by simulating how a real user would
@@ -409,6 +409,8 @@ and test server, see "Transactions and database setup" below.
409
409
 
410
410
  ### <a name="capybara-webkit"></a>Capybara-webkit
411
411
 
412
+ Note: `capybara-webkit` depends on QtWebkit which went EOL quite some time ago. There has been an attempt to revive the project but `capybara-webkit` is not yet (AFAIK) compatible with the revived version of QtWebKit (could be a good OSS project for someone) and as such is still limited to an old version of QtWebKit. This means its support for modern JS and CSS is severely limited. Y
413
+
412
414
  The [capybara-webkit driver](https://github.com/thoughtbot/capybara-webkit) is for true headless
413
415
  testing. It uses QtWebKit to start a rendering engine process. It can execute JavaScript as well.
414
416
  It is significantly faster than drivers like Selenium since it does not load an entire browser.
@@ -427,6 +429,8 @@ Capybara.javascript_driver = :webkit
427
429
 
428
430
  ### <a name="poltergeist"></a>Poltergeist
429
431
 
432
+ Note: `poltergeist` depends on PhantomJS for which active development ended quite some time ago (2.1.1). As such it is roughly equivalent to a 6-7 year old version of Safari, meaning lack of support for modern JS And CSS. If any effort to update PhantomJS succeeds in the future this situation could change.
433
+
430
434
  [Poltergeist](https://github.com/teampoltergeist/poltergeist) is another
431
435
  headless driver which integrates Capybara with
432
436
  [PhantomJS](http://phantomjs.org/). It is truly headless, so doesn't
@@ -85,6 +85,7 @@ module Capybara
85
85
  # [default_set_options = Hash] The default options passed to Node::set (Default: {})
86
86
  # [test_id = Symbol/String/nil] Optional attribute to match locator aginst with builtin selectors along with id (Default: nil)
87
87
  # [predicates_wait = Boolean] Whether Capybaras predicate matchers use waiting behavior by default (Default: true)
88
+ # [default_normalize_ws = Boolean] Whether text predicates and matchers use normalize whitespace behaviour (Default: false)
88
89
  #
89
90
  # === DSL Options
90
91
  #
@@ -486,6 +487,7 @@ Capybara.configure do |config|
486
487
  config.default_set_options = {}
487
488
  config.test_id = nil
488
489
  config.predicates_wait = true
490
+ config.default_normalize_ws = false
489
491
  end
490
492
 
491
493
  Capybara.register_driver :rack_test do |app|
@@ -169,7 +169,7 @@ module Capybara
169
169
  # Expectation that element has style
170
170
  #
171
171
  # @!method must_have_style
172
- # see {Capybara::SessionMatchers#assert_style}
172
+ # see {Capybara::Node::Matchers#assert_style}
173
173
  end
174
174
  end
175
175
  end
@@ -62,6 +62,7 @@ module Capybara
62
62
  #
63
63
  # Locate a text field or text area and fill it in with the given text
64
64
  # The field can be found via its name, id, Capybara.test_id attribute, or label text.
65
+ # If no locator is provided will operate on self or a descendant
65
66
  #
66
67
  # page.fill_in 'Name', with: 'Bob'
67
68
  #
@@ -82,6 +83,7 @@ module Capybara
82
83
  # @return [Capybara::Node::Element] The element filled_in
83
84
  def fill_in(locator = nil, with:, currently_with: nil, fill_options: {}, **find_options)
84
85
  find_options[:with] = currently_with if currently_with
86
+ find_options[:allow_self] = true if locator.nil?
85
87
  find(:fillable_field, locator, find_options).set(with, fill_options)
86
88
  end
87
89
 
@@ -90,8 +92,9 @@ module Capybara
90
92
 
91
93
  ##
92
94
  #
93
- # Find a radio button and mark it as checked. The radio button can be found
94
- # via name, id or label text.
95
+ # Find a descendant radio button and mark it as checked. The radio button can be found
96
+ # via name, id or label text. If no locator is provided this will match against self or
97
+ # a descendant.
95
98
  #
96
99
  # page.choose('Male')
97
100
  #
@@ -112,8 +115,9 @@ module Capybara
112
115
 
113
116
  ##
114
117
  #
115
- # Find a check box and mark it as checked. The check box can be found
116
- # via name, id or label text.
118
+ # Find a descendant check box and mark it as checked. The check box can be found
119
+ # via name, id or label text. If no locator is provided this will match against
120
+ # self or a descendant.
117
121
  #
118
122
  # page.check('German')
119
123
  #
@@ -135,8 +139,9 @@ module Capybara
135
139
 
136
140
  ##
137
141
  #
138
- # Find a check box and mark uncheck it. The check box can be found
139
- # via name, id or label text.
142
+ # Find a descendant check box and mark uncheck it. The check box can be found
143
+ # via name, id or label text. If no locator is provided this will match against
144
+ # self or a descendant.
140
145
  #
141
146
  # page.uncheck('German')
142
147
  #
@@ -170,7 +175,7 @@ module Capybara
170
175
  # @macro waiting_behavior
171
176
  #
172
177
  # @param value [String] Which option to select
173
- # @param from: [String] The id, Capybara.test_id atrtribute, name or label of the select box
178
+ # @param from [String] The id, Capybara.test_id atrtribute, name or label of the select box
174
179
  #
175
180
  # @return [Capybara::Node::Element] The option element selected
176
181
  def select(value = nil, from: nil, **options)
@@ -193,8 +198,8 @@ module Capybara
193
198
  #
194
199
  # @macro waiting_behavior
195
200
  #
196
- # @param value [String] Which option to unselect
197
- # @param from: [String] The id, Capybara.test_id attribute, name or label of the select box
201
+ # @param value [String] Which option to unselect
202
+ # @param from [String] The id, Capybara.test_id attribute, name or label of the select box
198
203
  #
199
204
  # @return [Capybara::Node::Element] The option element unselected
200
205
  def unselect(value = nil, from: nil, **options)
@@ -204,18 +209,19 @@ module Capybara
204
209
 
205
210
  ##
206
211
  #
207
- # Find a file field on the page and attach a file given its path. The file field can
212
+ # Find a descendant file field on the page and attach a file given its path. The file field can
208
213
  # be found via its name, id or label text. In the case of the file field being hidden for
209
214
  # styling reasons the `make_visible` option can be used to temporarily change the CSS of
210
- # the file field, attach the file, and then revert the CSS back to original.
215
+ # the file field, attach the file, and then revert the CSS back to original. If no locator is
216
+ # passed this will match self or a descendant.
211
217
  #
212
218
  # page.attach_file(locator, '/path/to/file.png')
213
219
  #
214
- # @overload attach_file([locator], path, **options)
220
+ # @overload attach_file([locator], paths, **options)
215
221
  # @macro waiting_behavior
216
222
  #
217
- # @param [String] locator Which field to attach the file to
218
- # @param [String] path The path of the file that will be attached, or an array of paths
223
+ # @param [String] locator Which field to attach the file to
224
+ # @param [String, Array<String>] paths The path(s) of the file(s) that will be attached
219
225
  #
220
226
  # @option options [Symbol] match (Capybara.match) The matching strategy to use (:one, :first, :prefer_exact, :smart).
221
227
  # @option options [Boolean] exact (Capybara.exact) Match the exact label name/contents or accept a partial match.
@@ -226,16 +232,17 @@ module Capybara
226
232
  # @option options [true, Hash] make_visible A Hash of CSS styles to change before attempting to attach the file, if `true` { opacity: 1, display: 'block', visibility: 'visible' } is used (may not be supported by all drivers)
227
233
  #
228
234
  # @return [Capybara::Node::Element] The file field element
229
- def attach_file(locator = nil, path, make_visible: nil, **options) # rubocop:disable Style/OptionalArguments
230
- Array(path).each do |p|
231
- raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
235
+ def attach_file(locator = nil, paths, make_visible: nil, **options) # rubocop:disable Style/OptionalArguments
236
+ Array(paths).each do |path|
237
+ raise Capybara::FileNotFound, "cannot attach file, #{path} does not exist" unless File.exist?(path.to_s)
232
238
  end
239
+ options[:allow_self] = true if locator.nil?
233
240
  # Allow user to update the CSS style of the file input since they are so often hidden on a page
234
241
  if make_visible
235
242
  ff = find(:file_field, locator, options.merge(visible: :all))
236
- while_visible(ff, make_visible) { |el| el.set(path) }
243
+ while_visible(ff, make_visible) { |el| el.set(paths) }
237
244
  else
238
- find(:file_field, locator, options).set(path)
245
+ find(:file_field, locator, options).set(paths)
239
246
  end
240
247
  end
241
248
 
@@ -258,7 +265,7 @@ module Capybara
258
265
 
259
266
  def select_datalist_option(input, value)
260
267
  datalist_options = input.evaluate_script(DATALIST_OPTIONS_SCRIPT)
261
- option = datalist_options.find { |o| o.values_at('value', 'label').include?(value) }
268
+ option = datalist_options.find { |opt| opt.values_at('value', 'label').include?(value) }
262
269
  raise ::Capybara::ElementNotFound, %(Unable to find datalist option "#{value}") unless option
263
270
  input.set(option['value'])
264
271
  rescue ::Capybara::NotSupportedByDriverError
@@ -291,17 +298,19 @@ module Capybara
291
298
  end
292
299
 
293
300
  def _check_with_label(selector, checked, locator, allow_label_click: session_options.automatic_label_click, **options)
301
+ options[:allow_self] = true if locator.nil?
302
+
294
303
  synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
295
304
  begin
296
305
  el = find(selector, locator, options)
297
306
  el.set(checked)
298
- rescue StandardError => e
299
- raise unless allow_label_click && catch_error?(e)
307
+ rescue StandardError => err
308
+ raise unless allow_label_click && catch_error?(err)
300
309
  begin
301
310
  el ||= find(selector, locator, options.merge(visible: :all))
302
- find(:label, for: el, visible: true).click unless el.checked? == checked
311
+ el.session.find(:label, for: el, visible: true).click unless el.checked? == checked
303
312
  rescue StandardError # swallow extra errors - raise original
304
- raise e
313
+ raise err
305
314
  end
306
315
  end
307
316
  end
@@ -312,7 +321,7 @@ module Capybara
312
321
  var css = arguments[0];
313
322
  for (var prop in css){
314
323
  if (css.hasOwnProperty(prop)) {
315
- this.style[prop] = css[prop]
324
+ this.style.setProperty(prop, css[prop], "important");
316
325
  }
317
326
  }
318
327
  JS
@@ -74,24 +74,22 @@ module Capybara
74
74
  # @raise [Capybara::FrozenInTime] If the return value of `Time.now` appears stuck
75
75
  #
76
76
  def synchronize(seconds = session_options.default_max_wait_time, errors: nil)
77
- if session.synchronized
77
+ return yield if session.synchronized
78
+
79
+ session.synchronized = true
80
+ timer = Capybara::Helpers.timer(expire_in: seconds)
81
+ begin
78
82
  yield
79
- else
80
- session.synchronized = true
81
- timer = Capybara::Helpers.timer(expire_in: seconds)
82
- begin
83
- yield
84
- rescue StandardError => e
85
- session.raise_server_error!
86
- raise e unless driver.wait? && catch_error?(e, errors)
87
- raise e if timer.expired?
88
- sleep(0.05)
89
- raise Capybara::FrozenInTime, 'Time appears to be frozen. Capybara does not work with libraries which freeze time, consider using time travelling instead' if timer.stalled?
90
- reload if session_options.automatic_reload
91
- retry
92
- ensure
93
- session.synchronized = false
94
- end
83
+ rescue StandardError => err
84
+ session.raise_server_error!
85
+ raise err unless driver.wait? && catch_error?(err, errors)
86
+ raise err if timer.expired?
87
+ sleep(0.05)
88
+ raise Capybara::FrozenInTime, 'Time appears to be frozen. Capybara does not work with libraries which freeze time, consider using time travelling instead' if timer.stalled?
89
+ reload if session_options.automatic_reload
90
+ retry
91
+ ensure
92
+ session.synchronized = false
95
93
  end
96
94
  end
97
95
 
@@ -55,9 +55,7 @@ module Capybara
55
55
 
56
56
  def _verify_title(title, options)
57
57
  query = Capybara::Queries::TitleQuery.new(title, options)
58
- synchronize(query.wait) do
59
- yield(query)
60
- end
58
+ synchronize(query.wait) { yield(query) }
61
59
  true
62
60
  end
63
61
  end
@@ -55,8 +55,8 @@ module Capybara
55
55
  #
56
56
  def text(type = nil, normalize_ws: false)
57
57
  type ||= :all unless session_options.ignore_hidden_elements || session_options.visible_text_only
58
- t = synchronize { type == :all ? base.all_text : base.visible_text }
59
- normalize_ws ? t.gsub(/[[:space:]]+/, ' ').strip : t
58
+ txt = synchronize { type == :all ? base.all_text : base.visible_text }
59
+ normalize_ws ? txt.gsub(/[[:space:]]+/, ' ').strip : txt
60
60
  end
61
61
 
62
62
  ##
@@ -78,19 +78,19 @@ module Capybara
78
78
  #
79
79
  # element.style('color', 'font-size') # => Computed values of CSS 'color' and 'font-size' styles
80
80
  #
81
- # @param [String] Names of the desired CSS properties
82
- # @return [Hash] Hash of the CSS property names to computed values
81
+ # @param [Array<String>] styles Names of the desired CSS properties
82
+ # @return [Hash] Hash of the CSS property names to computed values
83
83
  #
84
84
  def style(*styles)
85
85
  styles = styles.flatten.map(&:to_s)
86
86
  raise ArgumentError, 'You must specify at least one CSS style' if styles.empty?
87
87
  begin
88
88
  synchronize { base.style(styles) }
89
- rescue NotImplementedError => e
89
+ rescue NotImplementedError => err
90
90
  begin
91
91
  evaluate_script(STYLE_SCRIPT, *styles)
92
92
  rescue Capybara::NotSupportedByDriverError
93
- raise e
93
+ raise err
94
94
  end
95
95
  end
96
96
  end
@@ -108,7 +108,7 @@ module Capybara
108
108
  # Set the value of the form element to the given value.
109
109
  #
110
110
  # @param [String] value The new value
111
- # @param [Hash{}] options Driver specific options for how to set the value. Take default values from {Capybara#default_set_options}
111
+ # @param [Hash{}] options Driver specific options for how to set the value. Take default values from `Capybara#default_set_options` - See {Capybara::configure}
112
112
  #
113
113
  # @return [Capybara::Node::Element] The element
114
114
  def set(value, **options)
@@ -429,8 +429,8 @@ module Capybara
429
429
  begin
430
430
  reloaded = query_scope.reload.first(@query.name, @query.locator, @query.options)
431
431
  @base = reloaded.base if reloaded
432
- rescue StandardError => e
433
- raise e unless catch_error?(e)
432
+ rescue StandardError => err
433
+ raise err unless catch_error?(err)
434
434
  end
435
435
  end
436
436
  self
@@ -440,9 +440,8 @@ module Capybara
440
440
  %(#<Capybara::Node::Element tag="#{base.tag_name}" path="#{base.path}">)
441
441
  rescue NotSupportedByDriverError
442
442
  %(#<Capybara::Node::Element tag="#{base.tag_name}">)
443
- rescue StandardError => e
444
- raise unless session.driver.invalid_element_errors.any? { |et| e.is_a?(et) }
445
-
443
+ rescue StandardError => err
444
+ raise unless session.driver.invalid_element_errors.any? { |et| err.is_a?(et) }
446
445
  %(Obsolete #<Capybara::Node::Element>)
447
446
  end
448
447
 
@@ -223,6 +223,7 @@ module Capybara
223
223
  # @param [String] locator The locator for the specified selector
224
224
  # @option options [String, Regexp] text Only find elements which contain this text or match this regexp
225
225
  # @option options [String, Boolean] exact_text (Capybara.exact_text) When String the elements contained text must match exactly, when Boolean controls whether the :text option must match exactly
226
+ # @option options [Boolean] normalize_ws (Capybara.default_normalize_ws) Whether the `text`/`exact_text` options are compared against elment text with whitespace normalized or as returned by the driver
226
227
  # @option options [Boolean, Symbol] visible Only find elements with the specified visibility:
227
228
  # * true - only finds visible elements.
228
229
  # * false - finds invisible _and_ visible elements.
@@ -306,7 +307,7 @@ module Capybara
306
307
  end
307
308
 
308
309
  def options_include_minimum?(opts)
309
- %i[count minimum between].any? { |k| opts.key?(k) }
310
+ %i[count minimum between].any? { |key| opts.key?(key) }
310
311
  end
311
312
  end
312
313
  end
@@ -29,8 +29,8 @@ module Capybara
29
29
  # @return [String] The text of the element
30
30
  #
31
31
  def text(_type = nil, normalize_ws: false)
32
- t = native.text
33
- normalize_ws ? t.gsub(/[[:space:]]+/, ' ').strip : t
32
+ txt = native.text
33
+ normalize_ws ? txt.gsub(/[[:space:]]+/, ' ').strip : txt
34
34
  end
35
35
 
36
36
  ##
@@ -79,11 +79,11 @@ module Capybara
79
79
  if tag_name == 'textarea'
80
80
  native['_capybara_raw_value']
81
81
  elsif tag_name == 'select'
82
+ selected_options = find_xpath('.//option[@selected]')
82
83
  if multiple?
83
- native.xpath(".//option[@selected='selected']").map { |option| option[:value] || option.content }
84
+ selected_options.map(&method(:option_value))
84
85
  else
85
- option = native.xpath(".//option[@selected='selected']").first || native.xpath('.//option').first
86
- option[:value] || option.content if option
86
+ option_value(selected_options.first || find_xpath('.//option').first)
87
87
  end
88
88
  elsif tag_name == 'input' && %w[radio checkbox].include?(native[:type])
89
89
  native[:value] || 'on'
@@ -104,7 +104,7 @@ module Capybara
104
104
  return false if (tag_name == 'input') && (native[:type] == 'hidden')
105
105
 
106
106
  if check_ancestors
107
- !native.xpath("boolean(./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or @hidden or name()='script' or name()='head'])")
107
+ !find_xpath("boolean(./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or @hidden or name()='script' or name()='head'])")
108
108
  else
109
109
  # No need for an xpath if only checking the current element
110
110
  !(native.has_attribute?('hidden') || (native[:style] =~ /display:\s?none/) || %w[script head].include?(tag_name))
@@ -177,6 +177,13 @@ module Capybara
177
177
  def session_options
178
178
  Capybara.session_options
179
179
  end
180
+
181
+ private
182
+
183
+ def option_value(option)
184
+ return nil if option.nil?
185
+ option[:value] || option.content
186
+ end
180
187
  end
181
188
  end
182
189
  end
@@ -23,9 +23,9 @@ module Capybara
23
23
 
24
24
  def self.wait(options, default = Capybara.default_max_wait_time)
25
25
  # if no value or nil for the :wait option is passed it should default to the default
26
- w = options.fetch(:wait, nil)
27
- w = default if w.nil?
28
- w || 0
26
+ wait = options.fetch(:wait, nil)
27
+ wait = default if wait.nil?
28
+ wait || 0
29
29
  end
30
30
 
31
31
  ##
@@ -69,7 +69,7 @@ module Capybara
69
69
  private
70
70
 
71
71
  def count_specified?
72
- COUNT_KEYS.any? { |k| options.key? k }
72
+ COUNT_KEYS.any? { |key| options.key? key }
73
73
  end
74
74
 
75
75
  def count_message