watir 6.13.0 → 6.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (223) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +141 -0
  3. data/.travis.yml +6 -0
  4. data/CHANGES.md +12 -0
  5. data/Gemfile +4 -10
  6. data/README.md +64 -49
  7. data/Rakefile +28 -16
  8. data/lib/watir.rb +13 -15
  9. data/lib/watir/adjacent.rb +15 -13
  10. data/lib/watir/after_hooks.rb +8 -10
  11. data/lib/watir/alert.rb +7 -8
  12. data/lib/watir/aliases.rb +2 -2
  13. data/lib/watir/attribute_helper.rb +18 -20
  14. data/lib/watir/browser.rb +42 -75
  15. data/lib/watir/capabilities.rb +19 -10
  16. data/lib/watir/cell_container.rb +0 -2
  17. data/lib/watir/container.rb +4 -4
  18. data/lib/watir/cookies.rb +7 -8
  19. data/lib/watir/element_collection.rb +37 -22
  20. data/lib/watir/elements/area.rb +0 -2
  21. data/lib/watir/elements/button.rb +1 -3
  22. data/lib/watir/elements/cell.rb +0 -1
  23. data/lib/watir/elements/checkbox.rb +5 -7
  24. data/lib/watir/elements/date_field.rb +5 -9
  25. data/lib/watir/elements/date_time_field.rb +6 -10
  26. data/lib/watir/elements/dlist.rb +2 -4
  27. data/lib/watir/elements/element.rb +201 -99
  28. data/lib/watir/elements/file_field.rb +3 -4
  29. data/lib/watir/elements/font.rb +2 -4
  30. data/lib/watir/elements/form.rb +0 -2
  31. data/lib/watir/elements/hidden.rb +3 -4
  32. data/lib/watir/elements/html_elements.rb +24 -76
  33. data/lib/watir/elements/iframe.rb +57 -71
  34. data/lib/watir/elements/image.rb +3 -4
  35. data/lib/watir/elements/input.rb +0 -2
  36. data/lib/watir/elements/link.rb +2 -5
  37. data/lib/watir/elements/list.rb +4 -4
  38. data/lib/watir/elements/option.rb +3 -6
  39. data/lib/watir/elements/radio.rb +4 -6
  40. data/lib/watir/elements/row.rb +0 -1
  41. data/lib/watir/elements/select.rb +41 -43
  42. data/lib/watir/elements/svg_elements.rb +0 -116
  43. data/lib/watir/elements/table.rb +1 -2
  44. data/lib/watir/elements/table_cell.rb +2 -3
  45. data/lib/watir/elements/text_field.rb +4 -6
  46. data/lib/watir/exception.rb +0 -1
  47. data/lib/watir/extensions/nokogiri.rb +2 -4
  48. data/lib/watir/generator.rb +3 -3
  49. data/lib/watir/generator/base.rb +10 -10
  50. data/lib/watir/generator/base/generator.rb +26 -29
  51. data/lib/watir/generator/base/idl_sorter.rb +34 -32
  52. data/lib/watir/generator/base/spec_extractor.rb +132 -114
  53. data/lib/watir/generator/base/util.rb +1 -3
  54. data/lib/watir/generator/base/visitor.rb +140 -140
  55. data/lib/watir/generator/html.rb +4 -4
  56. data/lib/watir/generator/html/generator.rb +2 -4
  57. data/lib/watir/generator/html/spec_extractor.rb +33 -33
  58. data/lib/watir/generator/html/visitor.rb +14 -14
  59. data/lib/watir/generator/svg.rb +3 -3
  60. data/lib/watir/generator/svg/generator.rb +1 -3
  61. data/lib/watir/generator/svg/spec_extractor.rb +35 -35
  62. data/lib/watir/generator/svg/visitor.rb +14 -14
  63. data/lib/watir/has_window.rb +2 -4
  64. data/lib/watir/js_execution.rb +7 -9
  65. data/lib/watir/js_snippets.rb +3 -3
  66. data/lib/watir/js_snippets/attributeValues.js +11 -0
  67. data/lib/watir/legacy_wait.rb +7 -12
  68. data/lib/watir/locators.rb +9 -11
  69. data/lib/watir/locators/button/locator.rb +2 -3
  70. data/lib/watir/locators/button/selector_builder.rb +9 -9
  71. data/lib/watir/locators/button/selector_builder/xpath.rb +1 -1
  72. data/lib/watir/locators/button/validator.rb +2 -2
  73. data/lib/watir/locators/cell/locator.rb +0 -2
  74. data/lib/watir/locators/cell/selector_builder.rb +3 -5
  75. data/lib/watir/locators/element/locator.rb +85 -64
  76. data/lib/watir/locators/element/selector_builder.rb +40 -38
  77. data/lib/watir/locators/element/selector_builder/xpath.rb +20 -18
  78. data/lib/watir/locators/element/validator.rb +1 -1
  79. data/lib/watir/locators/row/locator.rb +0 -2
  80. data/lib/watir/locators/row/selector_builder.rb +6 -9
  81. data/lib/watir/locators/text_area/selector_builder.rb +1 -1
  82. data/lib/watir/locators/text_field/locator.rb +1 -3
  83. data/lib/watir/locators/text_field/selector_builder.rb +5 -5
  84. data/lib/watir/locators/text_field/selector_builder/xpath.rb +1 -1
  85. data/lib/watir/locators/text_field/validator.rb +3 -2
  86. data/lib/watir/logger.rb +11 -21
  87. data/lib/watir/navigation.rb +49 -0
  88. data/lib/watir/radio_set.rb +17 -18
  89. data/lib/watir/row_container.rb +3 -5
  90. data/lib/watir/screenshot.rb +2 -4
  91. data/lib/watir/user_editable.rb +13 -8
  92. data/lib/watir/version.rb +3 -0
  93. data/lib/watir/wait.rb +56 -55
  94. data/lib/watir/wait/timer.rb +1 -3
  95. data/lib/watir/window.rb +36 -45
  96. data/lib/watir/xpath_support.rb +1 -3
  97. data/lib/watirspec.rb +11 -11
  98. data/lib/watirspec/guards.rb +10 -7
  99. data/lib/watirspec/implementation.rb +3 -4
  100. data/lib/watirspec/rake_tasks.rb +30 -29
  101. data/lib/watirspec/remote_server.rb +3 -3
  102. data/lib/watirspec/runner.rb +1 -2
  103. data/lib/watirspec/server.rb +3 -0
  104. data/lib/watirspec/server/app.rb +14 -6
  105. data/spec/implementation_spec.rb +9 -9
  106. data/spec/locator_spec_helper.rb +3 -4
  107. data/spec/spec_helper.rb +3 -7
  108. data/spec/unit/container_spec.rb +9 -10
  109. data/spec/unit/element_locator_spec.rb +224 -219
  110. data/spec/unit/logger_spec.rb +4 -4
  111. data/spec/unit/unit_helper.rb +0 -2
  112. data/spec/unit/wait_spec.rb +26 -28
  113. data/spec/watirspec/adjacent_spec.rb +130 -130
  114. data/spec/watirspec/after_hooks_spec.rb +63 -63
  115. data/spec/watirspec/alert_spec.rb +6 -6
  116. data/spec/watirspec/attributes_spec.rb +6 -6
  117. data/spec/watirspec/browser_spec.rb +161 -162
  118. data/spec/watirspec/click_spec.rb +9 -9
  119. data/spec/watirspec/cookies_spec.rb +15 -14
  120. data/spec/watirspec/drag_and_drop_spec.rb +15 -16
  121. data/spec/watirspec/element_hidden_spec.rb +19 -21
  122. data/spec/watirspec/elements/area_spec.rb +18 -21
  123. data/spec/watirspec/elements/areas_spec.rb +13 -15
  124. data/spec/watirspec/elements/button_spec.rb +96 -99
  125. data/spec/watirspec/elements/buttons_spec.rb +17 -19
  126. data/spec/watirspec/elements/checkbox_spec.rb +102 -100
  127. data/spec/watirspec/elements/checkboxes_spec.rb +13 -15
  128. data/spec/watirspec/elements/collections_spec.rb +35 -37
  129. data/spec/watirspec/elements/date_field_spec.rb +46 -47
  130. data/spec/watirspec/elements/date_fields_spec.rb +13 -15
  131. data/spec/watirspec/elements/date_time_field_spec.rb +62 -57
  132. data/spec/watirspec/elements/date_time_fields_spec.rb +14 -15
  133. data/spec/watirspec/elements/dd_spec.rb +46 -48
  134. data/spec/watirspec/elements/dds_spec.rb +13 -15
  135. data/spec/watirspec/elements/del_spec.rb +27 -28
  136. data/spec/watirspec/elements/dels_spec.rb +13 -15
  137. data/spec/watirspec/elements/div_spec.rb +89 -91
  138. data/spec/watirspec/elements/divs_spec.rb +17 -19
  139. data/spec/watirspec/elements/dl_spec.rb +52 -54
  140. data/spec/watirspec/elements/dls_spec.rb +13 -15
  141. data/spec/watirspec/elements/dt_spec.rb +46 -48
  142. data/spec/watirspec/elements/dts_spec.rb +13 -15
  143. data/spec/watirspec/elements/element_spec.rb +240 -189
  144. data/spec/watirspec/elements/elements_spec.rb +16 -16
  145. data/spec/watirspec/elements/em_spec.rb +38 -40
  146. data/spec/watirspec/elements/ems_spec.rb +13 -15
  147. data/spec/watirspec/elements/filefield_spec.rb +45 -46
  148. data/spec/watirspec/elements/filefields_spec.rb +13 -15
  149. data/spec/watirspec/elements/font_spec.rb +11 -13
  150. data/spec/watirspec/elements/form_spec.rb +13 -15
  151. data/spec/watirspec/elements/forms_spec.rb +13 -15
  152. data/spec/watirspec/elements/frame_spec.rb +48 -50
  153. data/spec/watirspec/elements/frames_spec.rb +13 -15
  154. data/spec/watirspec/elements/hidden_spec.rb +23 -25
  155. data/spec/watirspec/elements/hiddens_spec.rb +13 -15
  156. data/spec/watirspec/elements/hn_spec.rb +22 -24
  157. data/spec/watirspec/elements/hns_spec.rb +13 -13
  158. data/spec/watirspec/elements/iframe_spec.rb +106 -74
  159. data/spec/watirspec/elements/iframes_spec.rb +16 -18
  160. data/spec/watirspec/elements/image_spec.rb +30 -32
  161. data/spec/watirspec/elements/images_spec.rb +13 -15
  162. data/spec/watirspec/elements/input_spec.rb +4 -5
  163. data/spec/watirspec/elements/ins_spec.rb +27 -29
  164. data/spec/watirspec/elements/inses_spec.rb +13 -15
  165. data/spec/watirspec/elements/label_spec.rb +17 -19
  166. data/spec/watirspec/elements/labels_spec.rb +13 -15
  167. data/spec/watirspec/elements/li_spec.rb +23 -25
  168. data/spec/watirspec/elements/link_spec.rb +45 -48
  169. data/spec/watirspec/elements/links_spec.rb +14 -16
  170. data/spec/watirspec/elements/lis_spec.rb +13 -15
  171. data/spec/watirspec/elements/list_spec.rb +14 -15
  172. data/spec/watirspec/elements/map_spec.rb +19 -20
  173. data/spec/watirspec/elements/maps_spec.rb +13 -15
  174. data/spec/watirspec/elements/meta_spec.rb +10 -10
  175. data/spec/watirspec/elements/metas_spec.rb +13 -15
  176. data/spec/watirspec/elements/ol_spec.rb +20 -21
  177. data/spec/watirspec/elements/ols_spec.rb +13 -15
  178. data/spec/watirspec/elements/option_spec.rb +63 -63
  179. data/spec/watirspec/elements/p_spec.rb +27 -26
  180. data/spec/watirspec/elements/pre_spec.rb +24 -25
  181. data/spec/watirspec/elements/pres_spec.rb +13 -15
  182. data/spec/watirspec/elements/ps_spec.rb +13 -15
  183. data/spec/watirspec/elements/radio_spec.rb +96 -97
  184. data/spec/watirspec/elements/radios_spec.rb +13 -15
  185. data/spec/watirspec/elements/select_list_spec.rb +244 -237
  186. data/spec/watirspec/elements/select_lists_spec.rb +15 -16
  187. data/spec/watirspec/elements/span_spec.rb +32 -31
  188. data/spec/watirspec/elements/spans_spec.rb +13 -15
  189. data/spec/watirspec/elements/strong_spec.rb +23 -24
  190. data/spec/watirspec/elements/strongs_spec.rb +13 -15
  191. data/spec/watirspec/elements/table_nesting_spec.rb +15 -14
  192. data/spec/watirspec/elements/table_spec.rb +61 -62
  193. data/spec/watirspec/elements/tables_spec.rb +15 -17
  194. data/spec/watirspec/elements/tbody_spec.rb +25 -26
  195. data/spec/watirspec/elements/tbodys_spec.rb +17 -19
  196. data/spec/watirspec/elements/td_spec.rb +20 -22
  197. data/spec/watirspec/elements/tds_spec.rb +9 -11
  198. data/spec/watirspec/elements/text_field_spec.rb +55 -56
  199. data/spec/watirspec/elements/text_fields_spec.rb +15 -16
  200. data/spec/watirspec/elements/textarea_spec.rb +2 -2
  201. data/spec/watirspec/elements/textareas_spec.rb +1 -1
  202. data/spec/watirspec/elements/tfoot_spec.rb +22 -23
  203. data/spec/watirspec/elements/tfoots_spec.rb +19 -19
  204. data/spec/watirspec/elements/thead_spec.rb +21 -23
  205. data/spec/watirspec/elements/theads_spec.rb +19 -19
  206. data/spec/watirspec/elements/tr_spec.rb +20 -22
  207. data/spec/watirspec/elements/trs_spec.rb +17 -19
  208. data/spec/watirspec/elements/ul_spec.rb +17 -19
  209. data/spec/watirspec/elements/uls_spec.rb +13 -14
  210. data/spec/watirspec/html/data_attributes.html +1 -0
  211. data/spec/watirspec/radio_set_spec.rb +100 -99
  212. data/spec/watirspec/relaxed_locate_spec.rb +19 -43
  213. data/spec/watirspec/screenshot_spec.rb +4 -4
  214. data/spec/watirspec/special_chars_spec.rb +2 -4
  215. data/spec/watirspec/support/rspec_matchers.rb +85 -22
  216. data/spec/watirspec/user_editable_spec.rb +84 -85
  217. data/spec/watirspec/wait_spec.rb +74 -95
  218. data/spec/watirspec/window_switching_spec.rb +131 -132
  219. data/spec/watirspec_helper.rb +12 -9
  220. data/support/travis.sh +4 -0
  221. data/support/version_differ.rb +12 -13
  222. data/watir.gemspec +29 -22
  223. metadata +76 -50
