Repository: saucelabs/sauce_bindings (language: python)

Issue:
Fix Links to Jobs in other Data Centers
Data centers now use
https://app.us-east-1.saucelabs.com/dashboard/tests/vdc
and
https://app.eu-central-1.saucelabs.com/dashboard/tests/vdc
and
https://app.apac-southeast-1.saucelabs.com/dashboard/tests/vdc

So need to update links to tests


Discussion / hints:

Fix patch:
diff --git a/java/main/src/main/java/com/saucelabs/saucebindings/DataCenter.java b/java/main/src/main/java/com/saucelabs/saucebindings/DataCenter.java
index fccc70aa..0f73452f 100644
--- a/java/main/src/main/java/com/saucelabs/saucebindings/DataCenter.java
+++ b/java/main/src/main/java/com/saucelabs/saucebindings/DataCenter.java
@@ -2,16 +2,30 @@
 
 import lombok.Getter;
 
+@Getter
 public enum DataCenter {
-    US_WEST("https://ondemand.us-west-1.saucelabs.com/wd/hub"),
-    US_EAST("https://ondemand.us-east-1.saucelabs.com/wd/hub"),
-    EU_CENTRAL("https://ondemand.eu-central-1.saucelabs.com/wd/hub"),
-    APAC_SOUTHEAST("https://ondemand.apac-southeast-1.saucelabs.com/wd/hub");
+    US_WEST("us-west-1"),
+    US_EAST("us-east-1"),
+    EU_CENTRAL("eu-central-1"),
+    APAC_SOUTHEAST("apac-southeast-1");
 
-    @Getter private final String value;
+    private final String value;
+    private final String endpoint;
+    private final String testLink;
+
+    @Deprecated
+    public String getValue() {
+        return this.endpoint;
+    }
 
     DataCenter(String value) {
         this.value = value;
+        this.endpoint = "https://ondemand." + value + ".saucelabs.com/wd/hub";
+        if ("us-west-1".equals(value)) {
+            this.testLink = "https://app.saucelabs.com/tests/";
+        } else {
+            this.testLink = "https://app." + value + ".saucelabs.com/tests/";
+        }
     }
 
     public String toString() {
diff --git a/java/main/src/main/java/com/saucelabs/saucebindings/SauceSession.java b/java/main/src/main/java/com/saucelabs/saucebindings/SauceSession.java
index e942d621..f407f330 100755
--- a/java/main/src/main/java/com/saucelabs/saucebindings/SauceSession.java
+++ b/java/main/src/main/java/com/saucelabs/saucebindings/SauceSession.java
@@ -56,7 +56,7 @@ public URL getSauceUrl() {
             if (sauceUrl != null) {
                 return sauceUrl;
             } else {
-                return new URL(getDataCenter().getValue());
+                return new URL(getDataCenter().getEndpoint());
             }
         } catch (MalformedURLException e) {
             throw new InvalidArgumentException("Invalid URL", e);
@@ -150,7 +150,7 @@ private void updateResult(String result) {
         String sauceReporter = String.format("SauceOnDemandSessionID=%s job-name=%s",
                 this.driver.getSessionId(),
                 this.sauceOptions.sauce().getName());
-        String sauceTestLink = String.format("Test Job Link: https://app.saucelabs.com/tests/%s",
+        String sauceTestLink = String.format("Test Job Link:" + getDataCenter().getTestLink() + "%s",
                 this.driver.getSessionId());
         System.out.print(sauceReporter + "\n" + sauceTestLink + "\n");
     }
diff --git a/python/saucebindings/options.py b/python/saucebindings/options.py
index 65619822..d5355be1 100644
--- a/python/saucebindings/options.py
+++ b/python/saucebindings/options.py
@@ -124,6 +124,14 @@ def __init__(self, browserName=None, validOptions=None, seleniumOptions=None, **
         for key, value in kwargs.items():
             self.set_capability(key, value)
 
+        if not os.getenv("SAUCE_USERNAME"):
+            raise KeyError("Cannot start session, Sauce Username is not set.")
+        elif not os.getenv("SAUCE_ACCESS_KEY"):
+            raise KeyError("Cannot start session, Sauce Access Key is not set.")
+        else:
+            self.options['sauce:options']['username'] = os.getenv("SAUCE_USERNAME")
+            self.options['sauce:options']['accessKey'] = os.getenv("SAUCE_ACCESS_KEY")
+
         if self.browser_version is None:
             self.set_capability('browserVersion', 'latest')
 
diff --git a/python/saucebindings/session.py b/python/saucebindings/session.py
index 6e3cd2de..655b4719 100644
--- a/python/saucebindings/session.py
+++ b/python/saucebindings/session.py
@@ -18,8 +18,6 @@ class SauceSession():
 
     def __init__(self, options=None, data_center='us-west', resolve_ip=False):
         self.options = options if options else SauceOptions.chrome()
-        self._username = os.getenv('SAUCE_USERNAME', None)
-        self._access_key = os.getenv('SAUCE_ACCESS_KEY', None)
         self.data_center = data_center if data_center else 'us-west'
         self._remote_url = None
         self._resolve_ip = resolve_ip if resolve_ip else False
@@ -36,11 +34,18 @@ def data_center(self, data_center):
 
         self._data_center = data_center
 
+    @property
+    def data_center_test_url(self):
+        if self.data_center != "us-west":
+            return "https://{}/tests/".format(data_centers[self._data_center]).replace("ondemand", "app")
+        else:
+            return "https://app.saucelabs.com/tests/"
+
     @property
     def remote_url(self):
         if self._remote_url is None:
             data_center = data_centers[self._data_center]
-            return 'https://{}:{}@{}:443/wd/hub'.format(self._username, self._access_key, data_center)
+            return 'https://{}/wd/hub'.format(data_center)
         else:
             return self._remote_url
 
@@ -49,11 +54,6 @@ def remote_url(self, remote_url):
         self._remote_url = remote_url
 
     def start(self):
-        if not self._username:
-            raise KeyError("Cannot start session, Sauce Username is not set.")
-        elif not self._access_key:
-            raise KeyError("Cannot start session, Sauce Access Key is not set.")
-
         self.driver = self.create_driver(self.remote_url, self.options.to_capabilities())
         return self.driver
 
@@ -84,7 +84,7 @@ def update_test_result(self, result_in):
         # The second print statement will output the job link to logging/console
         if self.driver is not None:
             print("SauceOnDemandSessioID={} job-name={}".format(self.driver.session_id, self.options.name))
-            print("Test Job Link: https://app.saucelabs.com/tests/{}".format(self.driver.session_id))
+            print("Test Job Link: {}{}".format(self.data_center_test_url, self.driver.session_id))
 
     def create_driver(self, url, capabilities):
         return webdriver.Remote(
diff --git a/ruby/.rubocop.yml b/ruby/.rubocop.yml
index 85f51309..05bc5d86 100644
--- a/ruby/.rubocop.yml
+++ b/ruby/.rubocop.yml
@@ -9,7 +9,7 @@ Layout/SpaceInsideHashLiteralBraces:
   EnforcedStyle: no_space
 
 Metrics/AbcSize:
-  Max: 25
+  Max: 27
 
 Metrics/BlockLength:
   Exclude:
diff --git a/ruby/Rakefile b/ruby/Rakefile
index 42fe79c6..3f797f7d 100644
--- a/ruby/Rakefile
+++ b/ruby/Rakefile
@@ -5,16 +5,18 @@ require 'rspec/core/rake_task'
 
 RSpec::Core::RakeTask.new(:spec)
 
-RSpec::Core::RakeTask.new(:examples) do |spec|
-  spec.pattern = 'spec/examples/*_spec.rb'
-end
+task default: %i[examples unit integration]
 
 RSpec::Core::RakeTask.new(:unit) do |spec|
   spec.pattern = 'spec/unit/*_spec.rb'
 end
 
-RSpec::Core::RakeTask.new(:integration) do |spec|
-  spec.pattern = 'spec/integration/*_spec.rb'
+desc 'Run examples in parallel'
+task :examples do
+  system 'parallel_split_test spec/examples/*_spec.rb'
 end
 
-task default: %i[examples unit integration]
+desc 'Run integration tests in parallel'
+task :integration do
+  system 'parallel_split_test spec/integration/*_spec.rb'
+end
diff --git a/ruby/lib/sauce_bindings/capybara_session.rb b/ruby/lib/sauce_bindings/capybara_session.rb
index 3790a381..f1bc89b1 100644
--- a/ruby/lib/sauce_bindings/capybara_session.rb
+++ b/ruby/lib/sauce_bindings/capybara_session.rb
@@ -15,9 +15,6 @@ def initialize(*)
     end
 
     def start
-      raise ArgumentError, "needs username; use `ENV['SAUCE_USERNAME']` or `Session#username=`" unless @username
-      raise ArgumentError, "needs access_key; use `ENV['SAUCE_ACCESS_KEY']` or `Session#access_key=`" unless @access_key
-
       @capybara_driver = Capybara.current_session.driver
       @driver = @capybara_driver.browser
     end
diff --git a/ruby/lib/sauce_bindings/options.rb b/ruby/lib/sauce_bindings/options.rb
index 3609e67e..00aa5f7c 100644
--- a/ruby/lib/sauce_bindings/options.rb
+++ b/ruby/lib/sauce_bindings/options.rb
@@ -86,7 +86,13 @@ def capabilities
         value = parse_w3c_key(key)
         caps[self.class.camel_case(key)] = value unless value.nil?
       end
+
       caps['sauce:options'] = {}
+      caps['sauce:options']['username'] = ENV['SAUCE_USERNAME'] ||
+                                          raise(ArgumentError, "needs username; use `ENV['SAUCE_USERNAME']`")
+      caps['sauce:options']['accessKey'] = ENV['SAUCE_ACCESS_KEY'] ||
+                                           raise(ArgumentError, "needs access key; use `ENV['SAUCE_ACCESS_KEY']`")
+
       SAUCE.each do |key|
         value = parse_sauce_key(key)
         caps['sauce:options'][self.class.camel_case(key)] = value unless value.nil?
diff --git a/ruby/lib/sauce_bindings/session.rb b/ruby/lib/sauce_bindings/session.rb
index 60cfa421..9c10cd97 100644
--- a/ruby/lib/sauce_bindings/session.rb
+++ b/ruby/lib/sauce_bindings/session.rb
@@ -6,10 +6,10 @@
 
 module SauceBindings
   class Session
-    DATA_CENTERS = {US_WEST: 'ondemand.us-west-1.saucelabs.com',
-                    US_EAST: 'ondemand.us-east-1.saucelabs.com',
-                    EU_CENTRAL: 'ondemand.eu-central-1.saucelabs.com',
-                    APAC_SOUTHEAST: 'ondemand.apac-southeast-1.saucelabs.com'}.freeze
+    DATA_CENTERS = {US_WEST: 'us-west-1',
+                    US_EAST: 'us-east-1',
+                    EU_CENTRAL: 'eu-central-1',
+                    APAC_SOUTHEAST: 'apac-southeast-1'}.freeze
 
     attr_writer :url
     attr_reader :driver, :options, :data_center
@@ -20,15 +20,10 @@ def initialize(options = nil, data_center: nil, http_client: nil, listener: nil)
       @http_client = http_client
       @listener = listener
 
-      @username = ENV['SAUCE_USERNAME']
-      @access_key = ENV['SAUCE_ACCESS_KEY']
       self.data_center = data_center || :US_WEST
     end
 
     def start
-      raise ArgumentError, "needs username; use `ENV['SAUCE_USERNAME']`" unless @username
-      raise ArgumentError, "needs access_key; use `ENV['SAUCE_ACCESS_KEY']`" unless @access_key
-
       @driver = Selenium::WebDriver.for :remote, to_selenium
     end
 
@@ -40,7 +35,10 @@ def stop(result)
       # The first print statement will automatically populate links on Jenkins to Sauce
       # The second print statement will output the job link to logging/console
       puts "SauceOnDemandSessionID=#{@driver.session_id} job-name=#{@options.name}"
-      puts "Test Job Link: https://app.saucelabs.com/tests/#{@driver.session_id}"
+
+      test_link = data_center == :US_WEST ? '' : "#{DATA_CENTERS[data_center]}."
+
+      puts "Test Job Link: https://app.#{test_link}saucelabs.com/tests/#{@driver.session_id}"
       @driver.quit
     end
 
@@ -60,7 +58,7 @@ def accessibility_results(js_lib: nil, frames: true, cross_origin: false)
     end
 
     def url
-      @url ||= "https://#{@username}:#{@access_key}@#{DATA_CENTERS[data_center]}:443/wd/hub"
+      @url ||= "https://ondemand.#{DATA_CENTERS[data_center]}.saucelabs.com/wd/hub"
     end
 
     def to_selenium
diff --git a/ruby/sauce_bindings.gemspec b/ruby/sauce_bindings.gemspec
index a356ffa2..152a824f 100644
--- a/ruby/sauce_bindings.gemspec
+++ b/ruby/sauce_bindings.gemspec
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
 
   spec.add_development_dependency 'bundler', '~> 2.0'
   spec.add_development_dependency 'capybara', '~> 3.16'
+  spec.add_development_dependency 'parallel_split_test', '~> 0.10'
   spec.add_development_dependency 'rake', '>= 12.3.3'
   spec.add_development_dependency 'rspec', '~> 3.0'
   spec.add_development_dependency 'rubocop', '~> 1.0'
diff --git a/ruby/spec/unit/capybara_session_spec.rb b/ruby/spec/unit/capybara_session_spec.rb
index edb158b9..ad4ebe1f 100644
--- a/ruby/spec/unit/capybara_session_spec.rb
+++ b/ruby/spec/unit/capybara_session_spec.rb
@@ -14,7 +14,9 @@ module SauceBindings
       {browserName: 'chrome',
        browserVersion: 'latest',
        platformName: 'Windows 10',
-       'sauce:options': {build: 'TEMP BUILD: 11'}}
+       'sauce:options': {username: 'foo',
+                         accessKey: '123',
+                         build: 'TEMP BUILD: 11'}}
     end
 
     def expect_request
diff --git a/ruby/spec/unit/deprecated_options_spec.rb b/ruby/spec/unit/deprecated_options_spec.rb
index 1c10f250..b8e6abdb 100644
--- a/ruby/spec/unit/deprecated_options_spec.rb
+++ b/ruby/spec/unit/deprecated_options_spec.rb
@@ -8,464 +8,474 @@ module SauceBindings
       allow(ENV).to receive(:[]).with('BUILD_TAG').and_return('')
       allow(ENV).to receive(:[]).with('BUILD_NAME').and_return('TEMP BUILD')
       allow(ENV).to receive(:[]).with('BUILD_NUMBER').and_return('11')
+      allow(ENV).to receive(:[]).with('SAUCE_USERNAME').and_return('foo')
+      allow(ENV).to receive(:[]).with('SAUCE_ACCESS_KEY').and_return('123')
     end
 
-    describe '#new' do
-      let(:default_options) do
-        {'browserName' => 'chrome',
-         'browserVersion' => 'latest',
-         'platformName' => 'Windows 10',
-         'sauce:options' => {'build' => 'TEMP BUILD: 11'}}
+    context 'when using deprecated methods' do
+      describe '#new' do
+        let(:default_options) do
+          {'browserName' => 'chrome',
+           'browserVersion' => 'latest',
+           'platformName' => 'Windows 10',
+           'sauce:options' => {'build' => 'TEMP BUILD: 11'}}
+        end
+
+        it 'uses latest Chrome version on Windows 10 by default' do
+          options = Options.new
+
+          expect(options.browser_name).to eq 'chrome'
+          expect(options.browser_version).to eq 'latest'
+          expect(options.platform_name).to eq 'Windows 10'
+        end
+
+        it 'accepts provided values for browser, browser version and platform name' do
+          options = Options.new(browser_name: 'firefox',
+                                browser_version: '123',
+                                platform_name: 'Mac')
+
+          expect(options.browser_name).to eq 'firefox'
+          expect(options.browser_version).to eq '123'
+          expect(options.platform_name).to eq 'Mac'
+        end
+
+        it 'accepts other w3c values' do
+          proxy = Selenium::WebDriver::Proxy.new(ssl: 'foo')
+          timeouts = {implicit: 1,
+                      page_load: 59,
+                      script: 29}
+          options = Options.new(accept_insecure_certs: true,
+                                page_load_strategy: 'eager',
+                                proxy: proxy,
+                                set_window_rect: true,
+                                unhandled_prompt_behavior: 'accept',
+                                strict_file_interactability: true,
+                                timeouts: timeouts)
+
+          expect(options.accept_insecure_certs).to eq true
+          expect(options.page_load_strategy).to eq 'eager'
+          expect(options.proxy).to eq proxy
+          expect(options.set_window_rect).to eq true
+          expect(options.unhandled_prompt_behavior).to eq 'accept'
+          expect(options.strict_file_interactability).to eq true
+          expect(options.timeouts).to eq timeouts
+        end
+
+        it 'accepts Sauce Labs specific settings' do
+          custom_data = {foo: 'foo',
+                         bar: 'bar'}
+          prerun = {executable: 'http://url.to/your/executable.exe',
+                    args: ['--silent', '-a', '-q'],
+                    background: false,
+                    timeout: 120}
+          tags = %w[foo bar foobar]
+          sauce_options = {
+            avoid_proxy: true,
+            build: 'Sample Build Name',
+            capture_performance: true,
+            chromedriver_version: '71',
+            command_timeout: 2,
+            custom_data: custom_data,
+            extended_debugging: true,
+            idle_timeout: 3,
+            iedriver_version: '3.141.0',
+            max_duration: 300,
+            name: 'Sample Test Name',
+            parent_tunnel: 'Mommy',
+            prerun: prerun,
+            priority: 0,
+            public: 'team',
+            record_logs: false,
+            record_screenshots: false,
+            record_video: false,
+            screen_resolution: '10x10',
+            selenium_version: '3.141.59',
+            tags: tags,
+            time_zone: 'San Francisco',
+            tunnel_identifier: 'tunnelname',
+            video_upload_on_pass: false
+          }
+
+          options = Options.new(**sauce_options)
+
+          expect(options.avoid_proxy).to eq true
+          expect(options.build).to eq 'Sample Build Name'
+          expect(options.capture_performance).to eq true
+          expect(options.chromedriver_version).to eq '71'
+          expect(options.command_timeout).to eq 2
+          expect(options.custom_data).to eq custom_data
+          expect(options.extended_debugging).to eq true
+          expect(options.idle_timeout).to eq 3
+          expect(options.iedriver_version).to eq '3.141.0'
+          expect(options.max_duration).to eq 300
+          expect(options.name).to eq 'Sample Test Name'
+          expect(options.parent_tunnel).to eq 'Mommy'
+          expect(options.prerun).to eq prerun
+          expect(options.priority).to eq 0
+          expect(options.public).to eq 'team'
+          expect(options.record_logs).to eq false
+          expect(options.record_screenshots).to eq false
+          expect(options.record_video).to eq false
+          expect(options.screen_resolution).to eq '10x10'
+          expect(options.selenium_version).to eq '3.141.59'
+          expect(options.tags).to eq tags
+          expect(options.time_zone).to eq 'San Francisco'
+          expect(options.tunnel_identifier).to eq 'tunnelname'
+          expect(options.video_upload_on_pass).to eq false
+        end
+
+        it 'accepts Selenium Capabilities and overrides default browser' do
+          caps = Selenium::WebDriver::Remote::Capabilities.firefox(accept_insecure_certs: true,
+                                                                   page_load_strategy: 'eager')
+          options = Options.new(selenium_options: caps)
+
+          expect(options.browser_name).to eq 'firefox'
+          expect(options.accept_insecure_certs).to eq true
+          expect(options.page_load_strategy).to eq 'eager'
+        end
+
+        it 'accepts Selenium Options and overrides default browser' do
+          browser_opts = Selenium::WebDriver::Firefox::Options.new(args: ['--foo'])
+          options = Options.new(selenium_options: browser_opts)
+
+          expect(options.browser_name).to eq 'firefox'
+          expect(options.selenium_options['moz:firefoxOptions']).to eq('args' => ['--foo'])
+        end
+
+        it 'accepts Selenium Capabilities and Options class instances' do
+          caps = Selenium::WebDriver::Remote::Capabilities.chrome(accept_insecure_certs: true,
+                                                                  page_load_strategy: 'eager')
+          browser_opts = Selenium::WebDriver::Chrome::Options.new(args: ['--foo'])
+          options = Options.new(selenium_options: [caps, browser_opts])
+
+          expect(options.page_load_strategy).to eq 'eager'
+          expect(options.accept_insecure_certs).to eq true
+          expect(options.selenium_options['goog:chromeOptions']).to eq('args' => ['--foo'])
+        end
+
+        it 'accepts W3C, Sauce, Browser Options and Capabilities at the same time' do
+          caps = Selenium::WebDriver::Remote::Capabilities.chrome(page_load_strategy: 'eager')
+          browser_opts = Selenium::WebDriver::Firefox::Options.new(args: ['--foo'])
+
+          options = Options.new(browser_version: '77',
+                                accept_insecure_certs: true,
+                                command_timeout: 2,
+                                time_zone: 'Alaska',
+                                selenium_options: [caps, browser_opts])
+
+          expect(options.browser_name).to eq 'firefox'
+          expect(options.browser_version).to eq '77'
+          expect(options.platform_name).to eq 'Windows 10'
+          expect(options.accept_insecure_certs).to eq true
+          expect(options.command_timeout).to eq 2
+          expect(options.time_zone).to eq 'Alaska'
+          expect(options.page_load_strategy).to eq 'eager'
+
+          expect(options.selenium_options['moz:firefoxOptions']).to eq('args' => ['--foo'])
+        end
+
+        it 'creates a default build value' do
+          options = Options.new
+          expect(options.build).to eq 'TEMP BUILD: 11'
+        end
+
+        it 'raises ArgumentError if parameter is not recognized as valid' do
+          expect { Options.new(foo: 'bar') }.to raise_exception(ArgumentError)
+        end
       end
 
-      it 'uses latest Chrome version on Windows 10 by default' do
-        options = Options.new
-
-        expect(options.browser_name).to eq 'chrome'
-        expect(options.browser_version).to eq 'latest'
-        expect(options.platform_name).to eq 'Windows 10'
-      end
-
-      it 'accepts provided values for browser, browser version and platform name' do
-        options = Options.new(browser_name: 'firefox',
-                              browser_version: '123',
-                              platform_name: 'Mac')
-
-        expect(options.browser_name).to eq 'firefox'
-        expect(options.browser_version).to eq '123'
-        expect(options.platform_name).to eq 'Mac'
-      end
-
-      it 'accepts other w3c values' do
-        proxy = Selenium::WebDriver::Proxy.new(ssl: 'foo')
-        timeouts = {implicit: 1,
-                    page_load: 59,
-                    script: 29}
-        options = Options.new(accept_insecure_certs: true,
-                              page_load_strategy: 'eager',
-                              proxy: proxy,
-                              set_window_rect: true,
-                              unhandled_prompt_behavior: 'accept',
-                              strict_file_interactability: true,
-                              timeouts: timeouts)
-
-        expect(options.accept_insecure_certs).to eq true
-        expect(options.page_load_strategy).to eq 'eager'
-        expect(options.proxy).to eq proxy
-        expect(options.set_window_rect).to eq true
-        expect(options.unhandled_prompt_behavior).to eq 'accept'
-        expect(options.strict_file_interactability).to eq true
-        expect(options.timeouts).to eq timeouts
-      end
-
-      it 'accepts Sauce Labs specific settings' do
-        custom_data = {foo: 'foo',
-                       bar: 'bar'}
-        prerun = {executable: 'http://url.to/your/executable.exe',
-                  args: ['--silent', '-a', '-q'],
-                  background: false,
-                  timeout: 120}
-        tags = %w[foo bar foobar]
-        sauce_options = {
-          avoid_proxy: true,
-          build: 'Sample Build Name',
-          capture_performance: true,
-          chromedriver_version: '71',
-          command_timeout: 2,
-          custom_data: custom_data,
-          extended_debugging: true,
-          idle_timeout: 3,
-          iedriver_version: '3.141.0',
-          max_duration: 300,
-          name: 'Sample Test Name',
-          parent_tunnel: 'Mommy',
-          prerun: prerun,
-          priority: 0,
-          public: 'team',
-          record_logs: false,
-          record_screenshots: false,
-          record_video: false,
-          screen_resolution: '10x10',
-          selenium_version: '3.141.59',
-          tags: tags,
-          time_zone: 'San Francisco',
-          tunnel_identifier: 'tunnelname',
-          video_upload_on_pass: false
-        }
-
-        options = Options.new(**sauce_options)
-
-        expect(options.avoid_proxy).to eq true
-        expect(options.build).to eq 'Sample Build Name'
-        expect(options.capture_performance).to eq true
-        expect(options.chromedriver_version).to eq '71'
-        expect(options.command_timeout).to eq 2
-        expect(options.custom_data).to eq custom_data
-        expect(options.extended_debugging).to eq true
-        expect(options.idle_timeout).to eq 3
-        expect(options.iedriver_version).to eq '3.141.0'
-        expect(options.max_duration).to eq 300
-        expect(options.name).to eq 'Sample Test Name'
-        expect(options.parent_tunnel).to eq 'Mommy'
-        expect(options.prerun).to eq prerun
-        expect(options.priority).to eq 0
-        expect(options.public).to eq 'team'
-        expect(options.record_logs).to eq false
-        expect(options.record_screenshots).to eq false
-        expect(options.record_video).to eq false
-        expect(options.screen_resolution).to eq '10x10'
-        expect(options.selenium_version).to eq '3.141.59'
-        expect(options.tags).to eq tags
-        expect(options.time_zone).to eq 'San Francisco'
-        expect(options.tunnel_identifier).to eq 'tunnelname'
-        expect(options.video_upload_on_pass).to eq false
-      end
-
-      it 'accepts Selenium Capabilities and overrides default browser' do
-        caps = Selenium::WebDriver::Remote::Capabilities.firefox(accept_insecure_certs: true,
-                                                                 page_load_strategy: 'eager')
-        options = Options.new(selenium_options: caps)
-
-        expect(options.browser_name).to eq 'firefox'
-        expect(options.accept_insecure_certs).to eq true
-        expect(options.page_load_strategy).to eq 'eager'
-      end
-
-      it 'accepts Selenium Options and overrides default browser' do
-        browser_opts = Selenium::WebDriver::Firefox::Options.new(args: ['--foo'])
-        options = Options.new(selenium_options: browser_opts)
-
-        expect(options.browser_name).to eq 'firefox'
-        expect(options.selenium_options['moz:firefoxOptions']).to eq('args' => ['--foo'])
-      end
-
-      it 'accepts Selenium Capabilities and Options class instances' do
-        caps = Selenium::WebDriver::Remote::Capabilities.chrome(accept_insecure_certs: true,
-                                                                page_load_strategy: 'eager')
-        browser_opts = Selenium::WebDriver::Chrome::Options.new(args: ['--foo'])
-        options = Options.new(selenium_options: [caps, browser_opts])
-
-        expect(options.page_load_strategy).to eq 'eager'
-        expect(options.accept_insecure_certs).to eq true
-        expect(options.selenium_options['goog:chromeOptions']).to eq('args' => ['--foo'])
-      end
-
-      it 'accepts W3C, Sauce, Browser Options and Capabilities at the same time' do
-        caps = Selenium::WebDriver::Remote::Capabilities.chrome(page_load_strategy: 'eager')
-        browser_opts = Selenium::WebDriver::Firefox::Options.new(args: ['--foo'])
-
-        options = Options.new(browser_version: '77',
-                              accept_insecure_certs: true,
-                              command_timeout: 2,
-                              time_zone: 'Alaska',
-                              selenium_options: [caps, browser_opts])
-
-        expect(options.browser_name).to eq 'firefox'
-        expect(options.browser_version).to eq '77'
-        expect(options.platform_name).to eq 'Windows 10'
-        expect(options.accept_insecure_certs).to eq true
-        expect(options.command_timeout).to eq 2
-        expect(options.time_zone).to eq 'Alaska'
-        expect(options.page_load_strategy).to eq 'eager'
-
-        expect(options.selenium_options['moz:firefoxOptions']).to eq('args' => ['--foo'])
-      end
-
-      it 'creates a default build value' do
-        options = Options.new
-        expect(options.build).to eq 'TEMP BUILD: 11'
-      end
-
-      it 'raises ArgumentError if parameter is not recognized as valid' do
-        expect { Options.new(foo: 'bar') }.to raise_exception(ArgumentError)
-      end
-    end
-
-    describe '#accessors' do
-      it 'parses w3c values' do
-        proxy = Selenium::WebDriver::Proxy.new(ssl: 'foo')
-        timeouts = {implicit: 1,
-                    page_load: 59,
-                    script: 29}
-
-        options = Options.new
-
-        options.browser_name = 'firefox'
-        options.browser_version = '7'
-        options.platform_name = 'macOS 10.14'
-        options.accept_insecure_certs = true
-        options.page_load_strategy = 'eager'
-        options.proxy = proxy
-        options.set_window_rect = true
-        options.unhandled_prompt_behavior = 'accept'
-        options.strict_file_interactability = true
-        options.timeouts = timeouts
-
-        expect(options.browser_name).to eq 'firefox'
-        expect(options.browser_version).to eq '7'
-        expect(options.platform_name).to eq 'macOS 10.14'
-        expect(options.accept_insecure_certs).to eq true
-        expect(options.page_load_strategy).to eq 'eager'
-        expect(options.proxy).to eq proxy
-        expect(options.set_window_rect).to eq true
-        expect(options.unhandled_prompt_behavior).to eq 'accept'
-        expect(options.strict_file_interactability).to eq true
-        expect(options.timeouts).to eq timeouts
-      end
-
-      it 'parses Sauce values' do
-        custom_data = {foo: 'foo',
-                       bar: 'bar'}
-        prerun = {executable: 'http://url.to/your/executable.exe',
-                  args: ['--silent', '-a', '-q'],
-                  background: false,
-                  timeout: 120}
-        tags = %w[foo bar foobar]
-
-        options = Options.new
-
-        options.avoid_proxy = true
-        options.build = 'Sample Build Name'
-        options.capture_performance = true
-        options.chromedriver_version = '71'
-        options.command_timeout = 2
-        options.custom_data = custom_data
-        options.extended_debugging = true
-        options.idle_timeout = 3
-        options.iedriver_version = '3.141.0'
-        options.max_duration = 300
-        options.name = 'Sample Test Name'
-        options.parent_tunnel = 'Mommy'
-        options.prerun = prerun
-        options.priority = 0
-        options.public = 'team'
-        options.record_logs = false
-        options.record_screenshots = false
-        options.record_video = false
-        options.screen_resolution = '10x10'
-        options.selenium_version = '3.141.59'
-        options.tags = tags
-        options.time_zone = 'San Francisco'
-        options.tunnel_identifier = 'tunnelname'
-        options.video_upload_on_pass = false
-
-        expect(options.avoid_proxy).to eq true
-        expect(options.build).to eq 'Sample Build Name'
-        expect(options.capture_performance).to eq true
-        expect(options.chromedriver_version).to eq '71'
-        expect(options.command_timeout).to eq 2
-        expect(options.custom_data).to eq custom_data
-        expect(options.extended_debugging).to eq true
-        expect(options.idle_timeout).to eq 3
-        expect(options.iedriver_version).to eq '3.141.0'
-        expect(options.max_duration).to eq 300
-        expect(options.name).to eq 'Sample Test Name'
-        expect(options.parent_tunnel).to eq 'Mommy'
-        expect(options.prerun).to eq prerun
-        expect(options.priority).to eq 0
-        expect(options.public).to eq 'team'
-        expect(options.record_logs).to eq false
-        expect(options.record_screenshots).to eq false
-        expect(options.record_video).to eq false
-        expect(options.screen_resolution).to eq '10x10'
-        expect(options.selenium_version).to eq '3.141.59'
-        expect(options.tags).to eq tags
-        expect(options.time_zone).to eq 'San Francisco'
-        expect(options.tunnel_identifier).to eq 'tunnelname'
-        expect(options.video_upload_on_pass).to eq false
-      end
-    end
-
-    describe '#merge_capabilities' do
-      it 'loads options from configuration' do
-        timeouts = {implicit: 1,
-                    page_load: 59,
-                    script: 29}
-        custom_data = {foo: 'foo',
-                       bar: 'bar'}
-        prerun = {executable: 'http://url.to/your/executable.exe',
-                  args: ['--silent', '-a', '-q'],
-                  background: false,
-                  timeout: 120}
-        tags = %w[foo bar foobar]
-
-        options = Options.new
-        yaml = YAML.load_file('spec/deprecated_options.yml')
-        options.merge_capabilities(yaml['example_values'])
-
-        expect(options.browser_name).to eq 'firefox'
-        expect(options.browser_version).to eq '123'
-        expect(options.platform_name).to eq 'Mac'
-        expect(options.accept_insecure_certs).to eq true
-        expect(options.page_load_strategy).to eq 'eager'
-        expect(options.set_window_rect).to eq true
-        expect(options.unhandled_prompt_behavior).to eq 'accept'
-        expect(options.strict_file_interactability).to eq true
-        expect(options.timeouts).to eq timeouts
-        expect(options.avoid_proxy).to eq true
-        expect(options.build).to eq 'Sample Build Name'
-        expect(options.capture_performance).to eq true
-        expect(options.chromedriver_version).to eq '71'
-        expect(options.command_timeout).to eq 2
-        expect(options.custom_data).to eq custom_data
-        expect(options.extended_debugging).to eq true
-        expect(options.idle_timeout).to eq 3
-        expect(options.iedriver_version).to eq '3.141.0'
-        expect(options.max_duration).to eq 300
-        expect(options.name).to eq 'Sample Test Name'
-        expect(options.parent_tunnel).to eq 'Mommy'
-        expect(options.prerun).to eq prerun
-        expect(options.priority).to eq 0
-        expect(options.public).to eq 'team'
-        expect(options.record_logs).to eq false
-        expect(options.record_screenshots).to eq false
-        expect(options.record_video).to eq false
-        expect(options.screen_resolution).to eq '10x10'
-        expect(options.selenium_version).to eq '3.141.59'
-        expect(options.tags).to eq tags
-        expect(options.time_zone).to eq 'San Francisco'
-        expect(options.tunnel_identifier).to eq 'tunnelname'
-        expect(options.video_upload_on_pass).to eq false
-      end
-
-      it 'raises exception if value not recognized' do
-        options = Options.new
-        yaml = YAML.load_file('spec/deprecated_options.yml')
-
-        msg = 'foo is not a valid parameter for Options class'
-        expect { options.merge_capabilities(yaml['invalid_option']) }.to raise_exception(ArgumentError, msg)
-      end
-    end
-
-    describe '#capabilities' do
-      it 'correctly generates capabilities for w3c values' do
-        proxy = Selenium::WebDriver::Proxy.new(ssl: 'foo')
-        timeouts = {implicit: 1,
-                    page_load: 59,
-                    script: 29}
-
-        options = Options.new(browser_name: 'firefox',
-                              platform_name: 'Mac',
-                              accept_insecure_certs: true,
-                              page_load_strategy: 'eager',
-                              proxy: proxy,
-                              set_window_rect: true,
-                              unhandled_prompt_behavior: 'accept',
-                              strict_file_interactability: true,
-                              timeouts: timeouts)
-
-        proxy_type = Selenium::WebDriver::VERSION[0] == '3' ? 'MANUAL' : 'manual'
-
-        expect(options.capabilities).to eq('browserName' => 'firefox',
-                                           'browserVersion' => 'latest',
-                                           'platformName' => 'Mac',
-                                           'acceptInsecureCerts' => true,
-                                           'pageLoadStrategy' => 'eager',
-                                           'proxy' => {'proxyType' => proxy_type, 'sslProxy' => 'foo'},
-                                           'setWindowRect' => true,
-                                           'unhandledPromptBehavior' => 'accept',
-                                           'strictFileInteractability' => true,
-                                           'timeouts' => {'implicit' => 1,
-                                                          'pageLoad' => 59,
-                                                          'script' => 29},
-                                           'sauce:options' => {'build' => 'TEMP BUILD: 11'})
+      describe '#accessors' do
+        it 'parses w3c values' do
+          proxy = Selenium::WebDriver::Proxy.new(ssl: 'foo')
+          timeouts = {implicit: 1,
+                      page_load: 59,
+                      script: 29}
+
+          options = Options.new
+
+          options.browser_name = 'firefox'
+          options.browser_version = '7'
+          options.platform_name = 'macOS 10.14'
+          options.accept_insecure_certs = true
+          options.page_load_strategy = 'eager'
+          options.proxy = proxy
+          options.set_window_rect = true
+          options.unhandled_prompt_behavior = 'accept'
+          options.strict_file_interactability = true
+          options.timeouts = timeouts
+
+          expect(options.browser_name).to eq 'firefox'
+          expect(options.browser_version).to eq '7'
+          expect(options.platform_name).to eq 'macOS 10.14'
+          expect(options.accept_insecure_certs).to eq true
+          expect(options.page_load_strategy).to eq 'eager'
+          expect(options.proxy).to eq proxy
+          expect(options.set_window_rect).to eq true
+          expect(options.unhandled_prompt_behavior).to eq 'accept'
+          expect(options.strict_file_interactability).to eq true
+          expect(options.timeouts).to eq timeouts
+        end
+
+        it 'parses Sauce values' do
+          custom_data = {foo: 'foo',
+                         bar: 'bar'}
+          prerun = {executable: 'http://url.to/your/executable.exe',
+                    args: ['--silent', '-a', '-q'],
+                    background: false,
+                    timeout: 120}
+          tags = %w[foo bar foobar]
+
+          options = Options.new
+
+          options.avoid_proxy = true
+          options.build = 'Sample Build Name'
+          options.capture_performance = true
+          options.chromedriver_version = '71'
+          options.command_timeout = 2
+          options.custom_data = custom_data
+          options.extended_debugging = true
+          options.idle_timeout = 3
+          options.iedriver_version = '3.141.0'
+          options.max_duration = 300
+          options.name = 'Sample Test Name'
+          options.parent_tunnel = 'Mommy'
+          options.prerun = prerun
+          options.priority = 0
+          options.public = 'team'
+          options.record_logs = false
+          options.record_screenshots = false
+          options.record_video = false
+          options.screen_resolution = '10x10'
+          options.selenium_version = '3.141.59'
+          options.tags = tags
+          options.time_zone = 'San Francisco'
+          options.tunnel_identifier = 'tunnelname'
+          options.video_upload_on_pass = false
+
+          expect(options.avoid_proxy).to eq true
+          expect(options.build).to eq 'Sample Build Name'
+          expect(options.capture_performance).to eq true
+          expect(options.chromedriver_version).to eq '71'
+          expect(options.command_timeout).to eq 2
+          expect(options.custom_data).to eq custom_data
+          expect(options.extended_debugging).to eq true
+          expect(options.idle_timeout).to eq 3
+          expect(options.iedriver_version).to eq '3.141.0'
+          expect(options.max_duration).to eq 300
+          expect(options.name).to eq 'Sample Test Name'
+          expect(options.parent_tunnel).to eq 'Mommy'
+          expect(options.prerun).to eq prerun
+          expect(options.priority).to eq 0
+          expect(options.public).to eq 'team'
+          expect(options.record_logs).to eq false
+          expect(options.record_screenshots).to eq false
+          expect(options.record_video).to eq false
+          expect(options.screen_resolution).to eq '10x10'
+          expect(options.selenium_version).to eq '3.141.59'
+          expect(options.tags).to eq tags
+          expect(options.time_zone).to eq 'San Francisco'
+          expect(options.tunnel_identifier).to eq 'tunnelname'
+          expect(options.video_upload_on_pass).to eq false
+        end
       end
 
-      it 'correctly generates capabilities for sauce values' do
-        custom_data = {foo: 'foo',
-                       bar: 'bar'}
-        prerun = {executable: 'http://url.to/your/executable.exe',
-                  args: ['--silent', '-a', '-q'],
-                  background: false,
-                  timeout: 120}
-        tags = %w[foo bar foobar]
-        sauce_options = {avoid_proxy: true,
-                         build: 'Sample Build Name',
-                         capture_performance: true,
-                         chromedriver_version: '71',
-                         command_timeout: 2,
-                         custom_data: custom_data,
-                         extended_debugging: true,
-                         idle_timeout: 3,
-                         iedriver_version: '3.141.0',
-                         max_duration: 300,
-                         name: 'Sample Test Name',
-                         parent_tunnel: 'Mommy',
-                         prerun: prerun,
-                         priority: 0,
-                         public: 'team',
-                         record_logs: false,
-                         record_screenshots: false,
-                         record_video: false,
-                         screen_resolution: '10x10',
-                         selenium_version: '3.141.59',
-                         tags: tags,
-                         time_zone: 'San Francisco',
-                         tunnel_identifier: 'tunnelname',
-                         video_upload_on_pass: false}
-
-        options = Options.new(**sauce_options)
-
-        prerun_caps = {'executable' => 'http://url.to/your/executable.exe',
-                       'args' => ['--silent', '-a', '-q'],
-                       'background' => false,
-                       'timeout' => 120}
-
-        expect(options.capabilities).to eq('browserName' => 'chrome',
-                                           'browserVersion' => 'latest',
-                                           'platformName' => 'Windows 10',
-                                           'sauce:options' => {'build' => 'Sample Build Name',
-                                                               'avoidProxy' => true,
-                                                               'capturePerformance' => true,
-                                                               'chromedriverVersion' => '71',
-                                                               'commandTimeout' => 2,
-                                                               'customData' => {'foo' => 'foo',
-                                                                                'bar' => 'bar'},
-                                                               'extendedDebugging' => true,
-                                                               'idleTimeout' => 3,
-                                                               'iedriverVersion' => '3.141.0',
-                                                               'maxDuration' => 300,
-                                                               'name' => 'Sample Test Name',
-                                                               'parentTunnel' => 'Mommy',
-                                                               'prerun' => prerun_caps,
-                                                               'priority' => 0,
-                                                               'public' => 'team',
-                                                               'recordLogs' => false,
-                                                               'recordScreenshots' => false,
-                                                               'recordVideo' => false,
-                                                               'screenResolution' => '10x10',
-                                                               'seleniumVersion' => '3.141.59',
-                                                               'tags' => %w[foo bar foobar],
-                                                               'timeZone' => 'San Francisco',
-                                                               'tunnelIdentifier' => 'tunnelname',
-                                                               'videoUploadOnPass' => false})
+      describe '#merge_capabilities' do
+        it 'loads options from configuration' do
+          timeouts = {implicit: 1,
+                      page_load: 59,
+                      script: 29}
+          custom_data = {foo: 'foo',
+                         bar: 'bar'}
+          prerun = {executable: 'http://url.to/your/executable.exe',
+                    args: ['--silent', '-a', '-q'],
+                    background: false,
+                    timeout: 120}
+          tags = %w[foo bar foobar]
+
+          options = Options.new
+          yaml = YAML.load_file('spec/deprecated_options.yml')
+          options.merge_capabilities(yaml['example_values'])
+
+          expect(options.browser_name).to eq 'firefox'
+          expect(options.browser_version).to eq '123'
+          expect(options.platform_name).to eq 'Mac'
+          expect(options.accept_insecure_certs).to eq true
+          expect(options.page_load_strategy).to eq 'eager'
+          expect(options.set_window_rect).to eq true
+          expect(options.unhandled_prompt_behavior).to eq 'accept'
+          expect(options.strict_file_interactability).to eq true
+          expect(options.timeouts).to eq timeouts
+          expect(options.avoid_proxy).to eq true
+          expect(options.build).to eq 'Sample Build Name'
+          expect(options.capture_performance).to eq true
+          expect(options.chromedriver_version).to eq '71'
+          expect(options.command_timeout).to eq 2
+          expect(options.custom_data).to eq custom_data
+          expect(options.extended_debugging).to eq true
+          expect(options.idle_timeout).to eq 3
+          expect(options.iedriver_version).to eq '3.141.0'
+          expect(options.max_duration).to eq 300
+          expect(options.name).to eq 'Sample Test Name'
+          expect(options.parent_tunnel).to eq 'Mommy'
+          expect(options.prerun).to eq prerun
+          expect(options.priority).to eq 0
+          expect(options.public).to eq 'team'
+          expect(options.record_logs).to eq false
+          expect(options.record_screenshots).to eq false
+          expect(options.record_video).to eq false
+          expect(options.screen_resolution).to eq '10x10'
+          expect(options.selenium_version).to eq '3.141.59'
+          expect(options.tags).to eq tags
+          expect(options.time_zone).to eq 'San Francisco'
+          expect(options.tunnel_identifier).to eq 'tunnelname'
+          expect(options.video_upload_on_pass).to eq false
+        end
+
+        it 'raises exception if value not recognized' do
+          options = Options.new
+          yaml = YAML.load_file('spec/deprecated_options.yml')
+
+          msg = 'foo is not a valid parameter for Options class'
+          expect { options.merge_capabilities(yaml['invalid_option']) }.to raise_exception(ArgumentError, msg)
+        end
       end
 
-      it 'correctly generates capabilities for selenium object values' do
-        caps = Selenium::WebDriver::Remote::Capabilities.chrome(accept_insecure_certs: true,
-                                                                page_load_strategy: 'eager')
-        browser_opts = Selenium::WebDriver::Chrome::Options.new(args: ['--foo'])
-        options = Options.new(selenium_options: [caps, browser_opts])
-
-        jwp_defaults = {'cssSelectorsEnabled' => true,
-                        'javascriptEnabled' => true,
-                        'nativeEvents' => false,
-                        'platform' => 'ANY',
-                        'rotatable' => false,
-                        'takesScreenshot' => false,
-                        'version' => ''}
-
-        expected_caps = {'browserName' => 'chrome',
-                         'browserVersion' => 'latest',
-                         'platformName' => 'Windows 10',
-                         'acceptInsecureCerts' => true,
-                         'pageLoadStrategy' => 'eager',
-                         'sauce:options' => {'build' => 'TEMP BUILD: 11'},
-                         'goog:chromeOptions' => {'args' => ['--foo']}}
-
-        expected = Selenium::WebDriver::VERSION[0] == '3' ? jwp_defaults.merge(expected_caps) : expected_caps
-
-        expect(options.capabilities).to eq expected
+      describe '#capabilities' do
+        it 'correctly generates capabilities for w3c values' do
+          proxy = Selenium::WebDriver::Proxy.new(ssl: 'foo')
+          timeouts = {implicit: 1,
+                      page_load: 59,
+                      script: 29}
+
+          options = Options.new(browser_name: 'firefox',
+                                platform_name: 'Mac',
+                                accept_insecure_certs: true,
+                                page_load_strategy: 'eager',
+                                proxy: proxy,
+                                set_window_rect: true,
+                                unhandled_prompt_behavior: 'accept',
+                                strict_file_interactability: true,
+                                timeouts: timeouts)
+
+          proxy_type = Selenium::WebDriver::VERSION[0] == '3' ? 'MANUAL' : 'manual'
+
+          expect(options.capabilities).to eq('browserName' => 'firefox',
+                                             'browserVersion' => 'latest',
+                                             'platformName' => 'Mac',
+                                             'acceptInsecureCerts' => true,
+                                             'pageLoadStrategy' => 'eager',
+                                             'proxy' => {'proxyType' => proxy_type, 'sslProxy' => 'foo'},
+                                             'setWindowRect' => true,
+                                             'unhandledPromptBehavior' => 'accept',
+                                             'strictFileInteractability' => true,
+                                             'timeouts' => {'implicit' => 1,
+                                                            'pageLoad' => 59,
+                                                            'script' => 29},
+                                             'sauce:options' => {'build' => 'TEMP BUILD: 11',
+                                                                 'username' => 'foo',
+                                                                 'accessKey' => '123'})
+        end
+
+        it 'correctly generates capabilities for sauce values' do
+          custom_data = {foo: 'foo',
+                         bar: 'bar'}
+          prerun = {executable: 'http://url.to/your/executable.exe',
+                    args: ['--silent', '-a', '-q'],
+                    background: false,
+                    timeout: 120}
+          tags = %w[foo bar foobar]
+          sauce_options = {avoid_proxy: true,
+                           build: 'Sample Build Name',
+                           capture_performance: true,
+                           chromedriver_version: '71',
+                           command_timeout: 2,
+                           custom_data: custom_data,
+                           extended_debugging: true,
+                           idle_timeout: 3,
+                           iedriver_version: '3.141.0',
+                           max_duration: 300,
+                           name: 'Sample Test Name',
+                           parent_tunnel: 'Mommy',
+                           prerun: prerun,
+                           priority: 0,
+                           public: 'team',
+                           record_logs: false,
+                           record_screenshots: false,
+                           record_video: false,
+                           screen_resolution: '10x10',
+                           selenium_version: '3.141.59',
+                           tags: tags,
+                           time_zone: 'San Francisco',
+                           tunnel_identifier: 'tunnelname',
+                           video_upload_on_pass: false}
+
+          options = Options.new(**sauce_options)
+
+          prerun_caps = {'executable' => 'http://url.to/your/executable.exe',
+                         'args' => ['--silent', '-a', '-q'],
+                         'background' => false,
+                         'timeout' => 120}
+
+          expect(options.capabilities).to eq('browserName' => 'chrome',
+                                             'browserVersion' => 'latest',
+                                             'platformName' => 'Windows 10',
+                                             'sauce:options' => {'build' => 'Sample Build Name',
+                                                                 'avoidProxy' => true,
+                                                                 'capturePerformance' => true,
+                                                                 'chromedriverVersion' => '71',
+                                                                 'commandTimeout' => 2,
+                                                                 'customData' => {'foo' => 'foo',
+                                                                                  'bar' => 'bar'},
+                                                                 'extendedDebugging' => true,
+                                                                 'idleTimeout' => 3,
+                                                                 'iedriverVersion' => '3.141.0',
+                                                                 'maxDuration' => 300,
+                                                                 'name' => 'Sample Test Name',
+                                                                 'parentTunnel' => 'Mommy',
+                                                                 'prerun' => prerun_caps,
+                                                                 'priority' => 0,
+                                                                 'public' => 'team',
+                                                                 'recordLogs' => false,
+                                                                 'recordScreenshots' => false,
+                                                                 'recordVideo' => false,
+                                                                 'screenResolution' => '10x10',
+                                                                 'seleniumVersion' => '3.141.59',
+                                                                 'tags' => %w[foo bar foobar],
+                                                                 'timeZone' => 'San Francisco',
+                                                                 'tunnelIdentifier' => 'tunnelname',
+                                                                 'username' => 'foo',
+                                                                 'accessKey' => '123',
+                                                                 'videoUploadOnPass' => false})
+        end
+
+        it 'correctly generates capabilities for selenium object values' do
+          caps = Selenium::WebDriver::Remote::Capabilities.chrome(accept_insecure_certs: true,
+                                                                  page_load_strategy: 'eager')
+          browser_opts = Selenium::WebDriver::Chrome::Options.new(args: ['--foo'])
+          options = Options.new(selenium_options: [caps, browser_opts])
+
+          jwp_defaults = {'cssSelectorsEnabled' => true,
+                          'javascriptEnabled' => true,
+                          'nativeEvents' => false,
+                          'platform' => 'ANY',
+                          'rotatable' => false,
+                          'takesScreenshot' => false,
+                          'version' => ''}
+
+          expected_caps = {'browserName' => 'chrome',
+                           'browserVersion' => 'latest',
+                           'platformName' => 'Windows 10',
+                           'acceptInsecureCerts' => true,
+                           'pageLoadStrategy' => 'eager',
+                           'sauce:options' => {'build' => 'TEMP BUILD: 11',
+                                               'username' => 'foo',
+                                               'accessKey' => '123'},
+                           'goog:chromeOptions' => {'args' => ['--foo']}}
+
+          expected = Selenium::WebDriver::VERSION[0] == '3' ? jwp_defaults.merge(expected_caps) : expected_caps
+
+          expect(options.capabilities).to eq expected
+        end
       end
     end
   end
diff --git a/ruby/spec/unit/options_spec.rb b/ruby/spec/unit/options_spec.rb
index 331d7bc8..e92ada7d 100644
--- a/ruby/spec/unit/options_spec.rb
+++ b/ruby/spec/unit/options_spec.rb
@@ -8,6 +8,8 @@ module SauceBindings
       allow(ENV).to receive(:[]).with('BUILD_TAG').and_return('')
       allow(ENV).to receive(:[]).with('BUILD_NAME').and_return('TEMP BUILD')
       allow(ENV).to receive(:[]).with('BUILD_NUMBER').and_return('11')
+      allow(ENV).to receive(:[]).with('SAUCE_USERNAME').and_return('foo')
+      allow(ENV).to receive(:[]).with('SAUCE_ACCESS_KEY').and_return('123')
     end
 
     describe '::chrome' do
@@ -526,7 +528,9 @@ module SauceBindings
                                            'timeouts' => {'implicit' => 1000,
                                                           'pageLoad' => 59_000,
                                                           'script' => 29_000},
-                                           'sauce:options' => {'build' => 'TEMP BUILD: 11'})
+                                           'sauce:options' => {'build' => 'TEMP BUILD: 11',
+                                                               'username' => 'foo',
+                                                               'accessKey' => '123'})
       end
 
       it 'correctly generates capabilities for sauce values' do
@@ -590,7 +594,9 @@ module SauceBindings
                                                                'tags' => %w[foo bar foobar],
                                                                'timeZone' => 'San Francisco',
                                                                'tunnelIdentifier' => 'tunnelname',
-                                                               'videoUploadOnPass' => false})
+                                                               'videoUploadOnPass' => false,
+                                                               'username' => 'foo',
+                                                               'accessKey' => '123'})
       end
 
       it 'correctly generates capabilities for selenium object values Selenium 3' do
