capybara 3.15.0 → 3.16.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 023614c44b5551f29984d882a7fb13b5ff240f589eff090cfb24c4f3a2787a47
4
- data.tar.gz: c5c1cd40b59700f743325cca40efbe9fd68df776c7f16f6d351336400e86cdd4
3
+ metadata.gz: e11c89bad9b8520ba44314b12052ee3b5845a3bd758a8b96bd29b2cda338a1e9
4
+ data.tar.gz: 8e52ab3d885733f71c1d0803d646890c788ec15cc8169c364c6497a21a299b54
5
5
  SHA512:
6
- metadata.gz: a76732bb72e5e5daefaf55a2bc4c895ef56d109905b9b3b2a5c96e229d97d783f1044dd6971ed21d4e63e55200a5e00a4641f50698f79346767fe498a5b894ad
7
- data.tar.gz: ac8d9499807a093c26ca861ed204087702b1a3713b757c6e9d84d43f399b38db36b3b1ab28471413dfd385b442b7636abe9f16194ae4ef17395a16d5e92b7a1c
6
+ metadata.gz: 16bcc0e6278f54605652cfe31d98647c0426bba37a1d5695ea7970117de9b9410cfe5d3aa8c154d023979ff24250801d01a26c179aad7ae0acb2124e74e375de
7
+ data.tar.gz: e49ed2c6600f114a259025d5e05076a1e2b670b68611eed7d60f3304c15a0a9faf7e476b15dd63c46bc552bb145fcdeb45694a0aa1f71459346f851734c538c8
data/History.md CHANGED
@@ -1,3 +1,15 @@
1
+ # Version 3.16
2
+ Release date: 2019-03-28
3
+
4
+ ### Changed
5
+
6
+ * Ruby 2.4.0+ is now required
7
+ * Selenium driver now defaults to using a persistent http client connection
8
+
9
+ ### Added
10
+
11
+ * :wait option in predicates now accepts `true` to selectively override when `Capybara.predicates_wait == false`
12
+
1
13
  # Version 3.15
2
14
  Release date: 2019-03-19
3
15
 
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jnicklas/capybara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
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
- **Note** You are viewing the README for the 3.15.x version of Capybara.
9
+ **Note** You are viewing the README for the 3.16.x version of Capybara.
10
10
 
11
11
 
12
12
  Capybara helps you test web applications by simulating how a real user would
@@ -419,7 +419,7 @@ teamcapybara repo once completely stable.
419
419
 
420
420
  ### <a name="capybara-webkit"></a>Capybara-webkit
421
421
 
