selenium-webdriver 2.53.4 → 3.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 (152) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +363 -10
  3. data/LICENSE +1 -1
  4. data/README.md +2 -3
  5. data/lib/selenium-webdriver.rb +0 -2
  6. data/lib/selenium/server.rb +69 -70
  7. data/lib/selenium/webdriver.rb +32 -23
  8. data/lib/selenium/webdriver/atoms.rb +18 -0
  9. data/lib/selenium/webdriver/atoms/getAttribute.js +8 -0
  10. data/lib/selenium/webdriver/chrome.rb +8 -6
  11. data/lib/selenium/webdriver/chrome/driver.rb +112 -0
  12. data/lib/selenium/webdriver/chrome/options.rb +168 -0
  13. data/lib/selenium/webdriver/chrome/profile.rb +17 -17
  14. data/lib/selenium/webdriver/chrome/service.rb +22 -89
  15. data/lib/selenium/webdriver/common.rb +13 -6
  16. data/lib/selenium/webdriver/common/action_builder.rb +49 -57
  17. data/lib/selenium/webdriver/common/alert.rb +5 -15
  18. data/lib/selenium/webdriver/common/bridge_helper.rb +10 -17
  19. data/lib/selenium/webdriver/common/driver.rb +53 -68
  20. data/lib/selenium/webdriver/common/driver_extensions/{has_input_devices.rb → has_addons.rb} +13 -23
  21. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +4 -8
  22. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +4 -7
  23. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +0 -4
  24. data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +0 -4
  25. data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +1 -5
  26. data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +0 -5
  27. data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +4 -9
  28. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +7 -7
  29. data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +2 -7
  30. data/lib/selenium/webdriver/common/element.rb +57 -39
  31. data/lib/selenium/webdriver/common/error.rb +204 -106
  32. data/lib/selenium/webdriver/common/file_reaper.rb +3 -11
  33. data/lib/selenium/webdriver/common/html5/local_storage.rb +6 -10
  34. data/lib/selenium/webdriver/common/html5/session_storage.rb +6 -10
  35. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +7 -18
  36. data/lib/selenium/webdriver/{safari/options.rb → common/interactions/input_device.rb} +20 -31
  37. data/lib/selenium/webdriver/common/interactions/interaction.rb +50 -0
  38. data/lib/selenium/webdriver/{safari/browser.rb → common/interactions/interactions.rb} +16 -15
  39. data/lib/selenium/webdriver/common/interactions/key_actions.rb +143 -0
  40. data/lib/selenium/webdriver/common/interactions/key_input.rb +62 -0
  41. data/lib/selenium/webdriver/{android.rb → common/interactions/none_input.rb} +11 -6
  42. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +353 -0
  43. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +132 -0
  44. data/lib/selenium/webdriver/common/keyboard.rb +7 -14
  45. data/lib/selenium/webdriver/common/keys.rb +99 -82
  46. data/lib/selenium/webdriver/common/log_entry.rb +3 -6
  47. data/lib/selenium/webdriver/common/logger.rb +140 -0
  48. data/lib/selenium/webdriver/common/logs.rb +2 -6
  49. data/lib/selenium/webdriver/common/mouse.rb +9 -14
  50. data/lib/selenium/webdriver/common/navigation.rb +2 -6
  51. data/lib/selenium/webdriver/common/options.rb +20 -23
  52. data/lib/selenium/webdriver/common/platform.rb +70 -97
  53. data/lib/selenium/webdriver/common/port_prober.rb +3 -4
  54. data/lib/selenium/webdriver/common/profile_helper.rb +6 -11
  55. data/lib/selenium/webdriver/common/proxy.rb +58 -72
  56. data/lib/selenium/webdriver/common/search_context.rb +22 -29
  57. data/lib/selenium/webdriver/common/service.rb +161 -0
  58. data/lib/selenium/webdriver/common/socket_lock.rb +6 -14
  59. data/lib/selenium/webdriver/common/socket_poller.rb +5 -12
  60. data/lib/selenium/webdriver/common/target_locator.rb +11 -15
  61. data/lib/selenium/webdriver/common/timeouts.rb +4 -8
  62. data/lib/selenium/webdriver/common/touch_action_builder.rb +2 -6
  63. data/lib/selenium/webdriver/common/touch_screen.rb +19 -23
  64. data/lib/selenium/webdriver/common/w3c_action_builder.rb +209 -0
  65. data/lib/selenium/webdriver/{phantomjs.rb → common/w3c_options.rb} +16 -14
  66. data/lib/selenium/webdriver/common/wait.rb +6 -13
  67. data/lib/selenium/webdriver/common/window.rb +48 -17
  68. data/lib/selenium/webdriver/common/zipper.rb +6 -10
  69. data/lib/selenium/webdriver/edge.rb +5 -12
  70. data/lib/selenium/webdriver/edge/bridge.rb +32 -63
  71. data/lib/selenium/webdriver/edge/driver.rb +73 -0
  72. data/lib/selenium/webdriver/edge/service.rb +18 -87
  73. data/lib/selenium/webdriver/firefox.rb +20 -11
  74. data/lib/selenium/webdriver/firefox/binary.rb +40 -56
  75. data/lib/selenium/webdriver/firefox/driver.rb +48 -0
  76. data/lib/selenium/webdriver/firefox/extension.rb +18 -8
  77. data/lib/selenium/webdriver/firefox/extension/prefs.json +3 -11
  78. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  79. data/lib/selenium/webdriver/firefox/launcher.rb +13 -22
  80. data/lib/selenium/webdriver/firefox/legacy/driver.rb +79 -0
  81. data/lib/selenium/webdriver/{iphone.rb → firefox/marionette/bridge.rb} +25 -6
  82. data/lib/selenium/webdriver/firefox/marionette/driver.rb +96 -0
  83. data/lib/selenium/webdriver/firefox/options.rb +149 -0
  84. data/lib/selenium/webdriver/firefox/profile.rb +46 -46
  85. data/lib/selenium/webdriver/firefox/profiles_ini.rb +8 -18
  86. data/lib/selenium/webdriver/firefox/service.rb +23 -83
  87. data/lib/selenium/webdriver/firefox/util.rb +0 -4
  88. data/lib/selenium/webdriver/ie.rb +4 -8
  89. data/lib/selenium/webdriver/ie/driver.rb +90 -0
  90. data/lib/selenium/webdriver/ie/options.rb +136 -0
  91. data/lib/selenium/webdriver/ie/service.rb +58 -0
  92. data/lib/selenium/webdriver/remote.rb +8 -16
  93. data/lib/selenium/webdriver/remote/bridge.rb +96 -565
  94. data/lib/selenium/webdriver/remote/capabilities.rb +76 -94
  95. data/lib/selenium/webdriver/remote/driver.rb +49 -0
  96. data/lib/selenium/webdriver/remote/http/common.rb +22 -20
  97. data/lib/selenium/webdriver/remote/http/curb.rb +9 -12
  98. data/lib/selenium/webdriver/remote/http/default.rb +54 -41
  99. data/lib/selenium/webdriver/remote/http/persistent.rb +9 -8
  100. data/lib/selenium/webdriver/remote/oss/bridge.rb +586 -0
  101. data/lib/selenium/webdriver/remote/oss/commands.rb +221 -0
  102. data/lib/selenium/webdriver/remote/response.rb +39 -27
  103. data/lib/selenium/webdriver/remote/server_error.rb +1 -5
  104. data/lib/selenium/webdriver/remote/w3c/bridge.rb +573 -0
  105. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +290 -0
  106. data/lib/selenium/webdriver/remote/w3c/commands.rb +148 -0
  107. data/lib/selenium/webdriver/safari.rb +20 -29
  108. data/lib/selenium/webdriver/{firefox/w3c_bridge.rb → safari/driver.rb} +21 -30
  109. data/lib/selenium/webdriver/safari/service.rb +57 -0
  110. data/lib/selenium/webdriver/support.rb +1 -2
  111. data/lib/selenium/webdriver/support/abstract_event_listener.rb +17 -4
  112. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -5
  113. data/lib/selenium/webdriver/support/color.rb +57 -42
  114. data/lib/selenium/webdriver/support/escaper.rb +41 -0
  115. data/lib/selenium/webdriver/support/event_firing_bridge.rb +36 -40
  116. data/lib/selenium/webdriver/support/select.rb +33 -86
  117. data/selenium-webdriver.gemspec +22 -25
  118. metadata +254 -261
  119. data/lib/selenium-client.rb +0 -21
  120. data/lib/selenium/client.rb +0 -57
  121. data/lib/selenium/client/base.rb +0 -151
  122. data/lib/selenium/client/driver.rb +0 -29
  123. data/lib/selenium/client/errors.rb +0 -28
  124. data/lib/selenium/client/extensions.rb +0 -132
  125. data/lib/selenium/client/idiomatic.rb +0 -507
  126. data/lib/selenium/client/javascript_expression_builder.rb +0 -135
  127. data/lib/selenium/client/javascript_frameworks/jquery.rb +0 -32
  128. data/lib/selenium/client/javascript_frameworks/prototype.rb +0 -32
  129. data/lib/selenium/client/legacy_driver.rb +0 -1722
  130. data/lib/selenium/client/protocol.rb +0 -123
  131. data/lib/selenium/client/selenium_helper.rb +0 -49
  132. data/lib/selenium/rake/server_task.rb +0 -176
  133. data/lib/selenium/webdriver/android/bridge.rb +0 -68
  134. data/lib/selenium/webdriver/chrome/bridge.rb +0 -139
  135. data/lib/selenium/webdriver/common/core_ext/base64.rb +0 -28
  136. data/lib/selenium/webdriver/common/core_ext/dir.rb +0 -61
  137. data/lib/selenium/webdriver/common/html5/location.rb +0 -19
  138. data/lib/selenium/webdriver/common/w3c_error.rb +0 -194
  139. data/lib/selenium/webdriver/edge/legacy_support.rb +0 -117
  140. data/lib/selenium/webdriver/firefox/bridge.rb +0 -89
  141. data/lib/selenium/webdriver/ie/bridge.rb +0 -88
  142. data/lib/selenium/webdriver/ie/server.rb +0 -133
  143. data/lib/selenium/webdriver/iphone/bridge.rb +0 -64
  144. data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -78
  145. data/lib/selenium/webdriver/phantomjs/service.rb +0 -130
  146. data/lib/selenium/webdriver/remote/commands.rb +0 -211
  147. data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -668
  148. data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -236
  149. data/lib/selenium/webdriver/remote/w3c_commands.rb +0 -132
  150. data/lib/selenium/webdriver/safari/bridge.rb +0 -135
  151. data/lib/selenium/webdriver/safari/resources/client.js +0 -7255
  152. data/lib/selenium/webdriver/safari/server.rb +0 -187
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
- #
3
1
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
2
  # or more contributor license agreements. See the NOTICE file