@@ -637,7 +643,9 @@ module SauceBindings
                          'platformName' => 'Windows 10',
                          'acceptInsecureCerts' => true,
                          'pageLoadStrategy' => 'eager',
-                         'sauce:options' => {'build' => 'TEMP BUILD: 11'},
+                         'sauce:options' => {'build' => 'TEMP BUILD: 11',
+                                             'username' => 'foo',
+                                             'accessKey' => '123'},
                          'goog:chromeOptions' => {'args' => ['--foo']}}
 
         expect(options.capabilities).to eq expected_caps
diff --git a/ruby/spec/unit/session_spec.rb b/ruby/spec/unit/session_spec.rb
index 92fc6b25..ca2b3cf0 100644
--- a/ruby/spec/unit/session_spec.rb
+++ b/ruby/spec/unit/session_spec.rb
@@ -13,7 +13,9 @@ module SauceBindings
       {browserName: 'chrome',
        browserVersion: 'latest',
        platformName: 'Windows 10',
-       'sauce:options': {build: 'TEMP BUILD: 11'}}
+       'sauce:options': {username: 'foo',
+                         accessKey: '123',
+                         build: 'TEMP BUILD: 11'}}
     end
 
     def expect_request
@@ -40,11 +42,13 @@ def expect_request
       it 'creates default Options instance if none is provided' do
         session = Session.new
 
