selenium-webdriver 3.0.0.beta4.0 → 4.0.0.alpha5

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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +679 -0
  3. data/Gemfile +2 -0
  4. data/LICENSE +1 -1
  5. data/README.md +1 -1
  6. data/lib/selenium-webdriver.rb +2 -2
  7. data/lib/selenium/server.rb +23 -16
  8. data/lib/selenium/webdriver.rb +43 -25
  9. data/lib/selenium/webdriver/atoms.rb +20 -1
  10. data/lib/selenium/webdriver/atoms/findElements.js +122 -0
  11. data/lib/selenium/webdriver/atoms/getAttribute.js +84 -11
  12. data/lib/selenium/webdriver/atoms/isDisplayed.js +100 -0
  13. data/lib/selenium/webdriver/chrome.rb +15 -20
  14. data/lib/selenium/webdriver/chrome/bridge.rb +29 -66
  15. data/lib/selenium/webdriver/{edge/service.rb → chrome/driver.rb} +19 -22
  16. data/lib/selenium/webdriver/chrome/options.rb +221 -0
  17. data/lib/selenium/webdriver/chrome/profile.rb +6 -7
  18. data/lib/selenium/webdriver/chrome/service.rb +20 -20
  19. data/lib/selenium/webdriver/common.rb +19 -11
  20. data/lib/selenium/webdriver/common/action_builder.rb +98 -246
  21. data/lib/selenium/webdriver/common/alert.rb +2 -7
  22. data/lib/selenium/webdriver/common/driver.rb +89 -51
  23. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +45 -0
  24. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +50 -0
  25. data/lib/selenium/webdriver/common/driver_extensions/{has_input_devices.rb → has_debugger.rb} +12 -25
  26. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +38 -0
  27. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +3 -5
  28. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +51 -0
  29. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +3 -3
  30. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +51 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +2 -2
  32. data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +2 -2
  33. data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +2 -2
  34. data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +4 -4
  35. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +9 -3
  36. data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +3 -5
  37. data/lib/selenium/webdriver/common/element.rb +32 -10
  38. data/lib/selenium/webdriver/common/error.rb +103 -121
  39. data/lib/selenium/webdriver/common/file_reaper.rb +3 -5
  40. data/lib/selenium/webdriver/common/html5/local_storage.rb +2 -2
  41. data/lib/selenium/webdriver/common/html5/session_storage.rb +2 -2
  42. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +3 -2
  43. data/lib/selenium/webdriver/common/interactions/input_device.rb +54 -0
  44. data/lib/selenium/webdriver/common/interactions/interaction.rb +53 -0
  45. data/lib/selenium/webdriver/{phantomjs.rb → common/interactions/interactions.rb} +17 -20
  46. data/lib/selenium/webdriver/common/interactions/key_actions.rb +145 -0
  47. data/lib/selenium/webdriver/common/interactions/key_input.rb +66 -0
  48. data/lib/selenium/webdriver/common/interactions/none_input.rb +36 -0
  49. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +363 -0
  50. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +139 -0
  51. data/lib/selenium/webdriver/common/keys.rb +37 -15
  52. data/lib/selenium/webdriver/common/log_entry.rb +4 -4
  53. data/lib/selenium/webdriver/common/logger.rb +147 -0
  54. data/lib/selenium/webdriver/common/logs.rb +2 -2
  55. data/lib/selenium/webdriver/common/manager.rb +177 -0
  56. data/lib/selenium/webdriver/common/navigation.rb +2 -2
  57. data/lib/selenium/webdriver/common/options.rb +47 -105
  58. data/lib/selenium/webdriver/common/platform.rb +44 -38
  59. data/lib/selenium/webdriver/common/port_prober.rb +8 -19
  60. data/lib/selenium/webdriver/common/profile_helper.rb +13 -5
  61. data/lib/selenium/webdriver/common/proxy.rb +14 -8
  62. data/lib/selenium/webdriver/common/search_context.rb +16 -20
  63. data/lib/selenium/webdriver/common/service.rb +115 -30
  64. data/lib/selenium/webdriver/common/socket_lock.rb +12 -7
  65. data/lib/selenium/webdriver/common/socket_poller.rb +29 -22
  66. data/lib/selenium/webdriver/common/target_locator.rb +6 -6
  67. data/lib/selenium/webdriver/common/timeouts.rb +2 -2
  68. data/lib/selenium/webdriver/common/wait.rb +14 -8
  69. data/lib/selenium/webdriver/common/window.rb +38 -2
  70. data/lib/selenium/webdriver/common/zipper.rb +3 -5
  71. data/lib/selenium/webdriver/edge.rb +33 -20
  72. data/lib/selenium/webdriver/edge_chrome/bridge.rb +30 -0
  73. data/lib/selenium/webdriver/edge_chrome/driver.rb +38 -0
  74. data/lib/selenium/webdriver/{common/driver_extensions/has_touch_screen.rb → edge_chrome/options.rb} +10 -12
  75. data/lib/selenium/webdriver/edge_chrome/profile.rb +33 -0
  76. data/lib/selenium/webdriver/edge_chrome/service.rb +36 -0
  77. data/lib/selenium/webdriver/edge_html/driver.rb +39 -0
  78. data/lib/selenium/webdriver/edge_html/options.rb +91 -0
  79. data/lib/selenium/webdriver/edge_html/service.rb +47 -0
  80. data/lib/selenium/webdriver/firefox.rb +24 -29
  81. data/lib/selenium/webdriver/firefox/bridge.rb +15 -39
  82. data/lib/selenium/webdriver/firefox/{util.rb → driver.rb} +13 -19
  83. data/lib/selenium/webdriver/firefox/extension.rb +28 -8
  84. data/lib/selenium/webdriver/firefox/options.rb +162 -0
  85. data/lib/selenium/webdriver/firefox/profile.rb +23 -82
  86. data/lib/selenium/webdriver/firefox/profiles_ini.rb +5 -5
  87. data/lib/selenium/webdriver/firefox/service.rb +18 -37
  88. data/lib/selenium/webdriver/ie.rb +13 -19
  89. data/lib/selenium/webdriver/ie/driver.rb +40 -0
  90. data/lib/selenium/webdriver/ie/options.rb +118 -0
  91. data/lib/selenium/webdriver/ie/service.rb +20 -20
  92. data/lib/selenium/webdriver/remote.rb +15 -17
  93. data/lib/selenium/webdriver/remote/bridge.rb +281 -300
  94. data/lib/selenium/webdriver/remote/capabilities.rb +102 -83
  95. data/lib/selenium/webdriver/remote/commands.rb +132 -192
  96. data/lib/selenium/webdriver/remote/driver.rb +52 -0
  97. data/lib/selenium/webdriver/remote/http/common.rb +23 -13
  98. data/lib/selenium/webdriver/remote/http/curb.rb +10 -7
  99. data/lib/selenium/webdriver/remote/http/default.rb +52 -32
  100. data/lib/selenium/webdriver/remote/http/persistent.rb +8 -4
  101. data/lib/selenium/webdriver/remote/response.rb +32 -35
  102. data/lib/selenium/webdriver/remote/server_error.rb +2 -2
  103. data/lib/selenium/webdriver/safari.rb +24 -22
  104. data/lib/selenium/webdriver/safari/bridge.rb +21 -21
  105. data/lib/selenium/webdriver/safari/driver.rb +41 -0
  106. data/lib/selenium/webdriver/safari/options.rb +66 -0
  107. data/lib/selenium/webdriver/safari/service.rb +8 -24
  108. data/lib/selenium/webdriver/support.rb +3 -2
  109. data/lib/selenium/webdriver/support/abstract_event_listener.rb +2 -2
  110. data/lib/selenium/webdriver/support/block_event_listener.rb +3 -3
  111. data/lib/selenium/webdriver/support/color.rb +13 -13
  112. data/lib/selenium/webdriver/support/escaper.rb +2 -2
  113. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  114. data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
  115. data/lib/selenium/webdriver/support/select.rb +20 -21
  116. data/lib/selenium/webdriver/version.rb +24 -0
  117. data/selenium-webdriver.gemspec +31 -17
  118. metadata +331 -248
  119. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  120. data/lib/selenium/webdriver/common/keyboard.rb +0 -69
  121. data/lib/selenium/webdriver/common/mouse.rb +0 -88
  122. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -81
  123. data/lib/selenium/webdriver/common/touch_screen.rb +0 -121
  124. data/lib/selenium/webdriver/common/w3c_error.rb +0 -191
  125. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  126. data/lib/selenium/webdriver/edge/legacy_support.rb +0 -117
  127. data/lib/selenium/webdriver/firefox/binary.rb +0 -186
  128. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  129. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  130. data/lib/selenium/webdriver/firefox/launcher.rb +0 -114
  131. data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
  132. data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
  133. data/lib/selenium/webdriver/firefox/w3c_bridge.rb +0 -79
  134. data/lib/selenium/webdriver/ie/bridge.rb +0 -76
  135. data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -65
  136. data/lib/selenium/webdriver/phantomjs/service.rb +0 -66
  137. data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -682
  138. data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -228
  139. data/lib/selenium/webdriver/remote/w3c_commands.rb +0 -135
