webdrivers 4.0.1 → 4.1.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.
@@ -42,9 +42,10 @@ module Webdrivers
42
42
  # Returns currently installed Chrome/Chromium version.
43
43
  #
44
44
  # @return [Gem::Version]
45
- def chrome_version
45
+ def browser_version
46
46
  normalize_version ChromeFinder.version
47
47
  end
48
+ alias chrome_version browser_version
48
49
 
49
50
  #
50
51
  # Returns url with domain for calls to get this driver.
@@ -102,7 +103,7 @@ module Webdrivers
102
103
  # @example
103
104
  # 73.0.3683.75 -> 73.0.3683
104
105
  def release_version
105
- chrome = normalize_version(chrome_version)
106
+ chrome = normalize_version(browser_version)
106
107
  normalize_version(chrome.segments[0..2].join('.'))
107
108
  end
108
109
 
@@ -19,6 +19,7 @@ module Webdrivers
19
19
  end
20
20
 
21
21
  DEFAULT_CACHE_TIME = 86_400 # 24 hours
22
+ DEFAULT_INSTALL_DIR = File.expand_path(File.join(ENV['HOME'], '.webdrivers'))
22
23
 
23
24
  class << self
24
25
  attr_accessor :proxy_addr, :proxy_port, :proxy_user, :proxy_pass
@@ -30,7 +31,8 @@ module Webdrivers
30
31
  # are set, it defaults to 86,400 Seconds (24 hours).
31
32
  #
32
33
  def cache_time
33
- (ENV['WD_CACHE_TIME'] || @cache_time || DEFAULT_CACHE_TIME).to_i
34
+ @cache_time ||= (ENV['WD_CACHE_TIME'] || DEFAULT_CACHE_TIME)
35
+ @cache_time.to_i
34
36
  end
35
37
 
36
38
  #
@@ -38,7 +40,7 @@ module Webdrivers
38
40
  #
39
41
  # @return [String]
40
42
  def install_dir
41
- @install_dir || ENV['WD_INSTALL_DIR'] || File.expand_path(File.join(ENV['HOME'], '.webdrivers'))
43
+ @install_dir ||= ENV['WD_INSTALL_DIR'] || DEFAULT_INSTALL_DIR
42
44
  end
43
45
 
44
46
  def logger
@@ -65,7 +67,7 @@ module Webdrivers
65
67
  raise 'Webdrivers.net_http_ssl_fix is no longer available.' \
66
68
  ' Please see https://github.com/titusfortner/webdrivers#ssl_connect-errors.'
67
69
  end
68
- end
70
+ end
69
71
 
70
72
  class Common
71
73
  class << self
@@ -76,7 +78,7 @@ end
76
78
  #
77
79
  # @return [Gem::Version]
78
80
  def required_version
79
- normalize_version @required_version
81
+ normalize_version(@required_version ||= nil)
80
82
  end
81
83
 
82
84
  #
@@ -109,7 +111,7 @@ end
109
111
  #
110
112
  # @return [String]
111
113
  def driver_path
112
- System.escape_path File.join(System.install_dir, file_name)
114
+ File.absolute_path File.join(System.install_dir, file_name)
113
115
  end
114
116
 
115
117
  private
@@ -145,7 +147,7 @@ end
145
147
  end
146
148
 
147
149
  def binary_version
148
- version = System.call("#{driver_path} --version")
150
+ version = System.call(driver_path, '--version')
149
151
  Webdrivers.logger.debug "Current version of #{driver_path} is #{version}"
150
152
  version