422
- 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.
422
+ Note: `capybara-webkit` depends on QtWebkit which went end-of-life quite some time ago. There has been an attempt to revive the project but `capybara-webkit` is not yet (as far as I know) compatible with the revived version of QtWebKit (could be a good open source 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.
423
423
 
424
424
  The [capybara-webkit driver](https://github.com/thoughtbot/capybara-webkit) is for true headless
425
425
  testing. It uses QtWebKit to start a rendering engine process. It can execute JavaScript as well.
@@ -3,7 +3,7 @@
3
3
  module Capybara
4
4
  # @api private
5
5
  module Helpers
6
- module_function
6
+ module_function # rubocop:disable Layout/IndentationWidth
7
7
 
8
8
  ##
9
9
  # @deprecated
@@ -8,7 +8,7 @@ module Capybara
8
8
  # and continuously retry finding the element until either the element is found or the time
9
9
  # expires. The length of time +find+ will wait is controlled through {Capybara.default_max_wait_time}
10
10
  #
11
- # @option options [false, Numeric] wait (Capybara.default_max_wait_time) Maximum time to wait for matching element to appear.
11
+ # @option options [false, true, Numeric] wait (Capybara.default_max_wait_time) Maximum time to wait for matching element to appear.
12
12
 
13
13
  ##
14
14
  #
@@ -76,7 +76,7 @@ module Capybara
76
76
  def synchronize(seconds = nil, errors: nil)
77
77
  return yield if session.synchronized
78
78
 
79
- seconds = session_options.default_max_wait_time if seconds.nil?
79
+ seconds = session_options.default_max_wait_time if [nil, true].include? seconds
80
80
  session.synchronized = true
81
81
  timer = Capybara::Helpers.timer(expire_in: seconds)
82
82
  begin
@@ -13,7 +13,7 @@ module Capybara
13
13
  # and continuously retry finding the element until either the element is found or the time
14
14
  # expires. The length of time +find+ will wait is controlled through {Capybara.default_max_wait_time}
15
15
  # and defaults to 2 seconds.
16
- # @option options [false, Numeric] wait (Capybara.default_max_wait_time) Maximum time to wait for matching element to appear.
16
+ # @option options [false, true, Numeric] wait (Capybara.default_max_wait_time) Maximum time to wait for matching element to appear.
17
17
  #
18
18
  # page.find('#foo').find('.bar')
19
19
  # page.find(:xpath, './/div[contains(., "bar")]')
@@ -98,7 +98,7 @@ module Capybara
98
98
 
99
99
  invalid_names = invalid_keys.map(&:inspect).join(', ')
100
100
  valid_names = valid_keys.map(&:inspect).join(', ')
101
- raise ArgumentError, "invalid keys #{invalid_names}, should be one of #{valid_names}"
101
+ raise ArgumentError, "Invalid option(s) #{invalid_names}, should be one of #{valid_names}"
102
102
  end
103
103
  end
104
104
  end
@@ -271,7 +271,7 @@ module Capybara
271
271
 
272
272
  def assert_valid_keys
273
273
  unless VALID_MATCH.include?(match)
274
- raise ArgumentError, "invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(', ')}"
274
+ raise ArgumentError, "Invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(', ')}"
275
275
  end
276
276
 
277
277
  unhandled_options = @options.keys.reject do |option_name|
@@ -284,7 +284,7 @@ module Capybara
284
284
 
285
285
  invalid_names = unhandled_options.map(&:inspect).join(', ')
286
286
  valid_names = (valid_keys - [:allow_self]).map(&:inspect).join(', ')
287
- raise ArgumentError, "invalid keys #{invalid_names}, should be one of #{valid_names}"
287
+ raise ArgumentError, "Invalid option(s) #{invalid_names}, should be one of #{valid_names}"
288
288
  end
289
289
 
290
290
  def filtered_expression(expr)
@@ -56,7 +56,7 @@ private
56
56
  end
57
57
 
58
58
  def request_method
59
- self[:method] =~ /post/i ? :post : :get
59
+ self[:method].to_s.match?(/post/i) ? :post : :get
60
60
  end
61
61
 
62
62
  def merge_param!(params, key, value)
@@ -107,7 +107,7 @@ module Capybara
107
107
  # See {Capybara::Node::Matchers#has_unchecked_field?}
108
108
 
109
109
  # RSpec matcher for text content
110
- # See {Capybara::SessionMatchers#assert_text}
110
+ # See {Capybara::Node::Matchers#assert_text}
111
111
  def have_text(*args)
112
112
  Matchers::HaveText.new(*args)
113
113
  end
@@ -7,13 +7,13 @@ module Capybara
7
7
  value = str.dup
8
8
  out = +''
9
9
  out << value.slice!(0...1) if value =~ /^[-_]/
10
- out << (value[0] =~ NMSTART ? value.slice!(0...1) : escape_char(value.slice!(0...1)))
10
+ out << (value[0].match?(NMSTART) ? value.slice!(0...1) : escape_char(value.slice!(0...1)))
11
11
  out << value.gsub(/[^a-zA-Z0-9_-]/) { |char| escape_char char }
12
12
  out
13
13
  end
14
14
 
15
15
  def self.escape_char(char)
16
- char =~ %r{[ -/:-~]} ? "\\#{char}" : format('\\%06x', char.ord)
16
+ char.match?(%r{[ -/:-~]}) ? "\\#{char}" : format('\\%06x', char.ord)
17
17
  end
18
18
 
19
19
  def self.split(css)
@@ -7,3 +7,11 @@ module XPath
7
7
  end
8
8
  end
9
9
  end
10
+
11
+ module XPath
12
+ module DSL
13
+ def join(*expressions)
14
+ XPath::Expression.new(:join, *[self, expressions].flatten)
15
+ end
16
+ end
17
+ end
@@ -459,100 +459,92 @@ Capybara.add_selector(:table, locator_type: [String, Symbol]) do
459
459
  expression_filter(:with_cols, valid_values: [Array]) do |xpath, cols|
460
460
  col_conditions = cols.map do |col|
461
461
  if col.is_a? Hash
462
- col.reduce(nil) do |xp, (header, cell)|
463
- header_xp = XPath.descendant(:th)[XPath.string.n.is(header)]
464
- cell_xp = XPath.descendant(:tr)[header_xp].descendant(:td)
465
- next cell_xp[XPath.string.n.is(cell)] unless xp
466
-
467
- table_ancestor = XPath.ancestor(:table)[1]
468
- xp = XPath::Expression.new(:join, table_ancestor, xp)
469
- cell_xp[XPath.string.n.is(cell) & XPath.position.equals(xp.preceding_sibling(:td).count.plus(1))]
462
+ col.reduce(nil) do |xp, (header, cell_str)|
463
+ header = XPath.descendant(:th)[XPath.string.n.is(header)]
464
+ td = XPath.descendant(:tr)[header].descendant(:td)
465
+ cell_condition = XPath.string.n.is(cell_str)
466
+ cell_condition &= prev_col_position?(XPath.ancestor(:table)[1].join(xp)) if xp
467
+ td[cell_condition]
470
468
  end
471
469
  else
472
- cells_xp = col.reduce(nil) do |xp, cell|
473
- cell_conditions = [XPath.string.n.is(cell)]
474
- if xp
475
- prev_row_xp = XPath::Expression.new(:join, XPath.ancestor(:tr)[1].preceding_sibling(:tr), xp)
476
- cell_conditions << XPath.position.equals(prev_row_xp.preceding_sibling(:td).count.plus(1))
470
+ cells_xp = col.reduce(nil) do |prev_cell, cell_str|
471
+ cell_condition = XPath.string.n.is(cell_str)
472
+
473
+ if prev_cell
474
+ prev_cell = XPath.ancestor(:tr)[1].preceding_sibling(:tr).join(prev_cell)
475
+ cell_condition &= prev_col_position?(prev_cell)
477
476
  end
478
- XPath.descendant(:td)[cell_conditions.reduce :&]
477
+
478
+ XPath.descendant(:td)[cell_condition]
479
479
  end
480
- XPath::Expression.new(:join, XPath.descendant(:tr), cells_xp)
480
+ XPath.descendant(:tr).join(cells_xp)
481
481
  end
482
482
  end.reduce(:&)
483
483
  xpath[col_conditions]
484
484
  end
485
485
 
486
486
  expression_filter(:cols, valid_values: [Array]) do |xpath, cols|
487
- raise ArgumentError, ":cols must be an Array of Arrays" unless cols.all? { |col| col.is_a? Array }
487
+ raise ArgumentError, ':cols must be an Array of Arrays' unless cols.all? { |col| col.is_a? Array }
488
488
 
489
489
  rows = cols.transpose
490
- xpath = xpath[XPath.descendant(:tbody).descendant(:tr).count.equals(rows.size) | (XPath.descendant(:tr).count.equals(rows.size) & ~XPath.descendant(:tbody))]
491
-
492
- col_conditions = rows.map do |row|
493
- row_conditions = row.map do |cell|
494
- XPath.self(:td)[XPath.string.n.is(cell)]
495
- end
496
- row_conditions = row_conditions.reverse.reduce do |cond, cell|
497
- cell[XPath.following_sibling[cond]]
498
- end
499
- row_xpath = XPath.descendant(:tr)[XPath.descendant(:td)[row_conditions]]
500
- row_xpath[XPath.descendant(:td).count.equals(row.size)]
501
- end.reduce(:&)
502
-
503
- xpath[col_conditions]
490
+ col_conditions = rows.map { |row| match_row(row, match_size: true) }.reduce(:&)
491
+ xpath[match_row_count(rows.size)][col_conditions]
504
492
  end
505
493
 
506
494
  expression_filter(:with_rows, valid_values: [Array]) do |xpath, rows|
507
- rows_conditions = rows.map do |row|
508
- if row.is_a? Hash
509
- row_conditions = row.map do |header, cell|
510
- header_xp = XPath.ancestor(:table)[1].descendant(:tr)[1].descendant(:th)[XPath.string.n.is(header)]
511
- XPath.descendant(:td)[
512
- XPath.string.n.is(cell) & XPath.position.equals(header_xp.preceding_sibling.count.plus(1))
513
- ]
514
- end.reduce(:&)
515
- XPath.descendant(:tr)[row_conditions]
516
- else
517
- row_conditions = row.map do |cell|
518
- XPath.self(:td)[XPath.string.n.is(cell)]
519
- end
520
- row_conditions = row_conditions.reverse.reduce do |cond, cell|
521
- cell[XPath.following_sibling[cond]]
522
- end
523
- XPath.descendant(:tr)[XPath.descendant(:td)[row_conditions]]
524
- end
525
- end.reduce(:&)
495
+ rows_conditions = rows.map { |row| match_row(row) }.reduce(:&)
526
496
  xpath[rows_conditions]
527
497
  end
528
498
 
529
499
  expression_filter(:rows, valid_values: [Array]) do |xpath, rows|
530
- xpath = xpath[XPath.descendant(:tbody).descendant(:tr).count.equals(rows.size) | (XPath.descendant(:tr).count.equals(rows.size) & ~XPath.descendant(:tbody))]
531
- rows_conditions = rows.map do |row|
532
- row_xpath = if row.is_a? Hash
533
- row_conditions = row.map do |header, cell|
534
- header_xp = XPath.ancestor(:table)[1].descendant(:tr)[1].descendant(:th)[XPath.string.n.is(header)]
535
- XPath.descendant(:td)[
536
- XPath.string.n.is(cell) & XPath.position.equals(header_xp.preceding_sibling.count.plus(1))
537
- ]
538
- end.reduce(:&)
539
- XPath.descendant(:tr)[row_conditions]
500
+ rows_conditions = rows.map { |row| match_row(row, match_size: true) }.reduce(:&)
501
+ xpath[match_row_count(rows.size)][rows_conditions]
502
+ end
503
+
504
+ describe_expression_filters do |caption: nil, **|
505
+ " with caption \"#{caption}\"" if caption
506
+ end
507
+
508
+ def prev_col_position?(cell)
509
+ XPath.position.equals(cell_position(cell))
510
+ end
511
+
512
+ def cell_position(cell)
513
+ cell.preceding_sibling(:td).count.plus(1)
514
+ end
515
+
516
+ def match_row(row, match_size: false)
517
+ xp = XPath.descendant(:tr)[
518
+ if row.is_a? Hash
519
+ row_match_cells_to_headers(row)
540
520
  else
541
- row_conditions = row.map do |cell|
542
- XPath.self(:td)[XPath.string.n.is(cell)]
543
- end
544
- row_conditions = row_conditions.reverse.reduce do |cond, cell|
545
- cell[XPath.following_sibling[cond]]
546
- end
547
- XPath.descendant(:tr)[XPath.descendant(:td)[row_conditions]]
521
+ XPath.descendant(:td)[row_match_ordered_cells(row)]
548
522
  end
549
- row_xpath[XPath.descendant(:td).count.equals(row.size)]
523
+ ]
524
+ xp = xp[XPath.descendant(:td).count.equals(row.size)] if match_size
525
+ xp
526
+ end
527
+
528
+ def match_row_count(size)
529
+ XPath.descendant(:tbody).descendant(:tr).count.equals(size) | (XPath.descendant(:tr).count.equals(size) & ~XPath.descendant(:tbody))
530
+ end
531
+
532
+ def row_match_cells_to_headers(row)
533
+ row.map do |header, cell|
534
+ header_xp = XPath.ancestor(:table)[1].descendant(:tr)[1].descendant(:th)[XPath.string.n.is(header)]
535
+ XPath.descendant(:td)[
536
+ XPath.string.n.is(cell) & XPath.position.equals(header_xp.preceding_sibling.count.plus(1))
537
+ ]
550
538
  end.reduce(:&)
551
- xpath[rows_conditions]
552
539
  end
553
540
 
554
- describe_expression_filters do |caption: nil, **|
555
- " with caption \"#{caption}\"" if caption
541
+ def row_match_ordered_cells(row)
542
+ row_conditions = row.map do |cell|
543
+ XPath.self(:td)[XPath.string.n.is(cell)]
544
+ end
545
+ row_conditions.reverse.reduce do |cond, cell|
546
+ cell[XPath.following_sibling[cond]]
547
+ end
556
548
  end
557
549
  end
558
550
 
@@ -16,6 +16,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
16
16
 
17
17
  def self.load_selenium
18
18
  require 'selenium-webdriver'
19
+ require 'capybara/selenium/patches/persistent_client'
19
20
  warn "Warning: You're using an unsupported version of selenium-webdriver, please upgrade." if Gem.loaded_specs['selenium-webdriver'].version < Gem::Version.new('3.5.0')
20
21
  rescue LoadError => err
21
22
  raise err if err.message !~ /selenium-webdriver/
@@ -25,8 +26,12 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
25
26
 
26
27
  def browser
27
28
  @browser ||= begin
28
- if options[:timeout]
29
- options[:http_client] ||= Selenium::WebDriver::Remote::Http::Default.new(read_timeout: options[:timeout])
29
+ options[:http_client] ||= begin
30
+ if options[:timeout]
31
+ ::Capybara::Selenium::PersistentClient.new(read_timeout: options[:timeout])
32
+ else
33
+ ::Capybara::Selenium::PersistentClient.new
34
+ end
30
35
  end
31
36
  processed_options = options.reject { |key, _val| SPECIAL_OPTIONS.include?(key) }
32
37
  Selenium::WebDriver.for(options[:browser], processed_options).tap do |driver|
@@ -177,7 +182,10 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
177
182
  browser.window_handles
178
183
  end
179
184
 
180
- def open_new_window
185
+ def open_new_window(kind = :tab)
186
+ browser.manage.new_window(kind)
187
+ rescue NoMethodError, Selenium::WebDriver::Error::WebDriverError
188
+ # If not supported by the driver or browser default to using JS
181
189
  browser.execute_script('window.open();')
182
190
  end
183
191
 
@@ -322,7 +330,7 @@ private
322
330
  wait.until do
323
331
  alert = @browser.switch_to.alert
324
332
  regexp = text.is_a?(Regexp) ? text : Regexp.escape(text.to_s)
325
- alert.text.match(regexp) ? alert : nil
333
+ alert.text.match?(regexp) ? alert : nil
326
334
  end
327
335
  rescue Selenium::WebDriver::Error::TimeOutError
328
336
  raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{text}" if text}"
@@ -342,7 +350,7 @@ private
342
350
  when Array
343
351
  arg.map { |arr| unwrap_script_result(arr) }
344
352
  when Hash
345
- arg.each { |key, value| arg[key] = unwrap_script_result(value) }
353
+ arg.transform_values! { |value| unwrap_script_result(value) }
346
354
  when Selenium::WebDriver::Element
347
355
  build_node(arg)
348
356
  else
@@ -3,7 +3,7 @@
3
3
  require 'capybara/selenium/nodes/safari_node'
4
4
 
5
5
  module Capybara::Selenium::Driver::SafariDriver
6
- private
6
+ private # rubocop:disable Layout/IndentationWidth
7
7
 
8
8
  def build_node(native_node, initial_cache = {})
9
9
  ::Capybara::Selenium::SafariNode.new(self, native_node, initial_cache)
@@ -2,7 +2,9 @@
2
2
 
3
3
  class Capybara::Selenium::Node
4
4
  module Html5Drag
5
- private
5
+ # Implement methods to emulate HTML5 drag and drop
6
+
7
+ private # rubocop:disable Layout/IndentationWidth
6
8
 
7
9
  def html5_drag_to(element)
8
10
  driver.execute_script MOUSEDOWN_TRACKER
@@ -15,9 +15,7 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
15
15
  def set_file(value) # rubocop:disable Naming/AccessorMethodName
16
16
  super(value)
17
17
  rescue ::Selenium::WebDriver::Error::ExpectedError => err
18
- if err.message =~ /File not found : .+\n.+/m
19
- raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload"
20
- end
18
+ raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload" if err.message.match?(/File not found : .+\n.+/m)
21
19
 
22
20
  raise
23
21
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara
4
+ module Selenium
5
+ class PersistentClient < ::Selenium::WebDriver::Remote::Http::Default
6
+ def close
7
+ super
8
+ @http.finish if @http&.started?
9
+ end
10
+
11
+ private
12
+
13
+ def http
14
+ super.tap do |http|
15
+ http.start unless http.started?
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -263,7 +263,7 @@ module Capybara
263
263
 
264
264
  if base_uri && [nil, 'http', 'https'].include?(visit_uri.scheme)
265
265
  if visit_uri.relative?
266
- visit_uri_parts = visit_uri.to_hash.delete_if { |_k, value| value.nil? }
266
+ visit_uri_parts = visit_uri.to_hash.compact
267
267
 
268
268
  # Useful to people deploying to a subdirectory
269
269
  # and/or single page apps where only the url fragment changes
@@ -458,9 +458,13 @@ module Capybara
458
458
  #
459
459
  # @return [Capybara::Window] window that has been opened
460
460
  #
461
- def open_new_window
461
+ def open_new_window(kind = :tab)
462
462
  window_opened_by do
463
- driver.open_new_window
463
+ if driver.method(:open_new_window).arity.zero?
464
+ driver.open_new_window
465
+ else
466
+ driver.open_new_window(kind)
467
+ end
464
468
  end
465
469
  end
466
470
 
@@ -850,7 +854,7 @@ module Capybara
850
854
  when Array
851
855
  arg.map { |subarg| element_script_result(subarg) }
852
856
  when Hash
853
- arg.each { |key, value| arg[key] = element_script_result(value) }
857
+ arg.transform_values! { |value| element_script_result(value) }
854
858
  when Capybara::Driver::Node
855
859
  Capybara::Node::Element.new(self, arg, nil, nil)
856
860
  else
@@ -108,7 +108,7 @@ Capybara::SpecHelper.spec '#find' do
108
108
 
109
109
  it 'should warn if passed a non-valid locator type' do
110
110
  expect_any_instance_of(Kernel).to receive(:warn).with(/must respond to to_xpath or be an instance of String/)
111
- expect { @session.find(:xpath, 123) }.to raise_error # rubocop:disable RSpec/UnspecifiedException
111
+ expect { @session.find(:xpath, 123) }.to raise_error Exception # The exact error is not yet well defined
112
112
  end
113
113
  end
114
114
 
@@ -113,13 +113,20 @@ Capybara::SpecHelper.spec '#has_css?' do
113
113
  end
114
114
 
115
115
  context 'with predicates_wait == false' do
116
- it 'should not wait for content to appear', requires: [:js] do
116
+ before do
117
117
  Capybara.predicates_wait = false
118
- Capybara.default_max_wait_time = 2
118
+ Capybara.default_max_wait_time = 5
119
119
  @session.visit('/with_js')
120
120
  @session.click_link('Click me')
121
+ end
122
+
123
+ it 'should not wait for content to appear', requires: [:js] do
121
124
  expect(@session.has_css?("input[type='submit'][value='New Here']")).to be false
122
125
  end
126
+
127
+ it 'should should the default wait time if true is passed for :wait', requires: [:js] do
128
+ expect(@session.has_css?("input[type='submit'][value='New Here']", wait: true)).to be true
129
+ end
123
130
  end
124
131
 
125
132
  context 'with between' do
@@ -49,8 +49,8 @@ Capybara::SpecHelper.spec '#has_table?' do
49
49
  %w[Thomas Walpole Oceanside],
50
50
  %w[Danilo Wilkinson Johnsonville],
51
51
  %w[Vern Konopelski Everette],
52
- ["Ratke", "Lawrence", "East Sorayashire"],
53
- ["Palmer", "Sawayn", "West Trinidad"]
52
+ ['Ratke', 'Lawrence', 'East Sorayashire'],
53
+ ['Palmer', 'Sawayn', 'West Trinidad']
54
54
  ])