@@ -1,5 +1,5 @@
1
- # encoding: utf-8
2
- #
1
+ # frozen_string_literal: true
2
+
3
3
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
4
  # or more contributor license agreements. See the NOTICE file
5
5
  # distributed with this work for additional information
@@ -36,9 +36,7 @@ module Selenium
36
36
  end
37
37
 
38
38
  def add_extension(path)
39
- unless File.file?(path)
40
- raise Error::WebDriverError, "could not find extension at #{path.inspect}"
41
- end
39
+ raise Error::WebDriverError, "could not find extension at #{path.inspect}" unless File.file?(path)
42
40
 
43
41
  @extensions << path
44
42
  end
@@ -79,8 +77,8 @@ module Selenium
79
77
 
80
78
  extensions.concat(@encoded_extensions)
81
79
 
82
- opts = {directory: @directory || layout_on_disk}
83
- opts[:extensions] = extensions if extensions
80
+ opts = {'directory' => directory || layout_on_disk}
81
+ opts['extensions'] = extensions if extensions.any?
84
82
  opts
85
83
  end
86
84
 
@@ -99,6 +97,7 @@ module Selenium
99
97
 
100
98
  def read_model_prefs
101
99
  return {} unless @model
100
+
102
101
  JSON.parse File.read(prefs_file_for(@model))
