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 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