55
55
  end
56
56
 
@@ -84,8 +84,8 @@ Capybara::SpecHelper.spec '#has_table?' do
84
84
  %w[Thomas Walpole Oceanside],
85
85
  %w[Danilo Wilkinson Johnsonville],
86
86
  %w[Vern Konopelski Everette],
87
- ["Ratke", "Lawrence", "East Sorayashire"],
88
- ["Palmer", "Sawayn", "West Trinidad"]
87
+ ['Ratke', 'Lawrence', 'East Sorayashire'],
88
+ ['Palmer', 'Sawayn', 'West Trinidad']
89
89
  ])
90
90
  end
91
91
 
@@ -100,7 +100,7 @@ module Capybara
100
100
 
101
101
  def silence_stream(stream)
102
102
  old_stream = stream.dup
103
- stream.reopen(RbConfig::CONFIG['host_os'] =~ /rmswin|mingw/ ? 'NUL:' : '/dev/null')
103
+ stream.reopen(RbConfig::CONFIG['host_os'].match?(/rmswin|mingw/) ? 'NUL:' : '/dev/null')
104
104
  stream.sync = true
105
105
  yield
106
106
  ensure
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Capybara
4
- VERSION = '3.15.0'
4
+ VERSION = '3.16.0'
5
5
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'selenium-webdriver'
5
+
6
+ require 'sauce_whisk'
7
+ # require 'shared_selenium_session'
8
+ # require 'rspec/shared_spec_matchers'
9
+
10
+ Capybara.register_driver :sauce_chrome do |app|
11
+ options = {
12
+ selenium_version: '3.141.59',
13
+ platform: 'macOS 10.12',
14
+ browser_name: 'chrome',
15
+ version: '65.0',
16
+ name: 'Capybara test',
17
+ build: ENV['TRAVIS_REPO_SLUG'] || "Ruby-RSpec-Selenium: Local-#{Time.now.to_i}",
18
+ username: ENV['SAUCE_USERNAME'],
19
+ access_key: ENV['SAUCE_ACCESS_KEY']
20
+ }
21
+
22
+ options.delete(:browser_name)
23
+
24
+ capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(options)
25
+ url = 'https://ondemand.saucelabs.com:443/wd/hub'
26
+
27
+ Capybara::Selenium::Driver.new(app,
28
+ browser: :remote, url: url,
29
+ desired_capabilities: capabilities,
30
+ options: Selenium::WebDriver::Chrome::Options.new(args: ['']))
31
+ end
32
+
33
+ CHROME_REMOTE_DRIVER = :sauce_chrome
34
+
35
+ module TestSessions
36
+ Chrome = Capybara::Session.new(CHROME_REMOTE_DRIVER, TestApp)
37
+ end
38
+
39
+ skipped_tests = %i[response_headers status_code trigger download]
40
+
41
+ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example|
42
+ end
@@ -474,8 +474,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
474
474
  it 'can set and clear a text field' do