103
102
  end
104
103
 
@@ -1,5 +1,5 @@
1
- # encoding: utf-8
2
- #
1
+ # frozen_string_literal: true
2
+
3
3
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
4
  # or more contributor license agreements. See the NOTICE file
5
5
  # distributed with this work for additional information
@@ -20,29 +20,29 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Chrome
23
- #
24
- # @api private
25
- #
26
-
27
23
  class Service < WebDriver::Service
28
24
  DEFAULT_PORT = 9515
25
+ EXECUTABLE = 'chromedriver'
26
+ MISSING_TEXT = <<~ERROR
27
+ Unable to find chromedriver. Please download the server from
28
+ https://chromedriver.storage.googleapis.com/index.html and place it somewhere on your PATH.
29
+ More info at https://github.com/SeleniumHQ/selenium/wiki/ChromeDriver.
30
+ ERROR
31
+ SHUTDOWN_SUPPORTED = true
29
32
 
30
33
  private
31
34
 
32
- def start_process
33
- server_command = [@executable_path, "--port=#{@port}", *@extra_args]
34
- @process = ChildProcess.build(*server_command)
35
-
36
- @process.io.inherit! if $DEBUG
37
- @process.start
38
- end
39
-
40
- def stop_server
41
- connect_to_server { |http| http.get('/shutdown') }
42
- end
43
-
44
- def cannot_connect_error_text
45
- "unable to connect to chromedriver #{@host}:#{@port}"
35
+ # Note: This processing is deprecated
36
+ def extract_service_args(driver_opts)
37
+ driver_args = super
38
+ driver_opts = driver_opts.dup
39
+ driver_args << "--log-path=#{driver_opts.delete(:log_path)}" if driver_opts.key?(:log_path)
40
+ driver_args << "--url-base=#{driver_opts.delete(:url_base)}" if driver_opts.key?(:url_base)
41
+ driver_args << "--port-server=#{driver_opts.delete(:port_server)}" if driver_opts.key?(:port_server)
42
+ driver_args << "--whitelisted-ips=#{driver_opts.delete(:whitelisted_ips)}" if driver_opts.key?(:whitelisted_ips)
43
+ driver_args << "--verbose" if driver_opts.key?(:verbose)
44
+ driver_args << "--silent" if driver_opts.key?(:silent)
45
+ driver_args
46
46
  end