-        expected_results = {url: 'https://foo:123@ondemand.us-west-1.saucelabs.com:443/wd/hub',
+        expected_results = {url: 'https://ondemand.us-west-1.saucelabs.com/wd/hub',
                             desired_capabilities: {'browserName' => 'chrome',
                                                    'browserVersion' => 'latest',
                                                    'platformName' => 'Windows 10',
-                                                   'sauce:options' => {'build' => 'TEMP BUILD: 11'}}}
+                                                   'sauce:options' => {'build' => 'TEMP BUILD: 11',
+                                                                       'username' => 'foo',
+                                                                       'accessKey' => '123'}}}
         expect(session.to_selenium).to eq expected_results
       end
 
@@ -54,12 +58,14 @@ def expect_request
                                     idle_timeout: 4)
         session = Session.new(sauce_opts)
 
-        expected_results = {url: 'https://foo:123@ondemand.us-west-1.saucelabs.com:443/wd/hub',
+        expected_results = {url: 'https://ondemand.us-west-1.saucelabs.com/wd/hub',
                             desired_capabilities: {'browserName' => 'chrome',
                                                    'browserVersion' => '123',
                                                    'platformName' => 'Mac',
                                                    'sauce:options' => {'idleTimeout' => 4,
-                                                                       'build' => 'TEMP BUILD: 11'}}}
+                                                                       'build' => 'TEMP BUILD: 11',
+                                                                       'username' => 'foo',
+                                                                       'accessKey' => '123'}}}
         expect(session.to_selenium).to eq expected_results
       end
 