475
475
  session.visit 'https://reactjs.org/docs/forms.html'
476
476
  session.all(:css, 'h2#controlled-components ~ p a', text: 'Try it on CodePen')[0].click
477
- sleep 2 # give codepen a chance to stabilize result frame
478
- session.within_frame(:css, 'iframe.result-iframe') do
477
+ session.within_frame(:css, 'iframe.result-iframe[src^="https://s.codepen.io"]', wait: 10) do
479
478
  session.fill_in('Name:', with: 'abc')
480
479
  session.accept_prompt 'A name was submitted: abc' do
481
480
  session.click_button('Submit')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.15.0
4
+ version: 3.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Walpole
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain:
12
12
  - gem-public_cert.pem
13
- date: 2019-03-19 00:00:00.000000000 Z
13
+ date: 2019-03-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: addressable
@@ -264,6 +264,20 @@ dependencies:
264
264
  - - ">="
265
265
  - !ruby/object:Gem::Version
266
266
  version: '0'
267
+ - !ruby/object:Gem::Dependency
268
+ name: rubocop-performance
269
+ requirement: !ruby/object:Gem::Requirement
270
+ requirements:
271
+ - - ">="
272
+ - !ruby/object:Gem::Version
273
+ version: '0'
274
+ type: :development
275
+ prerelease: false
276
+ version_requirements: !ruby/object:Gem::Requirement
277
+ requirements:
278
+ - - ">="
279
+ - !ruby/object:Gem::Version
280
+ version: '0'
267
281
  - !ruby/object:Gem::Dependency