47
47
  end # Service
48
48
  end # Chrome
@@ -1,5 +1,5 @@
1
- # encoding: utf-8
2
- #
1
+ # frozen_string_literal: true
2
+
3
3
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
4
  # or more contributor license agreements. See the NOTICE file
5
5
  # distributed with this work for additional information
@@ -17,7 +17,6 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
- require 'selenium/webdriver/common/w3c_error'
21
20
  require 'selenium/webdriver/common/error'
22
21
  require 'selenium/webdriver/common/platform'
23
22
  require 'selenium/webdriver/common/proxy'
@@ -30,33 +29,42 @@ require 'selenium/webdriver/common/port_prober'
30
29
  require 'selenium/webdriver/common/zipper'
31
30
  require 'selenium/webdriver/common/wait'
32
31
  require 'selenium/webdriver/common/alert'
33
- require 'selenium/webdriver/common/mouse'
34
- require 'selenium/webdriver/common/keyboard'
35
- require 'selenium/webdriver/common/touch_screen'
36
32
  require 'selenium/webdriver/common/target_locator'
37
33
  require 'selenium/webdriver/common/navigation'
38
34
  require 'selenium/webdriver/common/timeouts'
39
35
  require 'selenium/webdriver/common/window'
36
+ require 'selenium/webdriver/common/logger'
40
37
  require 'selenium/webdriver/common/logs'
41
- require 'selenium/webdriver/common/options'
38
+ require 'selenium/webdriver/common/manager'
42
39
  require 'selenium/webdriver/common/search_context'
40
+ require 'selenium/webdriver/common/interactions/key_actions'
41
+ require 'selenium/webdriver/common/interactions/pointer_actions'
42
+ require 'selenium/webdriver/common/interactions/interactions'
43
+ require 'selenium/webdriver/common/interactions/input_device'
44
+ require 'selenium/webdriver/common/interactions/interaction'
45
+ require 'selenium/webdriver/common/interactions/none_input'
46
+ require 'selenium/webdriver/common/interactions/key_input'
47
+ require 'selenium/webdriver/common/interactions/pointer_input'
43
48
  require 'selenium/webdriver/common/action_builder'
44
- require 'selenium/webdriver/common/touch_action_builder'
45
49
  require 'selenium/webdriver/common/html5/shared_web_storage'
46
50
  require 'selenium/webdriver/common/html5/local_storage'
47
51
  require 'selenium/webdriver/common/html5/session_storage'
48
52
  require 'selenium/webdriver/common/driver_extensions/takes_screenshot'
49
53
  require 'selenium/webdriver/common/driver_extensions/rotatable'
50
- require 'selenium/webdriver/common/driver_extensions/has_input_devices'
51
54
  require 'selenium/webdriver/common/driver_extensions/has_web_storage'
55
+ require 'selenium/webdriver/common/driver_extensions/downloads_files'
52
56
  require 'selenium/webdriver/common/driver_extensions/has_location'
53
57
  require 'selenium/webdriver/common/driver_extensions/has_session_id'
54
- require 'selenium/webdriver/common/driver_extensions/has_touch_screen'
55
58
  require 'selenium/webdriver/common/driver_extensions/has_remote_status'
59
+ require 'selenium/webdriver/common/driver_extensions/has_network_conditions'
56
60
  require 'selenium/webdriver/common/driver_extensions/has_network_connection'
61
+ require 'selenium/webdriver/common/driver_extensions/has_permissions'
62
+ require 'selenium/webdriver/common/driver_extensions/has_debugger'
57
63
  require 'selenium/webdriver/common/driver_extensions/uploads_files'
64
+ require 'selenium/webdriver/common/driver_extensions/has_addons'
65
+ require 'selenium/webdriver/common/driver_extensions/has_devtools'
58
66
  require 'selenium/webdriver/common/keys'
59
- require 'selenium/webdriver/common/bridge_helper'
60
67
  require 'selenium/webdriver/common/profile_helper'
68
+ require 'selenium/webdriver/common/options'
61
69
  require 'selenium/webdriver/common/driver'
62
70
  require 'selenium/webdriver/common/element'