5
3
  # distributed with this work for additional information
@@ -20,7 +18,6 @@
20
18
  module Selenium
21
19
  module WebDriver
22
20
  module HTML5
23
-
24
21
  class LocalStorage
25
22
  include SharedWebStorage
26
23
 
@@ -32,29 +29,28 @@ module Selenium
32
29
  end
33
30
 
34
31
  def [](key)
35
- @bridge.getLocalStorageItem key
32
+ @bridge.local_storage_item key
36
33
  end
37
34
 
38
35
  def []=(key, value)
39
- @bridge.setLocalStorageItem key, value
36
+ @bridge.local_storage_item key, value
40
37
  end
41
38
 
42
39
  def delete(key)
43
- @bridge.removeLocalStorageItem key
40
+ @bridge.remove_local_storage_item key
44
41
  end
45
42
 
46
43
  def clear
47
- @bridge.clearLocalStorage
44
+ @bridge.clear_local_storage
48
45
  end
49
46
 
50
47
  def size
51
- @bridge.getLocalStorageSize
48
+ @bridge.local_storage_size
52
49
  end
53
50
 
54
51
  def keys
55
- @bridge.getLocalStorageKeys.reverse
52
+ @bridge.local_storage_keys.reverse
56
53
  end
57
-
58
54
  end # LocalStorage
