capybara 3.30.0 → 3.31.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +21 -0
  3. data/README.md +1 -1
  4. data/lib/capybara/dsl.rb +10 -2
  5. data/lib/capybara/minitest.rb +18 -4
  6. data/lib/capybara/node/element.rb +11 -8
  7. data/lib/capybara/node/finders.rb +5 -1
  8. data/lib/capybara/node/matchers.rb +24 -15
  9. data/lib/capybara/node/simple.rb +1 -1
  10. data/lib/capybara/queries/base_query.rb +2 -1
  11. data/lib/capybara/rack_test/node.rb +34 -9
  12. data/lib/capybara/result.rb +24 -4
  13. data/lib/capybara/rspec/matchers.rb +27 -27
  14. data/lib/capybara/rspec/matchers/base.rb +12 -6
  15. data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
  16. data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
  17. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  18. data/lib/capybara/rspec/matchers/have_selector.rb +15 -7
  19. data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
  20. data/lib/capybara/rspec/matchers/have_text.rb +2 -2
  21. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  22. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  23. data/lib/capybara/rspec/matchers/match_style.rb +2 -2
  24. data/lib/capybara/rspec/matchers/spatial_sugar.rb +2 -1
  25. data/lib/capybara/selector.rb +2 -0
  26. data/lib/capybara/selector/definition/label.rb +1 -1
  27. data/lib/capybara/selector/definition/select.rb +31 -12
  28. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
  29. data/lib/capybara/selenium/extensions/html5_drag.rb +24 -8
  30. data/lib/capybara/selenium/node.rb +23 -6
  31. data/lib/capybara/selenium/nodes/chrome_node.rb +4 -2
  32. data/lib/capybara/selenium/nodes/edge_node.rb +1 -1
  33. data/lib/capybara/selenium/nodes/firefox_node.rb +1 -1
  34. data/lib/capybara/session.rb +30 -15
  35. data/lib/capybara/spec/public/test.js +40 -6
  36. data/lib/capybara/spec/session/all_spec.rb +45 -5
  37. data/lib/capybara/spec/session/assert_text_spec.rb +5 -5
  38. data/lib/capybara/spec/session/fill_in_spec.rb +20 -0
  39. data/lib/capybara/spec/session/has_css_spec.rb +3 -3
  40. data/lib/capybara/spec/session/has_select_spec.rb +28 -0
  41. data/lib/capybara/spec/session/has_text_spec.rb +5 -1
  42. data/lib/capybara/spec/session/node_spec.rb +92 -3
  43. data/lib/capybara/spec/views/form.erb +6 -1
  44. data/lib/capybara/version.rb +1 -1
  45. data/spec/rack_test_spec.rb +0 -1
  46. data/spec/result_spec.rb +4 -0
  47. data/spec/selenium_spec_chrome.rb +2 -1
  48. metadata +2 -2
@@ -15,45 +15,45 @@ module Capybara
15
15
  # RSpec matcher for whether the element(s) matching a given selector exist.
16
16
  #
17
17
  # @see Capybara::Node::Matchers#assert_selector
18
- def have_selector(*args, &optional_filter_block)
19
- Matchers::HaveSelector.new(*args, &optional_filter_block)
18
+ def have_selector(*args, **kw_args, &optional_filter_block)
19
+ Matchers::HaveSelector.new(*args, **kw_args, &optional_filter_block)
20
20
  end
21
21
 
22
22
  # RSpec matcher for whether the element(s) matching a group of selectors exist.
23
23
  #
24
24
  # @see Capybara::Node::Matchers#assert_all_of_selectors
25
- def have_all_of_selectors(*args, &optional_filter_block)
26
- Matchers::HaveAllSelectors.new(*args, &optional_filter_block)
25
+ def have_all_of_selectors(*args, **kw_args, &optional_filter_block)
26
+ Matchers::HaveAllSelectors.new(*args, **kw_args, &optional_filter_block)
27
27
  end
28
28
 
29
29
  # RSpec matcher for whether no element(s) matching a group of selectors exist.
30
30
  #
31
31
  # @see Capybara::Node::Matchers#assert_none_of_selectors
32
- def have_none_of_selectors(*args, &optional_filter_block)
33
- Matchers::HaveNoSelectors.new(*args, &optional_filter_block)
32
+ def have_none_of_selectors(*args, **kw_args, &optional_filter_block)
33
+ Matchers::HaveNoSelectors.new(*args, **kw_args, &optional_filter_block)
34
34
  end