@@ -1,6 +1,5 @@
1
1
  module Watir
2
2
  class Capabilities
3
-
4
3
  attr_reader :options
5
4
 
6
5
  def initialize(browser, options = {})
@@ -48,10 +47,11 @@ module Watir
48
47
 
49
48
  http_client = @options.delete(:http_client)
50
49
 
51
- %i(open_timeout read_timeout client_timeout).each do |t|
50
+ %i[open_timeout read_timeout client_timeout].each do |t|
52
51
  next if http_client.nil? || !respond_to?(t)
53
- Watir.logger.warn "You can now pass #{t} value directly into Watir::Browser opt without needing to use :http_client",
54
- ids: [:http_client, :use_capabilities]
52
+
53
+ msg = "You can pass #{t} value directly into Watir::Browser opt without needing to use :http_client"
54
+ Watir.logger.warn msg, ids: %i[http_client use_capabilities]
55
55
  end
56
56
 
57
57
  http_client ||= Selenium::WebDriver::Remote::Http::Default.new
@@ -62,6 +62,11 @@ module Watir
62
62
  @selenium_opts[:http_client] = http_client
63
63
  end
64
64
 
65
+ # TODO: - this will get addressed with Capabilities Update
66
+ # rubocop:disable Metrics/AbcSize
67
+ # rubocop:disable Metrics/MethodLength
68
+ # rubocop:disable Metrics/PerceivedComplexity:
69
+ # rubocop:disable Metrics/CyclomaticComplexity::
65
70
  def process_browser_options
