watir 6.7.3 → 6.8.0

Sign up to get free protection for your applications and to get access to all the features.
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