@@ -71,11 +77,13 @@ def expect_request
       it 'uses provided Data Center' do
         session = Session.new(data_center: :EU_CENTRAL)
 
-        expected_results = {url: 'https://foo:123@ondemand.eu-central-1.saucelabs.com:443/wd/hub',
+        expected_results = {url: 'https://ondemand.eu-central-1.saucelabs.com/wd/hub',
                             desired_capabilities: {'browserName' => 'chrome',
                                                    'browserVersion' => 'latest',
                                                    'platformName' => 'Windows 10',
-                                                   'sauce:options' => {'build' => 'TEMP BUILD: 11'}}}
+                                                   'sauce:options' => {'build' => 'TEMP BUILD: 11',
+                                                                       'username' => 'foo',
+                                                                       'accessKey' => '123'}}}
         expect(session.to_selenium).to eq expected_results
       end
 
@@ -106,12 +114,6 @@ def expect_request
         expect(driver).to be_a Selenium::WebDriver::Driver
       end
 
-      it 'uses username and access key from ENV' do
-        session = Session.new
-
-        expect(session.url).to include('foo:123')
-      end
-
       it 'raises exception if no username set' do
         allow(ENV).to receive(:[]).with('SAUCE_USERNAME')
 
@@ -146,7 +148,7 @@ def expect_request
         session = Session.new
         session.data_center = :US_EAST
 