66
71
  browser_options = @options.delete(:options) || {}
67
72
 
@@ -83,8 +88,8 @@ module Watir
83
88
  if browser_options.is_a? Selenium::WebDriver::Firefox::Options
84
89
  @selenium_opts[:options] = browser_options
85
90
  if profile
86
- Watir.logger.deprecate 'Initializing Browser with both :profile and :option', ':profile as a key inside :option',
87
- ids: [:firefox_profile]
91
+ msg = 'Initializing Browser with both :profile and :option', ':profile as a key inside :option'
92
+ Watir.logger.deprecate msg, ids: [:firefox_profile]
88
93
  end
89
94
  end
90
95
  if @options.delete(:headless)
@@ -106,16 +111,21 @@ module Watir
106
111
  @options[Selenium::WebDriver::Firefox::Options::KEY] = {'args' => args + ['--headless']}
107
112
  end
108
113
  if @browser == :safari && @options.delete(:technology_preview)
109
- @options["safari.options"] = {'technologyPreview' => true}
114
+ @options['safari.options'] = {'technologyPreview' => true}
110
115
  end
111
116
  end
112
117
  end
118
+ # rubocop:enable Metrics/AbcSize
119
+ # rubocop:enable Metrics/MethodLength
120
+ # rubocop:enable Metrics/PerceivedComplexity:
121
+ # rubocop:enable Metrics/CyclomaticComplexity::
113
122
 
114
123
  def process_capabilities
115
124
  caps = @options.delete(:desired_capabilities)
116
125
 
117
126
  if caps
118
- Watir.logger.warn 'You can now pass values directly into Watir::Browser opt without needing to use :desired_capabilities',
127
+ msg = 'You can pass values directly into Watir::Browser opt without needing to use :desired_capabilities'
128
+ Watir.logger.warn msg,
119
129
  ids: [:use_capabilities]
120
130
  @selenium_opts.merge!(@options)
121
131
  else
@@ -124,6 +134,5 @@ module Watir
124
134
 
125
135
  @selenium_opts[:desired_capabilities] = caps
126
136
  end
127
-
128
137
  end
129
- end
138
+ end
@@ -1,6 +1,5 @@
1
1
  module Watir
2
2
  module CellContainer
3
-
4
3
  #
5
4
  # Returns table cell.
6
5
  #
@@ -20,6 +19,5 @@ module Watir
20
19
  def cells(*args)
21
20
  CellCollection.new(self, extract_selector(args).merge(tag_name: /^(th|td)$/))
22
21
  end
23
-
24
22
  end # CellContainer
25
23
  end # Watir
@@ -36,19 +36,19 @@ module Watir
36
36
  def extract_selector(selectors)
37
37
  case selectors.size
38
38
  when 2
39
- Watir.logger.deprecate "Using ordered parameters to locate elements (:#{selectors.first}, #{selectors.last.inspect})",
39
+ msg = "Using ordered parameters to locate elements (:#{selectors.first}, #{selectors.last.inspect})"
40
+ Watir.logger.deprecate msg,
40
41
  "{#{selectors.first}: #{selectors.last.inspect}}",
41
42
  ids: [:selector_parameters]
42
- return { selectors[0] => selectors[1] }
43
+ return {selectors[0] => selectors[1]}
43
44
  when 1
44
45
  obj = selectors.first
45
- return obj if obj.kind_of? Hash
46
+ return obj if obj.is_a? Hash
46
47
  when 0
47
48
  return {}
48
49
  end
49
50
 
50
51
  raise ArgumentError, "expected Hash, got #{selectors.inspect}"
51
52
  end