35
35
 
36
36
  # RSpec matcher for whether the element(s) matching any of a group of selectors exist.
37
37
  #
38
38
  # @see Capybara::Node::Matchers#assert_any_of_selectors
39
- def have_any_of_selectors(*args, &optional_filter_block)
40
- Matchers::HaveAnySelectors.new(*args, &optional_filter_block)
39
+ def have_any_of_selectors(*args, **kw_args, &optional_filter_block)
40
+ Matchers::HaveAnySelectors.new(*args, **kw_args, &optional_filter_block)
41
41
  end
42
42
 
43
43
  # RSpec matcher for whether the current element matches a given selector.
44
44
  #
45
45
  # @see Capybara::Node::Matchers#assert_matches_selector
46
- def match_selector(*args, &optional_filter_block)
47
- Matchers::MatchSelector.new(*args, &optional_filter_block)
46
+ def match_selector(*args, **kw_args, &optional_filter_block)
47
+ Matchers::MatchSelector.new(*args, **kw_args, &optional_filter_block)
48
48
  end
49
49
 
50
50
  %i[css xpath].each do |selector|
51
51
  define_method "have_#{selector}" do |expr, **options, &optional_filter_block|
52
- Matchers::HaveSelector.new(selector, expr, options, &optional_filter_block)
52
+ Matchers::HaveSelector.new(selector, expr, **options, &optional_filter_block)
53
53
  end
54
54
 
55
55
  define_method "match_#{selector}" do |expr, **options, &optional_filter_block|
56
- Matchers::MatchSelector.new(selector, expr, options, &optional_filter_block)
56
+ Matchers::MatchSelector.new(selector, expr, **options, &optional_filter_block)
57
57
  end
58
58
  end
59
59
 
@@ -79,7 +79,7 @@ module Capybara
79
79
 
80
80
  %i[link button field select table].each do |selector|
81
81
  define_method "have_#{selector}" do |locator = nil, **options, &optional_filter_block|
82
- Matchers::HaveSelector.new(selector, locator, options, &optional_filter_block)
82
+ Matchers::HaveSelector.new(selector, locator, **options, &optional_filter_block)
83
83
  end
84
84
  end
85
85
 
@@ -110,7 +110,7 @@ module Capybara
110
110
 
111
111
  %i[checked unchecked].each do |state|
112
112
  define_method "have_#{state}_field" do |locator = nil, **options, &optional_filter_block|
113
- Matchers::HaveSelector.new(:field, locator, options.merge(state => true), &optional_filter_block)
113
+ Matchers::HaveSelector.new(:field, locator, **options.merge(state => true), &optional_filter_block)
114
114
  end
115
115
  end
116
116
 
@@ -127,27 +127,27 @@ module Capybara
127
127
  # RSpec matcher for text content.
128
128
  #
129
129
  # @see Capybara::Node::Matchers#assert_text
130
- def have_text(*args)
131
- Matchers::HaveText.new(*args)
130
+ def have_text(text_or_type, *args, **options)
131
+ Matchers::HaveText.new(text_or_type, *args, **options)
132
132
  end
133
133
  alias_method :have_content, :have_text
134
134
 
135
135
  def have_title(title, **options)
136
- Matchers::HaveTitle.new(title, options)
136
+ Matchers::HaveTitle.new(title, **options)
137
137
  end
138
138
 
139
139
  # RSpec matcher for the current path.
140
140
  #
141
141
  # @see Capybara::SessionMatchers#assert_current_path
142
142
  def have_current_path(path, **options)
143
- Matchers::HaveCurrentPath.new(path, options)
143
+ Matchers::HaveCurrentPath.new(path, **options)
144
144
  end
145
145
 
146
146
  # RSpec matcher for element style.
147
147
  #
148
148
  # @see Capybara::Node::Matchers#matches_style?
149
149
  def match_style(styles, **options)
150
- Matchers::MatchStyle.new(styles, options)
150
+ Matchers::MatchStyle.new(styles, **options)
151
151
  end
152
152
 
153
153
  ##
@@ -161,30 +161,30 @@ module Capybara
161
161
  %w[selector css xpath text title current_path link button
162
162
  field checked_field unchecked_field select table
163
163
  sibling ancestor].each do |matcher_type|
