selenium-webdriver 2.8.0 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
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.6 through 1.9), JRuby and Rubinius.
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
 
@@ -1,5 +1,5 @@
1
1
 
2
- # Copyright 2006 ThoughtWorks, Inc
2
+ # Copyright 2011 Software Freedom Conservatory
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -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 = verify_model(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
- values = args.map do |arg|
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
- # 30
36
- # 31
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
- nil, # 30
71
- nil, # 31
72
- InvalidSelectorError # 32
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
- @bridge.sendModifierKeyToActiveElement Keys[key], true
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
- @bridge.sendModifierKeyToActiveElement Keys[key], false
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] || raise(Error::UnsupportedOperationError, "no such key #{key.inspect}")
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
- def self.unzip(path)
12
- destination = Dir.mktmpdir("unzip")
13
- FileReaper << destination
11
+ class << self
14
12
 
15
- Zip::ZipFile.open(path) do |zip|
16
- zip.each do |entry|
17
- to = File.join(destination, entry.name)
18
- dirname = File.dirname(to)
13
+ def unzip(path)
14
+ destination = Dir.mktmpdir("unzip")
15
+ FileReaper << destination
19
16
 
20
- FileUtils.mkdir_p dirname unless File.exist? dirname
21
- zip.extract(entry, to)
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
- destination
26
- end
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
- def self.zip(path)
29
- # can't use Tempfile here since it doesn't support File::BINARY mode on 1.8
30
- # can't use Dir.mktmpdir(&blk) because of http://jira.codehaus.org/browse/JRUBY-4082
31
- tmp_dir = Dir.mktmpdir
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
- Zip::ZipFile.open(zip_path, Zip::ZipFile::CREATE) { |zip|
36
- ::Find.find(path) do |file|
37
- next if File.directory?(file)
43
+ def zip_file(path)
44
+ with_tmp_zip do |zip|
45
+ add_zip_entry zip, path, File.basename(path)
38
46
 
39
- entry = Zip::ZipEntry.new(zip_path, file.sub("#{path}/", ''))
40
- entry.follow_symlinks = true
47
+ zip.commit
48
+ File.open(zip.name, "rb") { |io| Base64.strict_encode64 io.read }
49
+ end
50
+ end
41
51
 
42
- zip.add entry, file
43
- end
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
- File.open(zip_path, "rb") { |io| Base64.strict_encode64 io.read }
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'
@@ -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 = http_client
68
- @capabilities = create_session(desired_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
- [DriverExtensions::HasInputDevices, DriverExtensions::TakesScreenshot]
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
- execute :sendKeysToElement, {:id => element}, {:value => keys}
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.8.0
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-06 00:00:00 +02:00
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.7
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