52
-
53
53
  end # Container
54
54
  end # Watir
@@ -2,7 +2,6 @@ require 'yaml'
2
2
 
3
3
  module Watir
4
4
  class Cookies
5
-
6
5
  def initialize(control)
7
6
  @control = control
8
7
  end
@@ -56,7 +55,8 @@ module Watir
56
55
  def add(name, value, opts = {})
57
56
  cookie = {
58
57
  name: name,
59
- value: value}
58
+ value: value
59
+ }
60
60
  cookie[:secure] = opts[:secure] if opts.key?(:secure)
61
61
  cookie[:path] = opts[:path] if opts.key?(:path)
62
62
  expires = opts[:expires]
@@ -115,20 +115,19 @@ module Watir
115
115
  #
116
116
 
117
117
  def load(file = '.cookies')
118
- YAML.load(IO.read(file)).each do |c|
118
+ YAML.safe_load(IO.read(file), [::Symbol]).each do |c|
119
119
  add(c.delete(:name), c.delete(:value), c)
120
120
  end
121
121
  end
122
122
 
123
123
  private
124
124
 
125
- def to_time(t)
126
- if t.respond_to?(:to_time)
127
- t.to_time
125
+ def to_time(time)
126
+ if time.respond_to?(:to_time)
127
+ time.to_time
128
128
  else
129
- ::Time.local t.year, t.month, t.day, t.hour, t.min, t.sec
129
+ ::Time.local time.year, time.month, time.day, time.hour, time.min, time.sec
130
130
  end
131
131
  end
132
-
133
132
  end # Cookies
134
133
  end # Watir
@@ -1,5 +1,4 @@
1
1
  module Watir
2
-
3
2
  #
4
3
  # Base class for element collections.
5
4
  #
@@ -29,10 +28,10 @@ module Watir
29
28
  to_a.each(&blk)
30
29
  end
31
30
 
32
- alias_method :length, :count
33
- alias_method :size, :count
31
+ alias length count
32
+ alias size count
34
33
 
35
- alias_method :empty?, :none?
34
+ alias empty? none?
36
35
 
37
36
  #
38
37
  # Get the element at the given index or range.
@@ -50,7 +49,7 @@ module Watir
50
49
  if value.is_a?(Range)
51
50
  to_a[value]
52
51
  elsif @selector.key? :adjacent
53
- to_a[value] || element_class.new(@query_scope, {invalid_locator: true})
52
+ to_a[value] || element_class.new(@query_scope, invalid_locator: true)
54
53
  elsif @to_a && @to_a[value]
55
54
  @to_a[value]
56
55
  else
@@ -87,19 +86,21 @@ module Watir
87
86
  def to_a
88
87
  hash = {}
89
88
  @to_a ||=
90
- elements.map.with_index do |e, idx|
91
- element = element_class.new(@query_scope, @selector.merge(element: e, index: idx))
92
- if [Watir::HTMLElement, Watir::Input].include? element.class
93
- tag_name = @selector[:tag_name] || element.tag_name.to_sym
94
- hash[tag_name] ||= 0
95
- hash[tag_name] += 1
96
- Watir.element_class_for(tag_name).new(@query_scope, @selector.merge(element: e,
97
- tag_name: tag_name,
98
- index: hash[tag_name] - 1))
99
- else
100
- element
101
- end
89
+ elements.map.with_index do |e, idx|
90
+ selector = @selector.merge(element: e)
91
+ selector[:index] = idx
92
+ element = element_class.new(@query_scope, selector)
93
+ if [Watir::HTMLElement, Watir::Input].include? element.class
94
+ tag_name = @selector[:tag_name] || element.tag_name.to_sym
95
+ hash[tag_name] ||= 0
96
+ hash[tag_name] += 1
97
+ selector[:index] = hash[tag_name] - 1
98
+ selector[:tag_name] = tag_name
99
+ Watir.element_class_for(tag_name).new(@query_scope, selector)
100
+ else
101
+ element
102
102
  end
103
+ end
103
104
  end
104
105
 
105
106
  #
@@ -138,26 +139,40 @@ module Watir
138
139
  def ==(other)
139
140
  to_a == other.to_a
140
141
  end
141
- alias_method :eql?, :==
142
+ alias eql? ==
142
143
 
143
144
  #
144
145
  # Creates a Collection containing elements of two collections.
145
146
  #
146
147
  # @example
147
- # (browser.select_list(name: "new_user_languages").options + browser.select_list(id: "new_user_role").options).size
148
+ # options = browser.select_list(name: "new_user_languages").options
149
+ # (options + browser.select_list(id: "new_user_role").options).size
148
150
  # #=> 8
149
151
  #
150
152
 
151
153
  private
152
154
 
153
155
  def elements
154
- @locator ||= build_locator
155
- @elements ||= @locator.locate_all
156
+ ensure_context
157
+ if @query_scope.is_a?(Browser)
158
+ locate_all
159
+ else
160
+ # This gives all of the standard Watir waiting behaviors to Collections
161
+ @query_scope.send(:element_call) { locate_all }
162
+ end
163
+ end
164
+
165
+ def ensure_context
166
+ @query_scope.locate if @query_scope.relocate?
167
+ @query_scope.switch_to! if @query_scope.is_a?(IFrame)
168
+ end
169
+
170
+ def locate_all
171
+ build_locator.locate_all
156
172
  end
157
173
 
158
174
  def element_class
159
175
  Kernel.const_get(self.class.name.sub(/Collection$/, ''))
160
176
  end
161
-
162
177
  end # ElementCollection
163
178
  end # Watir
@@ -1,12 +1,10 @@
1
1
  module Watir
2
2
  class Area < HTMLElement
3
-
4
3
  #
5
4
  # @todo temporarily add href attribute
6
5
  #
7
6
  # @see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23192
8
7
  #
9
8
  attribute String, :href, :href
10
-
11
9
  end # Area
12
10
  end # Watir
@@ -1,5 +1,4 @@
1
1
  module Watir
2
-
3
2
  #
4
3
  # Class representing button elements.
5
4
  #
@@ -7,10 +6,9 @@ module Watir
7
6
  #
8
7
 
9
8
  class Button < HTMLElement
10
-
11
9
  inherit_attributes_from Watir::Input
12
10
 
13
- VALID_TYPES = %w[button reset submit image]
11
+ VALID_TYPES = %w[button reset submit image].freeze
14
12
 
15
13
  #
16
14
  # Returns the text of the button.
@@ -1,5 +1,4 @@
1
1
  module Watir
2
-
3
2
  #
4
3
  # Custom class representing table cell (th or td).
5
4
  #
@@ -1,6 +1,5 @@
1
1
  module Watir
2
2
  class CheckBox < Input
3
-
4
3
  #
