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 +4 -4
- data/History.md +12 -0
- data/README.md +2 -2
- data/lib/capybara/helpers.rb +1 -1
- data/lib/capybara/node/actions.rb +1 -1
- data/lib/capybara/node/base.rb +1 -1
- data/lib/capybara/node/finders.rb +1 -1
- data/lib/capybara/queries/base_query.rb +1 -1
- data/lib/capybara/queries/selector_query.rb +2 -2
- data/lib/capybara/rack_test/form.rb +1 -1
- data/lib/capybara/rspec/matchers.rb +1 -1
- data/lib/capybara/selector/css.rb +2 -2
- data/lib/capybara/selector/xpath_extensions.rb +8 -0
- data/lib/capybara/selector.rb +62 -70
- data/lib/capybara/selenium/driver.rb +13 -5
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +1 -1
- data/lib/capybara/selenium/extensions/html5_drag.rb +3 -1
- data/lib/capybara/selenium/nodes/chrome_node.rb +1 -3
- data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
- data/lib/capybara/session.rb +8 -4
- data/lib/capybara/spec/session/find_spec.rb +1 -1
- data/lib/capybara/spec/session/has_css_spec.rb +9 -2
- data/lib/capybara/spec/session/has_table_spec.rb +4 -4
- data/lib/capybara/spec/spec_helper.rb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/spec/sauce_spec_chrome.rb +42 -0
- data/spec/shared_selenium_session.rb +1 -2
- metadata +33 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e11c89bad9b8520ba44314b12052ee3b5845a3bd758a8b96bd29b2cda338a1e9
|
|
4
|
+
data.tar.gz: 8e52ab3d885733f71c1d0803d646890c788ec15cc8169c364c6497a21a299b54
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
[](https://gitter.im/jnicklas/capybara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
7
7
|
[](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.
|
|
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
|
|
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.
|
data/lib/capybara/helpers.rb
CHANGED
|
@@ -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
|
#
|
data/lib/capybara/node/base.rb
CHANGED
|
@@ -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
|
|
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, "
|
|
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, "
|
|
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, "
|
|
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)
|
|
@@ -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::
|
|
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]
|
|
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
|
|
16
|
+
char.match?(%r{[ -/:-~]}) ? "\\#{char}" : format('\\%06x', char.ord)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def self.split(css)
|
data/lib/capybara/selector.rb
CHANGED
|
@@ -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,
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
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 |
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
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
|
-
|
|
477
|
+
|
|
478
|
+
XPath.descendant(:td)[cell_condition]
|
|
479
479
|
end
|
|
480
|
-
XPath
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
555
|
-
|
|
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
|
-
|
|
29
|
-
|
|
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.
|
|
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)
|
|
@@ -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
|
|
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
|
data/lib/capybara/session.rb
CHANGED
|
@@ -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.
|
|
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.
|
|
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 #
|
|
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
|
-
|
|
116
|
+
before do
|
|
117
117
|
Capybara.predicates_wait = false
|
|
118
|
-
Capybara.default_max_wait_time =
|
|
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
|
-
[
|
|
53
|
-
[
|
|
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
|
-
[
|
|
88
|
-
[
|
|
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']
|
|
103
|
+
stream.reopen(RbConfig::CONFIG['host_os'].match?(/rmswin|mingw/) ? 'NUL:' : '/dev/null')
|
|
104
104
|
stream.sync = true
|
|
105
105
|
yield
|
|
106
106
|
ensure
|
data/lib/capybara/version.rb
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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-
|
|
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.
|
|
644
|
+
version: 2.4.0
|
|
615
645
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
616
646
|
requirements:
|
|
617
647
|
- - ">="
|