selenium-webdriver 4.1.0 → 4.4.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.
- checksums.yaml +4 -4
- data/CHANGES +85 -1
- data/LICENSE +1 -1
- data/NOTICE +1 -1
- data/lib/selenium/server.rb +15 -10
- data/lib/selenium/webdriver/bidi/session.rb +38 -0
- data/lib/selenium/webdriver/bidi.rb +55 -0
- data/lib/selenium/webdriver/chrome/features.rb +5 -0
- data/lib/selenium/webdriver/chrome/options.rb +33 -19
- data/lib/selenium/webdriver/chrome.rb +0 -14
- data/lib/selenium/webdriver/common/action_builder.rb +108 -21
- data/lib/selenium/webdriver/common/driver.rb +22 -55
- data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_bidi.rb} +12 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +10 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +1 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +2 -67
- data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +1 -1
- data/lib/selenium/webdriver/common/element.rb +1 -1
- data/lib/selenium/webdriver/common/error.rb +1 -1
- data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
- data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -25
- data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -1
- data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
- data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
- data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +59 -70
- data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
- data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
- data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
- data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
- data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
- data/lib/selenium/webdriver/common/interactions/scroll.rb +57 -0
- data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
- data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
- data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
- data/lib/selenium/webdriver/common/interactions/wheel_input.rb +42 -0
- data/lib/selenium/webdriver/common/keys.rb +1 -0
- data/lib/selenium/webdriver/common/manager.rb +0 -27
- data/lib/selenium/webdriver/common/options.rb +2 -9
- data/lib/selenium/webdriver/common/platform.rb +4 -4
- data/lib/selenium/webdriver/common/search_context.rb +0 -6
- data/lib/selenium/webdriver/common/service_manager.rb +2 -3
- data/lib/selenium/webdriver/common/shadow_root.rb +1 -1
- data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
- data/lib/selenium/webdriver/common/takes_screenshot.rb +1 -1
- data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +83 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +73 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
- data/lib/selenium/webdriver/common/websocket_connection.rb +156 -0
- data/lib/selenium/webdriver/common/window.rb +6 -6
- data/lib/selenium/webdriver/common/zipper.rb +1 -1
- data/lib/selenium/webdriver/common.rb +17 -3
- data/lib/selenium/webdriver/devtools/network_interceptor.rb +176 -0
- data/lib/selenium/webdriver/devtools/request.rb +1 -1
- data/lib/selenium/webdriver/devtools/response.rb +1 -1
- data/lib/selenium/webdriver/devtools.rb +6 -112
- data/lib/selenium/webdriver/edge/features.rb +1 -0
- data/lib/selenium/webdriver/firefox/driver.rb +1 -0
- data/lib/selenium/webdriver/firefox/features.rb +2 -5
- data/lib/selenium/webdriver/firefox/options.rb +3 -1
- data/lib/selenium/webdriver/firefox/profile.rb +1 -5
- data/lib/selenium/webdriver/firefox/util.rb +46 -0
- data/lib/selenium/webdriver/firefox.rb +1 -14
- data/lib/selenium/webdriver/ie.rb +0 -14
- data/lib/selenium/webdriver/remote/bridge.rb +54 -19
- data/lib/selenium/webdriver/remote/commands.rb +15 -6
- data/lib/selenium/webdriver/remote/driver.rb +0 -1
- data/lib/selenium/webdriver/remote/http/default.rb +6 -12
- data/lib/selenium/webdriver/remote/response.rb +2 -2
- data/lib/selenium/webdriver/safari.rb +0 -14
- data/lib/selenium/webdriver/support/cdp_client_generator.rb +4 -4
- data/lib/selenium/webdriver/support/color.rb +7 -7
- data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -1
- data/lib/selenium/webdriver/support/guards.rb +1 -1
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +1 -0
- data/selenium-webdriver.gemspec +9 -6
- metadata +64 -12
- data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
|
@@ -123,8 +123,8 @@ module Selenium
|
|
|
123
123
|
# @see ActionBuilder
|
|
124
124
|
#
|
|
125
125
|
|
|
126
|
-
def action
|
|
127
|
-
bridge.action
|
|
126
|
+
def action(**opts)
|
|
127
|
+
bridge.action(**opts)
|
|
128
128
|
end
|
|
129
129
|
|
|
130
130
|
def mouse
|
|
@@ -248,6 +248,15 @@ module Selenium
|
|
|
248
248
|
bridge.execute_async_script(script, *args)
|
|
249
249
|
end
|
|
250
250
|
|
|
251
|
+
#
|
|
252
|
+
# @return [VirtualAuthenticator]
|
|
253
|
+
# @see VirtualAuthenticator
|
|
254
|
+
#
|
|
255
|
+
|
|
256
|
+
def add_virtual_authenticator(options)
|
|
257
|
+
bridge.add_virtual_authenticator(options)
|
|
258
|
+
end
|
|
259
|
+
|
|
251
260
|
#-------------------------------- sugar --------------------------------
|
|
252
261
|
|
|
253
262
|
#
|
|
@@ -307,71 +316,29 @@ module Selenium
|
|
|
307
316
|
|
|
308
317
|
attr_reader :bridge
|
|
309
318
|
|
|
310
|
-
def create_bridge(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
desired_capabilities = opts.delete(:desired_capabilities)
|
|
317
|
-
if desired_capabilities
|
|
318
|
-
WebDriver.logger.deprecate(':desired_capabilities as a parameter for driver initialization',
|
|
319
|
-
':capabilities with an Array value of capabilities/options if necessary',
|
|
320
|
-
id: :desired_capabilities)
|
|
321
|
-
desired_capabilities = Remote::Capabilities.new(desired_capabilities) if desired_capabilities.is_a?(Hash)
|
|
322
|
-
cap_array << desired_capabilities
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
options = opts.delete(:options)
|
|
326
|
-
if options
|
|
327
|
-
WebDriver.logger.deprecate(':options as a parameter for driver initialization',
|
|
328
|
-
':capabilities with an Array of value capabilities/options if necessary',
|
|
329
|
-
id: :browser_options)
|
|
330
|
-
cap_array << options
|
|
319
|
+
def create_bridge(capabilities: nil, options: nil, url: nil, service: nil, http_client: nil)
|
|
320
|
+
Remote::Bridge.new(http_client: http_client,
|
|
321
|
+
url: url || service_url(service)).tap do |bridge|
|
|
322
|
+
generated_caps = options ? options.as_json : generate_capabilities(capabilities)
|
|
323
|
+
bridge.create_session(generated_caps)
|
|
331
324
|
end
|
|
332
|
-
|
|
333
|
-
capabilities = generate_capabilities(cap_array)
|
|
334
|
-
|
|
335
|
-
bridge_opts = {http_client: opts.delete(:http_client), url: opts.delete(:url)}
|
|
336
|
-
raise ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
|
|
337
|
-
|
|
338
|
-
bridge = Remote::Bridge.new(**bridge_opts)
|
|
339
|
-
|
|
340
|
-
bridge.create_session(capabilities)
|
|
341
|
-
bridge
|
|
342
325
|
end
|
|
343
326
|
|
|
344
|
-
def generate_capabilities(
|
|
345
|
-
|
|
327
|
+
def generate_capabilities(capabilities)
|
|
328
|
+
Array(capabilities).map { |cap|
|
|
346
329
|
if cap.is_a? Symbol
|
|
347
330
|
cap = Remote::Capabilities.send(cap)
|
|
348
|
-
elsif cap.is_a? Hash
|
|
349
|
-
new_message = 'Capabilities instance initialized with the Hash, or build values with Options class'
|
|
350
|
-
WebDriver.logger.deprecate("passing a Hash value to :capabilities",
|
|
351
|
-
new_message,
|
|
352
|
-
id: :capabilities_hash)
|
|
353
|
-
cap = Remote::Capabilities.new(cap)
|
|
354
331
|
elsif !cap.respond_to? :as_json
|
|
355
332
|
msg = ":capabilities parameter only accepts objects responding to #as_json which #{cap.class} does not"
|
|
356
333
|
raise ArgumentError, msg
|
|
357
334
|
end
|
|
358
|
-
cap
|
|
335
|
+
cap.as_json
|
|
359
336
|
}.inject(:merge) || Remote::Capabilities.send(browser || :new)
|
|
360
337
|
end
|
|
361
338
|
|
|
362
|
-
def service_url(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
next unless opts.key? key
|
|
366
|
-
|
|
367
|
-
WebDriver.logger.deprecate(":#{key}", ':service with an instance of Selenium::WebDriver::Service',
|
|
368
|
-
id: "service_#{key}".to_sym)
|
|
369
|
-
end
|
|
370
|
-
service_config ||= Service.send(browser,
|
|
371
|
-
args: opts.delete(:driver_opts),
|
|
372
|
-
path: opts.delete(:driver_path),
|
|
373
|
-
port: opts.delete(:port))
|
|
374
|
-
@service = service_config.launch
|
|
339
|
+
def service_url(service)
|
|
340
|
+
service ||= Service.send(browser)
|
|
341
|
+
@service = service.launch
|
|
375
342
|
@service.uri
|
|
376
343
|
end
|
|
377
344
|
|
|
@@ -20,12 +20,19 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module DriverExtensions
|
|
23
|
-
module
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
module HasBiDi
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# Retrieves WebDriver BiDi connection.
|
|
27
|
+
#
|
|
28
|
+
# @return [BiDi]
|
|
29
|
+
#
|
|
30
|
+
|
|
31
|
+
def bidi
|
|
32
|
+
@bidi ||= Selenium::WebDriver::BiDi.new(url: capabilities[:web_socket_url])
|
|
27
33
|
end
|
|
28
|
-
|
|
34
|
+
|
|
35
|
+
end # HasBiDi
|
|
29
36
|
end # DriverExtensions
|
|
30
37
|
end # WebDriver
|
|
31
38
|
end # Selenium
|
|
@@ -52,6 +52,16 @@ module Selenium
|
|
|
52
52
|
@bridge.start_cast_tab_mirroring(name)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
#
|
|
56
|
+
# Starts a tab mirroring session on a specific receiver target.
|
|
57
|
+
#
|
|
58
|
+
# @param [String] name the sink to use as the target
|
|
59
|
+
#
|
|
60
|
+
|
|
61
|
+
def start_cast_desktop_mirroring(name)
|
|
62
|
+
@bridge.start_cast_desktop_mirroring(name)
|
|
63
|
+
end
|
|
64
|
+
|
|
55
65
|
#
|
|
56
66
|
# Gets error messages when there is any issue in a Cast session.
|
|
57
67
|
#
|
|
@@ -27,8 +27,7 @@ module Selenium
|
|
|
27
27
|
# a `with` statement. The state of the context on the server is
|
|
28
28
|
# saved before entering the block, and restored upon exiting it.
|
|
29
29
|
#
|
|
30
|
-
# @param [String]
|
|
31
|
-
# @param [String] value what to set the permission to
|
|
30
|
+
# @param [String] value which context gets set (either 'chrome' or 'content')
|
|
32
31
|
#
|
|
33
32
|
|
|
34
33
|
def context=(value)
|
|
@@ -114,7 +114,7 @@ module Selenium
|
|
|
114
114
|
execute_script(mutation_listener)
|
|
115
115
|
devtools.page.add_script_to_evaluate_on_new_document(source: mutation_listener)
|
|
116
116
|
|
|
117
|
-
devtools.runtime.on(:binding_called
|
|
117
|
+
devtools.runtime.on(:binding_called) { |event| log_mutation_event(event) }
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
def log_mutation_event(params)
|
|
@@ -61,75 +61,10 @@ module Selenium
|
|
|
61
61
|
#
|
|
62
62
|
|
|
63
63
|
def intercept(&block)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
id = params['requestId']
|
|
67
|
-
if params.key?('responseStatusCode') || params.key?('responseErrorReason')
|
|
68
|
-
intercept_response(id, params, &pending_response_requests.delete(id))
|
|
69
|
-
else
|
|
70
|
-
intercept_request(id, params, &block)
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
devtools.fetch.enable(patterns: [{requestStage: 'Request'}, {requestStage: 'Response'}])
|
|
64
|
+
@interceptor ||= DevTools::NetworkInterceptor.new(devtools)
|
|
65
|
+
@interceptor.intercept(&block)
|
|
74
66
|
end
|
|
75
67
|
|
|
76
|
-
private
|
|
77
|
-
|
|
78
|
-
def pending_response_requests
|
|
79
|
-
@pending_response_requests ||= {}
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def intercept_request(id, params, &block)
|
|
83
|
-
original = DevTools::Request.from(id, params)
|
|
84
|
-
mutable = DevTools::Request.from(id, params)
|
|
85
|
-
|
|
86
|
-
block.call(mutable) do |&continue| # rubocop:disable Performance/RedundantBlockCall
|
|
87
|
-
pending_response_requests[id] = continue
|
|
88
|
-
|
|
89
|
-
if original == mutable
|
|
90
|
-
devtools.fetch.continue_request(request_id: id)
|
|
91
|
-
else
|
|
92
|
-
devtools.fetch.continue_request(
|
|
93
|
-
request_id: id,
|
|
94
|
-
url: mutable.url,
|
|
95
|
-
method: mutable.method,
|
|
96
|
-
post_data: mutable.post_data,
|
|
97
|
-
headers: mutable.headers.map do |k, v|
|
|
98
|
-
{name: k, value: v}
|
|
99
|
-
end
|
|
100
|
-
)
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def intercept_response(id, params)
|
|
106
|
-
return devtools.fetch.continue_request(request_id: id) unless block_given?
|
|
107
|
-
|
|
108
|
-
body = fetch_response_body(id)
|
|
109
|
-
original = DevTools::Response.from(id, body, params)
|
|
110
|
-
mutable = DevTools::Response.from(id, body, params)
|
|
111
|
-
yield mutable
|
|
112
|
-
|
|
113
|
-
if original == mutable
|
|
114
|
-
devtools.fetch.continue_request(request_id: id)
|
|
115
|
-
else
|
|
116
|
-
devtools.fetch.fulfill_request(
|
|
117
|
-
request_id: id,
|
|
118
|
-
body: (Base64.strict_encode64(mutable.body) if mutable.body),
|
|
119
|
-
response_code: mutable.code,
|
|
120
|
-
response_headers: mutable.headers.map do |k, v|
|
|
121
|
-
{name: k, value: v}
|
|
122
|
-
end
|
|
123
|
-
)
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def fetch_response_body(id)
|
|
128
|
-
devtools.fetch.get_response_body(request_id: id).dig('result', 'body')
|
|
129
|
-
rescue Error::WebDriverError
|
|
130
|
-
# CDP fails to get body on certain responses (301) and raises:
|
|
131
|
-
# Can only get response body on requests captured after headers received.
|
|
132
|
-
end
|
|
133
68
|
end # HasNetworkInterception
|
|
134
69
|
end # DriverExtensions
|
|
135
70
|
end # WebDriver
|
|
@@ -29,7 +29,7 @@ module Selenium
|
|
|
29
29
|
def self.for_error(error)
|
|
30
30
|
return if error.nil?
|
|
31
31
|
|
|
32
|
-
klass_name = error.split
|
|
32
|
+
klass_name = error.split.map(&:capitalize).join.sub(/Error$/, '')
|
|
33
33
|
const_get("#{klass_name}Error", false)
|
|
34
34
|
rescue NameError
|
|
35
35
|
WebDriverError
|
|
@@ -22,8 +22,15 @@ require 'securerandom'
|
|
|
22
22
|
module Selenium
|
|
23
23
|
module WebDriver
|
|
24
24
|
module Interactions
|
|
25
|
+
#
|
|
26
|
+
# Superclass for the input device sources
|
|
27
|
+
# Manages Array of Interaction instances for the device
|
|
28
|
+
#
|
|
29
|
+
# @api private
|
|
30
|
+
#
|
|
31
|
+
|
|
25
32
|
class InputDevice
|
|
26
|
-
attr_reader :name, :actions
|
|
33
|
+
attr_reader :name, :actions, :type
|
|
27
34
|
|
|
28
35
|
def initialize(name = nil)
|
|
29
36
|
@name = name || SecureRandom.uuid
|
|
@@ -44,9 +51,8 @@ module Selenium
|
|
|
44
51
|
add_action(Pause.new(self, duration))
|
|
45
52
|
end
|
|
46
53
|
|
|
47
|
-
def
|
|
48
|
-
actions
|
|
49
|
-
actions.empty?
|
|
54
|
+
def encode
|
|
55
|
+
{type: type, id: name, actions: @actions.map(&:encode)} unless @actions.empty?
|
|
50
56
|
end
|
|
51
57
|
end # InputDevice
|
|
52
58
|
end # Interactions
|
|
@@ -20,37 +20,24 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Interactions
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
#
|
|
24
|
+
# Superclass for classes defining actions
|
|
25
|
+
# Do not initialize directly, only use subclass
|
|
26
|
+
#
|
|
27
|
+
# @api private
|
|
28
|
+
#
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
class Interaction
|
|
31
|
+
attr_reader :type
|
|
27
32
|
|
|
28
33
|
def initialize(source)
|
|
29
|
-
|
|
30
|
-
raise TypeError,
|
|
31
|
-
"#{source.type} is not a valid input type"
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
@source = source
|
|
34
|
+
assert_source(source)
|
|
35
35
|
end
|
|
36
|
-
end
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
super(source)
|
|
41
|
-
@duration = duration
|
|
37
|
+
def assert_source(_source)
|
|
38
|
+
raise NotImplementedError, 'subclass responsibility'
|
|
42
39
|
end
|
|
43
|
-
|
|
44
|
-
def type
|
|
45
|
-
PAUSE
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def encode
|
|
49
|
-
output = {type: type}
|
|
50
|
-
output[:duration] = (@duration * 1000).to_i if @duration
|
|
51
|
-
output
|
|
52
|
-
end
|
|
53
|
-
end # Interaction
|
|
40
|
+
end
|
|
54
41
|
end # Interactions
|
|
55
42
|
end # WebDriver
|
|
56
43
|
end # Selenium
|
|
@@ -23,20 +23,40 @@ module Selenium
|
|
|
23
23
|
KEY = :key
|
|
24
24
|
POINTER = :pointer
|
|
25
25
|
NONE = :none
|
|
26
|
-
|
|
26
|
+
WHEEL = :wheel
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# Class methods for initializing known Input devices
|
|
30
|
+
#
|
|
27
31
|
|
|
28
32
|
class << self
|
|
29
|
-
def key(name)
|
|
33
|
+
def key(name = nil)
|
|
30
34
|
KeyInput.new(name)
|
|
31
35
|
end
|
|
32
36
|
|
|
33
|
-
def pointer(kind,
|
|
34
|
-
PointerInput.new(kind,
|
|
37
|
+
def pointer(kind = :mouse, name: nil)
|
|
38
|
+
PointerInput.new(kind, name: name)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def mouse(name: nil)
|
|
42
|
+
pointer(name: name)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def pen(name: nil)
|
|
46
|
+
pointer(:pen, name: name)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def touch(name: nil)
|
|
50
|
+
pointer(:touch, name: name)
|
|
35
51
|
end
|
|
36
52
|
|
|
37
53
|
def none(name = nil)
|
|
38
54
|
NoneInput.new(name)
|
|
39
55
|
end
|
|
56
|
+
|
|
57
|
+
def wheel(name = nil)
|
|
58
|
+
WheelInput.new(name)
|
|
59
|
+
end
|
|
40
60
|
end
|
|
41
61
|
end # Interactions
|
|
42
62
|
end # WebDriver
|
|
@@ -134,12 +134,16 @@ module Selenium
|
|
|
134
134
|
#
|
|
135
135
|
|
|
136
136
|
def key_action(*args, action: nil, device: nil)
|
|
137
|
-
key_input =
|
|
137
|
+
key_input = key_input(device)
|
|
138
138
|
click(args.shift) if args.first.is_a? Element
|
|
139
139
|
key_input.send(action, args.last)
|
|
140
140
|
tick(key_input)
|
|
141
141
|
self
|
|
142
142
|
end
|
|
143
|
+
|
|
144
|
+
def key_input(name = nil)
|
|
145
|
+
device(name: name, type: Interactions::KEY) || add_key_input('keyboard')
|
|
146
|
+
end
|
|
143
147
|
end # KeyActions
|
|
144
148
|
end # WebDriver
|
|
145
149
|
end # Selenium
|
|
@@ -20,17 +20,18 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Interactions
|
|
23
|
+
#
|
|
24
|
+
# Creates actions specific to Key Input devices
|
|
25
|
+
#
|
|
26
|
+
# @api private
|
|
27
|
+
#
|
|
28
|
+
|
|
23
29
|
class KeyInput < InputDevice
|
|
24
30
|
SUBTYPES = {down: :keyDown, up: :keyUp, pause: :pause}.freeze
|
|
25
31
|
|
|
26
|
-
def
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def encode
|
|
31
|
-
return nil if no_actions?
|
|
32
|
-
|
|
33
|
-
{type: type, id: name, actions: @actions.map(&:encode)}
|
|
32
|
+
def initialize(name = nil)
|
|
33
|
+
super
|
|
34
|
+
@type = Interactions::KEY
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
def create_key_down(key)
|
|
@@ -41,25 +42,8 @@ module Selenium
|
|
|
41
42
|
add_action(TypingInteraction.new(self, :up, key))
|
|
42
43
|
end
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def initialize(source, type, key)
|
|
48
|
-
super(source)
|
|
49
|
-
@type = assert_type(type)
|
|
50
|
-
@key = Keys.encode_key(key)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def assert_type(type)
|
|
54
|
-
raise TypeError, "#{type.inspect} is not a valid key subtype" unless KeyInput::SUBTYPES.key? type
|
|
55
|
-
|
|
56
|
-
KeyInput::SUBTYPES[type]
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def encode
|
|
60
|
-
{type: @type, value: @key}
|
|
61
|
-
end
|
|
62
|
-
end # TypingInteraction
|
|
45
|
+
# Backward compatibility in case anyone called this directly
|
|
46
|
+
class TypingInteraction < Interactions::TypingInteraction; end
|
|
63
47
|
end # KeyInput
|
|
64
48
|
end # Interactions
|
|
65
49
|
end # WebDriver
|
|
@@ -20,15 +20,17 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Interactions
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
#
|
|
24
|
+
# Creates actions specific to null input source
|
|
25
|
+
# This is primarily used for adding pauses
|
|
26
|
+
#
|
|
27
|
+
# @api private
|
|
28
|
+
#
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
class NoneInput < InputDevice
|
|
31
|
+
def initialize(name = nil)
|
|
32
|
+
super
|
|
33
|
+
@type = Interactions::NONE
|
|
32
34
|
end
|
|
33
35
|
end # NoneInput
|
|
34
36
|
end # Interactions
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
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 Interactions
|
|
23
|
+
#
|
|
24
|
+
# Action to create a waiting period between actions
|
|
25
|
+
# Also used for synchronizing actions across devices
|
|
26
|
+
#
|
|
27
|
+
# @api private
|
|
28
|
+
#
|
|
29
|
+
|
|
30
|
+
class Pause < Interaction
|
|
31
|
+
def initialize(source, duration = nil)
|
|
32
|
+
super(source)
|
|
33
|
+
@duration = duration
|
|
34
|
+
@type = :pause
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def assert_source(source)
|
|
38
|
+
raise TypeError, "#{source.type} is not a valid input type" unless source.is_a? InputDevice
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def encode
|
|
42
|
+
output = {type: type}
|
|
43
|
+
output[:duration] = (@duration * 1000).to_i if @duration
|
|
44
|
+
output
|
|
45
|
+
end
|
|
46
|
+
end # Pause
|
|
47
|
+
end # Interactions
|
|
48
|
+
end # WebDriver
|
|
49
|
+
end # Selenium
|