-        expect(session.url).to eq('https://foo:123@ondemand.us-east-1.saucelabs.com:443/wd/hub')
+        expect(session.url).to eq('https://ondemand.us-east-1.saucelabs.com/wd/hub')
       end
 
       it 'raises exception if data center is invalid' do
@@ -185,7 +187,9 @@ def expect_request
                             desired_capabilities: {'browserName' => 'chrome',
                                                    'browserVersion' => 'latest',
                                                    'platformName' => 'Windows 10',
-                                                   'sauce:options' => {'build' => 'TEMP BUILD: 11'}}}
+                                                   'sauce:options' => {'build' => 'TEMP BUILD: 11',
+                                                                       'username' => ENV['SAUCE_USERNAME'],
+                                                                       'accessKey' => ENV['SAUCE_ACCESS_KEY']}}}
         expect(session.to_selenium).to eq expected_results
       end
     end


Test patch:
diff --git a/python/tests/unit/test_chrome.py b/python/tests/unit/test_chrome.py
index c9aa228d..ee0bd7ba 100644
--- a/python/tests/unit/test_chrome.py
+++ b/python/tests/unit/test_chrome.py
@@ -347,7 +347,9 @@ def test_capabilities_for_w3c(self):
                                  'timeouts': {'implicit': 1,
                                               'pageLoad': 59,
                                               'script': 29},