151
153
  rescue Errno::ENOENT
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Webdrivers
4
+ #
5
+ # @api private
6
+ #
7
+ class EdgeFinder
8
+ class << self
9
+ def version
10
+ version = send("#{System.platform}_version", location)
11
+
12
+ raise VersionError, 'Failed to find Edge binary or its version.' if version.nil? || version.empty?
13
+
14
+ Webdrivers.logger.debug "Browser version: #{version}"
15
+ version[/\d+\.\d+\.\d+\.\d+/] # Microsoft Edge 73.0.3683.75 -> 73.0.3683.75
16
+ end
17
+
18
+ def location
19
+ user_defined_location || send("#{System.platform}_location")
20
+ end
21
+
22
+ private
23
+
24
+ def user_defined_location
25
+ if Selenium::WebDriver::EdgeChrome.path
26
+ Webdrivers.logger.debug "Selenium::WebDriver::EdgeChrome.path: #{Selenium::WebDriver::EdgeChrome.path}"
27
+ return Selenium::WebDriver::EdgeChrome.path
28
+ end
29
+
30
+ return if ENV['WD_EDGE_CHROME_PATH'].nil?
31
+
32
+ Webdrivers.logger.debug "WD_EDGE_CHROME_PATH: #{ENV['WD_EDGE_CHROME_PATH']}"
33
+ ENV['WD_EDGE_CHROME_PATH']
34
+ end
35
+
36
+ def win_location
37
+ envs = %w[LOCALAPPDATA PROGRAMFILES PROGRAMFILES(X86)]
38
+ directories = ['\\Microsoft\\Edge Dev\\Application', '\\Microsoft\\Edge SxS\\Application']
39
+ file = 'msedge.exe'
40
+
41
+ directories.each do |dir|
42
+ envs.each do |root|
43
+ option = "#{ENV[root]}\\#{dir}\\#{file}"
44
+ return option if File.exist?(option)
45
+ end
46
+ end
47
+ nil
48
+ end
49
+
50
+ def mac_location
51
+ directories = ['', File.expand_path('~')]
52
+ files = ['/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
53
+ '/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev',
54
+ '/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary']
55
+
56
+ directories.each do |dir|
57
+ files.each do |file|
58
+ option = "#{dir}/#{file}"
59
+ return option if File.exist?(option)
60
+ end
61
+ end
62
+ nil
63
+ end
64
+
65
+ def linux_location
66
+ raise 'Default location not yet known'
67
+ end
68
+
69
+ def win_version(location)
70
+ System.call("powershell (Get-ItemProperty '#{location}').VersionInfo.ProductVersion")&.strip
71
+ end
72
+
73
+ def linux_version(location)
74
+ System.call(location, '--product-version')&.strip
75
+ end
76
+
77
+ def mac_version(location)
78
+ System.call(location, '--version')&.strip
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'shellwords'
4
+ require 'webdrivers/common'
5
+ require 'webdrivers/chromedriver'
6
+ require 'webdrivers/edge_finder'
7
+
8
+ module Webdrivers
9
+ class Edgedriver < Chromedriver
10
+ class << self
11
+ undef :chrome_version
12
+ #
13
+ # Returns currently installed Edge version.
14
+ #
15
+ # @return [Gem::Version]
16
+ def browser_version
17
+ normalize_version EdgeFinder.version
18
+ end
19
+
20
+ #
21
+ # Returns url with domain for calls to get this driver.
22
+ #
23
+ # @return [String]
24
+ def base_url
25
+ # 'https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/'
26
+ 'https://msedgedriver.azureedge.net/'
27
+ end
28
+
29
+ def remove
30
+ super
31
+ end
32
+
33
+ private
34
+
35
+ def latest_point_release(version)
36
+ # Microsoft doesn't currently provide LATEST_RELEASE_X.Y.Z - only use X
37
+ # but require the driver version be >= the passed in version
38
+ str = Network.get(URI.join(base_url, "LATEST_RELEASE_#{version.segments[0]}"))
39
+ latest_release = normalize_version(str.encode('ASCII-8BIT', 'UTF-16'))
40
+ raise VersionError unless latest_release >= version
41
+
42
+ latest_release
43
+ rescue NetworkError, VersionError
44
+ msg = failed_to_find_message(version)
45
+ Webdrivers.logger.debug msg
46
+ raise VersionError, msg
47
+ end
48
+
49
+ def failed_to_find_message(version)
50
+ msg = "Unable to find latest point release version for #{version}."
51
+ msg = begin
52
+ # str = Network.get(URI.join(base_url, 'LATEST_RELEASE'))
53
+ # Microsoft doesn't yet/ever support LATEST_RELEASE - Use Canary as latest
54
+ str = Network.get(URI.join(base_url, 'LATEST_CANARY'))
55
+ latest_release = normalize_version(str.encode('ASCII-8BIT', 'UTF-16'))
56
+ if version > latest_release
57
+ "#{msg} You appear to be using a non-production version of Edge."
58
+ else
59
+ msg
60
+ end
61
+ rescue NetworkError
62
+ "#{msg} A network issue is preventing determination of latest msedgedriver release."
63
+ end
64
+
65
+ "#{msg} Please set `Webdrivers::Edgedriver.required_version = <desired driver version>` "\
66
+ "to a known edgedriver version: Can not reach #{base_url}"
67
+ end
68
+
69
+ def file_name
70
+ System.platform == 'win' ? 'msedgedriver.exe' : 'msedgedriver'
71
+ end
72
+
73
+ def download_url
74
+ return @download_url if @download_url
75
+
76
+ version = if required_version == EMPTY_VERSION
77
+ latest_version
78
+ else
79
+ normalize_version(required_version)
80
+ end
81
+
82
+ file_name = System.platform == 'win' ? 'win32' : "#{System.platform}64"
83
+ url = "#{base_url}/#{version}/edgedriver_#{file_name}.zip"
84
+ Webdrivers.logger.debug "msedgedriver URL: #{url}"
85
+ @download_url = url
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ if defined? Selenium::WebDriver::EdgeChrome
92
+ if ::Selenium::WebDriver::Service.respond_to? :driver_path=
93
+ ::Selenium::WebDriver::EdgeChrome::Service.driver_path = proc { ::Webdrivers::Edgedriver.update }
94
+ else
95
+ # v3.141.0 and lower
96
+ module Selenium
97
+ module WebDriver
98
+ module EdgeChrome
99
+ def self.driver_path
100
+ @driver_path ||= Webdrivers::Edgedriver.update
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'rubygems/package'
4
4
  require 'zip'
