webdriver_manager 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e4aeaf20ec28b501c430be20216b74c11220a8df
4
- data.tar.gz: ae1628a32666ca6b9c2155b53818fdbc73016a67
3
+ metadata.gz: 3f0a5567c780cf6ec15dea2f8e3be9008bebe93f
4
+ data.tar.gz: a031045d7ec8bbebc1e569ddcd446187963e3742
5
5
  SHA512:
6
- metadata.gz: 42bae2ba53f1dd8091247960fbaa27b6251bd924ba71eed039c2ef0c3317a4b59fc6924a14e0127cac5a3332b2d79b18c83b30c0004a571d81acfc5d3aa01cdf
7
- data.tar.gz: c4b610941b9aae489bcd407bf13698b7c91b949fad88db68b555bd0219de9ac1513eee29fbaea90784cb129647f85153fea5afa5503935ac74429b4c2e05569c
6
+ metadata.gz: 3e3e053298e1452ec0abfd6829e8ed463d62257011790dac7e720e4bcb186f6da903eae4818e9f088beb4139fc092a95a6a8e51abeba04a61100145479e993dd
7
+ data.tar.gz: 9e695c5889e5d398a91a4650ee54e2fc0b9ee803bc2d7f342bf4ca67b71d28beb2d9ec443f32e592d75e4eb92ad077c6add039af9bc021d84847350816a4f3c3
data/.gitignore CHANGED
@@ -17,6 +17,7 @@
17
17
  *.swp
18
18
  *.bak
19
19
  .rspec_status
20
+ webdriver_manager.log
20
21
 
21
22
  # IDE-Specific
22
23
 
data/.hound.yml CHANGED
@@ -60,3 +60,8 @@ Metrics/MethodLength:
60
60
  # Encourage fewer parameters.
61
61
  Metrics/ParameterLists:
62
62
  Max: 4