@@ -1,5 +1,5 @@
1
- # encoding: utf-8
2
- #
1
+ # frozen_string_literal: true
2
+
3
3
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
4
  # or more contributor license agreements. See the NOTICE file
5
5
  # distributed with this work for additional information
@@ -19,342 +19,194 @@
19
19
 
20
20
  module Selenium
21
21
  module WebDriver
22
- #
23
- # The ActionBuilder provides the user a way to set up and perform
24
- # complex user interactions.
25
- #
26
- # This class should not be instantiated directly, but is created by
27
- # Selenium::WebDriver::DriverExtensions::HasInputDevices#action, which
28
- # is available on Driver instances that support the user interaction API.
29
- #
30
- # @example
31
- #
32
- # driver.action.key_down(:shift).
33
- # click(element).
34
- # click(second_element).
35
- # key_up(:shift).
36
- # drag_and_drop(element, third_element).
37
- # perform
38
- #
39
-
40
22
  class ActionBuilder
41
- #
42
- # @api private
43
- #
23
+ include KeyActions # Actions specific to key inputs
24
+ include PointerActions # Actions specific to pointer inputs
44
25
 
45
- def initialize(mouse, keyboard)
46
- @devices = {
47
- mouse: mouse,
48
- keyboard: keyboard
49
- }
26
+ attr_reader :devices
50
27
 
51
- @actions = []
52
- end
53
-
54
- #
55
- # Performs a modifier key press. Does not release
56
- # the modifier key - subsequent interactions may assume it's kept pressed.
57
- # Note that the modifier key is never released implicitly - either
58
- # #key_up(key) or #send_keys(:null) must be called to release the modifier.
59
- #
60
- # Equivalent to:
61
- # driver.action.click(element).send_keys(key)
62
- # # or
63
- # driver.action.click.send_keys(key)
64
- #
65
- # @example Press a key
66
28
  #
67
- # driver.action.key_down(:control).perform
29
+ # Initialize a W3C Action Builder. Differs from previous by requiring a bridge and allowing asynchronous actions.
30
+ # The W3C implementation allows asynchronous actions per device. e.g. A key can be pressed at the same time that
31
+ # the mouse is moving. Keep in mind that pauses must be added for other devices in order to line up the actions
32
+ # correctly when using asynchronous.
68
33
  #
69
- # @example Press a key on an element
70
- #
71
- # el = driver.find_element(id: "some_id")
72
- # driver.action.key_down(el, :shift).perform
73
- #
74
- # @param [:shift, :alt, :control, :command, :meta] The key to press.
75
- # @param [Selenium::WebDriver::Element] element An optional element
76
- # @raise [ArgumentError] if the given key is not a modifier
34
+ # @param [Selenium::WebDriver::Remote::Bridge] bridge the bridge for the current driver instance
35
+ # @param [Selenium::WebDriver::Interactions::PointerInput] mouse PointerInput for the mouse.
36
+ # @param [Selenium::WebDriver::Interactions::KeyInput] keyboard KeyInput for the keyboard.
37
+ # @param [Boolean] async Whether to perform the actions asynchronously per device. Defaults to false for
38
+ # backwards compatibility.
77
39
  # @return [ActionBuilder] A self reference.
78
40
  #
79
41
 
80
- def key_down(*args)
81
- @actions << [:mouse, :click, [args.shift]] if args.first.is_a? Element
82
-
83
- @actions << [:keyboard, :press, args]
84
- self
42
+ def initialize(bridge, mouse, keyboard, async = false)
43
+ # For backwards compatibility, automatically include mouse & keyboard
44
+ @bridge = bridge
45
+ @devices = [mouse, keyboard]
46
+ @async = async
85
47
  end
86
48
 
87
49
  #
88
- # Performs a modifier key release.
89
- # Releasing a non-depressed modifier key will yield undefined behaviour.
90
- #
91
- # @example Release a key
50
+ # Adds a PointerInput device of the given kind
92
51
  #
93
- # driver.action.key_up(:shift).perform
52
+ # @example Add a touch pointer input device
94
53
  #
95
- # @example Release a key from an element
54
+ # builder = device.action
55
+ # builder.add_pointer_input('touch', :touch)
96
56
  #