-                                 'sauce:options': {'build': 'Build Name'}}
+                                 'sauce:options': {'build': 'Build Name',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         assert options.to_capabilities() == expected_capabilities
 
@@ -408,7 +410,9 @@ def test_capabilities_for_sauce(self):
                                                    'tags': ['foo', 'bar'],
                                                    'timeZone': 'San Francisco',
                                                    'tunnelIdentifier': 'tunnelname',
-                                                   'videoUploadOnPass': False}}
+                                                   'videoUploadOnPass': False,
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         assert options.to_capabilities() == expected_capabilities
 
@@ -423,7 +427,9 @@ def test_capabilities_for_selenium(self):
                                  'browserVersion': 'latest',
                                  'platformName': 'Windows 10',
                                  'goog:chromeOptions': {'args': ['--foo'], 'extensions': []},
-                                 'sauce:options': {'build': 'Sample Build Name'},
+                                 'sauce:options': {'build': 'Sample Build Name',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')},
                                  'platform': 'ANY',
                                  'version': ''}
 
diff --git a/python/tests/unit/test_firefox.py b/python/tests/unit/test_firefox.py
index 36585cfb..3114e0ca 100644
--- a/python/tests/unit/test_firefox.py
+++ b/python/tests/unit/test_firefox.py
@@ -400,7 +400,9 @@ def test_capabilities_for_w3c(self):
                                  'timeouts': {'implicit': 1,
                                               'pageLoad': 59,
                                               'script': 29},