59
55
  end # HTML5
60
56
  end # WebDriver
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
- #
3
1
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
2
  # or more contributor license agreements. See the NOTICE file
5
3
  # distributed with this work for additional information
@@ -20,33 +18,32 @@
20
18
  module Selenium
21
19
  module WebDriver
22
20
  module HTML5
23
-
24
21
  class SessionStorage
25
22
  include Enumerable
26
23
  include SharedWebStorage
27
24
 
28
25
  def [](key)
29
- @bridge.getSessionStorageItem key
26
+ @bridge.session_storage_item key
30
27
  end
31
28
 
32
29
  def []=(key, value)
33
- @bridge.setSessionStorageItem key, value
30
+ @bridge.session_storage_item key, value
34
31
  end
35
32
 
36
33
  def delete(key)
37
- @bridge.removeSessionStorageItem key
34
+ @bridge.remove_session_storage_item key
38
35
  end
39
36
 
40
37
  def clear
41
- @bridge.clearSessionStorage
38
+ @bridge.clear_session_storage
42
39
  end
43
40
 
44
41
  def size
45
- @bridge.getSessionStorageSize
42
+ @bridge.session_storage_size
46
43
  end
47
44
 
48
45
  def keys
49
- @bridge.getSessionStorageKeys.reverse
46
+ @bridge.session_storage_keys.reverse
50
47
  end
