capybara 3.8.2 → 3.9.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 +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
|