164
- define_method "have_no_#{matcher_type}" do |*args, &optional_filter_block|
165
- Matchers::NegatedMatcher.new(send("have_#{matcher_type}", *args, &optional_filter_block))
164
+ define_method "have_no_#{matcher_type}" do |*args, **kw_args, &optional_filter_block|
165
+ Matchers::NegatedMatcher.new(send("have_#{matcher_type}", *args, **kw_args, &optional_filter_block))
166
166
  end
167
167
  end
168
168
  alias_method :have_no_content, :have_no_text
169
169
 
170
170
  %w[selector css xpath].each do |matcher_type|
171
- define_method "not_match_#{matcher_type}" do |*args, &optional_filter_block|
172
- Matchers::NegatedMatcher.new(send("match_#{matcher_type}", *args, &optional_filter_block))
171
+ define_method "not_match_#{matcher_type}" do |*args, **kw_args, &optional_filter_block|
172
+ Matchers::NegatedMatcher.new(send("match_#{matcher_type}", *args, **kw_args, &optional_filter_block))
173
173
  end
174
174
  end
175
175
 
176
176
  # RSpec matcher for whether sibling element(s) matching a given selector exist.
177
177
  #
178
178
  # @see Capybara::Node::Matchers#assert_sibling
179
- def have_sibling(*args, &optional_filter_block)
180
- Matchers::HaveSibling.new(*args, &optional_filter_block)
179
+ def have_sibling(*args, **kw_args, &optional_filter_block)
180
+ Matchers::HaveSibling.new(*args, **kw_args, &optional_filter_block)
181
181
  end
182
182
 
183
183
  # RSpec matcher for whether ancestor element(s) matching a given selector exist.
184
184
  #
185
185
  # @see Capybara::Node::Matchers#assert_ancestor
186
- def have_ancestor(*args, &optional_filter_block)
187
- Matchers::HaveAncestor.new(*args, &optional_filter_block)
186
+ def have_ancestor(*args, **kw_args, &optional_filter_block)
187
+ Matchers::HaveAncestor.new(*args, **kw_args, &optional_filter_block)
188
188
  end
189
189
 
190
190
  ##
@@ -12,22 +12,28 @@ module Capybara
12
12
 
13
13
  attr_reader :failure_message, :failure_message_when_negated
14
14
 
15
- def initialize(*args, &filter_block)
15
+ def initialize(*args, **kw_args, &filter_block)
16
16
  @args = args.dup
17
+ @kw_args = kw_args || {}
17
18
  @filter_block = filter_block
18
19
  end
19
20
 
20
21
  private
21
22
 
22
23
  def session_query_args
23
- if @args.last.is_a? Hash
24
- @args.last[:session_options] = session_options
25
- else
26
- @args.push(session_options: session_options)
27
- end
24
+ # if @args.last.is_a? Hash
25
+ # @args.last[:session_options] = session_options
26
+ # else
27
+ # @args.push(session_options: session_options)
28
+ # end
28
29
  @args
29
30
  end
30
31
 
32
+ def session_query_options
33
+ @kw_args[:session_options] = session_options
34
+ @kw_args
35
+ end
36
+
31
37
  def session_options
32
38
  @context_el ||= nil
33
39
  if @context_el.respond_to? :session_options
@@ -29,7 +29,8 @@ module Capybara
29
29
  private
30
30
 
31
31
  def options
32
- (@args.last.is_a?(Hash) ? @args : @args.push({})).last
32
+ # (@args.last.is_a?(Hash) ? @args : @args.push({})).last
33
+ @kw_args
33
34
  end
34
35
  end
35
36
  end
@@ -7,11 +7,11 @@ module Capybara
7
7
  module Matchers
8
8
  class HaveAncestor < CountableWrappedElementMatcher
9
9
  def element_matches?(el)
10
- el.assert_ancestor(*@args, &@filter_block)
10
+ el.assert_ancestor(*@args, **session_query_options, &@filter_block)
11
11
  end
12
12
 
13
13
  def element_does_not_match?(el)
14
- el.assert_no_ancestor(*@args, &@filter_block)
14
+ el.assert_no_ancestor(*@args, **session_query_options, &@filter_block)
15
15
  end
16
16
 
17
17
  def description