-                                 'sauce:options': {'build': 'Build Name'}}
+                                 'sauce:options': {'build': 'Build Name',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         assert options.to_capabilities() == expected_capabilities
 
@@ -459,7 +461,9 @@ def test_capabilities_for_sauce(self):
                                                    'tags': ['foo', 'bar'],
                                                    'timeZone': 'San Francisco',
                                                    'tunnelIdentifier': 'tunnelname',
-                                                   'videoUploadOnPass': False}}
+                                                   'videoUploadOnPass': False,
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         assert options.to_capabilities() == expected_capabilities
 
@@ -474,7 +478,9 @@ def test_capabilities_for_selenium(self):
                                  'browserVersion': 'latest',
                                  'platformName': 'Windows 10',
                                  'moz:firefoxOptions': {'args': ['--foo']},
-                                 'sauce:options': {'build': 'Sample Build Name'},
+                                 'sauce:options': {'build': 'Sample Build Name',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')},
                                  'acceptInsecureCerts': True
                                  }
 
diff --git a/python/tests/unit/test_ie.py b/python/tests/unit/test_ie.py
index 675255ea..009fa284 100644
--- a/python/tests/unit/test_ie.py
+++ b/python/tests/unit/test_ie.py
@@ -343,7 +343,9 @@ def test_capabilities_for_w3c(self):
                                  'timeouts': {'implicit': 1,
                                               'pageLoad': 59,
                                               'script': 29},