5
+ require 'English'
5
6
 
6
7
  module Webdrivers
7
8
  #
@@ -89,7 +90,7 @@ module Webdrivers
89
90
  when /tar\.bz2$/
90
91
  untarbz2_file(tempfile)
91
92
  when /\.zip$/
92
- unzip_file(tempfile)
93
+ unzip_file(tempfile, File.basename(target))
93
94
  else
94
95
  Webdrivers.logger.debug 'No Decompression needed'
95
96
  FileUtils.cp(tempfile, File.join(Dir.pwd, file_name))
@@ -114,19 +115,17 @@ module Webdrivers
114
115
  end
115
116
  end
116
117
 
117
- def unzip_file(filename)
118
+ def unzip_file(filename, driver_name)
118
119
  Webdrivers.logger.debug "Decompressing #{filename}"
119
120
 
120
121
  Zip::File.open(filename) do |zip_file|
121
- zip_file.each do |f|
122
- @top_path ||= f.name
123
- f_path = File.join(Dir.pwd, f.name)
124
- delete(f_path)
125
- FileUtils.mkdir_p(File.dirname(f_path)) unless File.exist?(File.dirname(f_path))
126
- zip_file.extract(f, f_path)
127
- end
122
+ driver = zip_file.get_entry(driver_name)
123
+ f_path = File.join(Dir.pwd, driver.name)
124
+ delete(f_path)
125
+ FileUtils.mkdir_p(File.dirname(f_path)) unless File.exist?(File.dirname(f_path))
126
+ zip_file.extract(driver, f_path)
128
127
  end
129
- @top_path
128
+ driver_name
130
129
  end
131
130
 
132
131
  def platform
@@ -145,15 +144,16 @@ module Webdrivers
145
144
  Selenium::WebDriver::Platform.bitsize
146
145
  end
147
146
 
148
- def call(cmd)
147
+ def call(process, arg = nil)
148
+ cmd = arg ? [process, arg] : process # Windows provides powershell command (process) only, no args.
149
149
  Webdrivers.logger.debug "making System call: #{cmd}"
150
- `#{cmd}`
151
- end
152
-
153
- def escape_path(path)
154
- return path.tr('/', '\\') if platform == 'win' # Windows
150
+ p = IO.popen(cmd)
151
+ out = p.read
152
+ p.close
153
+ raise "Failed to make system call: #{cmd}" unless $CHILD_STATUS.success?
155
154
 
156
- Shellwords.escape(path) # Linux and macOS
155
+ Webdrivers.logger.debug "System call returned: #{out}"
156
+ out
157
157
  end
158
158
  end
159
159
  end
@@ -19,8 +19,6 @@ namespace :webdrivers do
19
19
  desc 'Remove and download updated chromedriver if necessary'
20
20
  task :update, [:version] do |_, args|
21
21
  args.with_defaults(version: 0)
22
- Webdrivers.cache_time = ENV.fetch('WD_CACHE_TIME', 86_400)
23
- Webdrivers.install_dir = ENV.fetch('WD_INSTALL_DIR', nil)
24
22
  Webdrivers::Chromedriver.required_version = args.version
25
23
  Webdrivers::Chromedriver.update