51
48
 
52
49
  #
@@ -56,7 +53,6 @@ module Selenium
56
53
  def initialize(bridge)
57
54
  @bridge = bridge
58
55
  end
59
-
60
56
  end # SessionStorage
61
57
  end # HTML5
62
58
  end # WebDriver
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
- #
3
1
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
2
  # or more contributor license agreements. See the NOTICE file
5
3
  # distributed with this work for additional information
@@ -20,7 +18,6 @@
20
18
  module Selenium
21
19
  module WebDriver
22
20
  module HTML5
23
-
24
21
  module SharedWebStorage
25
22
  include Enumerable
26
23
 
@@ -30,31 +27,23 @@ module Selenium
30
27
  alias_method :member?, :key?
31
28
  alias_method :has_key?, :key?
32
29
 
33
- def fetch(key, &blk)
34
- if self.key? key
35
- return self[key]
36
- end
37
-
38
- if block_given?
39
- yield key
40
- else
41
- # should be KeyError, but it's 1.9-specific
42
- raise IndexError, "missing key #{key.inspect}"
43
- end
30
+ def fetch(key)
31
+ return self[key] if key? key
32
+ return yield(key) if block_given?
33
+ raise KeyError, "missing key #{key.inspect}"
44
34
  end
45
35
 
46
36
  def empty?
47
- size == 0
37
+ to_a.empty?
48
38
  end
49
39
 
50
- def each(&blk)
40
+ def each
51
41
  return enum_for(:each) unless block_given?
52
42
 
53
- keys.each do |k|
43
+ keys.each do |k| # rubocop:disable Performance/HashEachMethods
54
44
  yield k, self[k]
55
45
  end
56
46
  end
57
-
58
47
  end # SharedWebStorage
59
48
  end # HTML5
60
49
  end # WebDriver
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
- #
3
1
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
2
  # or more contributor license agreements. See the NOTICE file
5
3
  # distributed with this work for additional information
@@ -17,46 +15,37 @@
17
15
  # specific language governing permissions and limitations
18
16
  # under the License.
19
17
 
18
+ require 'securerandom'
19
+
20
20
  module Selenium
21
21
  module WebDriver
22
- module Safari
23
- class Options
24
- DEFAULT_PORT = 56485
25
-
26
- attr_accessor :port, :data_dir, :skip_extension_installation
22
+ module Interactions
23
+ class InputDevice
24
+ attr_reader :name, :actions
27
25
 
28
- def initialize(opts = {})
29
- extract_options(opts)
26
+ def initialize(name = nil)
27
+ @name = name || SecureRandom.uuid
28
+ @actions = []
30
29
  end
31
30
 
32
- def clean_session?
33
- !!@clean_session
31
+ def add_action(action)
32
+ raise TypeError, "#{action.inspect} is not a valid action" unless action.class < Interaction
33
+ @actions << action
34
34
  end
35
35
 
36
- def to_capabilities
37
- caps = Remote::Capabilities.safari
38
- caps.merge!('safari.options' => as_json)
39
-
40
- caps
36
+ def clear_actions
37
+ @actions.clear
41
38
  end
42
39
 
43
- def as_json
44
- {
45
- 'port' => port,
46
- 'dataDir' => data_dir,
47
- 'cleanSession' => clean_session?,
48
- }
40
+ def create_pause(duration = nil)
41
+ add_action(Pause.new(self, duration))
49
42
  end
50
43
 