5
4
  # Sets checkbox to the given value.
6
5
  #
@@ -18,7 +17,7 @@ module Watir
18
17
  def set(bool = true)
19
18
  set? == bool ? assert_enabled : click
20
19
  end
21
- alias_method :check, :set
20
+ alias check set
22
21
 
23
22
  #
24
23
  # Returns true if the element is checked
@@ -28,7 +27,7 @@ module Watir
28
27
  def set?
29
28
  element_call { @element.selected? }
30
29
  end
31
- alias_method :checked?, :set?
30
+ alias checked? set?
32
31
 
33
32
  #
34
33
  # Unsets checkbox.
@@ -37,17 +36,16 @@ module Watir
37
36
  def clear
38
37
  set false
39
38
  end
40
- alias_method :uncheck, :clear
41
-
39
+ alias uncheck clear
42
40
  end # CheckBox
43
41
 
44
42
  module Container
45
43
  def checkbox(*args)
46
- CheckBox.new(self, extract_selector(args).merge(tag_name: "input", type: "checkbox"))
44
+ CheckBox.new(self, extract_selector(args).merge(tag_name: 'input', type: 'checkbox'))
47
45
  end
48
46
 
49
47
  def checkboxes(*args)
50
- CheckBoxCollection.new(self, extract_selector(args).merge(tag_name: "input", type: "checkbox"))
48
+ CheckBoxCollection.new(self, extract_selector(args).merge(tag_name: 'input', type: 'checkbox'))
51
49
  end
52
50
  end # Container
53
51
 
@@ -1,6 +1,5 @@
1
1
  module Watir
2
2
  class DateField < Input
3
-
4
3
  #
5
4
  # Enter the provided value.
6
5
  #
@@ -11,23 +10,20 @@ module Watir
11
10
  message = "DateField##{__callee__} only accepts instances of Date or Time"
12
11
  raise ArgumentError, message unless [Date, ::Time].include?(date.class)
13
12
 
14
- date_string = date.strftime("%Y-%m-%d")
13
+ date_string = date.strftime('%Y-%m-%d')
15
14
  element_call(:wait_for_writable) { execute_js(:setValue, @element, date_string) }
16
15
  end
17
- alias_method :set, :set!
18
- alias_method :value=, :set
19
-
20
- protected
21
-
16
+ alias set set!
17
+ alias value= set
22
18
  end # DateField
23
19
 
24
20
  module Container
25
21
  def date_field(*args)
26
- DateField.new(self, extract_selector(args).merge(tag_name: "input", type: "date"))
22
+ DateField.new(self, extract_selector(args).merge(tag_name: 'input', type: 'date'))
27
23
  end
28
24
 
29
25
  def date_fields(*args)
30
- DateFieldCollection.new(self, extract_selector(args).merge(tag_name: "input", type: "date"))
26
+ DateFieldCollection.new(self, extract_selector(args).merge(tag_name: 'input', type: 'date'))
31
27
  end
32
28
  end # Container
33
29
 
@@ -1,33 +1,29 @@
1
1
  module Watir
2
2
  class DateTimeField < Input
3
-
4
3
  #
5
4
  # Enter the provided value.
6
5
  #
7
6
 
8
7
  def set!(date)
9
- date = DateTime.parse date if date.is_a?(String)
8
+ date = ::Time.parse date if date.is_a?(String)
10
9
 
11
10
  message = "DateTimeField##{__callee__} only accepts instances of DateTime or Time"
12
11
  raise ArgumentError, message unless [DateTime, ::Time].include?(date.class)
13
12
 
14
- date_time_string = date.strftime("%Y-%m-%dT%H:%M")
13
+ date_time_string = date.strftime('%Y-%m-%dT%H:%M')
15
14
  element_call(:wait_for_writable) { execute_js(:setValue, @element, date_time_string) }
16
15
  end
17
- alias_method :set, :set!
18
- alias_method :value=, :set
19
-
20
- protected
21
-
16
+ alias set set!
17
+ alias value= set
22
18
  end # DateTimeField
23
19
 
24
20
  module Container
25
21
  def date_time_field(*args)
26
- DateTimeField.new(self, extract_selector(args).merge(tag_name: "input", type: "datetime-local"))
22
+ DateTimeField.new(self, extract_selector(args).merge(tag_name: 'input', type: 'datetime-local'))
27
23
  end
28
24
 
29
25
  def date_time_fields(*args)
30
- DateTimeFieldCollection.new(self, extract_selector(args).merge(tag_name: "input", type: "datetime-local"))
26
+ DateTimeFieldCollection.new(self, extract_selector(args).merge(tag_name: 'input', type: 'datetime-local'))
31
27
  end
32
28
  end # Container
33
29
 
@@ -1,12 +1,10 @@
1
1
  module Watir
2
2
  class DList < HTMLElement
3
-
4
3
  def to_hash
5
- keys = dts.map { |e| e.text }
6
- values = dds.map { |e| e.text }
4
+ keys = dts.map(&:text)
5
+ values = dds.map(&:text)
7
6
 
8
7
  Hash[keys.zip(values)]
9
8
  end
10
-
11
9
  end # DList
12
10
  end # Watir
@@ -1,5 +1,4 @@
1
1
  module Watir
2
-
3
2
  #
4
3
  # Base class for HTML elements.
5
4
  #
@@ -32,9 +31,7 @@ module Watir
32
31
  def initialize(query_scope, selector)
33
32
  @query_scope = query_scope
34
33
 
35
- unless selector.kind_of? Hash
36
- raise ArgumentError, "invalid argument: #{selector.inspect}"
37
- end
34
+ raise ArgumentError, "invalid argument: #{selector.inspect}" unless selector.is_a? Hash
38
35
 
39
36
  @element = selector.delete(:element)
40
37
  @selector = selector
@@ -42,28 +39,30 @@ module Watir
42
39
 
43
40
  #
44
41
  # Returns true if element exists.
42
+ # Checking for staleness is deprecated
45
43
  #
46
44
  # @return [Boolean]
47
45
  #
48
46
 
49
47
  def exists?
50
- return false if @element && stale?
48
+ return false if located? && stale?
49
+
51
50
  assert_exists
52
51
  true
53
52
  rescue UnknownObjectException, UnknownFrameException
54
53
  false
55
54
  end
56
- alias_method :exist?, :exists?
55
+ alias exist? exists?
57
56
 
58
57
  def inspect
59
58
  string = "#<#{self.class}: "
60
59
  string << "keyword: #{keyword} " if keyword
61
- string << "located: #{!!@element}; "
62
- if @selector.empty?
63
- string << '{element: (selenium element)}'
64
- else
65
- string << selector_string
66
- end
60
+ string << "located: #{located?}; "
61
+ string << if @selector.empty?
62
+ '{element: (selenium element)}'
63
+ else
64
+ selector_string
65
+ end
67
66
  string << '>'
