selenium-webdriver 3.4.0 → 3.4.1

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 (44) hide show
  1. data/CHANGES +35 -1
  2. data/Gemfile.lock +54 -0
  3. data/lib/selenium/webdriver.rb +8 -10
  4. data/lib/selenium/webdriver/chrome.rb +2 -1
  5. data/lib/selenium/webdriver/chrome/{bridge.rb → driver.rb} +47 -32
  6. data/lib/selenium/webdriver/chrome/options.rb +170 -0
  7. data/lib/selenium/webdriver/common/driver.rb +20 -39
  8. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +5 -0
  9. data/lib/selenium/webdriver/common/element.rb +5 -1
  10. data/lib/selenium/webdriver/common/logger.rb +10 -0
  11. data/lib/selenium/webdriver/common/w3c_error.rb +2 -2
  12. data/lib/selenium/webdriver/edge.rb +2 -1
  13. data/lib/selenium/webdriver/edge/bridge.rb +2 -91
  14. data/lib/selenium/webdriver/edge/driver.rb +80 -0
  15. data/lib/selenium/webdriver/firefox.rb +6 -3
  16. data/lib/selenium/webdriver/firefox/driver.rb +50 -0
  17. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  18. data/lib/selenium/webdriver/firefox/legacy/driver.rb +81 -0
  19. data/lib/selenium/webdriver/firefox/marionette/driver.rb +101 -0
  20. data/lib/selenium/webdriver/firefox/options.rb +139 -0
  21. data/lib/selenium/webdriver/ie.rb +1 -1
  22. data/lib/selenium/webdriver/ie/{bridge.rb → driver.rb} +13 -13
  23. data/lib/selenium/webdriver/phantomjs.rb +1 -1
  24. data/lib/selenium/webdriver/phantomjs/{bridge.rb → driver.rb} +10 -13
  25. data/lib/selenium/webdriver/remote.rb +11 -13
  26. data/lib/selenium/webdriver/remote/bridge.rb +87 -586
  27. data/lib/selenium/webdriver/remote/capabilities.rb +3 -1
  28. data/lib/selenium/webdriver/remote/driver.rb +44 -0
  29. data/lib/selenium/webdriver/remote/http/default.rb +1 -1
  30. data/lib/selenium/webdriver/remote/oss/bridge.rb +586 -0
  31. data/lib/selenium/webdriver/remote/{commands.rb → oss/commands.rb} +9 -5
  32. data/lib/selenium/webdriver/remote/oss/driver.rb +44 -0
  33. data/lib/selenium/webdriver/remote/w3c/bridge.rb +573 -0
  34. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +266 -0
  35. data/lib/selenium/webdriver/remote/{w3c_commands.rb → w3c/commands.rb} +9 -4
  36. data/lib/selenium/webdriver/remote/w3c/driver.rb +41 -0
  37. data/lib/selenium/webdriver/safari.rb +3 -6
  38. data/lib/selenium/webdriver/safari/{bridge.rb → driver.rb} +14 -6
  39. data/selenium-webdriver.gemspec +1 -3
  40. metadata +29 -45
  41. data/lib/selenium/webdriver/firefox/bridge.rb +0 -70
  42. data/lib/selenium/webdriver/firefox/w3c_bridge.rb +0 -114
  43. data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -663
  44. data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -231
@@ -20,14 +20,16 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Remote
23
- class Bridge
23
+ module OSS
24
+
24
25
  #
25
26
  # https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#command-reference
27
+ # @api private
26
28
  #
27
29
 
28
- COMMANDS = {
30
+ class Bridge
29
31
 
30
- new_session: [:post, 'session'.freeze],
32
+ COMMANDS = {
31
33
  get_capabilities: [:get, 'session/:session_id'.freeze],
32
34
  status: [:get, 'status'.freeze],
33
35
 
@@ -212,8 +214,10 @@ module Selenium
212
214
 
213
215
  get_available_log_types: [:get, 'session/:session_id/log/types'.freeze],
214
216
  get_log: [:post, 'session/:session_id/log'.freeze]
215
- }.freeze
216
- end
217
+ }.freeze
218
+
219
+ end # Bridge
220
+ end # OSS
217
221
  end # Remote
218
222
  end # WebDriver