51
- private
52
-
53
- def extract_options(opts)
54
- @port = Integer(opts[:port] || DEFAULT_PORT)
55
- @data_dir = opts[:custom_data_dir] || opts[:data_dir]
56
- @clean_session = opts[:clean_session]
44
+ def no_actions? # Determine if only pauses are present
45
+ actions = @actions.reject { |action| action.type == Interaction::PAUSE }
46
+ actions.empty?
57
47
  end
58
-
59
- end # Options
60
- end # Safari
48
+ end # InputDevice
49
+ end # Interactions
61
50
  end # WebDriver
62
51
  end # Selenium
@@ -0,0 +1,50 @@
1
+ # Licensed to the Software Freedom Conservancy (SFC) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The SFC licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ module Selenium
19
+ module WebDriver
20
+ module Interactions
21
+ class Interaction
22
+ PAUSE = :pause
23
+
24
+ attr_reader :source
25
+
26
+ def initialize(source)
27
+ raise TypeError, "#{source.type} is not a valid input type" unless Interactions::SOURCE_TYPES.include? source.type
28
+ @source = source
29
+ end
30
+ end
31
+
32
+ class Pause < Interaction
33
+ def initialize(source, duration = nil)
34
+ super(source)
35
+ @duration = duration
36
+ end
37
+
38
+ def type
39
+ PAUSE
40
+ end
41
+
42
+ def encode
43
+ output = {type: type}
44
+ output[:duration] = (@duration * 1000).to_i if @duration
45
+ output
46
+ end
47
+ end # Interaction
48
+ end # Interactions
49
+ end # WebDriver
50
+ end # Selenium
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
- #
3
1
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
2
  # or more contributor license agreements. See the NOTICE file
5
3
  # distributed with this work for additional information
@@ -15,26 +13,29 @@
15
13
  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
14
  # KIND, either express or implied. See the License for the
17
15
  # specific language governing permissions and limitations
18
- # under the License.
16
+ # under the License
19
17
 
20
18
  module Selenium
21
19
  module WebDriver
22
- module Safari
23
-
24
- class Browser
25
- def start(*args)
26
- Platform.exit_hook { stop } # make sure we don't leave the browser running
20
+ module Interactions
21
+ KEY = :key
22
+ POINTER = :pointer
23
+ NONE = :none
24
+ SOURCE_TYPES = [KEY, POINTER, NONE].freeze
27
25
 
28
- @process = ChildProcess.new(Safari.path, *args)
29
- @process.io.inherit! if $DEBUG
30
- @process.start
26
+ class << self
27
+ def key(name)
28
+ KeyInput.new(name)
31
29
  end
32
30
 
33
- def stop
34
- @process.stop if @process
31
+ def pointer(kind, **kwargs)
32
+ PointerInput.new(kind, **kwargs)
35
33
  end
36
34
 
37
- end # Browser
38
- end # Safari
35
+ def none(name = nil)
36
+ NoneInput.new(name)
37
+ end
38
+ end
39
+ end # Interactions
39
40
  end # WebDriver
40
41
  end # Selenium