63
+
64
+ # Additions for WebDriver Manager
65
+
66
+ Metrics/ModuleLength:
67
+ Max: 135
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # WebDriver Manager
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/webdriver_manager.svg)](http://badge.fury.io/rb/webdriver_manager)
4
+ [![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jeffnyman/webdriver_manager/blob/master/LICENSE.txt)
5
+
6
+ [![Dependency Status](https://gemnasium.com/jeffnyman/webdriver_manager.png)](https://gemnasium.com/jeffnyman/webdriver_manager)
7
+
3
8
  The goal of WebDriver Manager is to allow automated testing solutions an ability to have WebDriver binary drivers downloaded automatically.
4
9
 
5
10
  ## Installation
@@ -20,7 +25,51 @@ You can also install WebDriver Manager just as you would any other gem:
20
25
 
21
26
  ## Usage
22
27
 
23
- Instructions coming soon.
28
+ ### Basic Usage
29
+
30
+ Here is an example script:
31
+
32
+ ```ruby
33
+ require "webdriver_manager"
34
+ require "watir"
35
+
36
+ browser = Watir::Browser.new :firefox
37
+
38
+ browser.quit()
39
+ ```
40
+
41
+ All you have to do is include `webdriver_manager`. Once it's included, the gem provides hooks into the operation of Selenium WebDriver. When Watir, in this case, is used to instantiate a new Firefox browser, this gem kicks in and makes sure that `geckodriver` (or `geckodriver.exe` on Windows) is available. If the driver binary is not available, it will be downloaded for you.
42
+
43
+ All driver binaries are placed in a `.webdrivers` directory within the relevant directory referred to by the `HOME` environment variable for your operating system.
44
+
45
+ ### Browser Drivers Supported
46
+
47
+ Currently WebDriver Manager supports only Chrome (chromedriver) and Firefox (geckodriver). I will be adding support for other browsers, such as Internet Explorer and Microsoft Edge, once I'm certain I have a fully reliable means of getting the drivers.
48
+
49
+ ### Logging
50
+
51
+ You can enable logging with WebDriver Manager with a command like this:
52
+
53
+ ```ruby
54
+ WebDriverManager.logger.level = :debug
55
+ ```
56
+
57
+ There are debug statements in the code base that will show you what's happening as WebDriver Manager operates. But you are free to add your own messages as well. For example, you could set the logging level to `info` and then add your own messages:
58
+
59
+ ```ruby
60
+ WebDriverManager.logger.level = :info
61
+ WebDriverManager.logger.info("Some Information")
62
+ ```
63
+
64
+ You can also set the logging output to a file:
65
+
66
+ ```ruby
67
+ WebDriverManager.logger.output = 'webdriver_manager.log'
68
+ ```
69
+
70
+ ### How It Works
71
+
72
+ WebDriver Manager works by providing an additional implementation to the `@driver_path` variable that Selenium uses when establishing an instance of a driver. For example, the [Chrome](https://github.com/SeleniumHQ/selenium/blob/master/rb/lib/selenium/webdriver/chrome.rb) implementation simply takes in a path for the driver. This gem overrides that with its own specific functionality for providing a standard path and making sure the relevant binaries are on that path and downloading them if not.
24
73
 
25
74
  ## Development
26
75
 
@@ -1,4 +1,11 @@
1
1
  require "webdriver_manager/version"
2
+ require "webdriver_manager/logger"
3
+ require "webdriver_manager/selenium"
2
4
 
3
5
  module WebDriverManager
6
+ class << self
7
+ def logger
8
+ @logger ||= WebDriverManager::Logger.new
9
+ end
10
+ end
4
11
  end
@@ -0,0 +1,64 @@
1
+ require "nokogiri"
2
+
3
+ module WebDriverManager
4
+ class ChromeDriver
5
+ extend Support
6
+
7
+ class << self
8
+ def current_binary
9
+ WebDriverManager.logger.debug("Checking Current Driver Version")
10
+ return nil unless driver_is_downloaded?
11
+ binary_version = `#{driver_binary} --version`
12
+ WebDriverManager.logger.debug(
13
+ "Current version of #{driver_binary} is #{binary_version}"
14
+ )
15
+ normalize(binary_version.match(/ChromeDriver (\d\.\d+)/)[1])
16
+ end
17
+
18
+ def driver_name
19
+ os_platform == "win" ? "chromedriver.exe" : "chromedriver"
20
+ end
21
+
22
+ def driver_base_url
23
+ "http://chromedriver.storage.googleapis.com"
24
+ end
25
+
26
+ def driver_binary_list
27
+ unless driver_url_is_reachable?
28
+ raise StandardError, "Unable to Access the Driver URL"
29
+ end
30
+
31
+ @binaries ||= begin
32
+ files = process_binary_files
33
+ process_binary_versions(files)
34
+ end
35
+ end
36
+
37
+ def process_binary_files
38
+ resource = Nokogiri::XML.parse(get(driver_base_url))
39
+ files = resource.css("Contents Key").collect(&:text)
40
+ files.select! { |file| file.include?(os_platform) }
41
+ end
42
+
43
+ def process_binary_versions(files)
44
+ binary_list = files.each_with_object({}) do |file, binary|
45
+ version = normalize(file[%r{^[^\/]+}])
46
+ binary[version] = "#{driver_base_url}/#{file}"
47
+ end
48
+
49
+ WebDriverManager.logger.debug(
50
+ "Versions Located at Driver URL: #{binary_list.keys}"
51
+ )
52
+
53
+ binary_list
54
+ end
55
+
56
+ # This method makes sure that versions are stored with the same
57
+ # style. For example, 2.10 will be stored exactly as that. But 2.9
58
+ # will be stored as 2.09.
59
+ def normalize(string)
60
+ string.size == 3 ? string.gsub('.', '.0').to_f : string.to_f
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,65 @@
1
+ require "nokogiri"
2
+
3
+ module WebDriverManager
4
+ class GeckoDriver
5
+ extend Support
6
+
7
+ class << self
8
+ def current_binary
9
+ WebDriverManager.logger.debug("Checking Current Driver Version")
10
+ return nil unless driver_is_downloaded?
11
+ binary_version = `#{driver_binary} --version`
12
+ WebDriverManager.logger.debug(
13
+ "Current version of #{driver_binary} is #{binary_version}"
14
+ )
15
+ normalize(binary_version.match(/geckodriver (\d+\.\d+\.\d+)/)[1])
16
+ end
17
+
18
+ def driver_name
19
+ os_platform == "win" ? "geckodriver.exe" : "geckodriver"
20
+ end
21
+
22
+ def driver_base_url
23
+ "https://github.com/mozilla/geckodriver/releases"
24
+ end
25
+
26
+ def driver_binary_list
27
+ unless driver_url_is_reachable?
28
+ raise StandardError, "Unable to Access the Driver URL"
29
+ end
30
+
31
+ @binaries ||= begin
32
+ files = process_binary_files
33
+ process_binary_versions(files)
34
+ end
35
+ end
36
+
37
+ def process_binary_files
38
+ resource = Nokogiri::XML.parse(get(driver_base_url))
39
+ files = resource.css(".release-downloads a")
40
+ .collect { |file| file["href"] }
41
+ files.reject! { |file| file.include?('archive') }
42
+ files.select! { |file| file.include?(os_platform) }
43
+ end
44
+
45
+ def process_binary_versions(files)
46
+ binary_list = files.each_with_object({}) do |file, binary|
47
+ version = normalize(file[/v(\d+\.\d+\.\d+)/, 1])
48
+ binary[version] = "https://github.com#{file}"
49
+ end
50
+
51
+ WebDriverManager.logger.debug(
52
+ "Versions Located at Driver URL: #{binary_list.keys}"
53
+ )
54
+
55
+ binary_list
56
+ end
57
+
58
+ def normalize(string)
59
+ string.match(/(\d+)\.(\d+\.\d+)/)
60
+ .to_a
61
+ .map { |v| v.tr('.', '') }[1..-1].join('.').to_f
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,54 @@
1
+ require "forwardable"
2
+ require "logger"
3
+
4
+ module WebDriverManager
5
+ class Logger
6
+ extend Forwardable
7
+ include ::Logger::Severity
8
+
9
+ def_delegators :@logger,
10
+ :debug, :debug?,
11
+ :info, :info?,
12
+ :warn, :warn?,
13
+ :error, :error?,
14
+ :fatal, :fatal?,
15
+ :level
16
+
17
+ def initialize
18
+ @logger = create_logger($stdout)
19
+ end
20
+
21
+ def level=(severity)
22
+ case severity.to_s.downcase
23
+ when 'debug'.freeze then @logger.level = DEBUG
24
+ when 'info'.freeze then @logger.level = INFO
25
+ when 'warn'.freeze then @logger.level = WARN
26
+ when 'error'.freeze then @logger.level = ERROR
27
+ else
28
+ raise ArgumentError, "invalid log level: #{severity}"
29
+ end
30
+ end
31
+
32
+ def output=(io)
33
+ if @logger.respond_to?(:reopen)
34
+ @logger.reopen(io)
35
+ else
36
+ @logger = create_logger(io)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def create_logger(output)
43
+ logger = ::Logger.new(output)
44
+ logger.progname = 'WebDriver Manager'
45
+ logger.level = ($DEBUG ? DEBUG : WARN)
46
+
47
+ logger.formatter = proc do |severity, time, progname, msg|
48
+ "#{time.strftime('%F %T')} #{severity} #{progname} #{msg}\n"
49
+ end
50
+
51
+ logger
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,21 @@
1
+ require "selenium-webdriver"
2
+
3
+ require "webdriver_manager/support"
4
+ require "webdriver_manager/drivers/driver_chrome"
5
+ require "webdriver_manager/drivers/driver_gecko"
6
+
7
+ module Selenium
8
+ module WebDriver
9
+ module Chrome
10
+ def self.driver_path
11
+ @driver_path ||= WebDriverManager::ChromeDriver.provision
12
+ end
13
+ end
14
+
15
+ module Firefox
16
+ def self.driver_path
17
+ @driver_path ||= WebDriverManager::GeckoDriver.provision
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,166 @@
1
+ module WebDriverManager
2
+ module Support
3
+ def provision
4
+ unless driver_url_is_reachable?
5
+ return current_binary.nil? ? nil : driver_binary
6
+ end
7
+
8
+ return driver_binary if current_binary == latest_binary
9
+
10
+ remove_binary && provision_driver
11
+ end
12
+
13
+ def provision_driver(version = nil)
14
+ url, filename = driver_filename(version)
15
+ Dir.mkdir(driver_repo) unless File.exist?(driver_repo)
16
+
17
+ Dir.chdir(driver_repo) do
18
+ download_driver(filename, url)
19
+ decompress_driver(filename)
20
+ end
21
+
22
+ set_driver_permissions
23
+ driver_binary
24
+ end
25
+
26
+ def remove_binary
27
+ WebDriverManager.logger.debug("Deleting #{driver_binary}")
28
+ FileUtils.rm_f(driver_binary)
29
+ end
30
+
31
+ def latest_binary
32
+ driver_binary_list.keys.sort.last
33
+ end
34
+
35
+ protected
36
+
37
+ def get(url)
38
+ response = Net::HTTP.get_response(URI(url))
39
+
40
+ case response
41
+ when Net::HTTPSuccess then response.body
42
+ when Net::HTTPRedirection
43
+ location = response['location']
44
+ WebDriverManager.logger.debug("Redirected to #{location}")
45
+ get(location)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def download_driver(filename, url)
52
+ FileUtils.rm_f(filename)
53
+
54
+ open(filename, "wb") do |file|
55
+ file.print(get(url))
56
+ end
57
+
58
+ raise "Unable to download #{url}" unless File.exist?(filename)
59
+ WebDriverManager.logger.debug("Successfully downloaded #{filename}")
60
+ end
61
+
62
+ def decompress_driver(filename)
63
+ dcf = decompress_file(filename)
64
+ WebDriverManager.logger.debug("Decompression Complete")
65
+
66
+ if dcf
67
+ WebDriverManager.logger.debug("Deleting #{filename}")
68
+ FileUtils.rm_f(filename)
69
+ end
70
+
71
+ return if File.exist?(driver_binary)
72
+ raise "Unable to decompress #{filename} to get #{driver_binary}"
73
+ end
74
+
75
+ def decompress_file(filename)
76
+ case filename
77
+ when /tar\.gz$/
78
+ WebDriverManager.logger.debug("Decompressing tar")
79
+ untargz_file(filename)
80
+ when /\.zip$/
81
+ WebDriverManager.logger.debug("Decompressing zip")
82
+ unzip_file(filename)
83
+ end
84
+ end
85
+
86
+ def unzip_file(filename)
87
+ require "zip"
88
+ Zip::File.open("#{Dir.pwd}/#{filename}") do |zip_file|
89
+ zip_file.each do |f|
90
+ @top_path ||= f.name
91
+ f_path = File.join(Dir.pwd, f.name)
92
+
93
+ remove_binary
94
+
95
+ zip_file.extract(f, f_path)
96
+ end
97
+ end
98
+ @top_path
99
+ end
100
+
101
+ def untargz_file(filename)
102
+ require "rubygems/package"
103
+ tar_extract = Gem::Package::TarReader.new(Zlib::GzipReader.open(filename))
104
+ file = File.open(driver_name, "w+b")
105
+ tar_extract.each { |entry| file << entry.read }
106
+ file.close
107
+ File.basename(file)
108
+ end
109
+
110
+ def set_driver_permissions
111
+ FileUtils.chmod("ugo+rx", driver_binary)
112
+ WebDriverManager.logger.debug(
113
+ "Completed download and processing of #{driver_binary}"
114
+ )
115
+ end
116
+
117
+ def driver_filename(version)
118
+ url = driver_download_url(version)
119
+ filename = File.basename(url)
120
+ [url, filename]
121
+ end
122
+
123
+ def driver_url_is_reachable?
124
+ get(driver_base_url)
125
+ WebDriverManager.logger.debug("Driver URL Available: #{driver_base_url}")
126
+ true
127
+ rescue StandardError
128
+ WebDriverManager.logger.debug(
129
+ "Driver URL Not Available: #{driver_base_url}"
130
+ )
131
+ false
132
+ end
133
+
134
+ def driver_is_downloaded?
135
+ result = File.exist?(driver_binary)
136
+ WebDriverManager.logger.debug("Driver Already Downloaded: #{result}")
137
+ result
138
+ end
139
+
140
+ def driver_download_url(version)
141
+ driver_binary_list[version || latest_binary]
142
+ end
143
+
144
+ def driver_binary
145
+ File.join(driver_repo, driver_name)
146
+ end
147
+
148
+ def driver_repo
149
+ File.expand_path(File.join(ENV['HOME'], ".webdrivers")).tap do |dir|
150
+ FileUtils.mkdir_p(dir)
151
+ end
152
+ end
153
+
154
+ def os_platform
155
+ cfg = RbConfig::CONFIG
156
+ case cfg['host_os']
157
+ when /linux/
158
+ cfg['host_cpu'] =~ /x86_64|amd64/ ? "linux64" : "linux32"
159
+ when /darwin/
160
+ "mac"
161
+ else
162
+ "win"
163
+ end
164
+ end
165
+ end
166
+ end
@@ -1,3 +1,3 @@
1
1
  module WebDriverManager
2
- VERSION = "0.1.0".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -27,6 +27,9 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency "rubocop"
28
28
  spec.add_development_dependency "pry"
29
29
 
30
+ spec.add_runtime_dependency "selenium-webdriver", "~> 3.0"
31
+ spec.add_runtime_dependency "nokogiri", "~> 1.8"
32
+
30
33
  spec.post_install_message = %{
31
34
  (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
32
35
  WebDriver Manager #{WebDriverManager::VERSION} has been installed.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webdriver_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Nyman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-06 00:00:00.000000000 Z
11
+ date: 2017-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,34 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: selenium-webdriver
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: nokogiri
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.8'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.8'
83
111
  description: Provides a method of automatically downloading WebDriver binaries.
84
112
  email:
85
113
  - jeffnyman@gmail.com
@@ -100,6 +128,11 @@ files:
100
128
  - bin/console
101
129
  - bin/setup
102
130
  - lib/webdriver_manager.rb
131
+ - lib/webdriver_manager/drivers/driver_chrome.rb
132
+ - lib/webdriver_manager/drivers/driver_gecko.rb
133
+ - lib/webdriver_manager/logger.rb
134
+ - lib/webdriver_manager/selenium.rb
135
+ - lib/webdriver_manager/support.rb
103
136
  - lib/webdriver_manager/version.rb
104
137
  - webdriver_manager.gemspec
105
138
  homepage: https://github.com/jeffnyman/webdriver_manager
@@ -107,7 +140,7 @@ licenses:
107
140
  - MIT
108
141
  metadata: {}
109
142
  post_install_message: "\n(::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)\n
110
- \ WebDriver Manager 0.1.0 has been installed.\n(::) (::) (::) (::) (::) (::) (::)
143
+ \ WebDriver Manager 0.2.0 has been installed.\n(::) (::) (::) (::) (::) (::) (::)
111
144
  (::) (::) (::) (::) (::)\n "
112
145
  rdoc_options: []
113
146
  require_paths:
@@ -124,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
157
  version: '0'
125
158
  requirements: []
126
159
  rubyforge_project:
127
- rubygems_version: 2.6.13
160
+ rubygems_version: 2.6.11
128
161
  signing_key:
129
162
  specification_version: 4
130
163
  summary: Provides a method of automatically downloading WebDriver binaries.