26
24
  Webdrivers.logger.info "Updated to chromedriver #{Webdrivers::Chromedriver.current_version}"
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :webdrivers do
4
+ require 'webdrivers/edgedriver'
5
+
6
+ namespace :edgedriver do
7
+ Webdrivers.logger.level = :info
8
+
9
+ desc 'Print current edgedriver version'
10
+ task :version do
11
+ gem_ver = Webdrivers::Edgedriver.current_version
12
+ if gem_ver
13
+ Webdrivers.logger.info "edgedriver #{gem_ver.version}"
14
+ else
15
+ Webdrivers.logger.warn 'No existing edgedriver found.'
16
+ end
17
+ end
18
+
19
+ desc 'Remove and download updated edgedriver if necessary'
20
+ task :update, [:version] do |_, args|
21
+ args.with_defaults(version: 0)
22
+ Webdrivers::Edgedriver.required_version = args.version
23
+ Webdrivers::Edgedriver.update
24
+ Webdrivers.logger.info "Updated to edgedriver #{Webdrivers::Edgedriver.current_version}"
25
+ end
26
+
27
+ desc 'Force remove edgedriver'
28
+ task :remove do
29
+ unless File.exist? Webdrivers::Edgedriver.driver_path
30
+ Webdrivers.logger.info 'No existing edgedriver to remove.'
31
+ next # Return early
32
+ end
33
+
34
+ cur_version = Webdrivers::Edgedriver.current_version
35
+ Webdrivers::Edgedriver.remove
36
+
37
+ if File.exist? Webdrivers::Edgedriver.driver_path # Failed for some reason
38
+ Webdrivers.logger.error 'Failed to remove edgedriver. Please try removing manually.'
39
+ else
40
+ Webdrivers.logger.info "Removed edgedriver #{cur_version}."
41
+ end
42
+ end
43
+ end
44
+ end
@@ -19,8 +19,6 @@ namespace :webdrivers do
19
19
  desc 'Remove and download updated geckodriver if necessary'
20
20
  task :update, [:version] do |_, args|
21
21
  args.with_defaults(version: 0)
22
- Webdrivers.cache_time = ENV.fetch('WD_CACHE_TIME', 86_400)
23
- Webdrivers.install_dir = ENV.fetch('WD_INSTALL_DIR', nil)
24
22
  Webdrivers::Geckodriver.required_version = args.version
25
23
  Webdrivers::Geckodriver.update
26
24
  Webdrivers.logger.info "Updated to geckodriver #{Webdrivers::Geckodriver.current_version}"
@@ -19,8 +19,6 @@ namespace :webdrivers do
19
19
  desc 'Remove and download updated IEDriverServer if necessary'
20
20
  task :update, [:version] do |_, args|
21
21
  args.with_defaults(version: 0)
22
- Webdrivers.cache_time = ENV.fetch('WD_CACHE_TIME', 86_400)
23
- Webdrivers.install_dir = ENV.fetch('WD_INSTALL_DIR', nil)
24
22
  Webdrivers::IEdriver.required_version = args.version
25
23
  Webdrivers::IEdriver.update
26
24
  Webdrivers.logger.info "Updated to IEDriverServer #{Webdrivers::IEdriver.current_version}"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Webdrivers
4
- VERSION = '4.0.1'
4
+ VERSION = '4.1.0'
5
5
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Webdrivers::ChromeFinder do
6
+ let(:chrome_finder) { described_class }
7
+
8
+ context 'when the user relies on the gem to figure out the location of Chrome' do
9
+ it 'determines the location correctly based on the current OS' do
10
+ expect(chrome_finder.location).not_to be_nil
11
+ end
12
+ end
13
+
14
+ context 'when the user provides a path to the Chrome binary' do
15
+ it 'uses Selenium::WebDriver::Chrome.path when it is defined' do
16
+ Selenium::WebDriver::Chrome.path = chrome_finder.location
17
+ allow(chrome_finder).to receive(:win_location)
18
+ allow(chrome_finder).to receive(:mac_location)
19
+ allow(chrome_finder).to receive(:linux_location)
20
+ expect(chrome_finder.version).not_to be_nil
21
+ expect(chrome_finder).not_to have_received(:win_location)
22
+ expect(chrome_finder).not_to have_received(:mac_location)
23
+ expect(chrome_finder).not_to have_received(:linux_location)
24
+ end
25
+
26
+ it "uses ENV['WD_CHROME_PATH'] when it is defined" do
27
+ allow(ENV).to receive(:[]).with('WD_CHROME_PATH').and_return(chrome_finder.location)
28
+ allow(chrome_finder).to receive(:win_location)
29
+ allow(chrome_finder).to receive(:mac_location)
30
+ allow(chrome_finder).to receive(:linux_location)
31
+ expect(chrome_finder.version).not_to be_nil
32
+ expect(chrome_finder).not_to have_received(:win_location)
33
+ expect(chrome_finder).not_to have_received(:mac_location)
34
+ expect(chrome_finder).not_to have_received(:linux_location)
35
+ end
36
+
37
+ it 'uses Selenium::WebDriver::Chrome.path over WD_CHROME_PATH' do
38
+ Selenium::WebDriver::Chrome.path = chrome_finder.location
39
+ allow(ENV).to receive(:[]).with('WD_CHROME_PATH').and_return('my_wd_chrome_path')
40
+ expect(chrome_finder.version).not_to be_nil
41
+ expect(ENV).not_to have_received(:[]).with('WD_CHROME_PATH')
42
+ end
43
+ end
44
+ end