selenium-webdriver 2.8.0 → 2.9.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.
- data/CHANGES +14 -0
- data/README +1 -1
- data/lib/selenium/client/legacy_driver.rb +1 -1
- data/lib/selenium/webdriver/chrome/bridge.rb +8 -1
- data/lib/selenium/webdriver/chrome/profile.rb +18 -1
- data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +43 -0
- data/lib/selenium/webdriver/common/element.rb +1 -15
- data/lib/selenium/webdriver/common/error.rb +10 -5
- data/lib/selenium/webdriver/common/keyboard.rb +7 -2
- data/lib/selenium/webdriver/common/keys.rb +25 -1
- data/lib/selenium/webdriver/common/profile_helper.rb +1 -1
- data/lib/selenium/webdriver/common/zipper.rb +53 -29
- data/lib/selenium/webdriver/common.rb +1 -0
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/ie/native/win32/IEDriver.dll +0 -0
- data/lib/selenium/webdriver/ie/native/x64/IEDriver.dll +0 -0
- data/lib/selenium/webdriver/remote/bridge.rb +26 -6
- data/lib/selenium/webdriver/remote/commands.rb +3 -0
- metadata +5 -4
data/CHANGES
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
2.9.0 (2011-10-21)
|
2
|
+
==================
|
3
|
+
|
4
|
+
* Support file uploads to the remote server (see Selenium::WebDriver::DriverExtensions::UploadsFiles)
|
5
|
+
* New exception: Selenium::WebDriver::Error::MoveTargetOutOfBoundsError
|
6
|
+
* Implemented Chrome::Profile#add_extension
|
7
|
+
* Better respect for preformatted text in Element#text
|
8
|
+
* Reduced scrolling during tests for IE and Firefox.
|
9
|
+
* Firefox:
|
10
|
+
* Support for experimental page load detection.
|
11
|
+
* IE:
|
12
|
+
* Better detection of where to click on links (#2675).
|
13
|
+
* Improve handling of modal dialogs (showModalDialog).
|
14
|
+
|
1
15
|
2.8.0 (2011-10-06)
|
2
16
|
==================
|
3
17
|
|
data/README
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= selenium-webdriver
|
2
2
|
|
3
|
-
This gem provides Ruby bindings for WebDriver and has been tested to work on MRI (1.8.
|
3
|
+
This gem provides Ruby bindings for WebDriver and has been tested to work on MRI (1.8.7 through 1.9), JRuby and Rubinius.
|
4
4
|
|
5
5
|
= INSTALL
|
6
6
|
|
@@ -66,10 +66,17 @@ module Selenium
|
|
66
66
|
caps.merge! 'chrome.switches' => switches.map { |e| e.to_s }
|
67
67
|
end
|
68
68
|
|
69
|
+
if profile
|
70
|
+
data = profile.as_json
|
71
|
+
|
72
|
+
caps.merge! 'chrome.profile' => data['zip'],
|
73
|
+
'chrome.extensions' => data['extensions']
|
74
|
+
end
|
75
|
+
|
76
|
+
|
69
77
|
caps.merge! 'chrome.binary' => Chrome.path if Chrome.path
|
70
78
|
caps.merge! 'chrome.nativeEvents' => true if native_events
|
71
79
|
caps.merge! 'chrome.verbose' => true if verbose
|
72
|
-
caps.merge! 'chrome.profile' => profile.as_json['zip'] if profile
|
73
80
|
caps.merge! 'chrome.detach' => detach.nil? || !!detach
|
74
81
|
end
|
75
82
|
|
@@ -10,7 +10,16 @@ module Selenium
|
|
10
10
|
include ProfileHelper
|
11
11
|
|
12
12
|
def initialize(model = nil)
|
13
|
-
@model
|
13
|
+
@model = verify_model(model)
|
14
|
+
@extensions = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_extension(path)
|
18
|
+
unless File.file?(path)
|
19
|
+
raise Error::WebDriverError, "could not find extension at #{path.inspect}"
|
20
|
+
end
|
21
|
+
|
22
|
+
@extensions << path
|
14
23
|
end
|
15
24
|
|
16
25
|
#
|
@@ -38,6 +47,14 @@ module Selenium
|
|
38
47
|
dir
|
39
48
|
end
|
40
49
|
|
50
|
+
def as_json(opts = nil)
|
51
|
+
extensions = @extensions.map do |crx_path|
|
52
|
+
Base64.strict_encode64 File.read(crx_path)
|
53
|
+
end
|
54
|
+
|
55
|
+
super.merge('extensions' => extensions)
|
56
|
+
end
|
57
|
+
|
41
58
|
private
|
42
59
|
|
43
60
|
def write_prefs_to(dir)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Selenium
|
2
|
+
module WebDriver
|
3
|
+
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
#
|
7
|
+
|
8
|
+
module DriverExtensions
|
9
|
+
module UploadsFiles
|
10
|
+
|
11
|
+
#
|
12
|
+
# Set the file detector to pass local files to a remote WebDriver.
|
13
|
+
#
|
14
|
+
# The detector is an object that responds to #call, and when called
|
15
|
+
# will determine if the given string represents a file. If it does,
|
16
|
+
# the path to the file on the local file system should be returned,
|
17
|
+
# otherwise nil or false.
|
18
|
+
#
|
19
|
+
# Example:
|
20
|
+
#
|
21
|
+
# driver = Selenium::WebDriver.for :remote
|
22
|
+
# driver.file_detector = lambda do |args|
|
23
|
+
# # args => ["/path/to/file"]
|
24
|
+
# str if File.exist?(args.first.to_s)
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# driver.find_element(:id => "upload").send_keys "/path/to/file"
|
28
|
+
#
|
29
|
+
# By default, no file detection is performed.
|
30
|
+
#
|
31
|
+
|
32
|
+
def file_detector=(detector)
|
33
|
+
unless detector.nil? or detector.respond_to? :call
|
34
|
+
raise ArgumentError, "detector must respond to #call"
|
35
|
+
end
|
36
|
+
|
37
|
+
bridge.file_detector = detector
|
38
|
+
end
|
39
|
+
|
40
|
+
end # UploadsFiles
|
41
|
+
end # DriverExtensions
|
42
|
+
end # WebDriver
|
43
|
+
end # Selenium
|
@@ -99,21 +99,7 @@ module Selenium
|
|
99
99
|
#
|
100
100
|
|
101
101
|
def send_keys(*args)
|
102
|
-
|
103
|
-
case arg
|
104
|
-
when Symbol
|
105
|
-
Keys[arg]
|
106
|
-
when Array
|
107
|
-
arg = arg.map { |e| e.kind_of?(Symbol) ? Keys[e] : e }.join
|
108
|
-
arg << Keys[:null]
|
109
|
-
|
110
|
-
arg
|
111
|
-
else
|
112
|
-
arg.to_s
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
bridge.sendKeysToElement @id, values
|
102
|
+
bridge.sendKeysToElement @id, Keys.encode(args)
|
117
103
|
end
|
118
104
|
alias_method :send_key, :send_keys
|
119
105
|
|
@@ -32,9 +32,12 @@ module Selenium
|
|
32
32
|
class NoAlertOpenError < WebDriverError; end # 27
|
33
33
|
class ScriptTimeOutError < WebDriverError; end # 28
|
34
34
|
class InvalidElementCoordinatesError < WebDriverError; end # 29
|
35
|
-
|
36
|
-
|
35
|
+
class IMENotAvailableError < WebDriverError; end # 30
|
36
|
+
class IMEEngineActivationFailedError < WebDriverError; end # 31
|
37
37
|
class InvalidSelectorError < WebDriverError; end # 32
|
38
|
+
# 33
|
39
|
+
class MoveTargetOutOfBoundsError < WebDriverError; end # 34
|
40
|
+
|
38
41
|
class UnsupportedOperationError < WebDriverError; end
|
39
42
|
|
40
43
|
Errors = [
|
@@ -67,9 +70,11 @@ module Selenium
|
|
67
70
|
NoAlertOpenError, # 27
|
68
71
|
ScriptTimeOutError, # 28
|
69
72
|
InvalidElementCoordinatesError, # 29
|
70
|
-
|
71
|
-
|
72
|
-
InvalidSelectorError
|
73
|
+
IMENotAvailableError, # 30
|
74
|
+
IMEEngineActivationFailedError, # 31
|
75
|
+
InvalidSelectorError, # 32
|
76
|
+
nil, # 33
|
77
|
+
MoveTargetOutOfBoundsError # 34
|
73
78
|
]
|
74
79
|
|
75
80
|
class << self
|
@@ -9,6 +9,7 @@ module Selenium
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def send_keys(*keys)
|
12
|
+
# TODO: use sendKeysToActiveElement
|
12
13
|
@bridge.getActiveElement.send_keys(*keys)
|
13
14
|
end
|
14
15
|
|
@@ -20,7 +21,9 @@ module Selenium
|
|
20
21
|
|
21
22
|
def press(key)
|
22
23
|
assert_modifier key
|
23
|
-
|
24
|
+
|
25
|
+
# TODO: use sendKeysToActiveElement
|
26
|
+
@bridge.sendModifierKeyToActiveElement Keys.encode([key]), true
|
24
27
|
end
|
25
28
|
|
26
29
|
#
|
@@ -31,7 +34,9 @@ module Selenium
|
|
31
34
|
|
32
35
|
def release(key)
|
33
36
|
assert_modifier key
|
34
|
-
|
37
|
+
|
38
|
+
# TODO: use sendKeysToActiveElement
|
39
|
+
@bridge.sendModifierKeyToActiveElement Keys.encode([key]), false
|
35
40
|
end
|
36
41
|
|
37
42
|
private
|
@@ -76,8 +76,32 @@ module Selenium
|
|
76
76
|
:command => "\xEE\x80\xBD" # alias
|
77
77
|
}
|
78
78
|
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
#
|
82
|
+
|
79
83
|
def self.[](key)
|
80
|
-
KEYS[key]
|
84
|
+
KEYS[key] or raise Error::UnsupportedOperationError, "no such key #{key.inspect}"
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# @api private
|
89
|
+
#
|
90
|
+
|
91
|
+
def self.encode(keys)
|
92
|
+
keys.map do |arg|
|
93
|
+
case arg
|
94
|
+
when Symbol
|
95
|
+
Keys[arg]
|
96
|
+
when Array
|
97
|
+
arg = arg.map { |e| e.kind_of?(Symbol) ? Keys[e] : e }.join
|
98
|
+
arg << Keys[:null]
|
99
|
+
|
100
|
+
arg
|
101
|
+
else
|
102
|
+
arg.to_s
|
103
|
+
end
|
104
|
+
end
|
81
105
|
end
|
82
106
|
|
83
107
|
end # Keys
|
@@ -52,7 +52,7 @@ module Selenium
|
|
52
52
|
# can't use Dir.mktmpdir(&blk) because of http://jira.codehaus.org/browse/JRUBY-4082
|
53
53
|
tmp_dir = Dir.mktmpdir
|
54
54
|
begin
|
55
|
-
zip_path = File.join(tmp_dir, "webdriver-profile-duplicate-#{json.hash}")
|
55
|
+
zip_path = File.join(tmp_dir, "webdriver-profile-duplicate-#{json.hash}.zip")
|
56
56
|
File.open(zip_path, "wb") { |zip_file| zip_file << Base64.decode64(data) }
|
57
57
|
|
58
58
|
new Zipper.unzip(zip_path)
|
@@ -8,47 +8,71 @@ module Selenium
|
|
8
8
|
|
9
9
|
EXTENSIONS = %w[.zip .xpi]
|
10
10
|
|
11
|
-
|
12
|
-
destination = Dir.mktmpdir("unzip")
|
13
|
-
FileReaper << destination
|
11
|
+
class << self
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
dirname = File.dirname(to)
|
13
|
+
def unzip(path)
|
14
|
+
destination = Dir.mktmpdir("unzip")
|
15
|
+
FileReaper << destination
|
19
16
|
|
20
|
-
|
21
|
-
zip.
|
17
|
+
Zip::ZipFile.open(path) do |zip|
|
18
|
+
zip.each do |entry|
|
19
|
+
to = File.join(destination, entry.name)
|
20
|
+
dirname = File.dirname(to)
|
21
|
+
|
22
|
+
FileUtils.mkdir_p dirname unless File.exist? dirname
|
23
|
+
zip.extract(entry, to)
|
24
|
+
end
|
22
25
|
end
|
26
|
+
|
27
|
+
destination
|
23
28
|
end
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
def zip(path)
|
31
|
+
with_tmp_zip do |zip|
|
32
|
+
::Find.find(path) do |file|
|
33
|
+
unless File.directory?(file)
|
34
|
+
add_zip_entry zip, file, file.sub("#{path}/", '')
|
35
|
+
end
|
36
|
+
end
|
27
37
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
begin
|
33
|
-
zip_path = File.join(tmp_dir, "webdriver-zip")
|
38
|
+
zip.commit
|
39
|
+
File.open(zip.name, "rb") { |io| Base64.strict_encode64 io.read }
|
40
|
+
end
|
41
|
+
end
|
34
42
|
|
35
|
-
|
36
|
-
|
37
|
-
|
43
|
+
def zip_file(path)
|
44
|
+
with_tmp_zip do |zip|
|
45
|
+
add_zip_entry zip, path, File.basename(path)
|
38
46
|
|
39
|
-
|
40
|
-
|
47
|
+
zip.commit
|
48
|
+
File.open(zip.name, "rb") { |io| Base64.strict_encode64 io.read }
|
49
|
+
end
|
50
|
+
end
|
41
51
|
|
42
|
-
|
43
|
-
|
44
|
-
|
52
|
+
private
|
53
|
+
|
54
|
+
def with_tmp_zip(&blk)
|
55
|
+
# can't use Tempfile here since it doesn't support File::BINARY mode on 1.8
|
56
|
+
# can't use Dir.mktmpdir(&blk) because of http://jira.codehaus.org/browse/JRUBY-4082
|
57
|
+
tmp_dir = Dir.mktmpdir
|
58
|
+
zip_path = File.join(tmp_dir, "webdriver-zip")
|
59
|
+
|
60
|
+
begin
|
61
|
+
Zip::ZipFile.open(zip_path, Zip::ZipFile::CREATE, &blk)
|
62
|
+
ensure
|
63
|
+
FileUtils.rm_rf tmp_dir
|
64
|
+
FileUtils.rm_rf zip_path
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_zip_entry(zip, file, entry_name)
|
69
|
+
entry = Zip::ZipEntry.new(zip.name, entry_name)
|
70
|
+
entry.follow_symlinks = true
|
45
71
|
|
46
|
-
|
47
|
-
ensure
|
48
|
-
FileUtils.rm_rf tmp_dir
|
72
|
+
zip.add entry, file
|
49
73
|
end
|
50
|
-
end
|
51
74
|
|
75
|
+
end
|
52
76
|
end # Zipper
|
53
77
|
end # WebDriver
|
54
78
|
end # Selenium
|
@@ -21,6 +21,7 @@ require 'selenium/webdriver/common/action_builder'
|
|
21
21
|
require 'selenium/webdriver/common/driver_extensions/takes_screenshot'
|
22
22
|
require 'selenium/webdriver/common/driver_extensions/rotatable'
|
23
23
|
require 'selenium/webdriver/common/driver_extensions/has_input_devices'
|
24
|
+
require 'selenium/webdriver/common/driver_extensions/uploads_files'
|
24
25
|
require 'selenium/webdriver/common/keys'
|
25
26
|
require 'selenium/webdriver/common/bridge_helper'
|
26
27
|
require 'selenium/webdriver/common/profile_helper'
|
Binary file
|
Binary file
|
Binary file
|
@@ -29,7 +29,7 @@ module Selenium
|
|
29
29
|
COMMANDS[name] = [verb, url.freeze]
|
30
30
|
end
|
31
31
|
|
32
|
-
attr_accessor :context, :http
|
32
|
+
attr_accessor :context, :http, :file_detector
|
33
33
|
attr_reader :capabilities
|
34
34
|
|
35
35
|
#
|
@@ -64,8 +64,8 @@ module Selenium
|
|
64
64
|
|
65
65
|
http_client.server_url = uri
|
66
66
|
|
67
|
-
@http
|
68
|
-
@capabilities
|
67
|
+
@http = http_client
|
68
|
+
@capabilities = create_session(desired_capabilities)
|
69
69
|
end
|
70
70
|
|
71
71
|
def browser
|
@@ -73,7 +73,11 @@ module Selenium
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def driver_extensions
|
76
|
-
[
|
76
|
+
[
|
77
|
+
DriverExtensions::HasInputDevices,
|
78
|
+
DriverExtensions::UploadsFiles,
|
79
|
+
DriverExtensions::TakesScreenshot
|
80
|
+
]
|
77
81
|
end
|
78
82
|
|
79
83
|
#
|
@@ -110,7 +114,7 @@ module Selenium
|
|
110
114
|
#
|
111
115
|
# alerts
|
112
116
|
#
|
113
|
-
|
117
|
+
|
114
118
|
def getAlert
|
115
119
|
execute :getAlert
|
116
120
|
end
|
@@ -270,6 +274,10 @@ module Selenium
|
|
270
274
|
execute :sendModifierKeyToActiveElement, {}, :value => key, :isdown => down
|
271
275
|
end
|
272
276
|
|
277
|
+
def sendKeysToActiveElement(key)
|
278
|
+
execute :sendKeysToActiveElement, {}, :value => key
|
279
|
+
end
|
280
|
+
|
273
281
|
def getElementTagName(element)
|
274
282
|
execute :getElementTagName, :id => element
|
275
283
|
end
|
@@ -305,7 +313,19 @@ module Selenium
|
|
305
313
|
end
|
306
314
|
|
307
315
|
def sendKeysToElement(element, keys)
|
308
|
-
|
316
|
+
if @file_detector && local_file = @file_detector.call(keys)
|
317
|
+
keys = upload(local_file)
|
318
|
+
end
|
319
|
+
|
320
|
+
execute :sendKeysToElement, {:id => element}, {:value => Array(keys)}
|
321
|
+
end
|
322
|
+
|
323
|
+
def upload(local_file)
|
324
|
+
unless File.file?(local_file)
|
325
|
+
raise WebDriverError::Error, "you may only upload files: #{local_file.inspect}"
|
326
|
+
end
|
327
|
+
|
328
|
+
execute :uploadFile, {}, :file => Zipper.zip_file(local_file)
|
309
329
|
end
|
310
330
|
|
311
331
|
def clearElement(element)
|
@@ -61,6 +61,7 @@ class Selenium::WebDriver::Remote::Bridge
|
|
61
61
|
command :setVisible, :post, "session/:session_id/visible"
|
62
62
|
command :getScreenOrientation, :get, "session/:session_id/orientation"
|
63
63
|
command :setScreenOrientation, :post, "session/:session_id/orientation"
|
64
|
+
command :uploadFile, :post, "session/:session_id/file"
|
64
65
|
|
65
66
|
# interactions API
|
66
67
|
command :click, :post, "session/:session_id/click"
|
@@ -69,4 +70,6 @@ class Selenium::WebDriver::Remote::Bridge
|
|
69
70
|
command :mouseUp, :post, "session/:session_id/buttonup"
|
70
71
|
command :mouseMoveTo, :post, "session/:session_id/moveto"
|
71
72
|
command :sendModifierKeyToActiveElement, :post, "session/:session_id/modifier"
|
73
|
+
command :sendKeysToActiveElement, :post, "session/:session_id/keys"
|
74
|
+
|
72
75
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: selenium-webdriver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 2.
|
5
|
+
version: 2.9.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jari Bakken
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-10-
|
13
|
+
date: 2011-10-21 00:00:00 +02:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -52,9 +52,9 @@ dependencies:
|
|
52
52
|
requirement: &id004 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
54
54
|
requirements:
|
55
|
-
- - "
|
55
|
+
- - "="
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: 1.0.
|
57
|
+
version: 1.0.9
|
58
58
|
type: :runtime
|
59
59
|
version_requirements: *id004
|
60
60
|
- !ruby/object:Gem::Dependency
|
@@ -168,6 +168,7 @@ files:
|
|
168
168
|
- lib/selenium/webdriver/common/driver_extensions/has_input_devices.rb
|
169
169
|
- lib/selenium/webdriver/common/driver_extensions/rotatable.rb
|
170
170
|
- lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb
|
171
|
+
- lib/selenium/webdriver/common/driver_extensions/uploads_files.rb
|
171
172
|
- lib/selenium/webdriver/firefox/binary.rb
|
172
173
|
- lib/selenium/webdriver/firefox/bridge.rb
|
173
174
|
- lib/selenium/webdriver/firefox/extension.rb
|