watir 6.7.3 → 6.8.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/CHANGES.md +11 -0
  4. data/lib/watir.rb +4 -1
  5. data/lib/watir/adjacent.rb +1 -1
  6. data/lib/watir/browser.rb +5 -3
  7. data/lib/watir/capabilities.rb +1 -0
  8. data/lib/watir/container.rb +1 -1
  9. data/lib/watir/elements/element.rb +31 -98
  10. data/lib/watir/elements/file_field.rb +1 -1
  11. data/lib/watir/elements/iframe.rb +1 -1
  12. data/lib/watir/elements/image.rb +1 -5
  13. data/lib/watir/elements/input.rb +15 -0
  14. data/lib/watir/elements/radio.rb +17 -0
  15. data/lib/watir/elements/select.rb +67 -20
  16. data/lib/watir/js_execution.rb +141 -0
  17. data/lib/watir/js_snippets.rb +16 -0
  18. data/lib/watir/js_snippets/backgroundColor.js +7 -0
  19. data/lib/watir/{atoms → js_snippets}/fireEvent.js +2 -0
  20. data/lib/watir/js_snippets/focus.js +3 -0
  21. data/lib/watir/{atoms → js_snippets}/getInnerHtml.js +1 -0
  22. data/lib/watir/js_snippets/getInnerText.js +19 -0
  23. data/lib/watir/{atoms → js_snippets}/getOuterHtml.js +2 -0
  24. data/lib/watir/js_snippets/getTextContent.js +19 -0
  25. data/lib/watir/js_snippets/isImageLoaded.js +3 -0
  26. data/lib/watir/js_snippets/selectOptionsLabel.js +10 -0
  27. data/lib/watir/js_snippets/selectOptionsText.js +10 -0
  28. data/lib/watir/js_snippets/selectOptionsValue.js +10 -0
  29. data/lib/watir/{atoms → js_snippets}/selectText.js +3 -0
  30. data/lib/watir/js_snippets/selectedOptions.js +11 -0
  31. data/lib/watir/js_snippets/setValue.js +3 -0
  32. data/lib/watir/locators/element/locator.rb +24 -10
  33. data/lib/watir/radio_set.rb +231 -0
  34. data/lib/watir/user_editable.rb +16 -2
  35. data/lib/watirspec/remote_server.rb +2 -1
  36. data/spec/browser_spec.rb +8 -2
  37. data/spec/spec_helper.rb +1 -0
  38. data/spec/watirspec/elements/div_spec.rb +22 -0
  39. data/spec/watirspec/elements/divs_spec.rb +1 -1
  40. data/spec/watirspec/elements/element_spec.rb +24 -7
  41. data/spec/watirspec/elements/labels_spec.rb +1 -1
  42. data/spec/watirspec/elements/radio_spec.rb +17 -3
  43. data/spec/watirspec/elements/radios_spec.rb +1 -1
  44. data/spec/watirspec/elements/select_list_spec.rb +167 -65
  45. data/spec/watirspec/elements/text_field_spec.rb +36 -0
  46. data/spec/watirspec/html/forms_with_input_elements.html +4 -2
  47. data/spec/watirspec/html/non_control_elements.html +1 -1
  48. data/spec/watirspec/radio_set_spec.rb +340 -0
  49. data/spec/watirspec_helper.rb +14 -1
  50. data/support/doctest_helper.rb +11 -8
  51. data/watir.gemspec +2 -2
  52. metadata +30 -11
  53. data/lib/watir/atoms.rb +0 -22
  54. data/lib/watir/atoms/README +0 -3
  55. data/lib/watir/extensions/select_text.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b930f2cf34bcc0aad97aa3ea3e8fc13b17e3ecc
4
- data.tar.gz: c499625ec63a5040ee9ad3d1fd37e2f4db5603c5
3
+ metadata.gz: a66dabc56ffe4185432094583faf989c4d63d178
4
+ data.tar.gz: bb71b8ee9d9d0ee4aa1ea1d8108cff79dd150615
5
5
  SHA512:
6
- metadata.gz: b1c18ce7ac92e2230145cd918590f659c0dd9d6b548962ba6345127bf7ab8a2784754145a0d39a6de9d9b67bcbcf869c27fbaad31a4444a3ab046f71d9f3e5e2
7
- data.tar.gz: c263afc6af431c74738b73b290b8613a99417d7243cee861ca3f41b09e7f58d6c08532c7cf0ebef492845b1d51dfc64333a736c322e2835a3cc9b282439dbd32
6
+ metadata.gz: 0e92e54f8c58808687de13dc63c7a8e2bbd2931e9bbc35492d0192a7d79f4385e16e1f1013b0105483dd0f88117c3b73dc0a59a3722717f7af5d7d252f46e6dc
7
+ data.tar.gz: 1d86e168b0b18eb97b3502311197ca045c902813f7596eeb13a6b0dcdb0696737f9fe557ed4285d2bf8df7a62f17ca56a69da25e643cc194e11419e4304a678c
data/.travis.yml CHANGED
@@ -9,6 +9,8 @@ notifications:
9
9
  secure: BLsBCm33R32VNRccrLx9F0P24X6BVpVHj1OWaN4Kyn6g9qXteIwC2VKVMnKNbifpojfMkrn0OeFQFK1O1DSOsC3mgzn/udoB+DnUGcSemFUn04xhbYF5SI+3zGPKPo0JLvjjdEKSSma84YwKdrj88pGUK34p01gL8hiaqjFzWdk=
10
10
  before_script:
11
11
  - support/travis.sh
12
+ - export PATH=~/.webdrivers:$PATH
13
+
12
14
  script: bundle exec rake $RAKE_TASK
13
15
 
14
16
  _version:
data/CHANGES.md CHANGED
@@ -1,3 +1,14 @@
1
+ ### 6.8.0 (2017-08-28)
2
+
3
+ * Add AfterHook executions to additional methods that can change DOM
4
+ * Deprecate `Select#select_value` in favor of `Select#select`
5
+ * Implement `Element` `#click!`, `#double_click!` & `#set!` with JavaScript
6
+ * Implement `Select#select!` and `Select#select_all!` with JavaScript
7
+ * Implement `Element#inner_text` and `Element#text_content`
8
+ * Implement `RadioSet`
9
+ * Implement `Input#label`
10
+ * Fix bug preventing Capabilities from handling :listener
11
+
1
12
  ### 6.7.3 (2017-08-20)
2
13
 
