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
@@ -1,70 +0,0 @@
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 Firefox
23
- # @api private
24
- class Bridge < Remote::Bridge
25
- def initialize(opts = {})
26
- opts[:desired_capabilities] ||= Remote::Capabilities.firefox
27
-
28
- if opts.key? :proxy
29
- WebDriver.logger.warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
30
- [DEPRECATION] `:proxy` is deprecated. Pass in as capability: `Remote::Capabilities.firefox(proxy: #{opts[:proxy]})`
31
- DEPRECATE
32
- opts[:desired_capabilities].proxy = opts.delete(:proxy)
33
- end
34
-
35
- unless opts.key?(:url)
36
- port = opts.delete(:port) || DEFAULT_PORT
37
- profile = opts.delete(:profile)
38
-
39
- Binary.path = opts[:desired_capabilities][:firefox_binary] if opts[:desired_capabilities][:firefox_binary]
40
- @launcher = Launcher.new Binary.new, port, profile
41
- @launcher.launch
42
- opts[:url] = @launcher.url
43
- end
44
-
45
- begin
46
- super(opts)
47
- rescue
48
- @launcher.quit if @launcher
49
- raise
50
- end
51
- end
52
-
53
- def browser
54
- :firefox
55
- end
56
-
57
- def driver_extensions
58
- [DriverExtensions::TakesScreenshot]
59
- end
60
-
61
- def quit
62
- super
63
- nil
64
- ensure
65
- @launcher.quit
66
- end
67
- end # Bridge
68
- end # Firefox
69
- end # WebDriver
70
- end # Selenium
@@ -1,114 +0,0 @@
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 Firefox
23
- # @api private
24
- class W3CBridge < Remote::W3CBridge
25
- def initialize(opts = {})
26
- opts[:desired_capabilities] = create_capabilities(opts)
27
-
28
- unless opts.key?(:url)
29
- driver_path = opts.delete(:driver_path) || Firefox.driver_path
30
- port = opts.delete(:port) || Service::DEFAULT_PORT
31
-
32
- opts[:driver_opts] ||= {}
33
- if opts.key? :service_args
34
- WebDriver.logger.warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
35
- [DEPRECATION] `:service_args` is deprecated. Pass switches using `driver_opts`
36
- DEPRECATE
37
- opts[:driver_opts][:args] = opts.delete(:service_args)
38
- end
39
-
40
- @service = Service.new(driver_path, port, opts.delete(:driver_opts))
41
- @service.start
42
- opts[:url] = @service.uri
43
- end
44
-
45
- super(opts)
46
- end
47
-
48
- def browser
49
- :firefox
50
- end
51
-
52
- def driver_extensions
53
- [DriverExtensions::TakesScreenshot,
54
- DriverExtensions::HasWebStorage]
55
- end
56
-
57
- def quit
58
- super
59
- ensure
60
- @service.stop if @service
61
- end
62
-
63
- # Support for geckodriver < 0.15
64
- def resize_window(width, height, handle = :current)
65
- super
66
- rescue Error::UnknownCommandError
67
- execute :set_window_size, {}, {width: width, height: height}
68
- end
69
-
70
- def window_size(handle = :current)
71
- data = super
72
- rescue Error::UnknownCommandError
73
- data = execute :get_window_size
74
- ensure
75
- return Dimension.new data['width'], data['height']
76
- end
77
-
78
- def reposition_window(x, y)
79
- super
80
- rescue Error::UnknownCommandError
81
- execute :set_window_position, {}, {x: x, y: y}
82
- end
83
-
84
- def window_position
85
- data = super
86
- rescue Error::UnknownCommandError
87
- data = execute :get_window_position
88
- ensure
89
- return Point.new data['x'], data['y']
90
- end
91
-
92
- private
93
-
94
- def create_capabilities(opts)
95
- caps = Remote::W3CCapabilities.firefox
96
- caps.merge!(opts.delete(:desired_capabilities)) if opts.key? :desired_capabilities
97
- firefox_options = caps[:firefox_options] || {}
98
- firefox_options = firefox_options_caps.merge(opts[:firefox_options]) if opts.key?(:firefox_options)
99
- if opts.key?(:profile)
100
- profile = opts.delete(:profile)
101
- unless profile.is_a?(Profile)
102
- profile = Profile.from_name(profile)
103
- end
104
- firefox_options[:profile] = profile.encoded
105
- end
106
-
107
- Binary.path = firefox_options[:binary] if firefox_options.key?(:binary)
108
- caps[:firefox_options] = firefox_options unless firefox_options.empty?
109
- caps
110
- end
111
- end # W3CBridge
112
- end # Firefox
113
- end # WebDriver
114
- end # Selenium
@@ -1,663 +0,0 @@
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
- #
26
- # Low level bridge to the remote server, through which the rest of the API works.
27
- #
28
- # @api private
29
- #
30
-
31
- class W3CBridge
32
- include BridgeHelper
33
- include Atoms
34
-
35
- attr_accessor :context, :http, :file_detector
36
- attr_reader :capabilities
37
-
38
- #
39
- # Initializes the bridge with the given server URL
40
- # @param [Hash] opts options for the driver
41
- # @option opts [String] :url url for the remote server
42
- # @option opts [Integer] :port port number for the remote server
43
- # @option opts [Object] :http_client an HTTP client instance that implements the same protocol as Http::Default
44
- # @option opts [Capabilities] :desired_capabilities an instance of Remote::Capabilities describing the capabilities you want
45
- #
46
-
47
- def initialize(opts = {})
48
-
49
- opts = opts.dup
50
-
51
- if opts.key?(:port)
52
- WebDriver.logger.warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
53
- [DEPRECATION] `:port` is deprecated. Use full url desired.
54
- DEPRECATE
55
- end
56
- port = opts.delete(:port) || 4444
57
-
58
- http_client = opts.delete(:http_client) { Http::Default.new }
59
- desired_capabilities = opts.delete(:desired_capabilities) { W3CCapabilities.firefox }
60
- url = opts.delete(:url) { "http://#{Platform.localhost}:#{port}/wd/hub" }
61
-
62
- desired_capabilities = W3CCapabilities.send(desired_capabilities) if desired_capabilities.is_a? Symbol
63
-
64
- desired_capabilities[:marionette] = opts.delete(:marionette) unless opts[:marionette].nil?
65
-
66
- unless opts.empty?
67
- raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
68
- end
69
-
70
- uri = url.is_a?(URI) ? url : URI.parse(url)
71
- uri.path += '/' unless uri.path =~ %r{\/$}
72
-
73
- http_client.server_url = uri
74
-
75
- @http = http_client
76
- @capabilities = create_session(desired_capabilities)
77
- @file_detector = nil
78
- end
79
-
80
- def browser
81
- @browser ||= (
82
- name = @capabilities.browser_name
83
- name ? name.tr(' ', '_').to_sym : 'unknown'
84
- )
85
- end
86
-
87
- def driver_extensions
88
- [DriverExtensions::UploadsFiles,
89
- DriverExtensions::TakesScreenshot,
90
- DriverExtensions::HasSessionId,
91
- DriverExtensions::Rotatable,
92
- DriverExtensions::HasRemoteStatus,
93
- DriverExtensions::HasWebStorage]
94
- end
95
-
96
- def commands(command)
97
- case command
98
- when :status, :is_element_displayed
99
- Bridge::COMMANDS[command]
100
- else
101
- COMMANDS[command]
102
- end
103
- end
104
-
105
- #
106
- # Returns the current session ID.
107
- #
108
-
109
- def session_id
110
- @session_id || raise(Error::WebDriverError, 'no current session exists')
111
- end
112
-
113
- def create_session(desired_capabilities)
114
- resp = execute :new_session, {}, {desiredCapabilities: desired_capabilities}
115
- @session_id = resp['sessionId']
116
- return W3CCapabilities.json_create(resp['capabilities'] || resp['value']) if @session_id
117
-
118
- raise Error::WebDriverError, 'no sessionId in returned payload'
119
- end
120
-
121
- def status
122
- execute :status
123
- end
124
-
125
- def get(url)
126
- execute :get, {}, {url: url}
127
- end
128
-
129
- def implicit_wait_timeout=(milliseconds)
130
- timeout('implicit', milliseconds)
131
- end
132
-
133
- def script_timeout=(milliseconds)
134
- timeout('script', milliseconds)
135
- end
136
-
137
- def timeout(type, milliseconds)
138
- type = 'pageLoad' if type == 'page load'
139
- execute :set_timeout, {}, {type => milliseconds}
140
- end
141
-
142
- #
143
- # alerts
144
- #
145
-
146
- def accept_alert
147
- execute :accept_alert
148
- end
149
-
150
- def dismiss_alert
151
- execute :dismiss_alert
152
- end
153
-
154
- def alert=(keys)
155
- execute :send_alert_text, {}, {value: keys.split(//), text: keys}
156
- end
157
-
158
- def alert_text
159
- execute :get_alert_text
160
- end
161
-
162
- #
163
- # navigation
164
- #
165
-
166
- def go_back
167
- execute :back
168
- end
169
-
170
- def go_forward
171
- execute :forward
172
- end
173
-
174
- def url
175
- execute :get_current_url
176
- end
177
-
178
- def title
179
- execute :get_title
180
- end
181
-
182
- def page_source
183
- execute_script('var source = document.documentElement.outerHTML;' \
184
- 'if (!source) { source = new XMLSerializer().serializeToString(document); }' \
185
- 'return source;')
186
- end
187
-
188
- def switch_to_window(name)
189
- execute :switch_to_window, {}, {handle: name}
190
- end
191
-
192
- def switch_to_frame(id)
193
- id = find_element_by('id', id) if id.is_a? String
194
- execute :switch_to_frame, {}, {id: id}
195
- end
196
-
197
- def switch_to_parent_frame
198
- execute :switch_to_parent_frame
199
- end
200
-
201
- def switch_to_default_content
202
- switch_to_frame nil
203
- end
204
-
205
- QUIT_ERRORS = [IOError].freeze
206
-
207
- def quit
208
- execute :delete_session
209
- http.close
210
- rescue *QUIT_ERRORS
211
- end
212
-
213
- def close
214
- execute :close_window
215
- end
216
-
217
- def refresh
218
- execute :refresh
219
- end
220
-
221
- #
222
- # window handling
223
- #
224
-
225
- def window_handles
226
- execute :get_window_handles
227
- end
228
-
229
- def window_handle
230
- execute :get_window_handle
231
- end
232
-
233
- def resize_window(width, height, handle = :current)
234
- unless handle == :current
235
- raise Error::WebDriverError, 'Switch to desired window before changing its size'
236
- end
237
- execute :set_window_rect, {}, {width: width, height: height}
238
- end
239
-
240
- def window_size(handle = :current)
241
- unless handle == :current
242
- raise Error::UnsupportedOperationError, 'Switch to desired window before getting its size'
243
- end
244
- data = execute :get_window_rect
245
-
246
- Dimension.new data['width'], data['height']
247
- end
248
-
249
- def minimize_window
250
- execute :minimize_window
251
- end
252
-
253
- def maximize_window(handle = :current)
254
- unless handle == :current
255
- raise Error::UnsupportedOperationError, 'Switch to desired window before changing its size'
256
- end
257
- execute :maximize_window
258
- end
259
-
260
- def full_screen_window
261
- execute :fullscreen_window
262
- end
263
-
264
- def reposition_window(x, y)
265
- execute :set_window_rect, {}, {x: x, y: y}
266
- end
267
-
268
- def window_position
269
- data = execute :get_window_rect
270
- Point.new data['x'], data['y']
271
- end
272
-
273
- def set_window_rect(x: nil, y: nil, width: nil, height: nil)
274
- execute :set_window_rect, {}, {x: x, y: y, width: width, height: height}
275
- end
276
-
277
- def window_rect
278
- data = execute :get_window_rect
279
- Rectangle.new data['x'], data['y'], data['width'], data['height']
280
- end
281
-
282
- def screenshot
283
- execute :take_screenshot
284
- end
285
-
286
- #
287
- # HTML 5
288
- #
289
-
290
- def local_storage_item(key, value = nil)
291
- if value
292
- execute_script("localStorage.setItem('#{key}', '#{value}')")
293
- else
294
- execute_script("return localStorage.getItem('#{key}')")
295
- end
296
- end
297
-
298
- def remove_local_storage_item(key)
299
- execute_script("localStorage.removeItem('#{key}')")
300
- end
301
-
302
- def local_storage_keys
303
- execute_script('return Object.keys(localStorage)')
304
- end
305
-
306
- def clear_local_storage
307
- execute_script('localStorage.clear()')
308
- end
309
-
310
- def local_storage_size
311
- execute_script('return localStorage.length')
312
- end
313
-
314
- def session_storage_item(key, value = nil)
315
- if value
316
- execute_script("sessionStorage.setItem('#{key}', '#{value}')")
317
- else
318
- execute_script("return sessionStorage.getItem('#{key}')")
319
- end
320
- end
321
-
322
- def remove_session_storage_item(key)
323
- execute_script("sessionStorage.removeItem('#{key}')")
324
- end
325
-
326
- def session_storage_keys
327
- execute_script('return Object.keys(sessionStorage)')
328
- end
329
-
330
- def clear_session_storage
331
- execute_script('sessionStorage.clear()')
332
- end
333
-
334
- def session_storage_size
335
- execute_script('return sessionStorage.length')
336
- end
337
-
338
- def location
339
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting location'
340
- end
341
-
342
- def set_location(_lat, _lon, _alt)
343
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting location'
344
- end
345
-
346
- def network_connection
347
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting network connection'
348
- end
349
-
350
- def network_connection=(_type)
351
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting network connection'
352
- end
353
-
354
- #
355
- # javascript execution
356
- #
357
-
358
- def execute_script(script, *args)
359
- result = execute :execute_script, {}, {script: script, args: args}
360
- unwrap_script_result result
361
- end
362
-
363
- def execute_async_script(script, *args)
364
- result = execute :execute_async_script, {}, {script: script, args: args}
365
- unwrap_script_result result
366
- end
367
-
368
- #
369
- # cookies
370
- #
371
-
372
- def options
373
- @options ||= WebDriver::W3COptions.new(self)
374
- end
375
-
376
- def add_cookie(cookie)
377
- execute :add_cookie, {}, {cookie: cookie}
378
- end
379
-
380
- def delete_cookie(name)
381
- execute :delete_cookie, name: name
382
- end
383
-
384
- def cookie(name)
385
- execute :get_cookie, name: name
386
- end
387
-
388
- def cookies
389
- execute :get_all_cookies
390
- end
391
-
392
- def delete_all_cookies
393
- execute :delete_all_cookies
394
- end
395
-
396
- #
397
- # actions
398
- #
399
-
400
- def action(async = false)
401
- W3CActionBuilder.new self,
402
- Interactions.pointer(:mouse, name: 'mouse'),
403
- Interactions.key('keyboard'),
404
- async
405
- end
406
- alias_method :actions, :action
407
-
408
- def mouse
409
- raise Error::UnsupportedOperationError, '#mouse is no longer supported, use #action instead'
410
- end
411
-
412
- def keyboard
413
- raise Error::UnsupportedOperationError, '#keyboard is no longer supported, use #action instead'
414
- end
415
-
416
- def send_actions(data)
417
- execute :actions, {}, {actions: data}
418
- end
419
-
420
- def release_actions
421
- execute :release_actions
422
- end
423
-
424
- def click_element(element)
425
- execute :element_click, id: element
426
- end
427
-
428
- # TODO: - Implement file verification
429
- def send_keys_to_element(element, keys)
430
- # Keep .split(//) for backward compatibility for now
431
- text = keys.join('')
432
- execute :element_send_keys, {id: element}, {value: text.split(//), text: text}
433
- end
434
-
435
- def clear_element(element)
436
- execute :element_clear, id: element
437
- end
438
-
439
- def submit_element(element)
440
- form = find_element_by('xpath', "./ancestor-or-self::form", element)
441
- execute_script("var e = arguments[0].ownerDocument.createEvent('Event');" \
442
- "e.initEvent('submit', true, true);" \
443
- 'if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }', form.as_json)
444
- end
445
-
446
- def drag_element(element, right_by, down_by)
447
- execute :drag_element, {id: element}, {x: right_by, y: down_by}
448
- end
449
-
450
- def touch_single_tap(element)
451
- execute :touch_single_tap, {}, {element: element}
452
- end
453
-
454
- def touch_double_tap(element)
455
- execute :touch_double_tap, {}, {element: element}
456
- end
457
-
458
- def touch_long_press(element)
459
- execute :touch_long_press, {}, {element: element}
460
- end
461
-
462
- def touch_down(x, y)
463
- execute :touch_down, {}, {x: x, y: y}
464
- end
465
-
466
- def touch_up(x, y)
467
- execute :touch_up, {}, {x: x, y: y}
468
- end
469
-
470
- def touch_move(x, y)
471
- execute :touch_move, {}, {x: x, y: y}
472
- end
473
-
474
- def touch_scroll(element, x, y)
475
- if element
476
- execute :touch_scroll, {}, {element: element,
477
- xoffset: x,
478
- yoffset: y}
479
- else
480
- execute :touch_scroll, {}, {xoffset: x, yoffset: y}
481
- end
482
- end
483
-
484
- def touch_flick(xspeed, yspeed)
485
- execute :touch_flick, {}, {xspeed: xspeed, yspeed: yspeed}
486
- end
487
-
488
- def touch_element_flick(element, right_by, down_by, speed)
489
- execute :touch_flick, {}, {element: element,
490
- xoffset: right_by,
491
- yoffset: down_by,
492
- speed: speed}
493
- end
494
-
495
- def screen_orientation=(orientation)
496
- execute :set_screen_orientation, {}, {orientation: orientation}
497
- end
498
-
499
- def screen_orientation
500
- execute :get_screen_orientation
501
- end
502
-
503
- #
504
- # element properties
505
- #
506
-
507
- def element_tag_name(element)
508
- execute :get_element_tag_name, id: element
509
- end
510
-
511
- def element_attribute(element, name)
512
- execute_atom :getAttribute, element, name
513
- end
514
-
515
- def element_property(element, name)
516
- execute :get_element_property, id: element.ref, name: name
517
- end
518
-
519
- def element_value(element)
520
- element_property element, 'value'
521
- end
522
-
523
- def element_text(element)
524
- execute :get_element_text, id: element
525
- end
526
-
527
- def element_location(element)
528
- data = execute :get_element_rect, id: element
529
-
530
- Point.new data['x'], data['y']
531
- end
532
-
533
- def element_rect(element)
534
- data = execute :get_element_rect, id: element
535
-
536
- Rectangle.new data['x'], data['y'], data['width'], data['height']
537
- end
538
-
539
- def element_location_once_scrolled_into_view(element)
540
- send_keys_to_element(element, [''])
541
- element_location(element)
542
- end
543
-
544
- def element_size(element)
545
- data = execute :get_element_rect, id: element
546
-
547
- Dimension.new data['width'], data['height']
548
- end
549
-
550
- def element_enabled?(element)
551
- execute :is_element_enabled, id: element
552
- end
553
-
554
- def element_selected?(element)
555
- execute :is_element_selected, id: element
556
- end
557
-
558
- def element_displayed?(element)
559
- execute :is_element_displayed, id: element
560
- end
561
-
562
- def element_value_of_css_property(element, prop)
563
- execute :get_element_css_value, id: element, property_name: prop
564
- end
565
-
566
- #
567
- # finding elements
568
- #
569
-
570
- def active_element
571
- Element.new self, element_id_from(execute(:get_active_element))
572
- end
573
-
574
- alias_method :switch_to_active_element, :active_element
575
-
576
- def find_element_by(how, what, parent = nil)
577
- how, what = convert_locators(how, what)
578
-
579
- id = if parent
580
- execute :find_child_element, {id: parent}, {using: how, value: what}
581
- else
582
- execute :find_element, {}, {using: how, value: what}
583
- end
584
- Element.new self, element_id_from(id)
585
- end
586
-
587
- def find_elements_by(how, what, parent = nil)
588
- how, what = convert_locators(how, what)
589
-
590
- ids = if parent
591
- execute :find_child_elements, {id: parent}, {using: how, value: what}
592
- else
593
- execute :find_elements, {}, {using: how, value: what}
594
- end
595
-
596
- ids.map { |id| Element.new self, element_id_from(id) }
597
- end
598
-
599
- private
600
-
601
- def convert_locators(how, what)
602
- case how
603
- when 'class name'
604
- how = 'css selector'
605
- what = ".#{escape_css(what)}"
606
- when 'id'
607
- how = 'css selector'
608
- what = "##{escape_css(what)}"
609
- when 'name'
610
- how = 'css selector'
611
- what = "*[name='#{escape_css(what)}']"
612
- when 'tag name'
613
- how = 'css selector'
614
- end
615
- [how, what]
616
- end
617
-
618
- #
619
- # executes a command on the remote server.
620
- #
621
- #
622
- # @return [WebDriver::Remote::Response]
623
- #
624
-
625
- def execute(command, opts = {}, command_hash = nil)
626
- verb, path = commands(command) || raise(ArgumentError, "unknown command: #{command.inspect}")
627
- path = path.dup
628
-
629
- path[':session_id'] = @session_id if path.include?(':session_id')
630
-
631
- begin
632
- opts.each do |key, value|
633
- path[key.inspect] = escaper.escape(value.to_s)
634
- end
635
- rescue IndexError
636
- raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
637
- end
638
-
639
- WebDriver.logger.info("-> #{verb.to_s.upcase} #{path}")
640
- http.call(verb, path, command_hash)['value']
641
- end
642
-
643
- def escaper
644
- @escaper ||= defined?(URI::Parser) ? URI::Parser.new : URI
645
- end
646
-
647
- ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]\(\)])/
648
- UNICODE_CODE_POINT = 30
649
-
650
- # Escapes invalid characters in CSS selector.
651
- # @see https://mathiasbynens.be/notes/css-escapes
652
- def escape_css(string)
653
- string = string.gsub(ESCAPE_CSS_REGEXP) { |match| "\\#{match}" }
654
- if !string.empty? && string[0] =~ /[[:digit:]]/
655
- string = "\\#{UNICODE_CODE_POINT + Integer(string[0])} #{string[1..-1]}"
656
- end
657
-
658
- string
659
- end
660
- end # W3CBridge
661
- end # Remote
662
- end # WebDriver
663
- end # Selenium