capybara 3.8.2 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +10 -0
- data/lib/capybara.rb +32 -10
- data/lib/capybara/config.rb +1 -0
- data/lib/capybara/dsl.rb +2 -2
- data/lib/capybara/helpers.rb +1 -0
- data/lib/capybara/node/actions.rb +4 -0
- data/lib/capybara/node/base.rb +1 -0
- data/lib/capybara/node/element.rb +3 -0
- data/lib/capybara/node/finders.rb +2 -0
- data/lib/capybara/node/simple.rb +1 -0
- data/lib/capybara/queries/base_query.rb +1 -0
- data/lib/capybara/queries/match_query.rb +1 -0
- data/lib/capybara/queries/selector_query.rb +34 -37
- data/lib/capybara/queries/text_query.rb +2 -0
- data/lib/capybara/rack_test/browser.rb +1 -0
- data/lib/capybara/rack_test/driver.rb +5 -0
- data/lib/capybara/rack_test/node.rb +2 -0
- data/lib/capybara/result.rb +2 -0
- data/lib/capybara/rspec/compound.rb +2 -0
- data/lib/capybara/rspec/matchers.rb +1 -0
- data/lib/capybara/selector.rb +14 -27
- data/lib/capybara/selector/builders/css_builder.rb +49 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +56 -0
- data/lib/capybara/selector/filter_set.rb +1 -0
- data/lib/capybara/selector/filters/base.rb +2 -0
- data/lib/capybara/selector/regexp_disassembler.rb +66 -0
- data/lib/capybara/selector/selector.rb +25 -5
- data/lib/capybara/selenium/driver.rb +8 -1
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +19 -1
- data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +1 -0
- data/lib/capybara/selenium/node.rb +7 -0
- data/lib/capybara/selenium/nodes/chrome_node.rb +2 -0
- data/lib/capybara/selenium/nodes/marionette_node.rb +37 -20
- data/lib/capybara/server.rb +4 -0
- data/lib/capybara/server/animation_disabler.rb +1 -0
- data/lib/capybara/session.rb +5 -0
- data/lib/capybara/session/config.rb +2 -0
- data/lib/capybara/spec/session/has_css_spec.rb +16 -0
- data/lib/capybara/spec/session/has_field_spec.rb +4 -0
- data/lib/capybara/spec/session/node_spec.rb +6 -0
- data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
- data/lib/capybara/spec/session/reset_session_spec.rb +15 -1
- data/lib/capybara/spec/session/selectors_spec.rb +12 -2
- data/lib/capybara/spec/views/form.erb +15 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/xpath_patches.rb +27 -0
- data/spec/dsl_spec.rb +15 -1
- data/spec/rack_test_spec.rb +6 -1
- data/spec/regexp_dissassembler_spec.rb +154 -0
- data/spec/selector_spec.rb +37 -2
- data/spec/selenium_spec_chrome.rb +2 -2
- data/spec/selenium_spec_firefox_remote.rb +2 -0
- data/spec/selenium_spec_marionette.rb +11 -0
- data/spec/shared_selenium_session.rb +20 -0
- data/spec/spec_helper.rb +4 -0
- metadata +7 -2
data/lib/capybara/result.rb
CHANGED
@@ -93,6 +93,7 @@ module Capybara
|
|
93
93
|
min, max = between.minmax
|
94
94
|
size = load_up_to(max + 1)
|
95
95
|
return 0 if between.include? size
|
96
|
+
|
96
97
|
return size <=> min
|
97
98
|
end
|
98
99
|
|
@@ -130,6 +131,7 @@ module Capybara
|
|
130
131
|
def load_up_to(num)
|
131
132
|
loop do
|
132
133
|
break if @result_cache.size >= num
|
134
|
+
|
133
135
|
@result_cache << @results_enum.next
|
134
136
|
end
|
135
137
|
@result_cache.size
|
@@ -43,6 +43,7 @@ if defined?(::RSpec::Expectations::Version)
|
|
43
43
|
syncer.synchronize do
|
44
44
|
@evaluator.reset
|
45
45
|
raise ::Capybara::ElementNotFound unless [matcher_1_matches?, matcher_2_matches?].all?
|
46
|
+
|
46
47
|
true
|
47
48
|
end
|
48
49
|
rescue StandardError
|
@@ -71,6 +72,7 @@ if defined?(::RSpec::Expectations::Version)
|
|
71
72
|
syncer.synchronize do
|
72
73
|
@evaluator.reset
|
73
74
|
raise ::Capybara::ElementNotFound unless [matcher_1_matches?, matcher_2_matches?].any?
|
75
|
+
|
74
76
|
true
|
75
77
|
end
|
76
78
|
rescue StandardError
|
data/lib/capybara/selector.rb
CHANGED
@@ -38,8 +38,11 @@ Capybara.add_selector(:id) do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
Capybara.add_selector(:field) do
|
41
|
+
visible { |options| :hidden if options[:type] == 'hidden' }
|
41
42
|
xpath do |locator, **options|
|
42
|
-
|
43
|
+
invalid_types = %w[submit image]
|
44
|
+
invalid_types << 'hidden' unless options[:type] == 'hidden'
|
45
|
+
xpath = XPath.descendant(:input, :textarea, :select)[!XPath.attr(:type).one_of(*invalid_types)]
|
43
46
|
locate_field(xpath, locator, options)
|
44
47
|
end
|
45
48
|
|
@@ -87,18 +90,7 @@ end
|
|
87
90
|
Capybara.add_selector(:link) do
|
88
91
|
xpath(:title, :alt) do |locator, href: true, alt: nil, title: nil, **|
|
89
92
|
xpath = XPath.descendant(:a)
|
90
|
-
xpath = xpath[
|
91
|
-
case href
|
92
|
-
when nil, false
|
93
|
-
!XPath.attr(:href)
|
94
|
-
when true
|
95
|
-
XPath.attr(:href)
|
96
|
-
when Regexp
|
97
|
-
nil # needs to be handled in filter
|
98
|
-
else
|
99
|
-
XPath.attr(:href) == href.to_s
|
100
|
-
end
|
101
|
-
]
|
93
|
+
xpath = xpath[@href_conditions = builder.attribute_conditions(href: href)]
|
102
94
|
|
103
95
|
unless locator.nil?
|
104
96
|
locator = locator.to_s
|
@@ -132,13 +124,19 @@ Capybara.add_selector(:link) do
|
|
132
124
|
|
133
125
|
describe_expression_filters do |**options|
|
134
126
|
desc = +''
|
135
|
-
|
127
|
+
if (href = options[:href])
|
128
|
+
if !href.is_a?(Regexp)
|
129
|
+
desc << " with href #{href.inspect}"
|
130
|
+
elsif @href_conditions
|
131
|
+
desc << " with href matching #{href.inspect}"
|
132
|
+
end
|
133
|
+
end
|
136
134
|
desc << ' with no href attribute' if options.fetch(:href, true).nil?
|
137
135
|
desc
|
138
136
|
end
|
139
137
|
|
140
138
|
describe_node_filters do |href: nil, **|
|
141
|
-
" with href matching #{href.inspect}" if href.is_a?
|
139
|
+
" with href matching #{href.inspect}" if href.is_a?(Regexp) && @href_conditions.nil?
|
142
140
|
end
|
143
141
|
end
|
144
142
|
|
@@ -472,18 +470,7 @@ Capybara.add_selector(:element) do
|
|
472
470
|
end
|
473
471
|
|
474
472
|
expression_filter(:attributes, matcher: /.+/) do |xpath, name, val|
|
475
|
-
|
476
|
-
when Regexp
|
477
|
-
xpath
|
478
|
-
when true
|
479
|
-
xpath[XPath.attr(name)]
|
480
|
-
when false
|
481
|
-
xpath[!XPath.attr(name)]
|
482
|
-
when XPath::Expression
|
483
|
-
xpath[XPath.attr(name)[val]]
|
484
|
-
else
|
485
|
-
xpath[XPath.attr(name.to_sym) == val]
|
486
|
-
end
|
473
|
+
xpath[builder.attribute_conditions(name => val)]
|
487
474
|
end
|
488
475
|
|
489
476
|
node_filter(:attributes, matcher: /.+/) do |node, name, val|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'xpath'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
class Selector
|
7
|
+
# @api private
|
8
|
+
class CSSBuilder
|
9
|
+
class << self
|
10
|
+
def attribute_conditions(attributes)
|
11
|
+
attributes.map do |attribute, value|
|
12
|
+
case value
|
13
|
+
when XPath::Expression
|
14
|
+
raise ArgumentError, "XPath expressions are not supported for the :#{attribute} filter with CSS based selectors"
|
15
|
+
when Regexp
|
16
|
+
Selector::RegexpDisassembler.new(value).substrings.map do |str|
|
17
|
+
"[#{attribute}*='#{str}'#{' i' if value.casefold?}]"
|
18
|
+
end.join
|
19
|
+
when true
|
20
|
+
"[#{attribute}]"
|
21
|
+
when false
|
22
|
+
':not([attribute])'
|
23
|
+
else
|
24
|
+
if attribute == :id
|
25
|
+
"##{::Capybara::Selector::CSS.escape(value)}"
|
26
|
+
else
|
27
|
+
"[#{attribute}='#{value}']"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end.join
|
31
|
+
end
|
32
|
+
|
33
|
+
def class_conditions(classes)
|
34
|
+
case classes
|
35
|
+
when XPath::Expression
|
36
|
+
raise ArgumentError, 'XPath expressions are not supported for the :class filter with CSS based selectors'
|
37
|
+
when Regexp
|
38
|
+
strs = Selector::RegexpDisassembler.new(classes).substrings
|
39
|
+
strs.map { |str| "[class*='#{str}'#{' i' if classes.casefold?}]" }.join
|
40
|
+
else
|
41
|
+
cls = Array(classes).group_by { |cl| cl.start_with? '!' }
|
42
|
+
(cls[false].to_a.map { |cl| ".#{Capybara::Selector::CSS.escape(cl)}" } +
|
43
|
+
cls[true].to_a.map { |cl| ":not(.#{Capybara::Selector::CSS.escape(cl.slice(1..-1))})" }).join
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'xpath'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
class Selector
|
7
|
+
# @api private
|
8
|
+
class XPathBuilder
|
9
|
+
class << self
|
10
|
+
def attribute_conditions(attributes)
|
11
|
+
attributes.map do |attribute, value|
|
12
|
+
case value
|
13
|
+
when XPath::Expression
|
14
|
+
XPath.attr(attribute)[value]
|
15
|
+
when Regexp
|
16
|
+
XPath.attr(attribute)[regexp_to_xpath_conditions(value)]
|
17
|
+
when true
|
18
|
+
XPath.attr(attribute)
|
19
|
+
when false, nil
|
20
|
+
!XPath.attr(attribute)
|
21
|
+
else
|
22
|
+
XPath.attr(attribute) == value.to_s
|
23
|
+
end
|
24
|
+
end.reduce(:&)
|
25
|
+
end
|
26
|
+
|
27
|
+
def class_conditions(classes)
|
28
|
+
case classes
|
29
|
+
when XPath::Expression
|
30
|
+
XPath.attr(:class)[classes]
|
31
|
+
when Regexp
|
32
|
+
XPath.attr(:class)[regexp_to_xpath_conditions(classes)]
|
33
|
+
else
|
34
|
+
Array(classes).map do |klass|
|
35
|
+
if klass.start_with?('!')
|
36
|
+
!XPath.attr(:class).contains_word(klass.slice(1..-1))
|
37
|
+
else
|
38
|
+
XPath.attr(:class).contains_word(klass)
|
39
|
+
end
|
40
|
+
end.reduce(:&)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def regexp_to_xpath_conditions(regexp)
|
47
|
+
condition = XPath.current
|
48
|
+
condition = condition.uppercase if regexp.casefold?
|
49
|
+
Selector::RegexpDisassembler.new(regexp).substrings.map do |str|
|
50
|
+
condition.contains(str)
|
51
|
+
end.reduce(:&)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -106,6 +106,7 @@ module Capybara
|
|
106
106
|
def add_filter(name, filter_class, *types, matcher: nil, **options, &block)
|
107
107
|
types.each { |type| options[type] = true }
|
108
108
|
raise 'ArgumentError', ':default option is not supported for filters with a :matcher option' if matcher && options[:default]
|
109
|
+
|
109
110
|
if filter_class <= Filters::ExpressionFilter
|
110
111
|
@expression_filters[name] = filter_class.new(name, matcher, block, options)
|
111
112
|
else
|
@@ -41,6 +41,7 @@ module Capybara
|
|
41
41
|
def apply(subject, name, value, skip_value)
|
42
42
|
return skip_value if skip?(value)
|
43
43
|
raise ArgumentError, "Invalid value #{value.inspect} passed to #{self.class.name.split('::').last} #{name}#{" : #{@name}" if @name.is_a?(Regexp)}" unless valid_value?(value)
|
44
|
+
|
44
45
|
if @block.arity == 2
|
45
46
|
@block.call(subject, value)
|
46
47
|
else
|
@@ -50,6 +51,7 @@ module Capybara
|
|
50
51
|
|
51
52
|
def valid_value?(value)
|
52
53
|
return true unless @options.key?(:valid_values)
|
54
|
+
|
53
55
|
Array(@options[:valid_values]).any? { |valid| valid === value } # rubocop:disable Style/CaseEquality
|
54
56
|
end
|
55
57
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
class Selector
|
5
|
+
# @api private
|
6
|
+
class RegexpDisassembler
|
7
|
+
def initialize(regexp)
|
8
|
+
@regexp = regexp
|
9
|
+
@regexp_source = regexp.source
|
10
|
+
end
|
11
|
+
|
12
|
+
def substrings
|
13
|
+
@substrings ||= begin
|
14
|
+
source = @regexp_source.dup
|
15
|
+
source.gsub!(/\\[^pgk]/, '.') # replace escaped characters with wildcard
|
16
|
+
source.gsub!(/\\[gk](?:<[^>]*>)?/, '.') # replace sub expressions and back references with wildcard
|
17
|
+
source.gsub!(/\\p\{[[:alpha:]]+\}?/, '.') # replace character properties with wildcard
|
18
|
+
source.gsub!(/\[\[:[a-z]+:\]\]/, '.') # replace posix classes with wildcard
|
19
|
+
while source.gsub!(/\[(?:[^\[\]]+)\]/, '.'); end # replace character classes with wildcard
|
20
|
+
source.gsub!(/\(\?<?[=!][^)]*\)/, '') # remove lookahead/lookbehind assertions
|
21
|
+
source.gsub!(/\(\?(?:<[^>]+>|>|:)/, '(') # replace named, atomic, and non-matching groups with unnamed matching groups
|
22
|
+
|
23
|
+
while source.gsub!(GROUP_REGEX) { |_m| simplify_group(Regexp.last_match) }; end
|
24
|
+
source.gsub!(/.[*?]\??/, '.') # replace optional character with wildcard
|
25
|
+
source.gsub!(/(.)\+\??/, '\1.') # replace one or more with character plus wildcard
|
26
|
+
source.gsub!(/(?<char>.)#{COUNTED_REP_REGEX.source}/) do |_m| # repeat counted characters
|
27
|
+
(Regexp.last_match[:char] * Regexp.last_match[:min_rep].to_i).tap { |str| str << '.' if Regexp.last_match[:max_rep] }
|
28
|
+
end
|
29
|
+
return [] if source.include?('|') # can't handle alternation here
|
30
|
+
|
31
|
+
strs = source.match(/\A\^?(.*?)\$?\Z/).captures[0].split('.').reject(&:empty?).uniq
|
32
|
+
strs = strs.map(&:upcase) if @regexp.casefold?
|
33
|
+
strs
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def simplify_group(matches)
|
40
|
+
if matches[:group].include?('|') # no support for alternation in groups
|
41
|
+
'.'
|
42
|
+
elsif matches[:one_or_more] # required but may repeat becomes text + wildcard
|
43
|
+
matches[:group][1..-2] + '.'
|
44
|
+
elsif matches[:optional] # optional group becomes wildcard
|
45
|
+
'.'
|
46
|
+
elsif matches[:min_rep]
|
47
|
+
(matches[:group] * matches[:min_rep].to_i).tap { |r| r << '.' if matches[:max_rep] }
|
48
|
+
else
|
49
|
+
matches[:group][1..-2]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
COUNTED_REP_REGEX = /\{(?<min_rep>\d*)(?:,(?<max_rep>\d*))?\}/
|
54
|
+
GROUP_REGEX = /
|
55
|
+
(?<group>\([^()]*\))
|
56
|
+
(?:
|
57
|
+
(?:
|
58
|
+
(?<optional>[*?]) |
|
59
|
+
(?<one_or_more>\+) |
|
60
|
+
(?:#{COUNTED_REP_REGEX.source})
|
61
|
+
)\??
|
62
|
+
)?
|
63
|
+
/x
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -4,6 +4,9 @@
|
|
4
4
|
|
5
5
|
require 'capybara/selector/filter_set'
|
6
6
|
require 'capybara/selector/css'
|
7
|
+
require 'capybara/selector/regexp_disassembler'
|
8
|
+
require 'capybara/selector/builders/xpath_builder'
|
9
|
+
require 'capybara/selector/builders/css_builder'
|
7
10
|
|
8
11
|
module Capybara
|
9
12
|
#
|
@@ -381,13 +384,29 @@ module Capybara
|
|
381
384
|
# * :all - finds visible and invisible elements.
|
382
385
|
# * :hidden - only finds invisible elements.
|
383
386
|
# * :visible - only finds visible elements.
|
384
|
-
def visible(default_visibility)
|
385
|
-
@default_visibility = default_visibility
|
387
|
+
def visible(default_visibility = nil, &block)
|
388
|
+
@default_visibility = block || default_visibility
|
386
389
|
end
|
387
390
|
|
388
|
-
def default_visibility(fallback = Capybara.ignore_hidden_elements)
|
389
|
-
|
390
|
-
|
391
|
+
def default_visibility(fallback = Capybara.ignore_hidden_elements, options = {})
|
392
|
+
vis = if @default_visibility&.respond_to?(:call)
|
393
|
+
@default_visibility.call(options)
|
394
|
+
else
|
395
|
+
@default_visibility
|
396
|
+
end
|
397
|
+
vis.nil? ? fallback : vis
|
398
|
+
end
|
399
|
+
|
400
|
+
# @api private
|
401
|
+
def builder
|
402
|
+
case format
|
403
|
+
when :css
|
404
|
+
Capybara::Selector::CSSBuilder
|
405
|
+
when :xpath
|
406
|
+
Capybara::Selector::XPathBuilder
|
407
|
+
else
|
408
|
+
raise NotImplementedError, "No builder exists for selector of type #{format}"
|
409
|
+
end
|
391
410
|
end
|
392
411
|
|
393
412
|
private
|
@@ -402,6 +421,7 @@ module Capybara
|
|
402
421
|
|
403
422
|
def locate_field(xpath, locator, **_options)
|
404
423
|
return xpath if locator.nil?
|
424
|
+
|
405
425
|
locate_xpath = xpath # Need to save original xpath for the label wrap
|
406
426
|
locator = locator.to_s
|
407
427
|
attr_matchers = [XPath.attr(:id) == locator,
|
@@ -17,6 +17,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
17
17
|
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')
|
18
18
|
rescue LoadError => err
|
19
19
|
raise err if err.message !~ /selenium-webdriver/
|
20
|
+
|
20
21
|
raise LoadError, "Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler."
|
21
22
|
end
|
22
23
|
|
@@ -117,6 +118,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
117
118
|
# Ensure the page is empty and trigger an UnhandledAlertError for any modals that appear during unload
|
118
119
|
until find_xpath('/html/body/*').empty?
|
119
120
|
raise Capybara::ExpectationNotMet, 'Timed out waiting for Selenium session reset' if timer.expired?
|
121
|
+
|
120
122
|
sleep 0.05
|
121
123
|
end
|
122
124
|
rescue Selenium::WebDriver::Error::UnhandledAlertError, Selenium::WebDriver::Error::UnexpectedAlertOpenError
|
@@ -184,6 +186,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
184
186
|
|
185
187
|
def close_window(handle)
|
186
188
|
raise ArgumentError, 'Not allowed to close the primary window' if handle == window_handles.first
|
189
|
+
|
187
190
|
within_given_window(handle) do
|
188
191
|
browser.close
|
189
192
|
end
|
@@ -260,7 +263,7 @@ private
|
|
260
263
|
end
|
261
264
|
|
262
265
|
def clear_browser_state
|
263
|
-
|
266
|
+
delete_all_cookies
|
264
267
|
clear_storage
|
265
268
|
rescue Selenium::WebDriver::Error::UnhandledError # rubocop:disable Lint/HandleExceptions
|
266
269
|
# delete_all_cookies fails when we've previously gone
|
@@ -268,6 +271,10 @@ private
|
|
268
271
|
# instead.
|
269
272
|
end
|
270
273
|
|
274
|
+
def delete_all_cookies
|
275
|
+
@browser.manage.delete_all_cookies
|
276
|
+
end
|
277
|
+
|
271
278
|
def clear_storage
|
272
279
|
clear_session_storage if options[:clear_session_storage]
|
273
280
|
clear_local_storage if options[:clear_local_storage]
|
@@ -9,7 +9,7 @@ module Capybara::Selenium::Driver::ChromeDriver
|
|
9
9
|
super
|
10
10
|
rescue NoMethodError => err
|
11
11
|
raise unless err.message =~ /full_screen_window/
|
12
|
-
|
12
|
+
|
13
13
|
result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {})
|
14
14
|
result['value']
|
15
15
|
end
|
@@ -20,6 +20,7 @@ module Capybara::Selenium::Driver::ChromeDriver
|
|
20
20
|
super
|
21
21
|
rescue Selenium::WebDriver::Error::UnknownError => err
|
22
22
|
raise unless err.message =~ /failed to change window state/
|
23
|
+
|
23
24
|
# Chromedriver doesn't wait long enough for state to change when coming out of fullscreen
|
24
25
|
# and raises unnecessary error. Wait a bit and try again.
|
25
26
|
sleep 0.5
|
@@ -37,7 +38,24 @@ module Capybara::Selenium::Driver::ChromeDriver
|
|
37
38
|
|
38
39
|
private
|
39
40
|
|
41
|
+
def delete_all_cookies
|
42
|
+
execute_cdp('Network.clearBrowserCookies')
|
43
|
+
rescue Selenium::WebDriver::Error::UnhandledError, Selenium::WebDriver::Error::WebDriverError
|
44
|
+
# If the CDP clear isn't supported do original limited clear
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
def execute_cdp(cmd, params = {})
|
49
|
+
args = { cmd: cmd, params: params }
|
50
|
+
result = bridge.http.call(:post, "session/#{bridge.session_id}/goog/cdp/execute", args)
|
51
|
+
result['value']
|
52
|
+
end
|
53
|
+
|
40
54
|
def build_node(native_node)
|
41
55
|
::Capybara::Selenium::ChromeNode.new(self, native_node)
|
42
56
|
end
|
57
|
+
|
58
|
+
def bridge
|
59
|
+
browser.send(:bridge)
|
60
|
+
end
|
43
61
|
end
|