97
- # el = driver.find_element(id: "some_id")
98
- # driver.action.key_up(el, :alt).perform
57
+ # @param [String] name name for the device
58
+ # @param [Symbol] kind kind of pointer device to create
59
+ # @return [Interactions::PointerInput] The pointer input added
99
60
  #
100
- # @param [:shift, :alt, :control, :command, :meta] The modifier key to release.
101
- # @param [Selenium::WebDriver::Element] element An optional element
102
- # @raise [ArgumentError] if the given key is not a modifier key
103
- # @return [ActionBuilder] A self reference.
104
61
  #
105
62
 
106
- def key_up(*args)
107
- @actions << [:mouse, :click, [args.shift]] if args.first.is_a? Element
108
-
109
- @actions << [:keyboard, :release, args]
110
- self
63
+ def add_pointer_input(kind, name)
64
+ new_input = Interactions.pointer(kind, name: name)
65
+ add_input(new_input)
66
+ new_input
111
67
  end
112
68
 
113
69
  #
114
- # Sends keys to the active element. This differs from calling
115
- # Element#send_keys(keys) on the active element in two ways:
116
- #
117
- # * The modifier keys included in this call are not released.
118
- # * There is no attempt to re-focus the element - so send_keys(:tab) for switching elements should work.
70
+ # Adds a KeyInput device
119
71
  #
120
- # @example Send the text "help" to an element
72
+ # @example Add a key input device
121
73
  #
122
- # el = driver.find_element(id: "some_id")
123
- # driver.action.send_keys(el, "help").perform
124
- #
125
- # @example Send the text "help" to the currently focused element
74
+ # builder = device.action
75
+ # builder.add_key_input('keyboard2')
126
76
  #
127
- # driver.action.send_keys("help").perform
77
+ # @param [String] name name for the device
78
+ # @return [Interactions::KeyInput] The key input added
128
79
  #
129
- # @param [Selenium::WebDriver::Element] element An optional element
130
- # @param [String] keys The keys to be sent.
131
- # @return [ActionBuilder] A self reference.
132
- #
133
-
134
- def send_keys(*args)
135
- @actions << [:mouse, :click, [args.shift]] if args.first.is_a? Element
136
80
 
137
- @actions << [:keyboard, :send_keys, args]
138
- self
81
+ def add_key_input(name)
82
+ new_input = Interactions.key(name)
83
+ add_input(new_input)
84
+ new_input
139
85
  end
140
86
 
141
87
  #
142
- # Clicks (without releasing) in the middle of the given element. This is
143
- # equivalent to:
144
- #
145
- # driver.action.move_to(element).click_and_hold
146
- #
147
- # @example Clicking and holding on some element
88
+ # Retrieves the input device for the given name
148
89
  #
149
- # el = driver.find_element(id: "some_id")
150
- # driver.action.click_and_hold(el).perform
151
- #
152
- # @param [Selenium::WebDriver::Element] element the element to move to and click.
153
- # @return [ActionBuilder] A self reference.
90
+ # @param [String] name name of the input device
91
+ # @return [Selenium::WebDriver::Interactions::InputDevice] input device with given name
154
92
  #
155
93
 
156
- def click_and_hold(element = nil)
157
- @actions << [:mouse, :down, [element]]
158
- self
94
+ def get_device(name)
95
+ @devices.find { |device| device.name == name.to_s }
159
96
  end
160
97
 
161
98
  #
162
- # Releases the depressed left mouse button at the current mouse location.
163
- #
164
- # @example Releasing an element after clicking and holding it
99
+ # Retrieves the current PointerInput devices
165
100
  #
166
- # el = driver.find_element(id: "some_id")
167
- # driver.action.click_and_hold(el).release.perform
168
- #
169
- # @return [ActionBuilder] A self reference.
101
+ # @return [Array] array of current PointerInput devices
170
102
  #
171
103
 
172
- def release(element = nil)
173
- @actions << [:mouse, :up, [element]]
174
- self
104
+ def pointer_inputs
105
+ @devices.select { |device| device.type == Interactions::POINTER }
175
106
  end
176
107
 
177
108
  #
178
- # Clicks in the middle of the given element. Equivalent to:
179
- #
180
- # driver.action.move_to(element).click
181
- #
182
- # When no element is passed, the current mouse position will be clicked.
183
- #
184
- # @example Clicking on an element
185
- #
186
- # el = driver.find_element(id: "some_id")
187
- # driver.action.click(el).perform
188
- #
189
- # @example Clicking at the current mouse position
109
+ # Retrieves the current KeyInput device
190
110
  #