@@ -0,0 +1,143 @@
1
+ # Licensed to the Software Freedom Conservancy (SFC) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The SFC licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ module Selenium
19
+ module WebDriver
20
+ module KeyActions
21
+ #
22
+ # Performs a key press. Does not release the key - subsequent interactions may assume it's kept pressed.
23
+ # Note that the key is never released implicitly - either W3CActionBuilder#key_up(key) or W3CActionBuilder#release_actions
24
+ # must be called to release the key.
25
+ #
26
+ # @example Press a key
27
+ #
28
+ # driver.action.key_down(:control).perform
29
+ #
30
+ # @example Press a key on an element
31
+ #
32
+ # el = driver.find_element(id: "some_id")
33
+ # driver.action.key_down(el, :shift).perform
34
+ #
35
+ # @overload key_down(key, device: nil)
36
+ # @param [Symbol, String] key The key to press
37
+ # @param [Symbol, String] device Optional name of the KeyInput device to press the key on
38
+ # @overload key_down(element, key, device: nil)
39
+ # @param [Element] element An optional element to move to first
40
+ # @param [Symbol, String] key The key to press
41
+ # @param [Symbol, String] device Optional name of the KeyInput device to press the key on
42
+ # @return [W3CActionBuilder] A self reference
43
+ #
44
+
45
+ def key_down(*args, device: nil)
46
+ key_action(*args, action: :create_key_down, device: device)
47
+ end
48
+
49
+ #
50
+ # Performs a key release.
51
+ # Releasing a non-depressed key will yield undefined behaviour.
52
+ #
53
+ # @example Release a key
54
+ #
55
+ # driver.action.key_up(:shift).perform
56
+ #
57
+ # @example Release a key from an element
58
+ #
59
+ # el = driver.find_element(id: "some_id")
60
+ # driver.action.key_up(el, :alt).perform
61
+ #
62
+ # @overload key_up(key, device: nil)
63
+ # @param [Symbol, String] key The key to press
64
+ # @param [Symbol, String] device Optional name of the KeyInput device to press the key on
65
+ # @overload key_up(element, key, device: nil)
66
+ # @param [Element] element An optional element to move to first
67
+ # @param [Symbol, String] key The key to release
68
+ # @param [Symbol, String] device Optional name of the KeyInput device to release the key on
69
+ # @return [W3CActionBuilder] A self reference
70
+ #
71
+
72
+ def key_up(*args, device: nil)
73
+ key_action(*args, action: :create_key_up, device: device)
74
+ end
75
+
76
+ #
77
+ # Sends keys to the active element. This differs from calling
78
+ # Element#send_keys(keys) on the active element in two ways:
79
+ #
80
+ # * The modifier keys included in this call are not released.
81
+ # * There is no attempt to re-focus the element - so send_keys(:tab) for switching elements should work.
82
+ #
83
+ # @example Send the text "help" to an element
84
+ #
85
+ # el = driver.find_element(id: "some_id")
86
+ # driver.action.send_keys(el, "help").perform
87
+ #
88
+ # @example Send the text "help" to the currently focused element
89
+ #
90
+ # driver.action.send_keys("help").perform
91
+ #
92
+ # @overload send_keys(keys, device: nil)
93
+ # @param [Array, Symbol, String] keys The key(s) to press and release
94
+ # @param [Symbol, String] device Optional name of the KeyInput device to press and release the keys on
95
+ # @overload send_keys(element, keys, device: nil)
96
+ # @param [Element] element An optional element to move to first
97
+ # @param [Array, Symbol, String] keys The key(s) to press and release
98
+ # @param [Symbol, String] device Optional name of the KeyInput device to press and release the keys on
99
+ # @return [W3CActionBuilder] A self reference
100
+ #
101
+
102
+ def send_keys(*args, device: nil)
103
+ click(args.shift) if args.first.is_a? Element
104
+ args.map { |x| x.is_a?(String) ? x.chars : x }.flatten.each do |arg|
105
+ key_down(arg, device: device)
106
+ key_up(arg, device: device)
107
+ end
108
+ self
109
+ end
110
+
111
+ private
112
+
113
+ #
114
+ # @api private
115
+ #
116
+ # @overload key_down(key, action: nil, device: nil)
117
+ # @param [Symbol, String] key The key to press
118
+ # @param [Symbol] action The name of the key action to perform
119
+ # @param [Symbol, String] device Optional name of the KeyInput device to press the key on
120
+ # @overload key_down(element, key, action: nil, device: nil)
121
+ # @param [Element] element An optional element to move to first
122
+ # @param [Symbol, String] key The key to press
123
+ # @param [Symbol] action The name of the key action to perform
124
+ # @param [Symbol, String] device Optional name of the KeyInput device to press the key on
125
+ #
126
+ # @param [Array] args
127
+ # @option args [Element] element An optional element to move to first
128
+ # @option args [Symbol, String] key The key to perform the action with
129
+ # @param [Symbol] action The name of the key action to perform
130
+ # @param [Symbol, String] device optional name of the KeyInput device to press the key on
131
+ # @return [W3CActionBuilder] A self reference
132
+ #
133
+
134
+ def key_action(*args, action: nil, device: nil)
135
+ key_input = get_device(device) || key_inputs.first
136
+ click(args.shift) if args.first.is_a? Element
137
+ key_input.send(action, args.last)
138
+ tick(key_input)
139
+ self
140
+ end
141
+ end # KeyActions
142
+ end # WebDriver
143
+ end # Selenium