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.
- checksums.yaml +7 -0
- data/CHANGES +363 -10
- data/LICENSE +1 -1
- data/README.md +2 -3
- data/lib/selenium-webdriver.rb +0 -2
- data/lib/selenium/server.rb +69 -70
- data/lib/selenium/webdriver.rb +32 -23
- data/lib/selenium/webdriver/atoms.rb +18 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +8 -0
- data/lib/selenium/webdriver/chrome.rb +8 -6
- data/lib/selenium/webdriver/chrome/driver.rb +112 -0
- data/lib/selenium/webdriver/chrome/options.rb +168 -0
- data/lib/selenium/webdriver/chrome/profile.rb +17 -17
- data/lib/selenium/webdriver/chrome/service.rb +22 -89
- data/lib/selenium/webdriver/common.rb +13 -6
- data/lib/selenium/webdriver/common/action_builder.rb +49 -57
- data/lib/selenium/webdriver/common/alert.rb +5 -15
- data/lib/selenium/webdriver/common/bridge_helper.rb +10 -17
- data/lib/selenium/webdriver/common/driver.rb +53 -68
- data/lib/selenium/webdriver/common/driver_extensions/{has_input_devices.rb → has_addons.rb} +13 -23
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +4 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +4 -7
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +0 -4
- data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +0 -4
- data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +1 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +0 -5
- data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +4 -9
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +7 -7
- data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +2 -7
- data/lib/selenium/webdriver/common/element.rb +57 -39
- data/lib/selenium/webdriver/common/error.rb +204 -106
- data/lib/selenium/webdriver/common/file_reaper.rb +3 -11
- data/lib/selenium/webdriver/common/html5/local_storage.rb +6 -10
- data/lib/selenium/webdriver/common/html5/session_storage.rb +6 -10
- data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +7 -18
- data/lib/selenium/webdriver/{safari/options.rb → common/interactions/input_device.rb} +20 -31
- data/lib/selenium/webdriver/common/interactions/interaction.rb +50 -0
- data/lib/selenium/webdriver/{safari/browser.rb → common/interactions/interactions.rb} +16 -15
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +143 -0
- data/lib/selenium/webdriver/common/interactions/key_input.rb +62 -0
- data/lib/selenium/webdriver/{android.rb → common/interactions/none_input.rb} +11 -6
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +353 -0
- data/lib/selenium/webdriver/common/interactions/pointer_input.rb +132 -0
- data/lib/selenium/webdriver/common/keyboard.rb +7 -14
- data/lib/selenium/webdriver/common/keys.rb +99 -82
- data/lib/selenium/webdriver/common/log_entry.rb +3 -6
- data/lib/selenium/webdriver/common/logger.rb +140 -0
- data/lib/selenium/webdriver/common/logs.rb +2 -6
- data/lib/selenium/webdriver/common/mouse.rb +9 -14
- data/lib/selenium/webdriver/common/navigation.rb +2 -6
- data/lib/selenium/webdriver/common/options.rb +20 -23
- data/lib/selenium/webdriver/common/platform.rb +70 -97
- data/lib/selenium/webdriver/common/port_prober.rb +3 -4
- data/lib/selenium/webdriver/common/profile_helper.rb +6 -11
- data/lib/selenium/webdriver/common/proxy.rb +58 -72
- data/lib/selenium/webdriver/common/search_context.rb +22 -29
- data/lib/selenium/webdriver/common/service.rb +161 -0
- data/lib/selenium/webdriver/common/socket_lock.rb +6 -14
- data/lib/selenium/webdriver/common/socket_poller.rb +5 -12
- data/lib/selenium/webdriver/common/target_locator.rb +11 -15
- data/lib/selenium/webdriver/common/timeouts.rb +4 -8
- data/lib/selenium/webdriver/common/touch_action_builder.rb +2 -6
- data/lib/selenium/webdriver/common/touch_screen.rb +19 -23
- data/lib/selenium/webdriver/common/w3c_action_builder.rb +209 -0
- data/lib/selenium/webdriver/{phantomjs.rb → common/w3c_options.rb} +16 -14
- data/lib/selenium/webdriver/common/wait.rb +6 -13
- data/lib/selenium/webdriver/common/window.rb +48 -17
- data/lib/selenium/webdriver/common/zipper.rb +6 -10
- data/lib/selenium/webdriver/edge.rb +5 -12
- data/lib/selenium/webdriver/edge/bridge.rb +32 -63
- data/lib/selenium/webdriver/edge/driver.rb +73 -0
- data/lib/selenium/webdriver/edge/service.rb +18 -87
- data/lib/selenium/webdriver/firefox.rb +20 -11
- data/lib/selenium/webdriver/firefox/binary.rb +40 -56
- data/lib/selenium/webdriver/firefox/driver.rb +48 -0
- data/lib/selenium/webdriver/firefox/extension.rb +18 -8
- data/lib/selenium/webdriver/firefox/extension/prefs.json +3 -11
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/launcher.rb +13 -22
- data/lib/selenium/webdriver/firefox/legacy/driver.rb +79 -0
- data/lib/selenium/webdriver/{iphone.rb → firefox/marionette/bridge.rb} +25 -6
- data/lib/selenium/webdriver/firefox/marionette/driver.rb +96 -0
- data/lib/selenium/webdriver/firefox/options.rb +149 -0
- data/lib/selenium/webdriver/firefox/profile.rb +46 -46
- data/lib/selenium/webdriver/firefox/profiles_ini.rb +8 -18
- data/lib/selenium/webdriver/firefox/service.rb +23 -83
- data/lib/selenium/webdriver/firefox/util.rb +0 -4
- data/lib/selenium/webdriver/ie.rb +4 -8
- data/lib/selenium/webdriver/ie/driver.rb +90 -0
- data/lib/selenium/webdriver/ie/options.rb +136 -0
- data/lib/selenium/webdriver/ie/service.rb +58 -0
- data/lib/selenium/webdriver/remote.rb +8 -16
- data/lib/selenium/webdriver/remote/bridge.rb +96 -565
- data/lib/selenium/webdriver/remote/capabilities.rb +76 -94
- data/lib/selenium/webdriver/remote/driver.rb +49 -0
- data/lib/selenium/webdriver/remote/http/common.rb +22 -20
- data/lib/selenium/webdriver/remote/http/curb.rb +9 -12
- data/lib/selenium/webdriver/remote/http/default.rb +54 -41
- data/lib/selenium/webdriver/remote/http/persistent.rb +9 -8
- data/lib/selenium/webdriver/remote/oss/bridge.rb +586 -0
- data/lib/selenium/webdriver/remote/oss/commands.rb +221 -0
- data/lib/selenium/webdriver/remote/response.rb +39 -27
- data/lib/selenium/webdriver/remote/server_error.rb +1 -5
- data/lib/selenium/webdriver/remote/w3c/bridge.rb +573 -0
- data/lib/selenium/webdriver/remote/w3c/capabilities.rb +290 -0
- data/lib/selenium/webdriver/remote/w3c/commands.rb +148 -0
- data/lib/selenium/webdriver/safari.rb +20 -29
- data/lib/selenium/webdriver/{firefox/w3c_bridge.rb → safari/driver.rb} +21 -30
- data/lib/selenium/webdriver/safari/service.rb +57 -0
- data/lib/selenium/webdriver/support.rb +1 -2
- data/lib/selenium/webdriver/support/abstract_event_listener.rb +17 -4
- data/lib/selenium/webdriver/support/block_event_listener.rb +1 -5
- data/lib/selenium/webdriver/support/color.rb +57 -42
- data/lib/selenium/webdriver/support/escaper.rb +41 -0
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +36 -40
- data/lib/selenium/webdriver/support/select.rb +33 -86
- data/selenium-webdriver.gemspec +22 -25
- metadata +254 -261
- data/lib/selenium-client.rb +0 -21
- data/lib/selenium/client.rb +0 -57
- data/lib/selenium/client/base.rb +0 -151
- data/lib/selenium/client/driver.rb +0 -29
- data/lib/selenium/client/errors.rb +0 -28
- data/lib/selenium/client/extensions.rb +0 -132
- data/lib/selenium/client/idiomatic.rb +0 -507
- data/lib/selenium/client/javascript_expression_builder.rb +0 -135
- data/lib/selenium/client/javascript_frameworks/jquery.rb +0 -32
- data/lib/selenium/client/javascript_frameworks/prototype.rb +0 -32
- data/lib/selenium/client/legacy_driver.rb +0 -1722
- data/lib/selenium/client/protocol.rb +0 -123
- data/lib/selenium/client/selenium_helper.rb +0 -49
- data/lib/selenium/rake/server_task.rb +0 -176
- data/lib/selenium/webdriver/android/bridge.rb +0 -68
- data/lib/selenium/webdriver/chrome/bridge.rb +0 -139
- data/lib/selenium/webdriver/common/core_ext/base64.rb +0 -28
- data/lib/selenium/webdriver/common/core_ext/dir.rb +0 -61
- data/lib/selenium/webdriver/common/html5/location.rb +0 -19
- data/lib/selenium/webdriver/common/w3c_error.rb +0 -194
- data/lib/selenium/webdriver/edge/legacy_support.rb +0 -117
- data/lib/selenium/webdriver/firefox/bridge.rb +0 -89
- data/lib/selenium/webdriver/ie/bridge.rb +0 -88
- data/lib/selenium/webdriver/ie/server.rb +0 -133
- data/lib/selenium/webdriver/iphone/bridge.rb +0 -64
- data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -78
- data/lib/selenium/webdriver/phantomjs/service.rb +0 -130
- data/lib/selenium/webdriver/remote/commands.rb +0 -211
- data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -668
- data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -236
- data/lib/selenium/webdriver/remote/w3c_commands.rb +0 -132
- data/lib/selenium/webdriver/safari/bridge.rb +0 -135
- data/lib/selenium/webdriver/safari/resources/client.js +0 -7255
- data/lib/selenium/webdriver/safari/server.rb +0 -187
|
@@ -0,0 +1,90 @@
|
|
|
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 IE
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Driver implementation for Internet Explorer supporting
|
|
24
|
+
# both OSS and W3C dialects of JSON wire protocol.
|
|
25
|
+
# @api private
|
|
26
|
+
#
|
|
27
|
+
|
|
28
|
+
class Driver < WebDriver::Driver
|
|
29
|
+
include DriverExtensions::TakesScreenshot
|
|
30
|
+
|
|
31
|
+
def initialize(opts = {})
|
|
32
|
+
opts[:desired_capabilities] = create_capabilities(opts)
|
|
33
|
+
|
|
34
|
+
unless opts.key?(:url)
|
|
35
|
+
driver_path = opts.delete(:driver_path) || IE.driver_path
|
|
36
|
+
driver_opts = opts.delete(:driver_opts) || {}
|
|
37
|
+
port = opts.delete(:port) || Service::DEFAULT_PORT
|
|
38
|
+
|
|
39
|
+
@service = Service.new(driver_path, port, driver_opts)
|
|
40
|
+
@service.start
|
|
41
|
+
opts[:url] = @service.uri
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
listener = opts.delete(:listener)
|
|
45
|
+
@bridge = Remote::Bridge.handshake(opts)
|
|
46
|
+
super(@bridge, listener: listener)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def browser
|
|
50
|
+
:internet_explorer
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def quit
|
|
54
|
+
super
|
|
55
|
+
ensure
|
|
56
|
+
@service.stop if @service
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def create_capabilities(opts)
|
|
62
|
+
caps = opts.delete(:desired_capabilities) { Remote::Capabilities.internet_explorer }
|
|
63
|
+
options = opts.delete(:options) { Options.new }
|
|
64
|
+
|
|
65
|
+
if opts.delete(:introduce_flakiness_by_ignoring_security_domains)
|
|
66
|
+
WebDriver.logger.deprecate ':introduce_flakiness_by_ignoring_security_domains',
|
|
67
|
+
'Selenium::WebDriver::IE::Options#ignore_protected_mode_settings='
|
|
68
|
+
options.ignore_protected_mode_settings = true
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
native_events = opts.delete(:native_events)
|
|
72
|
+
unless native_events.nil?
|
|
73
|
+
WebDriver.logger.deprecate ':native_events', 'Selenium::WebDriver::IE::Options#native_events='
|
|
74
|
+
options.native_events = native_events
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Backward compatibility with older IEDriverServer versions
|
|
78
|
+
caps[:ignore_protected_mode_settings] = options.ignore_protected_mode_settings
|
|
79
|
+
caps[:native_events] = options.native_events
|
|
80
|
+
|
|
81
|
+
options = options.as_json
|
|
82
|
+
caps.merge!(options) unless options.empty?
|
|
83
|
+
|
|
84
|
+
caps
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end # Driver
|
|
88
|
+
end # IE
|
|
89
|
+
end # WebDriver
|
|
90
|
+
end # Selenium
|
|
@@ -0,0 +1,136 @@
|
|
|
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 IE
|
|
21
|
+
class Options
|
|
22
|
+
KEY = 'se:ieOptions'.freeze
|
|
23
|
+
SCROLL_TOP = 0
|
|
24
|
+
SCROLL_BOTTOM = 1
|
|
25
|
+
CAPABILITIES = {
|
|
26
|
+
browser_attach_timeout: 'browserAttachTimeout',
|
|
27
|
+
element_scroll_behavior: 'elementScrollBehavior',
|
|
28
|
+
full_page_screenshot: 'ie.enableFullPageScreenshot',
|
|
29
|
+
ensure_clean_session: 'ie.ensureCleanSession',
|
|
30
|
+
file_upload_dialog_timeout: 'ie.fileUploadDialogTimeout',
|
|
31
|
+
force_create_process_api: 'ie.forceCreateProcessApi',
|
|
32
|
+
force_shell_windows_api: 'ie.forceShellWindowsApi',
|
|
33
|
+
ignore_protected_mode_settings: 'ignoreProtectedModeSettings',
|
|
34
|
+
ignore_zoom_level: 'ignoreZoomSetting',
|
|
35
|
+
initial_browser_url: 'initialBrowserUrl',
|
|
36
|
+
native_events: 'nativeEvents',
|
|
37
|
+
persistent_hover: 'enablePersistentHover',
|
|
38
|
+
require_window_focus: 'requireWindowFocus',
|
|
39
|
+
use_per_process_proxy: 'ie.usePerProcessProxy',
|
|
40
|
+
validate_cookie_document_type: 'ie.validateCookieDocumentType'
|
|
41
|
+
}.freeze
|
|
42
|
+
|
|
43
|
+
CAPABILITIES.each_key do |key|
|
|
44
|
+
define_method key do
|
|
45
|
+
@options[key]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
define_method "#{key}=" do |value|
|
|
49
|
+
@options[key] = value
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
attr_reader :args, :options
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
# Create a new Options instance
|
|
57
|
+
#
|
|
58
|
+
# @example
|
|
59
|
+
# options = Selenium::WebDriver::IE::Options.new(args: ['--host=127.0.0.1'])
|
|
60
|
+
# driver = Selenium::WebDriver.for(:ie, options: options)
|
|
61
|
+
#
|
|
62
|
+
# @example
|
|
63
|
+
# options = Selenium::WebDriver::IE::Options.new
|
|
64
|
+
# options.element_scroll_behavior = Selenium::WebDriver::IE::Options::SCROLL_BOTTOM
|
|
65
|
+
# driver = Selenium::WebDriver.for(:ie, options: options)
|
|
66
|
+
#
|
|
67
|
+
# @param [Hash] opts the pre-defined options
|
|
68
|
+
# @option opts [Array<String>] args
|
|
69
|
+
# @option opts [Integer] browser_attach_timeout
|
|
70
|
+
# @option opts [Integer] element_scroll_behavior Either SCROLL_TOP or SCROLL_BOTTOM
|
|
71
|
+
# @option opts [Boolean] full_page_screenshot
|
|
72
|
+
# @option opts [Boolean] ensure_clean_session
|
|
73
|
+
# @option opts [Integer] file_upload_dialog_timeout
|
|
74
|
+
# @option opts [Boolean] force_create_process_api
|
|
75
|
+
# @option opts [Boolean] force_shell_windows_api
|
|
76
|
+
# @option opts [Boolean] ignore_protected_mode_settings
|
|
77
|
+
# @option opts [Boolean] ignore_zoom_level
|
|
78
|
+
# @option opts [String] initial_browser_url
|
|
79
|
+
# @option opts [Boolean] native_events
|
|
80
|
+
# @option opts [Boolean] persistent_hover
|
|
81
|
+
# @option opts [Boolean] require_window_focus
|
|
82
|
+
# @option opts [Boolean] use_per_process_proxy
|
|
83
|
+
# @option opts [Boolean] validate_cookie_document_type
|
|
84
|
+
#
|
|
85
|
+
|
|
86
|
+
def initialize(**opts)
|
|
87
|
+
@args = opts.delete(:args) || []
|
|
88
|
+
@options = opts
|
|
89
|
+
@options[:native_events] ||= true
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
#
|
|
93
|
+
# Add a command-line argument to use when starting Internet Explorer.
|
|
94
|
+
#
|
|
95
|
+
# @param [String] arg The command-line argument to add
|
|
96
|
+
#
|
|
97
|
+
|
|
98
|
+
def add_argument(arg)
|
|
99
|
+
@args << arg
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
#
|
|
103
|
+
# Add a new option not yet handled by these bindings.
|
|
104
|
+
#
|
|
105
|
+
# @example
|
|
106
|
+
# options = Selenium::WebDriver::IE::Options.new
|
|
107
|
+
# options.add_option(:foo, 'bar')
|
|
108
|
+
#
|
|
109
|
+
# @param [String, Symbol] name Name of the option
|
|
110
|
+
# @param [Boolean, String, Integer] value Value of the option
|
|
111
|
+
#
|
|
112
|
+
|
|
113
|
+
def add_option(name, value)
|
|
114
|
+
@options[name] = value
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
# @api private
|
|
119
|
+
#
|
|
120
|
+
|
|
121
|
+
def as_json(*)
|
|
122
|
+
opts = {}
|
|
123
|
+
|
|
124
|
+
CAPABILITIES.each do |capability_alias, capability_name|
|
|
125
|
+
capability_value = @options.delete(capability_alias)
|
|
126
|
+
opts[capability_name] = capability_value unless capability_value.nil?
|
|
127
|
+
end
|
|
128
|
+
opts['ie.browserCommandLineSwitches'] = @args.join(' ') if @args.any?
|
|
129
|
+
opts.merge!(@options)
|
|
130
|
+
|
|
131
|
+
{KEY => opts}
|
|
132
|
+
end
|
|
133
|
+
end # Options
|
|
134
|
+
end # IE
|
|
135
|
+
end # WebDriver
|
|
136
|
+
end # Selenium
|
|
@@ -0,0 +1,58 @@
|
|
|
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 IE
|
|
21
|
+
#
|
|
22
|
+
# @api private
|
|
23
|
+
#
|
|
24
|
+
|
|
25
|
+
class Service < WebDriver::Service
|
|
26
|
+
DEFAULT_PORT = 5555
|
|
27
|
+
@executable = 'IEDriverServer'.freeze
|
|
28
|
+
@missing_text = <<-ERROR.gsub(/\n +| {2,}/, ' ').freeze
|
|
29
|
+
Unable to find IEDriverServer. Please download the server from
|
|
30
|
+
http://selenium-release.storage.googleapis.com/index.html and place it somewhere on your PATH.
|
|
31
|
+
More info at https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver.
|
|
32
|
+
ERROR
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def start_process
|
|
37
|
+
@process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
|
|
38
|
+
@process.start
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def cannot_connect_error_text
|
|
42
|
+
"unable to connect to IE server #{@host}:#{@port}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def extract_service_args(driver_opts)
|
|
46
|
+
driver_args = super
|
|
47
|
+
driver_args << "--log-level=#{driver_opts.delete(:log_level).to_s.upcase}" if driver_opts.key?(:log_level)
|
|
48
|
+
driver_args << "--log-file=#{driver_opts.delete(:log_file)}" if driver_opts.key?(:log_file)
|
|
49
|
+
driver_args << "--implementation=#{driver_opts.delete(:implementation).to_s.upcase}" if driver_opts.key?(:implementation)
|
|
50
|
+
driver_args << "--host=#{driver_opts.delete(:host)}" if driver_opts.key?(:host)
|
|
51
|
+
driver_args << "--extract_path=#{driver_opts.delete(:extract_path)}" if driver_opts.key?(:extract_path)
|
|
52
|
+
driver_args << "--silent" if driver_opts[:silent] == true
|
|
53
|
+
driver_args
|
|
54
|
+
end
|
|
55
|
+
end # Server
|
|
56
|
+
end # IE
|
|
57
|
+
end # WebDriver
|
|
58
|
+
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
|
|
@@ -19,23 +17,17 @@
|
|
|
19
17
|
|
|
20
18
|
require 'uri'
|
|
21
19
|
|
|
22
|
-
require 'selenium/webdriver/remote/capabilities'
|
|
23
|
-
require 'selenium/webdriver/remote/w3c_capabilities'
|
|
24
20
|
require 'selenium/webdriver/remote/bridge'
|
|
25
|
-
require 'selenium/webdriver/remote/
|
|
26
|
-
require 'selenium/webdriver/remote/server_error'
|
|
21
|
+
require 'selenium/webdriver/remote/driver'
|
|
27
22
|
require 'selenium/webdriver/remote/response'
|
|
28
|
-
require 'selenium/webdriver/remote/
|
|
29
|
-
require 'selenium/webdriver/remote/w3c_commands'
|
|
23
|
+
require 'selenium/webdriver/remote/server_error'
|
|
30
24
|
require 'selenium/webdriver/remote/http/common'
|
|
31
25
|
require 'selenium/webdriver/remote/http/default'
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
# @api private
|
|
37
|
-
module Remote
|
|
27
|
+
require 'selenium/webdriver/remote/capabilities'
|
|
28
|
+
require 'selenium/webdriver/remote/oss/bridge'
|
|
29
|
+
require 'selenium/webdriver/remote/oss/commands'
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
31
|
+
require 'selenium/webdriver/remote/w3c/bridge'
|
|
32
|
+
require 'selenium/webdriver/remote/w3c/capabilities'
|
|
33
|
+
require 'selenium/webdriver/remote/w3c/commands'
|
|
@@ -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,624 +18,141 @@
|
|
|
20
18
|
module Selenium
|
|
21
19
|
module WebDriver
|
|
22
20
|
module Remote
|
|
23
|
-
|
|
24
|
-
#
|
|
25
|
-
# Low level bridge to the remote server, through which the rest of the API works.
|
|
26
|
-
#
|
|
27
|
-
# @api private
|
|
28
|
-
#
|
|
29
|
-
|
|
30
21
|
class Bridge
|
|
22
|
+
include Atoms
|
|
31
23
|
include BridgeHelper
|
|
32
24
|
|
|
33
|
-
|
|
25
|
+
PORT = 4444
|
|
26
|
+
COMMANDS = {
|
|
27
|
+
new_session: [:post, 'session'.freeze]
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
attr_accessor :context, :http, :file_detector
|
|
31
|
+
attr_reader :capabilities, :dialect
|
|
34
32
|
|
|
35
33
|
#
|
|
36
|
-
#
|
|
34
|
+
# Implements protocol handshake which:
|
|
37
35
|
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
# a URL template, which can include some arguments, much like the definitions on the server.
|
|
42
|
-
# the :session_id parameter is implicitly handled, but the remainder will become required method arguments.
|
|
43
|
-
# @param verb [Symbol]
|
|
44
|
-
# the appropriate http verb, such as :get, :post, or :delete
|
|
36
|
+
# 1. Creates session with driver.
|
|
37
|
+
# 2. Sniffs response.
|
|
38
|
+
# 3. Based on the response, understands which dialect we should use.
|
|
45
39
|
#
|
|
40
|
+
# @return [OSS:Bridge, W3C::Bridge]
|
|
41
|
+
#
|
|
42
|
+
def self.handshake(**opts)
|
|
43
|
+
desired_capabilities = opts.delete(:desired_capabilities)
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
if desired_capabilities.is_a?(Symbol)
|
|
46
|
+
unless Remote::Capabilities.respond_to?(desired_capabilities)
|
|
47
|
+
raise Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
|
|
48
|
+
end
|
|
49
|
+
desired_capabilities = Remote::Capabilities.__send__(desired_capabilities)
|
|
50
|
+
end
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
bridge = new(opts)
|
|
53
|
+
capabilities = bridge.create_session(desired_capabilities)
|
|
54
|
+
|
|
55
|
+
case bridge.dialect
|
|
56
|
+
when :oss
|
|
57
|
+
Remote::OSS::Bridge.new(capabilities, bridge.session_id, opts)
|
|
58
|
+
when :w3c
|
|
59
|
+
Remote::W3C::Bridge.new(capabilities, bridge.session_id, opts)
|
|
60
|
+
else
|
|
61
|
+
raise WebDriverError, 'cannot understand dialect'
|
|
62
|
+
end
|
|
63
|
+
end
|
|
53
64
|
|
|
54
65
|
#
|
|
55
|
-
# Initializes the bridge with the given server URL
|
|
56
|
-
#
|
|
57
|
-
# @
|
|
58
|
-
# @
|
|
59
|
-
# @
|
|
66
|
+
# Initializes the bridge with the given server URL
|
|
67
|
+
# @param [Hash] opts options for the driver
|
|
68
|
+
# @option opts [String] :url url for the remote server
|
|
69
|
+
# @option opts [Object] :http_client an HTTP client instance that implements the same protocol as Http::Default
|
|
70
|
+
# @option opts [Capabilities] :desired_capabilities an instance of Remote::Capabilities describing the capabilities you want
|
|
71
|
+
# @api private
|
|
60
72
|
#
|
|
61
73
|
|
|
62
74
|
def initialize(opts = {})
|
|
63
75
|
opts = opts.dup
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
desired_capabilities = opts.delete(:desired_capabilities) { Capabilities.firefox }
|
|
67
|
-
url = opts.delete(:url) { "http://#{Platform.localhost}:4444/wd/hub" }
|
|
76
|
+
http_client = opts.delete(:http_client) { Http::Default.new }
|
|
77
|
+
url = opts.delete(:url) { "http://#{Platform.localhost}:#{PORT}/wd/hub" }
|
|
68
78
|
|
|
69
79
|
unless opts.empty?
|
|
70
80
|
raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
|
|
71
81
|
end
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
raise Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
desired_capabilities = Capabilities.send(desired_capabilities)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
uri = url.kind_of?(URI) ? url : URI.parse(url)
|
|
82
|
-
uri.path += "/" unless uri.path =~ /\/$/
|
|
83
|
+
uri = url.is_a?(URI) ? url : URI.parse(url)
|
|
84
|
+
uri.path += '/' unless uri.path =~ %r{\/$}
|
|
83
85
|
|
|
84
86
|
http_client.server_url = uri
|
|
85
87
|
|
|
86
|
-
@http
|
|
87
|
-
@capabilities = create_session(desired_capabilities)
|
|
88
|
-
|
|
88
|
+
@http = http_client
|
|
89
89
|
@file_detector = nil
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
def browser
|
|
93
|
-
@browser ||= (
|
|
94
|
-
name = @capabilities.browser_name
|
|
95
|
-
name ? name.gsub(" ", "_").to_sym : 'unknown'
|
|
96
|
-
)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def driver_extensions
|
|
100
|
-
[
|
|
101
|
-
DriverExtensions::HasInputDevices,
|
|
102
|
-
DriverExtensions::UploadsFiles,
|
|
103
|
-
DriverExtensions::TakesScreenshot,
|
|
104
|
-
DriverExtensions::HasSessionId,
|
|
105
|
-
DriverExtensions::Rotatable,
|
|
106
|
-
DriverExtensions::HasTouchScreen,
|
|
107
|
-
DriverExtensions::HasLocation,
|
|
108
|
-
DriverExtensions::HasNetworkConnection,
|
|
109
|
-
DriverExtensions::HasRemoteStatus,
|
|
110
|
-
DriverExtensions::HasWebStorage
|
|
111
|
-
]
|
|
112
|
-
end
|
|
113
|
-
|
|
114
92
|
#
|
|
115
|
-
#
|
|
93
|
+
# Creates session handling both OSS and W3C dialects.
|
|
116
94
|
#
|
|
117
95
|
|
|
118
|
-
def session_id
|
|
119
|
-
@session_id || raise(Error::WebDriverError, "no current session exists")
|
|
120
|
-
end
|
|
121
|
-
|
|
122
96
|
def create_session(desired_capabilities)
|
|
123
|
-
|
|
124
|
-
@session_id = resp['sessionId'] or raise Error::WebDriverError, 'no sessionId in returned payload'
|
|
125
|
-
|
|
126
|
-
Capabilities.json_create resp['value']
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def status
|
|
130
|
-
execute :status
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def get(url)
|
|
134
|
-
execute :get, {}, :url => url
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def getCapabilities
|
|
138
|
-
Capabilities.json_create execute(:getCapabilities)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def setImplicitWaitTimeout(milliseconds)
|
|
142
|
-
execute :implicitlyWait, {}, :ms => milliseconds
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def setScriptTimeout(milliseconds)
|
|
146
|
-
execute :setScriptTimeout, {}, :ms => milliseconds
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def setTimeout(type, milliseconds)
|
|
150
|
-
execute :setTimeout, {}, :type => type, :ms => milliseconds
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
#
|
|
154
|
-
# alerts
|
|
155
|
-
#
|
|
156
|
-
|
|
157
|
-
def acceptAlert
|
|
158
|
-
execute :acceptAlert
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def dismissAlert
|
|
162
|
-
execute :dismissAlert
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def setAlertValue(keys)
|
|
166
|
-
execute :setAlertValue, {}, :text => keys.to_s
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def getAlertText
|
|
170
|
-
execute :getAlertText
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def setAuthentication(credentials)
|
|
174
|
-
execute :setAuthentication, {}, credentials
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
#
|
|
178
|
-
# navigation
|
|
179
|
-
#
|
|
180
|
-
|
|
181
|
-
def goBack
|
|
182
|
-
execute :goBack
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def goForward
|
|
186
|
-
execute :goForward
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def getCurrentUrl
|
|
190
|
-
execute :getCurrentUrl
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
def getTitle
|
|
194
|
-
execute :getTitle
|
|
195
|
-
end
|
|
97
|
+
response = execute(:new_session, {}, merged_capabilities(desired_capabilities))
|
|
196
98
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
def switchToWindow(name)
|
|
202
|
-
execute :switchToWindow, {}, :name => name
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def switchToFrame(id)
|
|
206
|
-
execute :switchToFrame, {}, :id => id
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def switchToParentFrame
|
|
210
|
-
execute :switchToParentFrame
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def switchToDefaultContent
|
|
214
|
-
execute :switchToFrame, {}, :id => nil
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
QUIT_ERRORS = [IOError]
|
|
218
|
-
|
|
219
|
-
def quit
|
|
220
|
-
execute :quit
|
|
221
|
-
http.close
|
|
222
|
-
rescue *QUIT_ERRORS
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def close
|
|
226
|
-
execute :close
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
def refresh
|
|
230
|
-
execute :refresh
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
#
|
|
234
|
-
# window handling
|
|
235
|
-
#
|
|
236
|
-
|
|
237
|
-
def getWindowHandles
|
|
238
|
-
execute :getWindowHandles
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def getCurrentWindowHandle
|
|
242
|
-
execute :getCurrentWindowHandle
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
def setWindowSize(width, height, handle = :current)
|
|
246
|
-
execute :setWindowSize, {:window_handle => handle},
|
|
247
|
-
:width => width,
|
|
248
|
-
:height => height
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
def maximizeWindow(handle = :current)
|
|
252
|
-
execute :maximizeWindow, :window_handle => handle
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
def getWindowSize(handle = :current)
|
|
256
|
-
data = execute :getWindowSize, :window_handle => handle
|
|
257
|
-
|
|
258
|
-
Dimension.new data['width'], data['height']
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
def setWindowPosition(x, y, handle = :current)
|
|
262
|
-
execute :setWindowPosition, {:window_handle => handle},
|
|
263
|
-
:x => x, :y => y
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
def getWindowPosition(handle = :current)
|
|
267
|
-
data = execute :getWindowPosition, :window_handle => handle
|
|
268
|
-
|
|
269
|
-
Point.new data['x'], data['y']
|
|
270
|
-
end
|
|
99
|
+
@session_id = response['sessionId']
|
|
100
|
+
oss_status = response['status']
|
|
101
|
+
value = response['value']
|
|
271
102
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
#
|
|
277
|
-
# HTML 5
|
|
278
|
-
#
|
|
279
|
-
|
|
280
|
-
def getLocalStorageItem(key)
|
|
281
|
-
execute :getLocalStorageItem, :key => key
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
def removeLocalStorageItem(key)
|
|
285
|
-
execute :removeLocalStorageItem, :key => key
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
def getLocalStorageKeys
|
|
289
|
-
execute :getLocalStorageKeys
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
def setLocalStorageItem(key, value)
|
|
293
|
-
execute :setLocalStorageItem, {}, :key => key, :value => value
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
def clearLocalStorage
|
|
297
|
-
execute :clearLocalStorage
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
def getLocalStorageSize
|
|
301
|
-
execute :getLocalStorageSize
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def getSessionStorageItem(key)
|
|
305
|
-
execute :getSessionStorageItem, :key => key
|
|
306
|
-
end
|
|
103
|
+
if value.is_a?(Hash)
|
|
104
|
+
@session_id = value['sessionId'] if value.key?('sessionId')
|
|
307
105
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
execute :getSessionStorageKeys
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
def setSessionStorageItem(key, value)
|
|
317
|
-
execute :setSessionStorageItem, {}, :key => key, :value => value
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
def clearSessionStorage
|
|
321
|
-
execute :clearSessionStorage
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
def getSessionStorageSize
|
|
325
|
-
execute :getSessionStorageSize
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
def getLocation
|
|
329
|
-
obj = execute(:getLocation) || {} # android returns null
|
|
330
|
-
Location.new obj['latitude'], obj['longitude'], obj['altitude']
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
def setLocation(lat, lon, alt)
|
|
334
|
-
loc = {:latitude => lat, :longitude => lon, :altitude => alt}
|
|
335
|
-
execute :setLocation, {}, :location => loc
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
def getNetworkConnection
|
|
339
|
-
execute :getNetworkConnection
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
def setNetworkConnection(type)
|
|
343
|
-
execute :setNetworkConnection, {}, :parameters => {:type => type}
|
|
344
|
-
end
|
|
345
|
-
|
|
346
|
-
#
|
|
347
|
-
# javascript execution
|
|
348
|
-
#
|
|
349
|
-
|
|
350
|
-
def executeScript(script, *args)
|
|
351
|
-
assert_javascript_enabled
|
|
352
|
-
|
|
353
|
-
result = execute :executeScript, {}, :script => script, :args => args
|
|
354
|
-
unwrap_script_result result
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
def executeAsyncScript(script, *args)
|
|
358
|
-
assert_javascript_enabled
|
|
359
|
-
|
|
360
|
-
result = execute :executeAsyncScript, {}, :script => script, :args => args
|
|
361
|
-
unwrap_script_result result
|
|
362
|
-
end
|
|
363
|
-
|
|
364
|
-
#
|
|
365
|
-
# cookies
|
|
366
|
-
#
|
|
367
|
-
|
|
368
|
-
def addCookie(cookie)
|
|
369
|
-
execute :addCookie, {}, :cookie => cookie
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
def deleteCookie(name)
|
|
373
|
-
execute :deleteCookie, :name => name
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
def getAllCookies
|
|
377
|
-
execute :getCookies
|
|
378
|
-
end
|
|
379
|
-
|
|
380
|
-
def deleteAllCookies
|
|
381
|
-
execute :deleteAllCookies
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
#
|
|
385
|
-
# actions
|
|
386
|
-
#
|
|
387
|
-
|
|
388
|
-
def clickElement(element)
|
|
389
|
-
execute :clickElement, :id => element
|
|
390
|
-
end
|
|
391
|
-
|
|
392
|
-
def click
|
|
393
|
-
execute :click, {}, :button => 0
|
|
394
|
-
end
|
|
395
|
-
|
|
396
|
-
def doubleClick
|
|
397
|
-
execute :doubleClick
|
|
398
|
-
end
|
|
399
|
-
|
|
400
|
-
def contextClick
|
|
401
|
-
execute :click, {}, :button => 2
|
|
402
|
-
end
|
|
403
|
-
|
|
404
|
-
def mouseDown
|
|
405
|
-
execute :mouseDown
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
def mouseUp
|
|
409
|
-
execute :mouseUp
|
|
410
|
-
end
|
|
411
|
-
|
|
412
|
-
def mouseMoveTo(element, x = nil, y = nil)
|
|
413
|
-
params = { :element => element }
|
|
414
|
-
|
|
415
|
-
if x && y
|
|
416
|
-
params.merge! :xoffset => x, :yoffset => y
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
execute :mouseMoveTo, {}, params
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
def sendKeysToActiveElement(key)
|
|
423
|
-
execute :sendKeysToActiveElement, {}, :value => key
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
def sendKeysToElement(element, keys)
|
|
427
|
-
if @file_detector && local_file = @file_detector.call(keys)
|
|
428
|
-
keys = upload(local_file)
|
|
106
|
+
if value.key?('capabilities')
|
|
107
|
+
value = value['capabilities']
|
|
108
|
+
elsif value.key?('value')
|
|
109
|
+
value = value['value']
|
|
110
|
+
end
|
|
429
111
|
end
|
|
430
112
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
def upload(local_file)
|
|
435
|
-
unless File.file?(local_file)
|
|
436
|
-
raise Error::WebDriverError, "you may only upload files: #{local_file.inspect}"
|
|
113
|
+
unless @session_id
|
|
114
|
+
raise Error::WebDriverError, 'no sessionId in returned payload'
|
|
437
115
|
end
|
|
438
116
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
execute :clearElement, :id => element
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
def submitElement(element)
|
|
447
|
-
execute :submitElement, :id => element
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
def dragElement(element, right_by, down_by)
|
|
451
|
-
execute :dragElement, {:id => element}, :x => right_by, :y => down_by
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
def touchSingleTap(element)
|
|
455
|
-
execute :touchSingleTap, {}, :element => element
|
|
456
|
-
end
|
|
457
|
-
|
|
458
|
-
def touchDoubleTap(element)
|
|
459
|
-
execute :touchDoubleTap, {}, :element => element
|
|
460
|
-
end
|
|
461
|
-
|
|
462
|
-
def touchLongPress(element)
|
|
463
|
-
execute :touchLongPress, {}, :element => element
|
|
464
|
-
end
|
|
465
|
-
|
|
466
|
-
def touchDown(x, y)
|
|
467
|
-
execute :touchDown, {}, :x => x, :y => y
|
|
468
|
-
end
|
|
469
|
-
|
|
470
|
-
def touchUp(x, y)
|
|
471
|
-
execute :touchUp, {}, :x => x, :y => y
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
def touchMove(x, y)
|
|
475
|
-
execute :touchMove, {}, :x => x, :y => y
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
def touchScroll(element, x, y)
|
|
479
|
-
if element
|
|
480
|
-
execute :touchScroll, {}, :element => element,
|
|
481
|
-
:xoffset => x,
|
|
482
|
-
:yoffset => y
|
|
117
|
+
if oss_status
|
|
118
|
+
WebDriver.logger.info 'Detected OSS dialect.'
|
|
119
|
+
@dialect = :oss
|
|
120
|
+
Capabilities.json_create(value)
|
|
483
121
|
else
|
|
484
|
-
|
|
122
|
+
WebDriver.logger.info 'Detected W3C dialect.'
|
|
123
|
+
@dialect = :w3c
|
|
124
|
+
W3C::Capabilities.json_create(value)
|
|
485
125
|
end
|
|
486
126
|
end
|
|
487
127
|
|
|
488
|
-
def touchFlick(xspeed, yspeed)
|
|
489
|
-
execute :touchFlick, {}, :xspeed => xspeed, :yspeed => yspeed
|
|
490
|
-
end
|
|
491
|
-
|
|
492
|
-
def touchElementFlick(element, right_by, down_by, speed)
|
|
493
|
-
execute :touchFlick, {}, :element => element,
|
|
494
|
-
:xoffset => right_by,
|
|
495
|
-
:yoffset => down_by,
|
|
496
|
-
:speed => speed
|
|
497
|
-
|
|
498
|
-
end
|
|
499
|
-
|
|
500
|
-
def setScreenOrientation(orientation)
|
|
501
|
-
execute :setScreenOrientation, {}, :orientation => orientation
|
|
502
|
-
end
|
|
503
|
-
|
|
504
|
-
def getScreenOrientation
|
|
505
|
-
execute :getScreenOrientation
|
|
506
|
-
end
|
|
507
|
-
|
|
508
|
-
#
|
|
509
|
-
# logs
|
|
510
|
-
#
|
|
511
|
-
|
|
512
|
-
def getAvailableLogTypes
|
|
513
|
-
types = execute :getAvailableLogTypes
|
|
514
|
-
Array(types).map { |e| e.to_sym }
|
|
515
|
-
end
|
|
516
|
-
|
|
517
|
-
def getLog(type)
|
|
518
|
-
data = execute :getLog, {}, :type => type.to_s
|
|
519
|
-
|
|
520
|
-
Array(data).map do |l|
|
|
521
|
-
begin
|
|
522
|
-
LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
|
|
523
|
-
rescue KeyError
|
|
524
|
-
next
|
|
525
|
-
end
|
|
526
|
-
end
|
|
527
|
-
end
|
|
528
|
-
|
|
529
|
-
#
|
|
530
|
-
# element properties
|
|
531
128
|
#
|
|
532
|
-
|
|
533
|
-
def getElementTagName(element)
|
|
534
|
-
execute :getElementTagName, :id => element
|
|
535
|
-
end
|
|
536
|
-
|
|
537
|
-
def getElementAttribute(element, name)
|
|
538
|
-
execute :getElementAttribute, :id => element, :name => name
|
|
539
|
-
end
|
|
540
|
-
|
|
541
|
-
def getElementValue(element)
|
|
542
|
-
execute :getElementValue, :id => element
|
|
543
|
-
end
|
|
544
|
-
|
|
545
|
-
def getElementText(element)
|
|
546
|
-
execute :getElementText, :id => element
|
|
547
|
-
end
|
|
548
|
-
|
|
549
|
-
def getElementLocation(element)
|
|
550
|
-
data = execute :getElementLocation, :id => element
|
|
551
|
-
|
|
552
|
-
Point.new data['x'], data['y']
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
def getElementLocationOnceScrolledIntoView(element)
|
|
556
|
-
data = execute :getElementLocationOnceScrolledIntoView, :id => element
|
|
557
|
-
|
|
558
|
-
Point.new data['x'], data['y']
|
|
559
|
-
end
|
|
560
|
-
|
|
561
|
-
def getElementSize(element)
|
|
562
|
-
data = execute :getElementSize, :id => element
|
|
563
|
-
|
|
564
|
-
Dimension.new data['width'], data['height']
|
|
565
|
-
end
|
|
566
|
-
|
|
567
|
-
def isElementEnabled(element)
|
|
568
|
-
execute :isElementEnabled, :id => element
|
|
569
|
-
end
|
|
570
|
-
|
|
571
|
-
def isElementSelected(element)
|
|
572
|
-
execute :isElementSelected, :id => element
|
|
573
|
-
end
|
|
574
|
-
|
|
575
|
-
def isElementDisplayed(element)
|
|
576
|
-
execute :isElementDisplayed, :id => element
|
|
577
|
-
end
|
|
578
|
-
|
|
579
|
-
def getElementValueOfCssProperty(element, prop)
|
|
580
|
-
execute :getElementValueOfCssProperty, :id => element, :property_name => prop
|
|
581
|
-
end
|
|
582
|
-
|
|
583
|
-
#
|
|
584
|
-
# finding elements
|
|
129
|
+
# Returns the current session ID.
|
|
585
130
|
#
|
|
586
131
|
|
|
587
|
-
def
|
|
588
|
-
|
|
589
|
-
end
|
|
590
|
-
alias_method :switchToActiveElement, :getActiveElement
|
|
591
|
-
|
|
592
|
-
def find_element_by(how, what, parent = nil)
|
|
593
|
-
if parent
|
|
594
|
-
id = execute :findChildElement, {:id => parent}, {:using => how, :value => what}
|
|
595
|
-
else
|
|
596
|
-
id = execute :findElement, {}, {:using => how, :value => what}
|
|
597
|
-
end
|
|
598
|
-
|
|
599
|
-
Element.new self, element_id_from(id)
|
|
132
|
+
def session_id
|
|
133
|
+
@session_id || raise(Error::WebDriverError, 'no current session exists')
|
|
600
134
|
end
|
|
601
135
|
|
|
602
|
-
def
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
ids = execute :findElements, {}, {:using => how, :value => what}
|
|
136
|
+
def browser
|
|
137
|
+
@browser ||= begin
|
|
138
|
+
name = @capabilities.browser_name
|
|
139
|
+
name ? name.tr(' ', '_').to_sym : 'unknown'
|
|
607
140
|
end
|
|
608
|
-
|
|
609
|
-
ids.map { |id| Element.new self, element_id_from(id) }
|
|
610
141
|
end
|
|
611
142
|
|
|
612
143
|
private
|
|
613
144
|
|
|
614
|
-
def assert_javascript_enabled
|
|
615
|
-
return if capabilities.javascript_enabled?
|
|
616
|
-
raise Error::UnsupportedOperationError, "underlying webdriver instance does not support javascript"
|
|
617
|
-
end
|
|
618
|
-
|
|
619
|
-
#
|
|
620
|
-
# executes a command on the remote server.
|
|
621
|
-
#
|
|
622
|
-
#
|
|
623
|
-
# Returns the 'value' of the returned payload
|
|
624
|
-
#
|
|
625
|
-
|
|
626
|
-
def execute(*args)
|
|
627
|
-
raw_execute(*args)['value']
|
|
628
|
-
end
|
|
629
|
-
|
|
630
145
|
#
|
|
631
146
|
# executes a command on the remote server.
|
|
632
147
|
#
|
|
633
148
|
# @return [WebDriver::Remote::Response]
|
|
634
149
|
#
|
|
635
150
|
|
|
636
|
-
def
|
|
637
|
-
verb, path =
|
|
638
|
-
path
|
|
151
|
+
def execute(command, opts = {}, command_hash = nil)
|
|
152
|
+
verb, path = commands(command) || raise(ArgumentError, "unknown command: #{command.inspect}")
|
|
153
|
+
path = path.dup
|
|
639
154
|
|
|
640
|
-
path[':session_id'] =
|
|
155
|
+
path[':session_id'] = session_id if path.include?(':session_id')
|
|
641
156
|
|
|
642
157
|
begin
|
|
643
158
|
opts.each { |key, value| path[key.inspect] = escaper.escape(value.to_s) }
|
|
@@ -645,12 +160,28 @@ module Selenium
|
|
|
645
160
|
raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
|
|
646
161
|
end
|
|
647
162
|
|
|
648
|
-
|
|
649
|
-
http.call
|
|
163
|
+
WebDriver.logger.info("-> #{verb.to_s.upcase} #{path}")
|
|
164
|
+
http.call(verb, path, command_hash)
|
|
650
165
|
end
|
|
651
166
|
|
|
652
167
|
def escaper
|
|
653
|
-
@escaper ||= defined?(URI::Parser) ? URI::
|
|
168
|
+
@escaper ||= defined?(URI::Parser) ? URI::DEFAULT_PARSER : URI
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def commands(command)
|
|
172
|
+
raise NotImplementedError unless command == :new_session
|
|
173
|
+
COMMANDS[command]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def merged_capabilities(oss_capabilities)
|
|
177
|
+
w3c_capabilities = W3C::Capabilities.from_oss(oss_capabilities)
|
|
178
|
+
|
|
179
|
+
{
|
|
180
|
+
desiredCapabilities: oss_capabilities,
|
|
181
|
+
capabilities: {
|
|
182
|
+
firstMatch: [w3c_capabilities]
|
|
183
|
+
}
|
|
184
|
+
}
|
|
654
185
|
end
|
|
655
186
|
|
|
656
187
|
end # Bridge
|