@@ -19,7 +19,8 @@ module Capybara
19
19
  end
20
20
 
21
21
  def query
22
- @query ||= Capybara::Queries::AncestorQuery.new(*session_query_args, &@filter_block)
22
+ # @query ||= Capybara::Queries::AncestorQuery.new(*session_query_args, &@filter_block)
23
+ @query ||= Capybara::Queries::AncestorQuery.new(*session_query_args, **session_query_options, &@filter_block)
23
24
  end
24
25
  end
25
26
  end
@@ -7,11 +7,11 @@ module Capybara
7
7
  module Matchers
8
8
  class HaveCurrentPath < WrappedElementMatcher
9
9
  def element_matches?(el)
10
- el.assert_current_path(*@args)
10
+ el.assert_current_path(current_path, **@kw_args)
11
11
  end
12
12
 
13
13
  def element_does_not_match?(el)
14
- el.assert_no_current_path(*@args)
14
+ el.assert_no_current_path(current_path, **@kw_args)
15
15
  end
16
16
 
17
17
  def description
@@ -6,12 +6,20 @@ module Capybara
6
6
  module RSpecMatchers
7
7
  module Matchers
8
8
  class HaveSelector < CountableWrappedElementMatcher
9
+ def initialize(*args, **kw_args, &filter_block)
10
+ super
11
+ if (RUBY_VERSION >= '2.7') && (@args.size < 2) && @kw_args.keys.any?(String) # rubocop:disable Style/GuardClause
12
+ @args.push(@kw_args)
13
+ @kw_args = {}
14
+ end
15
+ end
16
+
9
17
  def element_matches?(el)
10
- el.assert_selector(*@args, &@filter_block)
18
+ el.assert_selector(*@args, **session_query_options, &@filter_block)
11
19
  end
12
20
 
13
21
  def element_does_not_match?(el)
14
- el.assert_no_selector(*@args, &@filter_block)
22
+ el.assert_no_selector(*@args, **session_query_options, &@filter_block)
15
23
  end
16
24
 
17
25
  def description
@@ -19,13 +27,13 @@ module Capybara
19
27
  end
20
28
 
21
29
  def query
22
- @query ||= Capybara::Queries::SelectorQuery.new(*session_query_args, &@filter_block)
30
+ @query ||= Capybara::Queries::SelectorQuery.new(*session_query_args, **session_query_options, &@filter_block)
23
31
  end
24
32
  end
25
33
 
26
34
  class HaveAllSelectors < WrappedElementMatcher
27
35
  def element_matches?(el)
28
- el.assert_all_of_selectors(*@args, &@filter_block)
36
+ el.assert_all_of_selectors(*@args, **session_query_options, &@filter_block)
29
37
  end
30
38
 
31
39
  def does_not_match?(_actual)
@@ -39,7 +47,7 @@ module Capybara
39
47
 
40
48
  class HaveNoSelectors < WrappedElementMatcher
41
49
  def element_matches?(el)
42
- el.assert_none_of_selectors(*@args, &@filter_block)
50
+ el.assert_none_of_selectors(*@args, **session_query_options, &@filter_block)
43
51
  end
44
52
 
45
53
  def does_not_match?(_actual)
@@ -53,11 +61,11 @@ module Capybara
53
61
 
54
62
  class HaveAnySelectors < WrappedElementMatcher
55
63
  def element_matches?(el)
56
- el.assert_any_of_selectors(*@args, &@filter_block)
64
+ el.assert_any_of_selectors(*@args, **session_query_options, &@filter_block)
57
65
  end
58
66
 
59
67
  def does_not_match?(_actual)
60
- el.assert_none_of_selectors(*@args, &@filter_block)
68
+ el.assert_none_of_selectors(*@args, **session_query_options, &@filter_block)
61
69
  end
62
70
 
63
71
  def description
@@ -7,11 +7,11 @@ module Capybara
7
7
  module Matchers
8
8
  class HaveSibling < CountableWrappedElementMatcher
9
9
  def element_matches?(el)
10
- el.assert_sibling(*@args, &@filter_block)
10
+ el.assert_sibling(*@args, **session_query_options, &@filter_block)
11
11
  end
12
12
 
13
13
  def element_does_not_match?(el)
14
- el.assert_no_sibling(*@args, &@filter_block)
14
+ el.assert_no_sibling(*@args, **session_query_options, &@filter_block)
15
15
  end