68
67
  string
69
68
  end
@@ -71,6 +70,10 @@ module Watir
71
70
  #
72
71
  # Returns true if two elements are equal.
73
72
  #
73
+ # TODO: Address how this is affected by stale elements
74
+ # TODO: Address how this is affected by HTMLElement vs subclass
75
+ # TODO: Address how this is affected by a non-located element
76
+ #
74
77
  # @example
75
78
  # browser.text_field(name: "new_user_first_name") == browser.text_field(name: "new_user_first_name")
76
79
  # #=> true
@@ -79,10 +82,10 @@ module Watir
79
82
  def ==(other)
80
83
  other.is_a?(self.class) && wd == other.wd
81
84
  end
82
- alias_method :eql?, :==
85
+ alias eql? ==
83
86
 
84
87
  def hash
85
- @element ? @element.hash : super
88
+ located? ? @element.hash : super
86
89
  end
87
90
 
88
91
  #
@@ -176,7 +179,6 @@ module Watir
176
179
  browser.after_hooks.run
177
180
  end
178
181
 
179
-
180
182
  #
181
183
  # Right clicks the element.
182
184
  # Note that browser support may vary.
@@ -216,9 +218,9 @@ module Watir
216
218
  assert_is_element other
217
219
 
218
220
  value = element_call(:wait_for_present) do
219
- driver.action.
220
- drag_and_drop(@element, other.wd).
221
- perform
221
+ driver.action
222
+ .drag_and_drop(@element, other.wd)
223
+ .perform
222
224
  end
223
225
  browser.after_hooks.run
224
226
  value
@@ -237,9 +239,9 @@ module Watir
237
239
 
238
240
  def drag_and_drop_by(right_by, down_by)
239
241
  element_call(:wait_for_present) do
240
- driver.action.
241
- drag_and_drop_by(@element, right_by, down_by).
242
- perform
242
+ driver.action
243
+ .drag_and_drop_by(@element, right_by, down_by)
244
+ .perform
243
245
  end
244
246
  end
245
247
 
@@ -270,7 +272,44 @@ module Watir
270
272
  attribute_name = attribute_name.to_s.tr('_', '-') if attribute_name.is_a?(::Symbol)
271
273
  element_call { @element.attribute attribute_name }
272
274
  end
273
- alias_method :attribute, :attribute_value
275
+ alias attribute attribute_value
276
+
277
+ #
278
+ # Returns all attribute values. Attributes with special characters are returned as String,
279
+ # rest are returned as a Symbol.
280
+ #
281
+ # @return [Hash]
282
+ #
283
+ # @example
284
+ # browser.pre(id: 'rspec').attribute_values
285
+ # #=> {class:'ruby', id: 'rspec' }
286
+ #
287
+
288
+ def attribute_values
289
+ result = element_call { execute_js(:attributeValues, @element) }
290
+ result.keys.each do |key|
291
+ next unless key == key[/[a-zA-Z\-]*/]
292
+
293
+ result[key.tr('-', '_').to_sym] = result.delete(key)
294
+ end
295
+ result
296
+ end
297
+ alias attributes attribute_values
298
+
299
+ #
300
+ # Returns list of all attributes. Attributes with special characters are returned as String,
301
+ # rest are returned as a Symbol.
302
+ #
303
+ # @return [Array]
304
+ #
305
+ # @example
306
+ # browser.pre(id: 'rspec').attribute_list
307
+ # #=> [:class, :id]
308
+ #
309
+
310
+ def attribute_list
311
+ attribute_values.keys
312
+ end
274
313
 
275
314
  #
276
315
  # Sends sequence of keystrokes to element.
@@ -372,10 +411,10 @@ module Watir
372
411
  def center
373
412
  point = location
374
413
  dimensions = size
375
- Selenium::WebDriver::Point.new(point.x + (dimensions['width']/2),
376
- point.y + (dimensions['height']/2))
414
+ Selenium::WebDriver::Point.new(point.x + (dimensions['width'] / 2),
415
+ point.y + (dimensions['height'] / 2))
377
416
  end
378
- alias_method :centre, :center
417
+ alias centre center
379
418
 
380
419
  #
381
420
  # @api private
@@ -386,12 +425,13 @@ module Watir
386
425
  end
387
426
 
388
427
  #
389
- # @api private
428
+ # Returns underlying Selenium object of the Watir Element
429
+ #
430
+ # @return [Selenium::WebDriver::Element]
390
431
  #
391
432
 
392
433
  def wd
393
- assert_exists if @element.nil?
394
- return driver if @element.is_a? FramedDriver
434
+ assert_exists
395
435
  @element
396
436
  end
397
437
 
@@ -403,15 +443,19 @@ module Watir
403
443
  #
404
444
 
405
445
  def visible?
406
- Watir.logger.warn "#visible? behavior will be changing slightly, consider switching to #present? (more details: http://watir.com/element-existentialism/)",
407
- ids: [:visible_element]
408
- assert_exists
409
- @element.displayed?
410
- rescue Selenium::WebDriver::Error::StaleElementReferenceError
411
- Watir.logger.deprecate "Checking `#visible? == false` to determine a stale element", "`#stale? == true`",
412
- ids: [:stale_visible]
413
- reset!
414
- raise unknown_exception
446
+ msg = '#visible? behavior will be changing slightly, consider switching to #present? ' \
447
+ '(more details: http://watir.com/element-existentialism/)'
448
+ Watir.logger.warn msg, ids: [:visible_element]
449
+ displayed = display_check
450
+ if displayed.nil? && display_check
451
+ Watir.logger.deprecate 'Checking `#present? == false` to determine a stale element',
452
+ '`#stale? == true`',
453
+ reference: 'http://watir.com/staleness-changes',
454
+ ids: [:stale_visible]
455
+ end
456
+ raise unknown_exception if displayed.nil?
457
+
458
+ displayed
415
459
  end
416
460
 
417
461
  #
@@ -434,13 +478,14 @@ module Watir
434
478
  #
435
479
 
436
480
  def present?
437
- assert_exists
438
- @element.displayed?
439
- rescue Selenium::WebDriver::Error::StaleElementReferenceError
440
- Watir.logger.deprecate "Checking `#present? == false` to determine a stale element", "`#stale? == true`",
441
- ids: [:stale_present]
442
- reset!
443
- false
481
+ displayed = display_check
482
+ if displayed.nil? && display_check
483
+ Watir.logger.deprecate 'Checking `#present? == false` to determine a stale element',
484
+ '`#stale? == true`',
485
+ reference: 'http://watir.com/staleness-changes',
486
+ ids: [:stale_present]
487
+ end
488
+ displayed
444
489
  rescue UnknownObjectException, UnknownFrameException