268
282
  name: rubocop-rspec
269
283
  requirement: !ruby/object:Gem::Requirement
@@ -278,6 +292,20 @@ dependencies:
278
292
  - - ">="
279
293
  - !ruby/object:Gem::Version
280
294
  version: '0'
295
+ - !ruby/object:Gem::Dependency
296
+ name: sauce_whisk
297
+ requirement: !ruby/object:Gem::Requirement
298
+ requirements:
299
+ - - ">="
300
+ - !ruby/object:Gem::Version
301
+ version: '0'
302
+ type: :development
303
+ prerelease: false
304
+ version_requirements: !ruby/object:Gem::Requirement
305
+ requirements:
306
+ - - ">="
307
+ - !ruby/object:Gem::Version
308
+ version: '0'
281
309
  - !ruby/object:Gem::Dependency
282
310
  name: selenium-webdriver
283
311
  requirement: !ruby/object:Gem::Requirement
@@ -419,6 +447,7 @@ files:
419
447
  - lib/capybara/selenium/nodes/firefox_node.rb
420
448
  - lib/capybara/selenium/nodes/safari_node.rb
421
449
  - lib/capybara/selenium/patches/pause_duration_fix.rb
450
+ - lib/capybara/selenium/patches/persistent_client.rb
422
451
  - lib/capybara/server.rb
423
452
  - lib/capybara/server/animation_disabler.rb
424
453
  - lib/capybara/server/checker.rb
@@ -584,6 +613,7 @@ files:
584
613
  - spec/rspec/views_spec.rb
585
614
  - spec/rspec_matchers_spec.rb
586
615
  - spec/rspec_spec.rb
616
+ - spec/sauce_spec_chrome.rb
587
617
  - spec/selector_spec.rb
588
618
  - spec/selenium_spec_chrome.rb
589
619
  - spec/selenium_spec_chrome_remote.rb
@@ -611,7 +641,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
611
641
  requirements:
612
642
  - - ">="
613
643
  - !ruby/object:Gem::Version
614
- version: 2.3.0
644
+ version: 2.4.0
615
645
  required_rubygems_version: !ruby/object:Gem::Requirement
616
646
  requirements:
617
647
  - - ">="