16
16
 
17
17
  def description
@@ -19,7 +19,7 @@ module Capybara
19
19
  end
20
20
 
21
21
  def query
22
- @query ||= Capybara::Queries::SiblingQuery.new(*session_query_args, &@filter_block)
22
+ @query ||= Capybara::Queries::SiblingQuery.new(*session_query_args, **session_query_options, &@filter_block)
23
23
  end
24
24
  end
25
25
  end
@@ -7,11 +7,11 @@ module Capybara
7
7
  module Matchers
8
8
  class HaveText < CountableWrappedElementMatcher
9
9
  def element_matches?(el)
10
- el.assert_text(*@args)
10
+ el.assert_text(*@args, **@kw_args)
11
11
  end
12
12
 
13
13
  def element_does_not_match?(el)
14
- el.assert_no_text(*@args)
14
+ el.assert_no_text(*@args, **@kw_args)
15
15
  end
16
16
 
17
17
  def description
@@ -7,11 +7,11 @@ module Capybara
7
7
  module Matchers
8
8
  class HaveTitle < WrappedElementMatcher
9
9
  def element_matches?(el)
10
- el.assert_title(*@args)
10
+ el.assert_title(*@args, **@kw_args)
11
11
  end
12
12
 
13
13
  def element_does_not_match?(el)
14
- el.assert_no_title(*@args)
14
+ el.assert_no_title(*@args, **@kw_args)
15
15
  end
16
16
 
17
17
  def description
@@ -7,11 +7,11 @@ module Capybara
7
7
  module Matchers
8
8
  class MatchSelector < HaveSelector
9
9
  def element_matches?(el)
10
- el.assert_matches_selector(*@args, &@filter_block)
10
+ el.assert_matches_selector(*@args, **session_query_options, &@filter_block)
11
11
  end
12
12
 
13
13
  def element_does_not_match?(el)
14
- el.assert_not_matches_selector(*@args, &@filter_block)
14
+ el.assert_not_matches_selector(*@args, **session_query_options, &@filter_block)
15
15
  end
16
16
 
17
17
  def description
@@ -19,7 +19,7 @@ module Capybara
19
19
  end
20
20
 
21
21
  def query
22
- @query ||= Capybara::Queries::MatchQuery.new(*session_query_args, &@filter_block)
22
+ @query ||= Capybara::Queries::MatchQuery.new(*session_query_args, **session_query_options, &@filter_block)
23
23
  end
24
24
  end
25
25
  end
@@ -7,7 +7,7 @@ module Capybara
7
7
  module Matchers
8
8
  class MatchStyle < WrappedElementMatcher
9
9
  def element_matches?(el)
10
- el.assert_matches_style(*@args)
10
+ el.assert_matches_style(*@args, **@kw_args)
11
11
  end
12
12
 
13
13
  def does_not_match?(_actual)
@@ -28,7 +28,7 @@ module Capybara
28
28
  ##
29
29
  # @deprecated
30
30
  class HaveStyle < MatchStyle
31
- def initialize(*args, &filter_block)
31
+ def initialize(*args, **kw_args, &filter_block)
32
32
  warn 'HaveStyle matcher is deprecated, please use the MatchStyle matcher instead'
33
33
  super
34
34
  end
@@ -31,7 +31,8 @@ module Capybara
31
31
  private
32
32
 
33
33
  def options
34
- (@args.last.is_a?(Hash) ? @args : @args.push({})).last
34
+ # (@args.last.is_a?(Hash) ? @args : @args.push({})).last
35
+ @kw_args
35
36
  end
36
37
  end
37
38
  end
@@ -108,6 +108,8 @@ require 'capybara/selector/definition'
108
108
  # * :disabled (Boolean, :all) - Match disabled field? (Default: false)
109
109
  # * :multiple (Boolean) - Match fields that accept multiple values
110
110
  # * :options (Array<String>) - Exact match options
111
+ # * :enabled_options (Array<String>) - Exact match enabled options
112
+ # * :disabled_options (Array<String>) - Exact match disabled options
111
113
  # * :with_options (Array<String>) - Partial match options
112
114
  # * :selected (String, Array<String>) - Match the selection(s)
113
115
  # * :with_selected (String, Array<String>) - Partial match the selection(s)
@@ -2,7 +2,7 @@
2
2
 