3
14
  * Fix bug preventing Capabilities from handling :driver_opts (#629)
data/lib/watir.rb CHANGED
@@ -7,8 +7,9 @@ require 'watir/xpath_support'
7
7
  require 'watir/window'
8
8
  require 'watir/has_window'
9
9
  require 'watir/adjacent'
10
+ require 'watir/js_execution'
10
11
  require 'watir/alert'
11
- require 'watir/atoms'
12
+ require 'watir/js_snippets'
12
13
  require 'watir/container'
13
14
  require 'watir/cookies'
14
15
  require 'watir/capabilities'
@@ -148,6 +149,8 @@ require 'watir/elements/table_row'
148
149
  require 'watir/elements/table_section'
149
150
  require 'watir/elements/text_area'
150
151
  require 'watir/elements/text_field'
152
+ require 'watir/elements/input'
153
+ require 'watir/radio_set'
151
154
 
152
155
  require 'watir/locators'
153
156
  require 'watir/aliases'
@@ -111,7 +111,7 @@ module Watir
111
111
  plural = opt.delete(:plural)
112
112
  opt[:index] ||= 0 unless plural || opt.values.any? { |e| e.is_a? Regexp }
113
113
  klass = if !plural && opt[:tag_name]
114
- self.send(opt[:tag_name]).class
114
+ Watir.tag_to_class[opt[:tag_name].to_sym]
115
115
  elsif !plural
116
116
  HTMLElement
117
117
  elsif opt[:tag_name]
data/lib/watir/browser.rb CHANGED
@@ -91,6 +91,7 @@ module Watir
91
91
 
92
92
  def back
93
93
  @driver.navigate.back
94
+ @after_hooks.run
94
95
  end
95
96
 
96
97
  #
@@ -99,6 +100,7 @@ module Watir
99
100
 
100
101
  def forward
101
102
  @driver.navigate.forward
103
+ @after_hooks.run
102
104
  end
103
105
 
104
106
  #
@@ -255,12 +257,12 @@ module Watir
255
257
  # #=> true
256
258
  #
257
259
  # @param [String] script JavaScript snippet to execute
258
- # @param *args Arguments will be available in the given script in the 'arguments' pseudo-array
260
+ # @param args Arguments will be available in the given script in the 'arguments' pseudo-array
259
261
  #
260
262
 
261
263
  def execute_script(script, *args)
262
264
  args.map! { |e| e.kind_of?(Watir::Element) ? e.wd : e }
263
- returned = @driver.execute_script(script, *args)
265
+ returned = @driver.execute_script(script, *args).tap { @after_hooks.run }
264
266
 
265
267
  wrap_elements_in(self, returned)
266
268
  end
@@ -272,7 +274,7 @@ module Watir
272
274
  # browser.goto "www.google.com"
273
275
  # browser.send_keys "Watir", :return
274
276
  #
275
- # @param [String, Symbol] *args
277
+ # @param [String, Symbol] args
276
278
  #
277
279
 
278
280
  def send_keys(*args)
@@ -32,6 +32,7 @@ module Watir
32
32
 
33
33
  @selenium_opts[:port] = @options.delete(:port) if @options.key?(:port)
34
34
  @selenium_opts[:driver_opts] = @options.delete(:driver_opts) if @options.key?(:driver_opts)
35
+ @selenium_opts[:listener] = @options.delete(:listener) if @options.key?(:listener)
35
36
 
36
37
  process_browser_options
37
38
  process_capabilities
@@ -1,7 +1,7 @@
1
1
  module Watir
2
2
  module Container
3
3
  include XpathSupport
4
- include Atoms
4
+ include JSSnippets
5
5
 
6
6
  #
7
7
  # Returns element.
@@ -12,6 +12,7 @@ module Watir
12
12
  include EventuallyPresent
13
13
  include Waitable
14
14
  include Adjacent
15
+ include JSExecution
15
16
 
16
17
  attr_accessor :keyword
17
18
  attr_reader :selector
@@ -116,7 +117,7 @@ module Watir
116
117
  # @example Click an element with several modifier keys pressed
117
118
  # browser.element(name: "new_user_button").click(:shift, :control)
118
119
  #
119
- # @param [:shift, :alt, :control, :command, :meta] Modifier key(s) to press while clicking.
120
+ # @param [:shift, :alt, :control, :command, :meta] modifiers to press while clicking.
120
121
  #
121
122
 
122
123
  def click(*modifiers)
@@ -136,6 +137,18 @@ module Watir
136
137
  browser.after_hooks.run
137
138
  end
138
139
 
140
+ #
141
+ # Simulates JavaScript click event on element.
142
+ #
143
+ # @example Click an element
144
+ # browser.element(name: "new_user_button").click!
145
+ #
146
+
147
+ def click!
148
+ fire_event :click
149
+ browser.after_hooks.run
150
+ end
151
+
139
152
  #
140
153
  # Double clicks the element.
141
154
  # Note that browser support may vary.
@@ -149,6 +162,19 @@ module Watir
149
162
  browser.after_hooks.run
150
163
  end
151
164
 
165
+ #
166
+ # Simulates JavaScript double click event on element.
167
+ #
168
+ # @example
169
+ # browser.element(name: "new_user_button").double_click!
170
+ #
171
+
172
+ def double_click!
173
+ fire_event :dblclick
174
+ browser.after_hooks.run
175
+ end
176
+
177
+
152
178
  #
153
179
  # Right clicks the element.
154
180
  # Note that browser support may vary.
@@ -187,11 +213,13 @@ module Watir
187
213
  def drag_and_drop_on(other)
188
214
  assert_is_element other
189
215
 
190
- element_call(:wait_for_present) do
216
+ value = element_call(:wait_for_present) do
191
217
  driver.action.
192
218
  drag_and_drop(@element, other.wd).
193
219
  perform
194
220
  end
221
+ browser.after_hooks.run
222
+ value
195
223
  end
196
224
 
197
225
  #
@@ -213,36 +241,6 @@ module Watir
213
241
  end
214
242
  end
215
243
 
216
- #
217
- # Flashes (change background color to a new color and back a few times) element.
218
- #
219
- # @example
220
- # browser.text_field(name: "new_user_first_name").flash
221
- # browser.text_field(name: "new_user_first_name").flash(color: "green", flashes: 3, delay: 0.05)
222
- # browser.text_field(name: "new_user_first_name").flash(color: "yellow")
223
- # browser.text_field(name: "new_user_first_name").flash(flashes: 4)
224
- # browser.text_field(name: "new_user_first_name").flash(delay: 0.1)
225
- #
226
- # @param [String] color what color to flash with
227
- # @param [Integer] flashes number of times element should be flashed
228
- # @param [Integer, Float] delay how long to wait between flashes
229
- #
230
-
231
- def flash(color: 'red', flashes: 10, delay: 0)
232
- background_color = style("backgroundColor")
233
- element_color = driver.execute_script("arguments[0].style.backgroundColor", @element)
234
-
235
- flashes.times do |n|
236
- nextcolor = n.even? ? color : background_color
237
- driver.execute_script("arguments[0].style.backgroundColor = '#{nextcolor}'", @element)
238
- sleep(delay)
239
- end
240
-
241
- driver.execute_script("arguments[0].style.backgroundColor = arguments[1]", @element, element_color)
242
-
243
- self
244
- end
245
-
246
244
  #
247
245
  # Returns value of the element.
248
246
  #
@@ -271,59 +269,19 @@ module Watir
271
269
  end
272
270
  alias_method :attribute, :attribute_value
273
271
 
274
- #
275
- # Returns outer (inner + element itself) HTML code of element.
276
- #
277
- # @example
278
- # browser.div(id: 'foo').outer_html
279
- # #=> "<div id=\"foo\"><a href=\"#\">hello</a></div>"
280
- #
281
- # @return [String]
282
- #
283
-
284
- def outer_html
285
- element_call { execute_atom(:getOuterHtml, @element) }.strip
286
- end
287
- alias_method :html, :outer_html
288
-
289
- #
290
- # Returns inner HTML code of element.
291
- #
292
- # @example
293
- # browser.div(id: 'foo').inner_html
294
- # #=> "<a href=\"#\">hello</a>"
295
- #
296
- # @return [String]
297
- #
298
-
299
- def inner_html
300
- element_call { execute_atom(:getInnerHtml, @element) }.strip
301
- end
302
-
303
272
  #
304
273
  # Sends sequence of keystrokes to element.
305
274
  #
306
275
  # @example
307
276
  # browser.text_field(name: "new_user_first_name").send_keys "Watir", :return
308
277
  #
309
- # @param [String, Symbol] *args
278
+ # @param [String, Symbol] args
310
279
  #
311
280
 
312
281
  def send_keys(*args)
313
282
  element_call(:wait_for_writable) { @element.send_keys(*args) }
314
283
  end
315
284
 
316
- #
317
- # Focuses element.
318
- # Note that Firefox queues focus events until the window actually has focus.
319
- #
320
- # @see http://code.google.com/p/selenium/issues/detail?id=157
321
- #
322
-
323
- def focus
324
- element_call { driver.execute_script "return arguments[0].focus()", @element }
325
- end
326
-
327
285
  #
328
286
  # Returns true if this element is focused.
329
287
  #
@@ -334,24 +292,6 @@ module Watir
334
292
  element_call { @element == driver.switch_to.active_element }
335
293
  end
336
294
 
337
- #
338
- # Simulates JavaScript events on element.
339
- # Note that you may omit "on" from event name.
340
- #
341
- # @example
342
- # browser.button(name: "new_user_button").fire_event :click
343
- # browser.button(name: "new_user_button").fire_event "mousemove"
344
- # browser.button(name: "new_user_button").fire_event "onmouseover"
345
- #
346
- # @param [String, Symbol] event_name
347
- #
348
-
349
- def fire_event(event_name)
350
- event_name = event_name.to_s.sub(/^on/, '').downcase
351
-
352
- element_call { execute_atom :fireEvent, @element, event_name }
353
- end
354
-
355
295
  #
356
296
  # Scroll until the element is in the view screen
357
297
  #
@@ -546,13 +486,6 @@ module Watir
546
486
  @query_scope.browser
547
487
  end
548
488
 
549
- #
550
- # Delegates script execution to Browser or IFrame.
551
- #
552
- def execute_script(script, *args)
553
- @query_scope.execute_script(script, *args)
554
- end
555
-
556
489
  #
557
490
  # Returns true if a previously located element is no longer attached to DOM.
558
491
  #
@@ -4,7 +4,7 @@ module Watir
4
4
  #
5
5
  # Set the file field to the given path
6
6
  #
7
- # @param [String] a path
7
+ # @param [String] path
8
8
  # @raise [Errno::ENOENT] if the file doesn't exist
9
9
  #
10
10
 
@@ -64,7 +64,7 @@ module Watir
64
64
  args.map! { |e| e.kind_of?(Watir::Element) ? e.wd : e }
65
65
  returned = driver.execute_script(script, *args)
66
66
 
67
- browser.send :wrap_elements_in, self, returned
67
+ browser.send(:wrap_elements_in, self, returned).tap { browser.after_hooks.run }
68
68
  end
69
69
 
70
70
  def ensure_context
@@ -9,11 +9,7 @@ module Watir
9
9
 
10
10
  def loaded?
11
11
  return false unless complete?
12
-
13
- driver.execute_script(
14
- 'return typeof arguments[0].naturalWidth != "undefined" && arguments[0].naturalWidth > 0',
15
- @element
16
- )
12
+ element_call { execute_js(:isImageLoaded, @element) }
17
13
  end
18
14
 
19
15
  end # Image
@@ -0,0 +1,15 @@
1
+ module Watir
2
+ class Input < HTMLElement
3
+
4
+ #
5
+ # Returns label element associated with Input element.
6
+ #
7
+ # @return [Watir::Label]
8
+ #
9
+
10
+ def label
11
+ parent(tag_name: 'form').label(for: id)
12
+ end
13
+
14
+ end # Input
15
+ end # Watir
@@ -1,6 +1,11 @@
1
1
  module Watir
2
2
  class Radio < Input
3
3
 
4
+ def initialize(query_scope, selector)
5
+ super
6
+ @selector[:label] = @selector.delete(:text) if @selector.key?(:text)
7
+ end
8
+
4
9
  #
5
10
  # Selects this radio button.
6
11
  #
@@ -21,6 +26,18 @@ module Watir
21
26
  end
22
27
  alias_method :selected?, :set?
23
28
 
29
+ #
30
+ # Returns the text of the associated label.
31
+ # Returns empty string if no label is found.
32
+ #
33
+ # @return [String]
34
+ #
35
+
36
+ def text
37
+ l = label()
38
+ l.exist? ? l.text : ''
39
+ end
40
+
24
41
  end # Radio
25
42
 
26
43
  module Container
@@ -42,7 +42,7 @@ module Watir
42
42
  #
43
43
 
44
44
  def select(str_or_rx)
45
- select_by :text, str_or_rx
45
+ select_by str_or_rx
46
46
  end
47
47
 
48
48
  #
@@ -54,7 +54,29 @@ module Watir
54
54
  #
55
55
 
56
56
  def select_all(str_or_rx)
57
- select_all_by :text, str_or_rx
57
+ select_all_by str_or_rx
58
+ end
59
+
60
+ #
61
+ # Uses JavaScript to select the option whose text matches the given string.
62
+ #
63
+ # @param [String, Regexp] str_or_rx
64
+ # @raise [Watir::Exception::NoValueFoundException] if the value does not exist.
65
+ #
66
+
67
+ def select!(str_or_rx)
68
+ select_by!(str_or_rx, :single)
69
+ end
70
+
71
+ #
72
+ # Uses JavaScript to select all options whose text matches the given string.
73
+ #
74
+ # @param [String, Regexp] str_or_rx
75
+ # @raise [Watir::Exception::NoValueFoundException] if the value does not exist.
76
+ #
77
+
78
+ def select_all!(str_or_rx)
79
+ select_by!(str_or_rx, :multiple)
58
80
  end
59
81
 
60
82
  #
@@ -68,7 +90,8 @@ module Watir
68
90
  #
69
91
 
70
92
  def select_value(str_or_rx)
71
- select_by :value, str_or_rx
93
+ Watir.logger.deprecate '#select_value', "#select"
94
+ select_by str_or_rx
72
95
  end
73
96
 
74
97
  #
@@ -121,24 +144,13 @@ module Watir
121
144
  #
122
145
 
123
146
  def selected_options
124
- element_call do
125
- script = <<-SCRIPT
126
- var result = [];
127
- var options = arguments[0].options;
128
- for (var i = 0; i < options.length; i++) {
129
- var option = options[i];
130
- if (option.selected) { result.push(option) }
131
- }
132
- return result;
133
- SCRIPT
134
- @query_scope.execute_script(script, self)
135
- end
147
+ element_call { execute_js :selectedOptions, self }
136
148
  end
137
149
 
138
150
  private
139
151
 
140
- def select_by(how, str_or_rx)
141
- found = find_options(how, str_or_rx)
152
+ def select_by(str_or_rx)
153
+ found = find_options(:value, str_or_rx)
142
154
 
143
155
  if found && found.size > 1
144
156
  Watir.logger.deprecate "Selecting Multiple Options with #select", "#select_all"
@@ -147,9 +159,43 @@ module Watir
147
159
  raise NoValueFoundException, "#{str_or_rx.inspect} not found in select list"
148
160
  end
149
161
 
150
- def select_all_by(how, str_or_rx)
162
+ def select_by!(str_or_rx, number)
163
+ js_rx = case str_or_rx
164
+ when String
165
+ str_or_rx
166
+ when Regexp
167
+ str_or_rx.inspect.sub('\\A', '^').sub('\\Z', '$').sub('\\z', '$').sub(/^\//, '').sub(/\/[a-z]*$/, '')
168
+ .gsub(/\(\?#.+\)/, '').gsub(/\(\?-\w+:/, '(')
169
+ else
170
+ raise TypeError, "expected String or Regexp, got #{str_or_rx.inspect}:#{str_or_rx.class}"
171
+ end
172
+
173
+ element_call { execute_js(:selectOptionsText, self, js_rx, number.to_s) }
174
+ return selected_options.first.text if matching_option?(:text, str_or_rx)
175
+
176
+ element_call { execute_js(:selectOptionsLabel, self, js_rx, number.to_s) }
177
+ return selected_options.first.text if matching_option?(:label, str_or_rx)
178
+
179
+ element_call { execute_js(:selectOptionsValue, self, js_rx, number.to_s) }
180
+ return selected_options.first.text if matching_option?(:value, str_or_rx)
181
+
182
+ raise NoValueFoundException, "#{str_or_rx.inspect} not found in select list"
183
+ end
184
+
185
+ def matching_option?(how, what)
186
+ selected_options.each do |opt|
187
+ value = opt.send(how)
188
+ if what.is_a?(String) ? value == what : value =~ what
189
+ return true if opt.enabled?
190
+ raise Watir::Exception::ObjectDisabledException, "option matching #{what} by #{how} on #{inspect} is disabled"
191
+ end
192
+ end
193
+ false
194
+ end
195
+
196
+ def select_all_by(str_or_rx)
151
197
  raise Error, "you can only use #select_all on multi-selects" unless multiple?
152
- found = find_options(how, str_or_rx)
198
+ found = find_options :text, str_or_rx
153
199
 
154
200
  return select_matching(found) if found
155
201
  raise NoValueFoundException, "#{str_or_rx.inspect} not found in select list"
@@ -159,7 +205,8 @@ module Watir
159
205
  browser.wait_while do
160
206
  case str_or_rx
161
207
  when String, Numeric, Regexp
162
- @found = options(how => str_or_rx)
208
+ @found = how == :value ? options(value: str_or_rx) : []
209
+ @found = options(text: str_or_rx) if @found.empty?
163
210
  @found = options(label: str_or_rx) if @found.empty?
164
211
  @found.empty? && Watir.relaxed_locate?
165
212
  else