445
490
  false
446
491
  end
@@ -460,7 +505,7 @@ module Watir
460
505
  if property
461
506
  element_call { @element.style property }
462
507
  else
463
- attribute_value("style").to_s.strip
508
+ attribute_value('style').to_s.strip
464
509
  end
465
510
  end
466
511
 
@@ -474,16 +519,16 @@ module Watir
474
519
 
475
520
  def to_subtype
476
521
  tag = tag_name()
477
- klass = if tag == "input"
522
+ klass = if tag == 'input'
478
523
  case attribute_value(:type)
479
- when *Button::VALID_TYPES
480
- Button
481
524
  when 'checkbox'
482
525
  CheckBox
483
526
  when 'radio'
484
527
  Radio
485
528
  when 'file'
486
529
  FileField
530
+ when *Button::VALID_TYPES
531
+ Button
487
532
  else
488
533
  TextField
489
534
  end
@@ -512,22 +557,67 @@ module Watir
512
557
  #
513
558
 
514
559
  def stale?
515
- raise Watir::Exception::Error, "Can not check staleness of unused element" unless @element
516
- @query_scope.ensure_context
517
- @stale || stale_in_context?
560
+ raise Watir::Exception::Error, 'Can not check staleness of unused element' unless @element
561
+
562
+ ensure_context
563
+ stale_in_context?
518
564
  end
519
565
 
520
566
  def stale_in_context?
521
567
  @element.enabled? # any wire call will check for staleness
522
568
  false
523
569
  rescue Selenium::WebDriver::Error::ObsoleteElementError
524
- @stale = true
570
+ true
525
571
  end
526
572
 
527
573
  def reset!
528
574
  @element = nil
529
575
  end
530
576
 
577
+ #
578
+ # @api private
579
+ #
580
+
581
+ def locate
582
+ ensure_context
583
+ locate_in_context
584
+ end
585
+
586
+ #
587
+ # @api private
588
+ #
589
+ # Returns true if element has been previously located.
590
+ #
591
+ # @return [Boolean]
592
+ #
593
+
594
+ def located?
595
+ !!@element
596
+ end
597
+
598
+ #
599
+ # @api private
600
+ #
601
+ # This is a performance shortcut for ensuring context
602
+ # Returns true if ensuring context requires relocating the element.
603
+ #
604
+ # @return [Boolean]
605
+ #
606
+
607
+ def relocate?
608
+ located? && stale?
609
+ end
610
+
611
+ #
612
+ # @api private
613
+ #
614
+
615
+ def selector_string
616
+ return @selector.inspect if @query_scope.is_a?(Browser)
617
+
618
+ "#{@query_scope.selector_string} --> #{@selector.inspect}"
619
+ end
620
+
531
621
  protected
532
622
 
533
623
  def wait_for_exists
@@ -551,7 +641,8 @@ module Watir
551
641
  @query_scope.wait_for_present unless @query_scope.is_a? Browser
552
642
  wait_until_present
553
643
  rescue Watir::Wait::TimeoutError
554
- msg = "element located, but timed out after #{Watir.default_timeout} seconds, waiting for #{inspect} to be present"
644
+ msg = "element located, but timed out after #{Watir.default_timeout} seconds, " \
645
+ "waiting for #{inspect} to be present"
555
646
  raise unknown_exception, msg
556
647
  end
557
648
  end
@@ -560,7 +651,7 @@ module Watir
560
651
  return assert_enabled unless Watir.relaxed_locate?
561
652
 
562
653
  wait_for_exists
563
- return if [Input, Button, Select, Option].none? { |c| self.is_a? c }
654
+ return if [Input, Button, Select, Option].none? { |c| is_a? c }
564
655
 
565
656
  begin
566
657
  wait_until(&:enabled?)
@@ -570,7 +661,6 @@ module Watir
570
661
  end
571
662
 
572
663
  def wait_for_writable
573
- wait_for_exists
574
664
  wait_for_enabled
575
665
  unless Watir.relaxed_locate?
576
666
  raise_writable unless !respond_to?(:readonly?) || !readonly?
@@ -579,31 +669,28 @@ module Watir
579
669
  begin
580
670
  wait_until { !respond_to?(:readonly?) || !readonly? }
581
671
  rescue Watir::Wait::TimeoutError
582
- message = "element present and enabled, but timed out after #{Watir.default_timeout} seconds, waiting for #{inspect} to not be readonly"
672
+ message = "element present and enabled, but timed out after #{Watir.default_timeout} seconds, " \
673
+ "waiting for #{inspect} to not be readonly"
583
674
  raise ObjectReadOnlyException, message
584
675
  end
585
676
  end
586
677
 
587
- # Ensure that the element exists, making sure that it is not stale and located if necessary
678
+ # Locates if not previously found; does not check for staleness for performance reasons
588
679
  def assert_exists
589
- locate unless @element
590
- return if @element
591
- raise unknown_exception, "unable to locate element: #{inspect}"
592
- end
680
+ locate unless located?
681
+ return if located?
593
682
 
594
- def locate
595
- @locator = build_locator
596
- @element = @locator.locate
683
+ raise unknown_exception, "unable to locate element: #{inspect}"
597
684
  end
598
685
 
599
- def selector_string
600
- return @selector.inspect if @query_scope.is_a?(Browser)
601
- "#{@query_scope.send :selector_string} --> #{@selector.inspect}"
686
+ def ensure_context
687
+ @query_scope.locate if @query_scope.relocate?
688
+ @query_scope.switch_to! if @query_scope.is_a?(IFrame)
602
689
  end
603
690
 
604
- # Ensure the driver is in the desired browser context
605
- def ensure_context
606
- locate unless exists?
691
+ def locate_in_context
692
+ @locator = build_locator
693
+ @element = @locator.locate
607
694
  end
608
695
 
609
696
  private
@@ -613,17 +700,21 @@ module Watir
613
700
  end
614
701
 
615
702
  def raise_writable
616
- message = "element present and enabled, but timed out after #{Watir.default_timeout} seconds, waiting for #{inspect} to not be readonly"
703
+ message = "element present and enabled, but timed out after #{Watir.default_timeout} seconds, " \
704
+ "waiting for #{inspect} to not be readonly"
617
705
  raise ObjectReadOnlyException, message
618
706
  end
619
707
 
620
708
  def raise_disabled
621
- message = "element present, but timed out after #{Watir.default_timeout} seconds, waiting for #{inspect} to be enabled"
709
+ message = "element present, but timed out after #{Watir.default_timeout} seconds, " \
710
+ "waiting for #{inspect} to be enabled"
622
711
  raise ObjectDisabledException, message
623
712
  end
624
713
 