191
- # driver.action.click.perform
192
- #
193
- # @param [Selenium::WebDriver::Element] element An optional element to click.
194
- # @return [ActionBuilder] A self reference.
111
+ # @return [Selenium::WebDriver::Interactions::InputDevice] current KeyInput device
195
112
  #
196
113
 
197
- def click(element = nil)
198
- @actions << [:mouse, :click, [element]]
199
- self
114
+ def key_inputs
115
+ @devices.select { |device| device.type == Interactions::KEY }
200
116
  end
201
117
 
202
118
  #
203
- # Performs a double-click at middle of the given element. Equivalent to:
119
+ # Creates a pause for the given device of the given duration. If no duration is given, the pause will only wait
120
+ # for all actions to complete in that tick.
204
121
  #
205
- # driver.action.move_to(element).double_click
122
+ # @example Send keys to an element
206
123
  #
207
- # @example Double click an element
208
- #
209
- # el = driver.find_element(id: "some_id")
210
- # driver.action.double_click(el).perform
124
+ # action_builder = driver.action
125
+ # keyboard = action_builder.key_input
126
+ # el = driver.find_element(id: "some_id")
127
+ # driver.action.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys('keys').perform
211
128
  #
212
- # @param [Selenium::WebDriver::Element] element An optional element to move to.
129
+ # @param [InputDevice] device Input device to pause
130
+ # @param [Float] duration Duration to pause
213
131
  # @return [ActionBuilder] A self reference.
214
132
  #
215
133
 
216
- def double_click(element = nil)
217
- @actions << [:mouse, :double_click, [element]]
134
+ def pause(device, duration = nil)
135
+ device.create_pause(duration)
218
136
  self
219
137
  end
220
138
 
221
139
  #
222
- # Moves the mouse to the middle of the given element. The element is scrolled into
223
- # view and its location is calculated using getBoundingClientRect. Then the
224
- # mouse is moved to optional offset coordinates from the element.
140
+ # Creates multiple pauses for the given device of the given duration.
225
141
  #
226
- # Note that when using offsets, both coordinates need to be passed.
227
- #
228
- # @example Scroll element into view and move the mouse to it
142
+ # @example Send keys to an element
229
143
  #
144
+ # action_builder = driver.action
145
+ # keyboard = action_builder.key_input
230
146
  # el = driver.find_element(id: "some_id")
231
- # driver.action.move_to(el).perform
232
- #
233
- # @example
147
+ # driver.action.click(el).pauses(keyboard, 3).send_keys('keys').perform
234
148
  #
235
- # el = driver.find_element(id: "some_id")
236
- # driver.action.move_to(el, 100, 100).perform
237
- #
238
- # @param [Selenium::WebDriver::Element] element to move to.
239
- # @param [Integer] right_by Optional offset from the top-left corner. A negative value means
240
- # coordinates right from the element.
241
- # @param [Integer] down_by Optional offset from the top-left corner. A negative value means
242
- # coordinates above the element.
149
+ # @param [InputDevice] device Input device to pause
150
+ # @param [Integer] number of pauses to add for the device
151
+ # @param [Float] duration Duration to pause
243
152
  # @return [ActionBuilder] A self reference.
244
153
  #
245
154
 
246
- def move_to(element, right_by = nil, down_by = nil)
247
- @actions << if right_by && down_by
248
- [:mouse, :move_to, [element, Integer(right_by), Integer(down_by)]]
249
- else
250
- [:mouse, :move_to, [element]]
251
- end
252
-
155
+ def pauses(device, number, duration = nil)
156
+ number.times { device.create_pause(duration) }
253
157
  self
254
158
  end
255
159
 
256
160
  #