-                                 'sauce:options': {'build': 'Build Name'}}
+                                 'sauce:options': {'build': 'Build Name',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         assert options.to_capabilities() == expected_capabilities
 
@@ -402,7 +404,9 @@ def test_capabilities_for_sauce(self):
                                                    'tags': ['foo', 'bar'],
                                                    'timeZone': 'San Francisco',
                                                    'tunnelIdentifier': 'tunnelname',
-                                                   'videoUploadOnPass': False}}
+                                                   'videoUploadOnPass': False,
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         assert options.to_capabilities() == expected_capabilities
 
@@ -417,7 +421,9 @@ def test_capabilities_for_selenium(self):
                                  'browserVersion': 'latest',
                                  'platformName': 'Windows 10',
                                  'se:ieOptions': {'ie.browserCommandLineSwitches': '--foo'},
-                                 'sauce:options': {'build': 'Sample Build Name'},
+                                 'sauce:options': {'build': 'Sample Build Name',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')},
                                  'platform': 'WINDOWS',
                                  'version': ''
                                  }
diff --git a/python/tests/unit/test_old_options.py b/python/tests/unit/test_old_options.py
index a3e0e1eb..56b3fb05 100644
--- a/python/tests/unit/test_old_options.py
+++ b/python/tests/unit/test_old_options.py
@@ -419,7 +419,9 @@ def test_capabilities_for_w3c(self):
                                  'timeouts': {'implicit': 1,
                                               'pageLoad': 59,
                                               'script': 29},
-                                 'sauce:options': {'build': 'Build Name'}}
+                                 'sauce:options': {'build': 'Build Name',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         assert options.to_capabilities() == expected_capabilities
 
@@ -486,7 +488,9 @@ def test_capabilities_for_sauce(self):
                                                    'tags': ['foo', 'bar'],
                                                    'timeZone': 'San Francisco',
                                                    'tunnelIdentifier': 'tunnelname',
-                                                   'videoUploadOnPass': False}}
+                                                   'videoUploadOnPass': False,
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         assert options.to_capabilities() == expected_capabilities
 
@@ -503,7 +507,9 @@ def test_capabilities_for_selenium(self):
                                  'browserVersion': 'latest',
                                  'platformName': 'Windows 10',
                                  'moz:firefoxOptions': {'args': ['--foo'], 'prefs': {'foo': 'bar'}},
-                                 'sauce:options': {'build': 'Sample Build Name'}}
+                                 'sauce:options': {'build': 'Sample Build Name',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         if seleniumVersion[0] == '4':
             expected_capabilities['pageLoadStrategy'] = 'normal'
diff --git a/python/tests/unit/test_safari.py b/python/tests/unit/test_safari.py
index 52817d53..d66adce9 100644
--- a/python/tests/unit/test_safari.py
+++ b/python/tests/unit/test_safari.py
@@ -322,7 +322,9 @@ def test_capabilities_for_w3c(self):
                                  'timeouts': {'implicit': 1,
                                               'pageLoad': 59,
                                               'script': 29},
-                                 'sauce:options': {'build': 'Build Name'}}
+                                 'sauce:options': {'build': 'Build Name',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         assert options.to_capabilities() == expected_capabilities
 
@@ -379,7 +381,9 @@ def test_capabilities_for_sauce(self):
                                                    'tags': ['foo', 'bar'],
                                                    'timeZone': 'San Francisco',
                                                    'tunnelIdentifier': 'tunnelname',
-                                                   'videoUploadOnPass': False}}
+                                                   'videoUploadOnPass': False,
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         assert options.to_capabilities() == expected_capabilities
 
@@ -390,7 +394,9 @@ def test_capabilities_for_selenium(self):
         expected_capabilities = {'browserName': 'safari',
                                  'browserVersion': 'latest',
                                  'platformName': 'macOS 11',
-                                 'sauce:options': {'build': 'Sample Build Name'}
+                                 'sauce:options': {'build': 'Sample Build Name',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}
                                  }
 
         assert options.to_capabilities() == expected_capabilities
diff --git a/python/tests/unit/test_session.py b/python/tests/unit/test_session.py
index b4f52090..450fad7f 100644
--- a/python/tests/unit/test_session.py
+++ b/python/tests/unit/test_session.py
@@ -1,3 +1,5 @@
+import os
+
 import pytest
 
 from saucebindings.options import SauceOptions
@@ -63,11 +65,13 @@ def set_users(self, monkeypatch):
         monkeypatch.setenv("SAUCE_ACCESS_KEY", "1234")
 
     def test_creates_a_session_on_sauce_labs(self, mocker):
-        default_url = 'https://test-user:1234@ondemand.us-west-1.saucelabs.com:443/wd/hub'
+        default_url = 'https://ondemand.us-west-1.saucelabs.com/wd/hub'
         expected_caps = {'browserName': 'chrome',
                          'browserVersion': 'latest',
                          'platformName': 'Windows 10',
-                         'sauce:options': {'build': 'TEST BUILD: 11'}}
+                         'sauce:options': {'build': 'TEST BUILD: 11',
+                                                   'username': os.getenv('SAUCE_USERNAME'),
+                                                   'accessKey': os.getenv('SAUCE_ACCESS_KEY')}}
 
         sauce_session = SauceSession()
         mocker.patch.object(sauce_session, 'create_driver')
@@ -76,23 +80,6 @@ def test_creates_a_session_on_sauce_labs(self, mocker):
 
         sauce_session.create_driver.assert_called_once_with(default_url, expected_caps)
 
-    def test_raises_exception_if_no_username_set(self, monkeypatch):
-        monkeypatch.delenv("SAUCE_USERNAME")
-
-        session = SauceSession()
-
-        with pytest.raises(KeyError):
-            session.start()
-
-    def test_raises_exception_if_no_access_key_set(self, monkeypatch):
-        monkeypatch.delenv("SAUCE_ACCESS_KEY")
-
-        session = SauceSession()
-
-        with pytest.raises(KeyError):
-            session.start()
-
-
 class TestURL(object):
 
     def test_user_can_override_default_url(self):