capybara 2.13.0 → 2.14.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 +82 -17
- data/README.md +29 -0
- data/lib/capybara.rb +81 -116
- data/lib/capybara/config.rb +121 -0
- data/lib/capybara/cucumber.rb +1 -0
- data/lib/capybara/driver/base.rb +6 -0
- data/lib/capybara/dsl.rb +1 -3
- data/lib/capybara/helpers.rb +3 -3
- data/lib/capybara/node/actions.rb +2 -2
- data/lib/capybara/node/base.rb +7 -2
- data/lib/capybara/node/element.rb +7 -1
- data/lib/capybara/node/finders.rb +13 -3
- data/lib/capybara/node/matchers.rb +15 -4
- data/lib/capybara/node/simple.rb +5 -0
- data/lib/capybara/queries/base_query.rb +8 -3
- data/lib/capybara/queries/selector_query.rb +11 -9
- data/lib/capybara/queries/text_query.rb +9 -4
- data/lib/capybara/rack_test/browser.rb +8 -5
- data/lib/capybara/rspec.rb +3 -1
- data/lib/capybara/rspec/matcher_proxies.rb +41 -0
- data/lib/capybara/rspec/matchers.rb +19 -5
- data/lib/capybara/selector.rb +13 -4
- data/lib/capybara/selector/selector.rb +3 -3
- data/lib/capybara/selenium/driver.rb +20 -6
- data/lib/capybara/selenium/node.rb +6 -2
- data/lib/capybara/server.rb +6 -5
- data/lib/capybara/session.rb +71 -14
- data/lib/capybara/session/config.rb +100 -0
- data/lib/capybara/spec/public/test.js +1 -1
- data/lib/capybara/spec/session/all_spec.rb +11 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +24 -8
- data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
- data/lib/capybara/spec/session/find_field_spec.rb +1 -0
- data/lib/capybara/spec/session/find_spec.rb +4 -3
- data/lib/capybara/spec/session/has_selector_spec.rb +1 -3
- data/lib/capybara/spec/session/node_spec.rb +23 -17
- data/lib/capybara/spec/session/reset_session_spec.rb +1 -1
- data/lib/capybara/spec/session/window/become_closed_spec.rb +4 -4
- data/lib/capybara/spec/spec_helper.rb +22 -0
- data/lib/capybara/spec/views/form.erb +6 -1
- data/lib/capybara/spec/views/with_html.erb +1 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +1 -1
- data/spec/capybara_spec.rb +14 -2
- data/spec/dsl_spec.rb +1 -0
- data/spec/per_session_config_spec.rb +67 -0
- data/spec/rspec/shared_spec_matchers.rb +2 -2
- data/spec/rspec/views_spec.rb +4 -0
- data/spec/rspec_spec.rb +77 -0
- data/spec/session_spec.rb +44 -0
- data/spec/shared_selenium_session.rb +9 -0
- data/spec/spec_helper.rb +4 -0
- metadata +7 -3
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'forwardable'
|
3
|
+
require 'capybara/session/config'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
class Config
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
OPTIONS = [:app, :reuse_server, :threadsafe, :default_wait_time, :server, :default_driver, :javascript_driver]
|
10
|
+
|
11
|
+
attr_accessor :app
|
12
|
+
attr_reader :reuse_server, :threadsafe
|
13
|
+
attr_reader :session_options
|
14
|
+
attr_writer :default_driver, :javascript_driver
|
15
|
+
|
16
|
+
SessionConfig::OPTIONS.each do |method|
|
17
|
+
def_delegators :session_options, method, "#{method}="
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@session_options = Capybara::SessionConfig.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def reuse_server=(bool)
|
25
|
+
@reuse_server = bool
|
26
|
+
end
|
27
|
+
|
28
|
+
def threadsafe=(bool)
|
29
|
+
warn "Capybara.threadsafe == true is a BETA feature and may change in future minor versions" if bool
|
30
|
+
raise "Threadsafe setting cannot be changed once a session is created" if (bool != threadsafe) && Session.instance_created?
|
31
|
+
@threadsafe = bool
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
#
|
36
|
+
# Return the proc that Capybara will call to run the Rack application.
|
37
|
+
# The block returned receives a rack app, port, and host/ip and should run a Rack handler
|
38
|
+
# By default, Capybara will try to run webrick.
|
39
|
+
#
|
40
|
+
def server(&block)
|
41
|
+
if block_given?
|
42
|
+
warn "DEPRECATED: Passing a block to Capybara::server is deprecated, please use Capybara::register_server instead"
|
43
|
+
@server = block
|
44
|
+
else
|
45
|
+
@server
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
#
|
51
|
+
# Set the server to use.
|
52
|
+
#
|
53
|
+
# Capybara.server = :webrick
|
54
|
+
#
|
55
|
+
# @param [Symbol] name Name of the server type to use
|
56
|
+
# @see register_server
|
57
|
+
#
|
58
|
+
def server=(name)
|
59
|
+
@server = if name.respond_to? :call
|
60
|
+
name
|
61
|
+
else
|
62
|
+
Capybara.servers[name.to_sym]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
#
|
68
|
+
# @return [Symbol] The name of the driver to use by default
|
69
|
+
#
|
70
|
+
def default_driver
|
71
|
+
@default_driver || :rack_test
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
#
|
76
|
+
# @return [Symbol] The name of the driver used when JavaScript is needed
|
77
|
+
#
|
78
|
+
def javascript_driver
|
79
|
+
@javascript_driver || :selenium
|
80
|
+
end
|
81
|
+
|
82
|
+
# @deprecated Use default_max_wait_time instead
|
83
|
+
def default_wait_time
|
84
|
+
deprecate('default_wait_time', 'default_max_wait_time', true)
|
85
|
+
default_max_wait_time
|
86
|
+
end
|
87
|
+
|
88
|
+
# @deprecated Use default_max_wait_time= instead
|
89
|
+
def default_wait_time=(t)
|
90
|
+
deprecate('default_wait_time=', 'default_max_wait_time=')
|
91
|
+
self.default_max_wait_time = t
|
92
|
+
end
|
93
|
+
|
94
|
+
def deprecate(method, alternate_method, once=false)
|
95
|
+
@deprecation_notified ||= {}
|
96
|
+
warn "DEPRECATED: ##{method} is deprecated, please use ##{alternate_method} instead" unless once and @deprecation_notified[method]
|
97
|
+
@deprecation_notified[method]=true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class ConfigureDeprecator
|
102
|
+
def initialize(config)
|
103
|
+
@config = config
|
104
|
+
end
|
105
|
+
|
106
|
+
def method_missing(m, *args, &block)
|
107
|
+
if @config.respond_to?(m)
|
108
|
+
@config.public_send(m, *args, &block)
|
109
|
+
elsif Capybara.respond_to?(m)
|
110
|
+
warn "Calling #{m} from Capybara.configure is deprecated - please call it on Capybara directly ( Capybara.#{m}(...) )"
|
111
|
+
Capybara.public_send(m, *args, &block)
|
112
|
+
else
|
113
|
+
super
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def respond_to_missing?(m, include_private = false)
|
118
|
+
@config.respond_to_missing?(m, include_private) || Capybara.respond_to_missing?(m, include_private)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/capybara/cucumber.rb
CHANGED
data/lib/capybara/driver/base.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
class Capybara::Driver::Base
|
3
|
+
attr_writer :session
|
4
|
+
|
3
5
|
def current_url
|
4
6
|
raise NotImplementedError
|
5
7
|
end
|
@@ -139,6 +141,10 @@ class Capybara::Driver::Base
|
|
139
141
|
false
|
140
142
|
end
|
141
143
|
|
144
|
+
def session_options
|
145
|
+
(@session && @session.config) || Capybara.session_options
|
146
|
+
end
|
147
|
+
|
142
148
|
# @deprecated This method is being removed
|
143
149
|
def browser_initialized?
|
144
150
|
warn "DEPRECATED: #browser_initialized? is deprecated and will be removed in the next version of Capybara"
|
data/lib/capybara/dsl.rb
CHANGED
@@ -21,12 +21,10 @@ module Capybara
|
|
21
21
|
Capybara.using_session(name, &block)
|
22
22
|
end
|
23
23
|
|
24
|
-
##
|
25
|
-
#
|
26
24
|
# Shortcut to using a different wait time.
|
27
25
|
#
|
28
26
|
def using_wait_time(seconds, &block)
|
29
|
-
|
27
|
+
page.using_wait_time(seconds, &block)
|
30
28
|
end
|
31
29
|
|
32
30
|
##
|
data/lib/capybara/helpers.rb
CHANGED
@@ -46,11 +46,11 @@ module Capybara
|
|
46
46
|
# @param [String] html HTML code to inject into
|
47
47
|
# @return [String] The modified HTML code
|
48
48
|
#
|
49
|
-
def inject_asset_host(html)
|
50
|
-
if
|
49
|
+
def inject_asset_host(html, asset_host = Capybara.asset_host)
|
50
|
+
if asset_host && Nokogiri::HTML(html).css("base").empty?
|
51
51
|
match = html.match(/<head[^<]*?>/)
|
52
52
|
if match
|
53
|
-
return html.clone.insert match.end(0), "<base href='#{
|
53
|
+
return html.clone.insert match.end(0), "<base href='#{asset_host}' />"
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -293,9 +293,9 @@ module Capybara
|
|
293
293
|
|
294
294
|
def _check_with_label(selector, checked, locator, options)
|
295
295
|
locator, options = nil, locator if locator.is_a? Hash
|
296
|
-
allow_label_click = options.delete(:allow_label_click) {
|
296
|
+
allow_label_click = options.delete(:allow_label_click) { session_options.automatic_label_click }
|
297
297
|
|
298
|
-
synchronize(Capybara::Queries::BaseQuery
|
298
|
+
synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
|
299
299
|
begin
|
300
300
|
el = find(selector, locator, options)
|
301
301
|
el.set(checked)
|
data/lib/capybara/node/base.rb
CHANGED
@@ -74,7 +74,7 @@ module Capybara
|
|
74
74
|
# @return [Object] The result of the given block
|
75
75
|
# @raise [Capybara::FrozenInTime] If the return value of `Time.now` appears stuck
|
76
76
|
#
|
77
|
-
def synchronize(seconds=
|
77
|
+
def synchronize(seconds=session_options.default_max_wait_time, options = {})
|
78
78
|
start_time = Capybara::Helpers.monotonic_time
|
79
79
|
|
80
80
|
if session.synchronized
|
@@ -90,7 +90,7 @@ module Capybara
|
|
90
90
|
raise e if (Capybara::Helpers.monotonic_time - start_time) >= seconds
|
91
91
|
sleep(0.05)
|
92
92
|
raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if Capybara::Helpers.monotonic_time == start_time
|
93
|
-
reload if
|
93
|
+
reload if session_options.automatic_reload
|
94
94
|
retry
|
95
95
|
ensure
|
96
96
|
session.synchronized = false
|
@@ -114,6 +114,11 @@ module Capybara
|
|
114
114
|
query_scope
|
115
115
|
end
|
116
116
|
|
117
|
+
# @api private
|
118
|
+
def session_options
|
119
|
+
session.config
|
120
|
+
end
|
121
|
+
|
117
122
|
protected
|
118
123
|
|
119
124
|
def catch_error?(error, errors = nil)
|
@@ -55,7 +55,7 @@ module Capybara
|
|
55
55
|
# @return [String] The text of the element
|
56
56
|
#
|
57
57
|
def text(type=nil)
|
58
|
-
type ||= :all unless
|
58
|
+
type ||= :all unless session_options.ignore_hidden_elements or session_options.visible_text_only
|
59
59
|
synchronize do
|
60
60
|
if type == :all
|
61
61
|
base.all_text
|
@@ -374,6 +374,12 @@ module Capybara
|
|
374
374
|
%(#<Capybara::Node::Element tag="#{tag_name}" path="#{path}">)
|
375
375
|
rescue NotSupportedByDriverError
|
376
376
|
%(#<Capybara::Node::Element tag="#{tag_name}">)
|
377
|
+
rescue => e
|
378
|
+
if session.driver.invalid_element_errors.any? { |et| e.is_a?(et)}
|
379
|
+
%(Obsolete #<Capybara::Node::Element>)
|
380
|
+
else
|
381
|
+
raise
|
382
|
+
end
|
377
383
|
end
|
378
384
|
end
|
379
385
|
end
|
@@ -29,11 +29,16 @@ module Capybara
|
|
29
29
|
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
30
30
|
#
|
31
31
|
def find(*args, &optional_filter_block)
|
32
|
+
if args.last.is_a? Hash
|
33
|
+
args.last[:session_options] = session_options
|
34
|
+
else
|
35
|
+
args.push(session_options: session_options)
|
36
|
+
end
|
32
37
|
query = Capybara::Queries::SelectorQuery.new(*args, &optional_filter_block)
|
33
38
|
synchronize(query.wait) do
|
34
|
-
if (query.match == :smart or query.match == :prefer_exact)
|
39
|
+
if (query.match == :smart or query.match == :prefer_exact)
|
35
40
|
result = query.resolve_for(self, true)
|
36
|
-
result = query.resolve_for(self, false) if result.empty? && !query.exact?
|
41
|
+
result = query.resolve_for(self, false) if result.empty? && query.supports_exact? && !query.exact?
|
37
42
|
else
|
38
43
|
result = query.resolve_for(self)
|
39
44
|
end
|
@@ -208,6 +213,11 @@ module Capybara
|
|
208
213
|
# @return [Capybara::Result] A collection of found elements
|
209
214
|
#
|
210
215
|
def all(*args, &optional_filter_block)
|
216
|
+
if args.last.is_a? Hash
|
217
|
+
args.last[:session_options] = session_options
|
218
|
+
else
|
219
|
+
args.push(session_options: session_options)
|
220
|
+
end
|
211
221
|
query = Capybara::Queries::SelectorQuery.new(*args, &optional_filter_block)
|
212
222
|
synchronize(query.wait) do
|
213
223
|
result = query.resolve_for(self)
|
@@ -233,7 +243,7 @@ module Capybara
|
|
233
243
|
# @return [Capybara::Node::Element] The found element or nil
|
234
244
|
#
|
235
245
|
def first(*args, &optional_filter_block)
|
236
|
-
if
|
246
|
+
if session_options.wait_on_first_by_default
|
237
247
|
options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
238
248
|
args.push({minimum: 1}.merge(options))
|
239
249
|
end
|
@@ -114,8 +114,8 @@ module Capybara
|
|
114
114
|
#
|
115
115
|
def assert_all_of_selectors(*args, &optional_filter_block)
|
116
116
|
options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
117
|
-
selector = if args.first.is_a?(Symbol) then args.shift else
|
118
|
-
wait = options.fetch(:wait,
|
117
|
+
selector = if args.first.is_a?(Symbol) then args.shift else session_options.default_selector end
|
118
|
+
wait = options.fetch(:wait, session_options.default_max_wait_time)
|
119
119
|
synchronize(wait) do
|
120
120
|
args.each do |locator|
|
121
121
|
assert_selector(selector, locator, options, &optional_filter_block)
|
@@ -140,8 +140,8 @@ module Capybara
|
|
140
140
|
#
|
141
141
|
def assert_none_of_selectors(*args, &optional_filter_block)
|
142
142
|
options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
143
|
-
selector = if args.first.is_a?(Symbol) then args.shift else
|
144
|
-
wait = options.fetch(:wait,
|
143
|
+
selector = if args.first.is_a?(Symbol) then args.shift else session_options.default_selector end
|
144
|
+
wait = options.fetch(:wait, session_options.default_max_wait_time)
|
145
145
|
synchronize(wait) do
|
146
146
|
args.each do |locator|
|
147
147
|
assert_no_selector(selector, locator, options, &optional_filter_block)
|
@@ -680,6 +680,7 @@ module Capybara
|
|
680
680
|
private
|
681
681
|
|
682
682
|
def _verify_selector_result(query_args, optional_filter_block, &result_block)
|
683
|
+
_set_query_session_options(query_args)
|
683
684
|
query = Capybara::Queries::SelectorQuery.new(*query_args, &optional_filter_block)
|
684
685
|
synchronize(query.wait) do
|
685
686
|
result = query.resolve_for(self)
|
@@ -689,6 +690,7 @@ module Capybara
|
|
689
690
|
end
|
690
691
|
|
691
692
|
def _verify_match_result(query_args, optional_filter_block, &result_block)
|
693
|
+
_set_query_session_options(query_args)
|
692
694
|
query = Capybara::Queries::MatchQuery.new(*query_args, &optional_filter_block)
|
693
695
|
synchronize(query.wait) do
|
694
696
|
result = query.resolve_for(self.query_scope)
|
@@ -698,6 +700,7 @@ module Capybara
|
|
698
700
|
end
|
699
701
|
|
700
702
|
def _verify_text(query_args)
|
703
|
+
_set_query_session_options(query_args)
|
701
704
|
query = Capybara::Queries::TextQuery.new(*query_args)
|
702
705
|
synchronize(query.wait) do
|
703
706
|
count = query.resolve_for(self)
|
@@ -706,6 +709,14 @@ module Capybara
|
|
706
709
|
return true
|
707
710
|
end
|
708
711
|
|
712
|
+
def _set_query_session_options(query_args)
|
713
|
+
if query_args.last.is_a? Hash
|
714
|
+
query_args.last[:session_options] = session_options
|
715
|
+
else
|
716
|
+
query_args.push(session_options: session_options)
|
717
|
+
end
|
718
|
+
query_args
|
719
|
+
end
|
709
720
|
end
|
710
721
|
end
|
711
722
|
end
|
data/lib/capybara/node/simple.rb
CHANGED
@@ -6,13 +6,18 @@ module Capybara
|
|
6
6
|
COUNT_KEYS = [:count, :minimum, :maximum, :between]
|
7
7
|
|
8
8
|
attr_reader :options
|
9
|
+
attr_writer :session_options
|
10
|
+
|
11
|
+
def session_options
|
12
|
+
@session_options || Capybara.session_options
|
13
|
+
end
|
9
14
|
|
10
15
|
def wait
|
11
|
-
self.class.wait(options)
|
16
|
+
self.class.wait(options, session_options.default_max_wait_time)
|
12
17
|
end
|
13
18
|
|
14
|
-
def self.wait(options)
|
15
|
-
options.fetch(:wait,
|
19
|
+
def self.wait(options, default=Capybara.default_max_wait_time)
|
20
|
+
options.fetch(:wait, default) || 0
|
16
21
|
end
|
17
22
|
|
18
23
|
##
|
@@ -9,11 +9,13 @@ module Capybara
|
|
9
9
|
|
10
10
|
def initialize(*args, &filter_block)
|
11
11
|
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
12
|
+
self.session_options = @options.delete(:session_options)
|
13
|
+
|
12
14
|
@filter_block = filter_block
|
13
15
|
|
14
16
|
if args[0].is_a?(Symbol)
|
15
17
|
@selector = Selector.all.fetch(args.shift) do |selector_type|
|
16
|
-
|
18
|
+
raise ArgumentError, "Unknown selector type (:#{selector_type})"
|
17
19
|
nil
|
18
20
|
end
|
19
21
|
@locator = args.shift
|
@@ -21,16 +23,16 @@ module Capybara
|
|
21
23
|
@selector = Selector.all.values.find { |s| s.match?(args[0]) }
|
22
24
|
@locator = args.shift
|
23
25
|
end
|
24
|
-
@selector ||= Selector.all[
|
26
|
+
@selector ||= Selector.all[session_options.default_selector]
|
25
27
|
|
26
28
|
warn "Unused parameters passed to #{self.class.name} : #{args.to_s}" unless args.empty?
|
27
29
|
|
28
30
|
# for compatibility with Capybara 2.0
|
29
|
-
if
|
31
|
+
if session_options.exact_options and @selector == Selector.all[:option]
|
30
32
|
@options[:exact] = true
|
31
33
|
end
|
32
34
|
|
33
|
-
@expression = @selector.call(@locator, @options)
|
35
|
+
@expression = @selector.call(@locator, @options.merge(enable_aria_label: session_options.enable_aria_label))
|
34
36
|
|
35
37
|
warn_exact_usage
|
36
38
|
|
@@ -89,12 +91,12 @@ module Capybara
|
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
92
|
-
res &&=
|
94
|
+
res &&= node.session.using_wait_time(0){ @filter_block.call(node)} unless @filter_block.nil?
|
93
95
|
res
|
94
96
|
end
|
95
97
|
|
96
98
|
def visible
|
97
|
-
case (vis = options.fetch(:visible){ @selector.default_visibility })
|
99
|
+
case (vis = options.fetch(:visible){ @selector.default_visibility(session_options.ignore_hidden_elements) })
|
98
100
|
when true then :visible
|
99
101
|
when false then :all
|
100
102
|
else vis
|
@@ -103,11 +105,11 @@ module Capybara
|
|
103
105
|
|
104
106
|
def exact?
|
105
107
|
return false if !supports_exact?
|
106
|
-
options.fetch(:exact,
|
108
|
+
options.fetch(:exact, session_options.exact)
|
107
109
|
end
|
108
110
|
|
109
111
|
def match
|
110
|
-
options.fetch(:match,
|
112
|
+
options.fetch(:match, session_options.match)
|
111
113
|
end
|
112
114
|
|
113
115
|
def xpath(exact=nil)
|
@@ -205,7 +207,7 @@ module Capybara
|
|
205
207
|
end
|
206
208
|
|
207
209
|
def exact_text
|
208
|
-
options.fetch(:exact_text,
|
210
|
+
options.fetch(:exact_text, session_options.exact_text)
|
209
211
|
end
|
210
212
|
end
|
211
213
|
end
|