3
3
  Capybara.add_selector(:label, locator_type: [String, Symbol]) do
4
4
  label 'label'
5
- xpath(:for) do |locator, options|
5
+ xpath(:for) do |locator, **options|
6
6
  xpath = XPath.descendant(:label)
7
7
  unless locator.nil?
8
8
  locator_matchers = XPath.string.n.is(locator.to_s) | (XPath.attr(:id) == locator.to_s)
@@ -11,16 +11,26 @@ Capybara.add_selector(:select, locator_type: [String, Symbol]) do
11
11
  filter_set(:_field, %i[disabled multiple name placeholder])
12
12
 
13
13
  node_filter(:options) do |node, options|
14
- actual = if node.visible?
15
- node.all(:xpath, './/option', wait: false).map(&:text)
16
- else
17
- node.all(:xpath, './/option', visible: false, wait: false).map { |option| option.text(:all) }
18
- end
14
+ actual = options_text(node)
19
15
  (options.sort == actual.sort).tap do |res|
20
16
  add_error("Expected options #{options.inspect} found #{actual.inspect}") unless res
21
17
  end
22
18
  end
23
19
 
20
+ node_filter(:enabled_options) do |node, options|
21
+ actual = options_text(node) { |o| !o.disabled? }
22
+ (options.sort == actual.sort).tap do |res|
23
+ add_error("Expected enabled options #{options.inspect} found #{actual.inspect}") unless res
24
+ end
25
+ end
26
+
27
+ node_filter(:disabled_options) do |node, options|
28
+ actual = options_text(node, &:disabled?)
29
+ (options.sort == actual.sort).tap do |res|
30
+ add_error("Expected disabled options #{options.inspect} found #{actual.inspect}") unless res
31
+ end
32
+ end
33
+
24
34
  expression_filter(:with_options) do |expr, options|
25
35
  options.inject(expr) do |xpath, option|
26
36
  xpath[expression_for(:option, option)]
@@ -28,18 +38,14 @@ Capybara.add_selector(:select, locator_type: [String, Symbol]) do
28
38
  end
29
39
 
30
40
  node_filter(:selected) do |node, selected|
31
- actual = node.all(:xpath, './/option', visible: false, wait: false)
32
- .select(&:selected?)
33
- .map { |option| option.text(:all) }
41
+ actual = options_text(node, visible: false, &:selected?)
34
42
  (Array(selected).sort == actual.sort).tap do |res|
35
43
  add_error("Expected #{selected.inspect} to be selected found #{actual.inspect}") unless res
36
44
  end
37
45
  end
38
46
 
39
47
  node_filter(:with_selected) do |node, selected|
40
- actual = node.all(:xpath, './/option', visible: false, wait: false)
41
- .select(&:selected?)
42
- .map { |option| option.text(:all) }
48
+ actual = options_text(node, visible: false, &:selected?)
43
49
  (Array(selected) - actual).empty?.tap do |res|
44
50
  add_error("Expected at least #{selected.inspect} to be selected found #{actual.inspect}") unless res
45
51
  end
@@ -51,12 +57,25 @@ Capybara.add_selector(:select, locator_type: [String, Symbol]) do
51
57
  desc
52
58
  end
53
59
 
54
- describe_node_filters do |options: nil, selected: nil, with_selected: nil, disabled: nil, **|
60
+ describe_node_filters do |
61
+ options: nil, disabled_options: nil, enabled_options: nil,
62
+ selected: nil, with_selected: nil,
63
+ disabled: nil, **|
55
64
  desc = +''
56
65
  desc << " with options #{options.inspect}" if options
66
+ desc << " with disabled options #{disabled_options.inspect}}" if disabled_options
67
+ desc << " with enabled options #{enabled_options.inspect}" if enabled_options
57
68
  desc << " with #{selected.inspect} selected" if selected
58
69
  desc << " with at least #{with_selected.inspect} selected" if with_selected
59
70
  desc << ' which is disabled' if disabled
60
71
  desc
61
72
  end
73
+
74
+ def options_text(node, **opts, &filter_block)
75
+ opts[:wait] = false
76
+ opts[:visible] = false unless node.visible?
77
+ node.all(:xpath, './/option', **opts, &filter_block).map do |o|
78
+ o.text((:all if opts[:visible] == false))
79
+ end
80
+ end
62
81
  end