625
714
  def raise_present
626
- raise unknown_exception, "element located, but timed out after #{Watir.default_timeout} seconds, waiting for #{inspect} to be present"
715
+ message = "element located, but timed out after #{Watir.default_timeout} seconds, " \
716
+ "waiting for #{inspect} to be present"
717
+ raise unknown_exception, message
627
718
  end
628
719
 
629
720
  def element_class
@@ -635,76 +726,88 @@ module Watir
635
726
  end
636
727
 
637
728
  def assert_enabled
638
- unless element_call { @element.enabled? }
639
- raise ObjectDisabledException, "object is disabled #{inspect}"
640
- end
729
+ raise ObjectDisabledException, "object is disabled #{inspect}" unless element_call { @element.enabled? }
641
730
  end
642
731
 
643
732
  def assert_is_element(obj)
644
- unless obj.kind_of? Watir::Element
645
- raise TypeError, "execpted Watir::Element, got #{obj.inspect}:#{obj.class}"
646
- end
733
+ raise TypeError, "execpted Watir::Element, got #{obj.inspect}:#{obj.class}" unless obj.is_a? Watir::Element
647
734
  end
648
735
 
736
+ # Removes duplication in #present? & #visible? and makes setting deprecation notice easier
737
+ def display_check
738
+ assert_exists
739
+ @element.displayed?
740
+ rescue Selenium::WebDriver::Error::StaleElementReferenceError
741
+ reset!
742
+ nil
743
+ end
744
+
745
+ # TODO: - this will get addressed with Watir::Executor implementation
746
+ # rubocop:disable Metrics/AbcSize
747
+ # rubocop:disable Metrics/MethodLength
748
+ # rubocop:disable Metrics/PerceivedComplexity
749
+ # rubocop:disable Metrics/CyclomaticComplexity:
649
750
  def element_call(precondition = nil, &block)
650
751
  caller = caller_locations(1, 1)[0].label
651
752
  already_locked = Wait.timer.locked?
652
- unless already_locked
653
- Wait.timer = Wait::Timer.new(timeout: Watir.default_timeout)
654
- end
753
+ Wait.timer = Wait::Timer.new(timeout: Watir.default_timeout) unless already_locked
655
754
 
656
755
  begin
657
- check_condition(precondition)
756
+ check_condition(precondition, caller)
658
757
  Watir.logger.info "-> `Executing #{inspect}##{caller}`"
659
758
  yield
660
759
  rescue unknown_exception => ex
661
- if precondition.nil?
662
- element_call(:wait_for_exists, &block)
663
- end
760
+ element_call(:wait_for_exists, &block) if precondition.nil?
664
761
  msg = ex.message
665
- msg += "; Maybe look in an iframe?" if @query_scope.ensure_context && @query_scope.iframes.count > 0
762
+ msg += '; Maybe look in an iframe?' if @query_scope.iframe.exists?
666
763
  custom_attributes = @locator.nil? ? [] : @locator.selector_builder.custom_attributes
667
- msg += "; Watir treated #{custom_attributes} as a non-HTML compliant attribute, ensure that was intended" unless custom_attributes.empty?
764
+ unless custom_attributes.empty?
765
+ msg += "; Watir treated #{custom_attributes} as a non-HTML compliant attribute, ensure that was intended"
766
+ end
668
767
  raise unknown_exception, msg
669
768
  rescue Selenium::WebDriver::Error::StaleElementReferenceError
670
- @query_scope.ensure_context
671
769
  reset!
672
770
  retry
673
771
  rescue Selenium::WebDriver::Error::ElementNotVisibleError, Selenium::WebDriver::Error::ElementNotInteractableError
674
- raise_present unless Wait.timer.remaining_time > 0
772
+ raise_present unless Wait.timer.remaining_time.positive?
675
773
  raise_present unless %i[wait_for_present wait_for_enabled wait_for_writable].include?(precondition)
676
774
  retry
677
775
  rescue Selenium::WebDriver::Error::InvalidElementStateError
678
- raise_disabled unless Wait.timer.remaining_time > 0
776
+ raise_disabled unless Wait.timer.remaining_time.positive?
679
777
  raise_disabled unless %i[wait_for_present wait_for_enabled wait_for_writable].include?(precondition)
680
778
  retry
681
779
  rescue Selenium::WebDriver::Error::NoSuchWindowError
682
- raise Exception::NoMatchingWindowFoundException, "browser window was closed"
780
+ raise Exception::NoMatchingWindowFoundException, 'browser window was closed'
683
781
  ensure
684
782
  Watir.logger.info "<- `Completed #{inspect}##{caller}`"
685
783
  Wait.timer.reset! unless already_locked
686
784
  end
687
785
  end
786
+ # rubocop:enable Metrics/AbcSize
787
+ # rubocop:enable Metrics/MethodLength
788
+ # rubocop:enable Metrics/PerceivedComplexity
789
+ # rubocop:enable Metrics/CyclomaticComplexity:
688
790
 
689
- def check_condition(condition)
690
- Watir.logger.info "<- `Verifying precondition #{inspect}##{condition}`"
791
+ def check_condition(condition, caller)
792
+ Watir.logger.info "<- `Verifying precondition #{inspect}##{condition} for #{caller}`"
691
793
  begin
692
794
  condition.nil? ? assert_exists : send(condition)
693
795
  Watir.logger.info "<- `Verified precondition #{inspect}##{condition || 'assert_exists'}`"
694
796
  rescue unknown_exception
695
797
  raise unless condition.nil?
798
+
696
799
  Watir.logger.info "<- `Unable to satisfy precondition #{inspect}##{condition}`"
697
- check_condition(:wait_for_exists)
800
+ check_condition(:wait_for_exists, caller)
698
801
  end
699
802
  end
700
803
 
701
804
  def method_missing(meth, *args, &blk)
702
805
  method = meth.to_s
703
806
  if method =~ Locators::Element::SelectorBuilder::WILDCARD_ATTRIBUTE
704
- attribute_value(method.tr('_', '-'), *args)
807
+ attribute_value(meth, *args)
705
808
  elsif UserEditable.instance_methods(false).include?(meth) && content_editable?
706
809
  @content_editable = true
707
- self.extend UserEditable
810
+ extend UserEditable
708
811
  send(meth, *args, &blk)
709
812
  else
710
813
  super
@@ -712,8 +815,7 @@ module Watir
712
815
  end
713
816
 
714
817
  def respond_to_missing?(meth, *)
715
- Locators::Element::SelectorBuilder::WILDCARD_ATTRIBUTE === meth.to_s || super
818
+ meth.to_s =~ Locators::Element::SelectorBuilder::WILDCARD_ATTRIBUTE || super
716
819
  end
717
-
718
820
  end # Element
719
821
  end # Watir