257
- # Moves the mouse from its current position (or 0,0) by the given offset.
258
- # If the coordinates provided are outside the viewport (the mouse will
259
- # end up outside the browser window) then the viewport is scrolled to
260
- # match.
261
- #
262
- # @example Move the mouse to a certain offset from its current position
263
- #
264
- # driver.action.move_by(100, 100).perform
265
- #
266
- # @param [Integer] right_by horizontal offset. A negative value means moving the
267
- # mouse left.
268
- # @param [Integer] down_by vertical offset. A negative value means moving the mouse
269
- # up.
270
- # @return [ActionBuilder] A self reference.
271
- # @raise [MoveTargetOutOfBoundsError] if the provided offset is outside
272
- # the document's boundaries.
161
+ # Executes the actions added to the builder.
273
162
  #
274
163
 
275
- def move_by(right_by, down_by)
276
- @actions << [:mouse, :move_by, [Integer(right_by), Integer(down_by)]]
277
- self
164
+ def perform
165
+ @bridge.send_actions @devices.map(&:encode).compact
166
+ clear_all_actions
167
+ nil
278
168
  end
279
169
 
280
170
  #
281
- # Performs a context-click at middle of the given element. First performs
282
- # a move_to to the location of the element.
283
- #
284
- # @example Context-click at middle of given element
285
- #
286
- # el = driver.find_element(id: "some_id")
287
- # driver.action.context_click(el).perform
288
- #
289
- # @param [Selenium::WebDriver::Element] element An element to context click.
290
- # @return [ActionBuilder] A self reference.
171
+ # Clears all actions from the builder.
291
172
  #
292
173
 
293
- def context_click(element = nil)
294
- @actions << [:mouse, :context_click, [element]]
295
- self
174
+ def clear_all_actions
175
+ @devices.each(&:clear_actions)
296
176
  end
297
177
 
298
178
  #
299
- # A convenience method that performs click-and-hold at the location of the
300
- # source element, moves to the location of the target element, then
301
- # releases the mouse.
302
- #
303
- # @example Drag and drop one element onto another
304
- #
305
- # el1 = driver.find_element(id: "some_id1")
306
- # el2 = driver.find_element(id: "some_id2")
307
- # driver.action.drag_and_drop(el1, el2).perform
308
- #
309
- # @param [Selenium::WebDriver::Element] source element to emulate button down at.
310
- # @param [Selenium::WebDriver::Element] target element to move to and release the
311
- # mouse at.
312
- # @return [ActionBuilder] A self reference.
179
+ # Releases all action states from the browser.
313
180
  #
314
181
 
315
- def drag_and_drop(source, target)
316
- click_and_hold source
317
- move_to target
318
- release target
319
-
320
- self
182
+ def release_actions
183
+ @bridge.release_actions
321
184
  end
322
185
 
186
+ private
187
+
323
188
  #
324
- # A convenience method that performs click-and-hold at the location of
325
- # the source element, moves by a given offset, then releases the mouse.
326
- #
327
- # @example Drag and drop an element by offset
189
+ # Adds pauses for all devices but the given devices
328
190
  #
329
- # el = driver.find_element(id: "some_id1")
330
- # driver.action.drag_and_drop_by(el, 100, 100).perform
331
- #
332
- # @param [Selenium::WebDriver::Element] source Element to emulate button down at.
333
- # @param [Integer] right_by horizontal move offset.
334
- # @param [Integer] down_by vertical move offset.
335
- # @param [Selenium::WebDriver::Element] target Element to move to and release the
336
- # mouse at.
337
- # @return [ActionBuilder] A self reference.
191
+ # @param [Array[InputDevice]] action_devices Array of Input Devices performing an action in this tick.
338
192
  #
339
193
 
340
- def drag_and_drop_by(source, right_by, down_by)
341
- click_and_hold source
342
- move_by right_by, down_by
343
- release
194
+ def tick(*action_devices)
195
+ return if @async
344
196
 
345
- self
197
+ @devices.each { |device| device.create_pause unless action_devices.include? device }
346
198
  end
347
199
 
348
200
  #
349
- # Executes the actions added to the builder.
201
+ # Adds an InputDevice
350
202
  #
351
203
 
352
- def perform
353
- @actions.each do |receiver, method, args|
354
- @devices.fetch(receiver).__send__(method, *args)
204
+ def add_input(device)
205
+ unless @async
206
+ max_device = @devices.max { |a, b| a.actions.length <=> b.actions.length }
207
+ pauses(device, max_device.actions.length)
355
208
  end
356
-
357
- nil
209
+ @devices << device
358
210
  end
359
211
  end # ActionBuilder
360
212
  end # WebDriver