219
223
  end # Selenium
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Licensed to the Software Freedom Conservancy (SFC) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The SFC licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+
20
+ module Selenium
21
+ module WebDriver
22
+ module Remote
23
+ module OSS
24
+
25
+ #
26
+ # Driver implementation for remote server talking OSS dialect.
27
+ # @api private
28
+ #
29
+
30
+ class Driver < WebDriver::Driver
31
+ include DriverExtensions::UploadsFiles
32
+ include DriverExtensions::TakesScreenshot
33
+ include DriverExtensions::HasSessionId
34
+ include DriverExtensions::Rotatable
35
+ include DriverExtensions::HasTouchScreen
36
+ include DriverExtensions::HasLocation
37
+ include DriverExtensions::HasNetworkConnection
38
+ include DriverExtensions::HasRemoteStatus
39
+ include DriverExtensions::HasWebStorage
40
+ end # Driver
41
+ end # OSS
42
+ end # Remote
43
+ end # WebDriver
44
+ end # Selenium
@@ -0,0 +1,573 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Licensed to the Software Freedom Conservancy (SFC) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The SFC licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+
20
+ require 'json'
21
+
22
+ module Selenium
23
+ module WebDriver
24
+ module Remote
25
+ module W3C
26
+
27
+ #
28
+ # Low level bridge to the remote server implementing JSON wire
29
+ # protocol (W3C dialect), through which the rest of the API works.
30
+ # @api private
31
+ #
32
+
33
+ class Bridge < Remote::Bridge
34
+
35
+ def initialize(capabilities, session_id, **opts)
36
+ @capabilities = capabilities
37
+ @session_id = session_id
38
+ super(opts)
39
+ end
40
+
41
+ def dialect
42
+ :w3c
43
+ end
44
+
45
+ def commands(command)
46
+ case command
47
+ when :status, :is_element_displayed
48
+ Remote::OSS::Bridge::COMMANDS[command]
49
+ else
50
+ COMMANDS[command]
51
+ end
52
+ end
53
+
54
+ def status
55
+ execute :status
56
+ end
57
+
58
+ def get(url)
59
+ execute :get, {}, {url: url}
60
+ end
61
+
62
+ def implicit_wait_timeout=(milliseconds)
63
+ timeout('implicit', milliseconds)
64
+ end
65
+
66
+ def script_timeout=(milliseconds)
67
+ timeout('script', milliseconds)
68
+ end
69
+
70
+ def timeout(type, milliseconds)
71
+ type = 'pageLoad' if type == 'page load'
72
+ execute :set_timeout, {}, {type => milliseconds}
73
+ end
74
+
75
+ #
76
+ # alerts
77
+ #
78
+
79
+ def accept_alert
80
+ execute :accept_alert
81
+ end
82
+
83
+ def dismiss_alert
84
+ execute :dismiss_alert
85
+ end
86
+
87
+ def alert=(keys)
88
+ execute :send_alert_text, {}, {value: keys.split(//), text: keys}
89
+ end
90
+
91
+ def alert_text
92
+ execute :get_alert_text
93
+ end
94
+
95
+ #
96
+ # navigation
97
+ #
98
+
99
+ def go_back
100
+ execute :back
101
+ end
102
+
103
+ def go_forward
104
+ execute :forward
105
+ end
106
+
107
+ def url
108
+ execute :get_current_url
109
+ end
110
+
111
+ def title
112
+ execute :get_title
113
+ end
114
+
115
+ def page_source
116
+ execute_script('var source = document.documentElement.outerHTML;' \
117
+ 'if (!source) { source = new XMLSerializer().serializeToString(document); }' \
118
+ 'return source;')
119
+ end
120
+
121
+ def switch_to_window(name)
122
+ execute :switch_to_window, {}, {handle: name}
123
+ end
124
+
125
+ def switch_to_frame(id)
126
+ id = find_element_by('id', id) if id.is_a? String
127
+ execute :switch_to_frame, {}, {id: id}
128
+ end
129
+
130
+ def switch_to_parent_frame
131
+ execute :switch_to_parent_frame
132
+ end
133
+
134
+ def switch_to_default_content
135
+ switch_to_frame nil
136
+ end
137
+
138
+ QUIT_ERRORS = [IOError].freeze
139
+
140
+ def quit
141
+ execute :delete_session
142
+ http.close
143
+ rescue *QUIT_ERRORS
144
+ end
145
+
146
+ def close
147
+ execute :close_window
148
+ end
149
+
150
+ def refresh
151
+ execute :refresh
152
+ end
153
+
154
+ #
155
+ # window handling
156
+ #
157
+
158
+ def window_handles
159
+ execute :get_window_handles
160
+ end
161
+
162
+ def window_handle
163
+ execute :get_window_handle
164
+ end
165
+
166
+ def resize_window(width, height, handle = :current)
167
+ unless handle == :current
168
+ raise Error::WebDriverError, 'Switch to desired window before changing its size'
169
+ end
170
+ execute :set_window_rect, {}, {width: width, height: height}
171
+ end
172
+
173
+ def window_size(handle = :current)
174
+ unless handle == :current
175
+ raise Error::UnsupportedOperationError, 'Switch to desired window before getting its size'
176
+ end
177
+ data = execute :get_window_rect
178
+
179
+ Dimension.new data['width'], data['height']
180
+ end
181
+
182
+ def minimize_window
183
+ execute :minimize_window
184
+ end
185
+
186
+ def maximize_window(handle = :current)
187
+ unless handle == :current
188
+ raise Error::UnsupportedOperationError, 'Switch to desired window before changing its size'
189
+ end
190
+ execute :maximize_window
191
+ end
192
+
193
+ def full_screen_window
194
+ execute :fullscreen_window
195
+ end
196
+
197
+ def reposition_window(x, y)
198
+ execute :set_window_rect, {}, {x: x, y: y}
199
+ end
200
+
201
+ def window_position
202
+ data = execute :get_window_rect
203
+ Point.new data['x'], data['y']
204
+ end
205
+
206
+ def set_window_rect(x: nil, y: nil, width: nil, height: nil)
207
+ execute :set_window_rect, {}, {x: x, y: y, width: width, height: height}
208
+ end
209
+
210
+ def window_rect
211
+ data = execute :get_window_rect
212
+ Rectangle.new data['x'], data['y'], data['width'], data['height']
213
+ end
214
+
215
+ def screenshot
216
+ execute :take_screenshot
217
+ end
218
+
219
+ #
220
+ # HTML 5
221
+ #
222
+
223
+ def local_storage_item(key, value = nil)
224
+ if value
225
+ execute_script("localStorage.setItem('#{key}', '#{value}')")
226
+ else
227
+ execute_script("return localStorage.getItem('#{key}')")
228
+ end
229
+ end
230
+
231
+ def remove_local_storage_item(key)
232
+ execute_script("localStorage.removeItem('#{key}')")
233
+ end
234
+
235
+ def local_storage_keys
236
+ execute_script('return Object.keys(localStorage)')
237
+ end
238
+
239
+ def clear_local_storage
240
+ execute_script('localStorage.clear()')
241
+ end
242
+
243
+ def local_storage_size
244
+ execute_script('return localStorage.length')
245
+ end
246
+
247
+ def session_storage_item(key, value = nil)
248
+ if value
249
+ execute_script("sessionStorage.setItem('#{key}', '#{value}')")
250
+ else
251
+ execute_script("return sessionStorage.getItem('#{key}')")
252
+ end
253
+ end
254
+
255
+ def remove_session_storage_item(key)
256
+ execute_script("sessionStorage.removeItem('#{key}')")
257
+ end
258
+
259
+ def session_storage_keys
260
+ execute_script('return Object.keys(sessionStorage)')
261
+ end
262
+
263
+ def clear_session_storage
264
+ execute_script('sessionStorage.clear()')
265
+ end
266
+
267
+ def session_storage_size
268
+ execute_script('return sessionStorage.length')
269
+ end
270
+
271
+ def location
272
+ raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting location'
273
+ end
274
+
275
+ def set_location(_lat, _lon, _alt)
276
+ raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting location'
277
+ end
278
+
279
+ def network_connection
280
+ raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting network connection'
281
+ end
282
+
283
+ def network_connection=(_type)
284
+ raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting network connection'
285
+ end
286
+
287
+ #
288
+ # javascript execution
289
+ #
290
+
291
+ def execute_script(script, *args)
292
+ result = execute :execute_script, {}, {script: script, args: args}
293
+ unwrap_script_result result
294
+ end
295
+
296
+ def execute_async_script(script, *args)
297
+ result = execute :execute_async_script, {}, {script: script, args: args}
298
+ unwrap_script_result result
299
+ end
300
+
301
+ #
302
+ # cookies
303
+ #
304
+
305
+ def options
306
+ @options ||= WebDriver::W3COptions.new(self)
307
+ end
308
+
309
+ def add_cookie(cookie)
310
+ execute :add_cookie, {}, {cookie: cookie}
311
+ end
312
+
313
+ def delete_cookie(name)
314
+ execute :delete_cookie, name: name
315
+ end
316
+
317
+ def cookie(name)
318
+ execute :get_cookie, name: name
319
+ end
320
+
321
+ def cookies
322
+ execute :get_all_cookies
323
+ end
324
+
325
+ def delete_all_cookies
326
+ execute :delete_all_cookies
327
+ end
328
+
329
+ #
330
+ # actions
331
+ #
332
+
333
+ def action(async = false)
334
+ W3CActionBuilder.new self,
335
+ Interactions.pointer(:mouse, name: 'mouse'),
336
+ Interactions.key('keyboard'),
337
+ async
338
+ end
339
+ alias_method :actions, :action
340
+
341
+ def mouse
342
+ raise Error::UnsupportedOperationError, '#mouse is no longer supported, use #action instead'
343
+ end
344
+
345
+ def keyboard
346
+ raise Error::UnsupportedOperationError, '#keyboard is no longer supported, use #action instead'
347
+ end
348
+
349
+ def send_actions(data)
350
+ execute :actions, {}, {actions: data}
351
+ end
352
+
353
+ def release_actions
354
+ execute :release_actions
355
+ end
356
+
357
+ def click_element(element)
358
+ execute :element_click, id: element
359
+ end
360
+
361
+ # TODO: - Implement file verification
362
+ def send_keys_to_element(element, keys)
363
+ # Keep .split(//) for backward compatibility for now
364
+ text = keys.join('')
365
+ execute :element_send_keys, {id: element}, {value: text.split(//), text: text}
366
+ end
367
+
368
+ def clear_element(element)
369
+ execute :element_clear, id: element
370
+ end
371
+
372
+ def submit_element(element)
373
+ form = find_element_by('xpath', "./ancestor-or-self::form", element)
374
+ execute_script("var e = arguments[0].ownerDocument.createEvent('Event');" \
375
+ "e.initEvent('submit', true, true);" \
376
+ 'if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }', form.as_json)
377
+ end
378
+
379
+ def drag_element(element, right_by, down_by)
380
+ execute :drag_element, {id: element}, {x: right_by, y: down_by}
381
+ end
382
+
383
+ def touch_single_tap(element)
384
+ execute :touch_single_tap, {}, {element: element}
385
+ end
386
+
387
+ def touch_double_tap(element)
388
+ execute :touch_double_tap, {}, {element: element}
389
+ end
390
+
391
+ def touch_long_press(element)
392
+ execute :touch_long_press, {}, {element: element}
393
+ end
394
+
395
+ def touch_down(x, y)
396
+ execute :touch_down, {}, {x: x, y: y}
397
+ end
398
+
399
+ def touch_up(x, y)
400
+ execute :touch_up, {}, {x: x, y: y}
401
+ end
402
+
403
+ def touch_move(x, y)
404
+ execute :touch_move, {}, {x: x, y: y}
405
+ end
406
+
407
+ def touch_scroll(element, x, y)
408
+ if element
409
+ execute :touch_scroll, {}, {element: element,
410
+ xoffset: x,
411
+ yoffset: y}
412
+ else
413
+ execute :touch_scroll, {}, {xoffset: x, yoffset: y}
414
+ end
415
+ end
416
+
417
+ def touch_flick(xspeed, yspeed)
418
+ execute :touch_flick, {}, {xspeed: xspeed, yspeed: yspeed}
419
+ end
420
+
421
+ def touch_element_flick(element, right_by, down_by, speed)
422
+ execute :touch_flick, {}, {element: element,
423
+ xoffset: right_by,
424
+ yoffset: down_by,
425
+ speed: speed}
426
+ end
427
+
428
+ def screen_orientation=(orientation)
429
+ execute :set_screen_orientation, {}, {orientation: orientation}
430
+ end
431
+
432
+ def screen_orientation
433
+ execute :get_screen_orientation
434
+ end
435
+
436
+ #
437
+ # element properties
438
+ #
439
+
440
+ def element_tag_name(element)
441
+ execute :get_element_tag_name, id: element
442
+ end
443
+
444
+ def element_attribute(element, name)
445
+ execute_atom :getAttribute, element, name
446
+ end
447
+
448
+ def element_property(element, name)
449
+ execute :get_element_property, id: element.ref, name: name
450
+ end
451
+
452
+ def element_value(element)
453
+ element_property element, 'value'
454
+ end
455
+
456
+ def element_text(element)
457
+ execute :get_element_text, id: element
458
+ end
459
+
460
+ def element_location(element)
461
+ data = execute :get_element_rect, id: element
462
+
463
+ Point.new data['x'], data['y']
464
+ end
465
+
466
+ def element_rect(element)
467
+ data = execute :get_element_rect, id: element
468
+
469
+ Rectangle.new data['x'], data['y'], data['width'], data['height']
470
+ end
471
+
472
+ def element_location_once_scrolled_into_view(element)
473
+ send_keys_to_element(element, [''])
474
+ element_location(element)
475
+ end
476
+
477
+ def element_size(element)
478
+ data = execute :get_element_rect, id: element
479
+
480
+ Dimension.new data['width'], data['height']
481
+ end
482
+
483
+ def element_enabled?(element)
484
+ execute :is_element_enabled, id: element
485
+ end
486
+
487
+ def element_selected?(element)
488
+ execute :is_element_selected, id: element
489
+ end
490
+
491
+ def element_displayed?(element)
492
+ execute :is_element_displayed, id: element
493
+ end
494
+
495
+ def element_value_of_css_property(element, prop)
496
+ execute :get_element_css_value, id: element, property_name: prop
497
+ end
498
+
499
+ #
500
+ # finding elements
501
+ #
502
+
503
+ def active_element
504
+ Element.new self, element_id_from(execute(:get_active_element))
505
+ end
506
+
507
+ alias_method :switch_to_active_element, :active_element
508
+
509
+ def find_element_by(how, what, parent = nil)
510
+ how, what = convert_locators(how, what)
511
+
512
+ id = if parent
513
+ execute :find_child_element, {id: parent}, {using: how, value: what}
514
+ else
515
+ execute :find_element, {}, {using: how, value: what}
516
+ end
517
+ Element.new self, element_id_from(id)
518
+ end
519
+
520
+ def find_elements_by(how, what, parent = nil)
521
+ how, what = convert_locators(how, what)
522
+
523
+ ids = if parent
524
+ execute :find_child_elements, {id: parent}, {using: how, value: what}
525
+ else
526
+ execute :find_elements, {}, {using: how, value: what}
527
+ end
528
+
529
+ ids.map { |id| Element.new self, element_id_from(id) }
530
+ end
531
+
532
+ private
533
+
534
+ def execute(*)
535
+ super['value']
536
+ end
537
+
538
+ def convert_locators(how, what)
539
+ case how
540
+ when 'class name'
541
+ how = 'css selector'
542
+ what = ".#{escape_css(what)}"
543
+ when 'id'
544
+ how = 'css selector'
545
+ what = "##{escape_css(what)}"
546
+ when 'name'
547
+ how = 'css selector'
548
+ what = "*[name='#{escape_css(what)}']"
549
+ when 'tag name'
550
+ how = 'css selector'
551
+ end
552
+ [how, what]
553
+ end
554
+
555
+ ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]\(\)])/
556
+ UNICODE_CODE_POINT = 30
557
+
558
+ # Escapes invalid characters in CSS selector.
559
+ # @see https://mathiasbynens.be/notes/css-escapes
560
+ def escape_css(string)
561
+ string = string.gsub(ESCAPE_CSS_REGEXP) { |match| "\\#{match}" }
562
+ if !string.empty? && string[0] =~ /[[:digit:]]/
563
+ string = "\\#{UNICODE_CODE_POINT + Integer(string[0])} #{string[1..-1]}"
564
+ end
565
+
566
+ string
567
+ end
568
+
569
+ end # Bridge
570
+ end # W3C
571
+ end # Remote
572
+ end # WebDriver
573
+ end # Selenium