From 516a24bc288d563246c8dc0e9d5dee67e463ebe6 Mon Sep 17 00:00:00 2001 From: Titus Fortner Date: Wed, 5 Jun 2019 13:36:13 -0700 Subject: [PATCH] [rb] fix serialization methods --- rb/lib/selenium/webdriver/chrome/driver.rb | 8 ++- rb/lib/selenium/webdriver/chrome/options.rb | 4 +- rb/lib/selenium/webdriver/chrome/profile.rb | 4 +- rb/lib/selenium/webdriver/common.rb | 1 + rb/lib/selenium/webdriver/common/options.rb | 53 ++++++++++++++ rb/lib/selenium/webdriver/firefox/options.rb | 4 +- rb/lib/selenium/webdriver/ie/options.rb | 4 +- .../selenium/webdriver/chrome/profile_spec.rb | 4 +- .../selenium/webdriver/chrome/driver_spec.rb | 6 +- .../selenium/webdriver/chrome/options_spec.rb | 16 ++--- .../selenium/webdriver/edge/options_spec.rb | 13 ++-- .../webdriver/firefox/options_spec.rb | 30 ++++---- .../selenium/webdriver/ie/options_spec.rb | 72 +++++++++---------- .../selenium/webdriver/safari/options_spec.rb | 11 +-- 14 files changed, 144 insertions(+), 86 deletions(-) create mode 100644 rb/lib/selenium/webdriver/common/options.rb diff --git a/rb/lib/selenium/webdriver/chrome/driver.rb b/rb/lib/selenium/webdriver/chrome/driver.rb index b33f4c8b20ae1..964e79e17950e 100644 --- a/rb/lib/selenium/webdriver/chrome/driver.rb +++ b/rb/lib/selenium/webdriver/chrome/driver.rb @@ -72,12 +72,14 @@ def create_capabilities(opts) if profile profile = profile.as_json - options.add_argument("--user-data-dir=#{profile[:directory]}") if options.args.none?(&/user-data-dir/.method(:match?)) + if options.args.none?(&/user-data-dir/.method(:match?)) + options.add_argument("--user-data-dir=#{profile['directory']}") + end - if profile[:extensions] + if profile['extensions'] WebDriver.logger.deprecate 'Using Selenium::WebDriver::Chrome::Profile#extensions', 'Selenium::WebDriver::Chrome::Options#add_extension' - profile[:extensions].each do |extension| + profile['extensions'].each do |extension| options.add_encoded_extension(extension) end end diff --git a/rb/lib/selenium/webdriver/chrome/options.rb b/rb/lib/selenium/webdriver/chrome/options.rb index 63ec6a89b9603..763df03f88a96 100755 --- a/rb/lib/selenium/webdriver/chrome/options.rb +++ b/rb/lib/selenium/webdriver/chrome/options.rb @@ -20,7 +20,7 @@ module Selenium module WebDriver module Chrome - class Options + class Options < WebDriver::Common::Options attr_reader :args, :prefs, :options, :emulation, :extensions, :encoded_extensions attr_accessor :binary @@ -178,7 +178,7 @@ def as_json(*) opts[:mobileEmulation] = @emulation unless @emulation.empty? opts[:prefs] = @prefs unless @prefs.empty? - {KEY => opts} + {KEY => generate_as_json(opts)} end end # Options end # Chrome diff --git a/rb/lib/selenium/webdriver/chrome/profile.rb b/rb/lib/selenium/webdriver/chrome/profile.rb index be3cf585bcc58..98f49b76d2d39 100755 --- a/rb/lib/selenium/webdriver/chrome/profile.rb +++ b/rb/lib/selenium/webdriver/chrome/profile.rb @@ -77,8 +77,8 @@ def as_json(*) extensions.concat(@encoded_extensions) - opts = {directory: directory || layout_on_disk} - opts[:extensions] = extensions if extensions.any? + opts = {'directory' => directory || layout_on_disk} + opts['extensions'] = extensions if extensions.any? opts end diff --git a/rb/lib/selenium/webdriver/common.rb b/rb/lib/selenium/webdriver/common.rb index bea46bd787170..7688f0e7a5244 100644 --- a/rb/lib/selenium/webdriver/common.rb +++ b/rb/lib/selenium/webdriver/common.rb @@ -64,5 +64,6 @@ require 'selenium/webdriver/common/driver_extensions/has_addons' require 'selenium/webdriver/common/keys' require 'selenium/webdriver/common/profile_helper' +require 'selenium/webdriver/common/options' require 'selenium/webdriver/common/driver' require 'selenium/webdriver/common/element' diff --git a/rb/lib/selenium/webdriver/common/options.rb b/rb/lib/selenium/webdriver/common/options.rb new file mode 100644 index 0000000000000..c384c07cfa99d --- /dev/null +++ b/rb/lib/selenium/webdriver/common/options.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + module Common + class Options + private + + def generate_as_json(value) + if value.respond_to?(:as_json) + value.as_json + elsif value.is_a?(Hash) + value.each_with_object({}) { |(key, val), hash| hash[convert_json_key(key)] = generate_as_json(val) } + elsif value.is_a?(Array) + value.map(&method(:generate_as_json)) + elsif value.is_a?(Symbol) + value.to_s + else + value + end + end + + def convert_json_key(key) + key = camel_case(key) if key.is_a?(Symbol) + return key if key.is_a?(String) + + raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}" + end + + def camel_case(str) + str.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase } + end + end # Options + end # Common + end # WebDriver +end # Selenium diff --git a/rb/lib/selenium/webdriver/firefox/options.rb b/rb/lib/selenium/webdriver/firefox/options.rb index bca11aea4d63c..0f0e599d93745 100644 --- a/rb/lib/selenium/webdriver/firefox/options.rb +++ b/rb/lib/selenium/webdriver/firefox/options.rb @@ -20,7 +20,7 @@ module Selenium module WebDriver module Firefox - class Options + class Options < WebDriver::Common::Options attr_reader :args, :prefs, :options, :profile attr_accessor :binary, :log_level @@ -139,7 +139,7 @@ def as_json(*) opts[:prefs] = @prefs unless @prefs.empty? opts[:log] = {level: @log_level} if @log_level - {KEY => opts} + {KEY => generate_as_json(opts)} end private diff --git a/rb/lib/selenium/webdriver/ie/options.rb b/rb/lib/selenium/webdriver/ie/options.rb index 17dfb12f79b09..b536ca23e5e3b 100644 --- a/rb/lib/selenium/webdriver/ie/options.rb +++ b/rb/lib/selenium/webdriver/ie/options.rb @@ -20,7 +20,7 @@ module Selenium module WebDriver module IE - class Options + class Options < WebDriver::Common::Options KEY = 'se:ieOptions' SCROLL_TOP = 0 SCROLL_BOTTOM = 1 @@ -130,7 +130,7 @@ def as_json(*) opts['ie.browserCommandLineSwitches'] = @args.to_a.join(' ') if @args.any? opts.merge!(@options) - {KEY => opts} + {KEY => generate_as_json(opts)} end end # Options end # IE diff --git a/rb/spec/integration/selenium/webdriver/chrome/profile_spec.rb b/rb/spec/integration/selenium/webdriver/chrome/profile_spec.rb index 0b6c81de08020..366b95d9b0558 100755 --- a/rb/spec/integration/selenium/webdriver/chrome/profile_spec.rb +++ b/rb/spec/integration/selenium/webdriver/chrome/profile_spec.rb @@ -61,8 +61,8 @@ module Chrome expect(profile).to receive(:layout_on_disk).and_return 'ignored' - expect(profile.as_json).to eq(directory: 'ignored', - extensions: [Base64.strict_encode64('test')]) + expect(profile.as_json).to eq('directory' => 'ignored', + 'extensions' => [Base64.strict_encode64('test')]) end it "raises an error if the extension doesn't exist" do diff --git a/rb/spec/unit/selenium/webdriver/chrome/driver_spec.rb b/rb/spec/unit/selenium/webdriver/chrome/driver_spec.rb index 92cdbdc37e154..0dc751d15a468 100644 --- a/rb/spec/unit/selenium/webdriver/chrome/driver_spec.rb +++ b/rb/spec/unit/selenium/webdriver/chrome/driver_spec.rb @@ -56,7 +56,7 @@ module Chrome it 'lets the user override chrome.detach' do Driver.new(http_client: http, detach: true) - expect(caps['goog:chromeOptions'][:detach]).to be true + expect(caps['goog:chromeOptions']['detach']).to be true end it 'raises an ArgumentError if args is not an Array' do @@ -72,8 +72,8 @@ module Chrome Driver.new(http_client: http, profile: profile) profile_data = profile.as_json - expect(caps['goog:chromeOptions'][:args].first).to include(profile_data[:directory]) - expect(caps['goog:chromeOptions'][:extensions]).to eq(profile_data[:extensions]) + expect(caps['goog:chromeOptions']['args'].first).to include(profile_data['directory']) + expect(caps['goog:chromeOptions']['extensions']).to eq(profile_data['extensions']) end context 'with custom desired capabilities' do diff --git a/rb/spec/unit/selenium/webdriver/chrome/options_spec.rb b/rb/spec/unit/selenium/webdriver/chrome/options_spec.rb index ef296854999e0..e0cbce8c72b0c 100644 --- a/rb/spec/unit/selenium/webdriver/chrome/options_spec.rb +++ b/rb/spec/unit/selenium/webdriver/chrome/options_spec.rb @@ -154,14 +154,14 @@ module Chrome prefs: {a: 1}, extensions: ['/foo.crx'], options: {foo: :bar}, - emulation: {c: 3}) - json = opts.as_json - expect(json['goog:chromeOptions'][:args]).to eq(['foo']) - expect(json['goog:chromeOptions'][:binary]).to eq('/foo/bar') - expect(json['goog:chromeOptions'][:prefs]).to include(a: 1) - expect(json['goog:chromeOptions'][:extensions]).to include('bar') - expect(json['goog:chromeOptions'][:foo]).to eq(:bar) - expect(json['goog:chromeOptions'][:mobileEmulation]).to include(c: 3) + emulation: {device_name: 'mine'}) + + json = opts.as_json['goog:chromeOptions'] + expect(json).to eq('args' => ['foo'], 'binary' => '/foo/bar', + 'prefs' => {'a' => 1}, + 'extensions' => ['bar'], + 'foo' => 'bar', + 'mobileEmulation' => {'deviceName' => 'mine'}) end end end # Options diff --git a/rb/spec/unit/selenium/webdriver/edge/options_spec.rb b/rb/spec/unit/selenium/webdriver/edge/options_spec.rb index 33cad3bf59a49..bb22a8efff9f5 100644 --- a/rb/spec/unit/selenium/webdriver/edge/options_spec.rb +++ b/rb/spec/unit/selenium/webdriver/edge/options_spec.rb @@ -38,13 +38,14 @@ module Edge describe '#as_json' do it 'returns JSON hash' do - options = Options.new(in_private: true, start_page: 'http://seleniumhq.org') + options = Options.new(in_private: true, + start_page: 'http://seleniumhq.org') options.add_extension_path(__dir__) - expect(options.as_json).to eq( - 'ms:inPrivate' => true, - 'ms:extensionPaths' => [__dir__], - 'ms:startPage' => 'http://seleniumhq.org' - ) + + json = options.as_json + expect(json).to eq('ms:inPrivate' => true, + 'ms:extensionPaths' => [__dir__], + 'ms:startPage' => 'http://seleniumhq.org') end end end # Options diff --git a/rb/spec/unit/selenium/webdriver/firefox/options_spec.rb b/rb/spec/unit/selenium/webdriver/firefox/options_spec.rb index e627713ef5f1a..081ae451a48fe 100644 --- a/rb/spec/unit/selenium/webdriver/firefox/options_spec.rb +++ b/rb/spec/unit/selenium/webdriver/firefox/options_spec.rb @@ -97,7 +97,7 @@ module Firefox describe '#headless!' do it 'adds the -headless command-line flag' do options.headless! - expect(options.as_json['moz:firefoxOptions'][:args]).to include('-headless') + expect(options.as_json['moz:firefoxOptions']['args']).to include('-headless') end end @@ -127,20 +127,20 @@ module Firefox profile = Profile.new expect(profile).to receive(:encoded).and_return('foo') - opts = Options.new(args: ['foo'], - binary: '/foo/bar', - prefs: {a: 1}, - options: {foo: :bar}, - profile: profile, - log_level: :debug) - json = opts.as_json - - expect(json['moz:firefoxOptions'][:args]).to eq(['foo']) - expect(json['moz:firefoxOptions'][:binary]).to eq('/foo/bar') - expect(json['moz:firefoxOptions'][:prefs]).to include(a: 1) - expect(json['moz:firefoxOptions'][:foo]).to eq(:bar) - expect(json['moz:firefoxOptions'][:profile]).to eq('foo') - expect(json['moz:firefoxOptions'][:log]).to include(level: :debug) + options = Options.new(args: ['foo'], + binary: '/foo/bar', + prefs: {a: 1}, + options: {foo: :bar}, + profile: profile, + log_level: :debug) + + json = options.as_json['moz:firefoxOptions'] + expect(json).to eq('args' => ['foo'], + 'binary' => '/foo/bar', + 'prefs' => {"a" => 1}, + 'profile' => 'foo', + 'log' => {'level' => 'debug'}, + 'foo' => 'bar') end end end # Options diff --git a/rb/spec/unit/selenium/webdriver/ie/options_spec.rb b/rb/spec/unit/selenium/webdriver/ie/options_spec.rb index 69accc826fcc7..40fcf5432864e 100644 --- a/rb/spec/unit/selenium/webdriver/ie/options_spec.rb +++ b/rb/spec/unit/selenium/webdriver/ie/options_spec.rb @@ -127,42 +127,42 @@ module IE describe '#as_json' do it 'returns a JSON hash' do - opts = Options.new(args: ['foo'], - browser_attach_timeout: 30000, - element_scroll_behavior: true, - full_page_screenshot: true, - ensure_clean_session: true, - file_upload_dialog_timeout: 30000, - force_create_process_api: true, - force_shell_windows_api: true, - ignore_protected_mode_settings: false, - ignore_zoom_level: false, - initial_browser_url: 'http://google.com', - native_events: false, - persistent_hover: false, - require_window_focus: true, - use_per_process_proxy: true, - validate_cookie_document_type: true) - opts.add_option(:foo, 'bar') - - json = opts.as_json.fetch('se:ieOptions') - - expect(json['browserAttachTimeout']).to eq(30000) - expect(json['elementScrollBehavior']).to eq(true) - expect(json['ie.enableFullPageScreenshot']).to eq(true) - expect(json['ie.ensureCleanSession']).to eq(true) - expect(json['ie.fileUploadDialogTimeout']).to eq(30000) - expect(json['ie.forceCreateProcessApi']).to eq(true) - expect(json['ie.forceShellWindowsApi']).to eq(true) - expect(json['ignoreProtectedModeSettings']).to eq(false) - expect(json['ignoreZoomSetting']).to eq(false) - expect(json['initialBrowserUrl']).to eq('http://google.com') - expect(json['nativeEvents']).to eq(false) - expect(json['enablePersistentHover']).to eq(false) - expect(json['requireWindowFocus']).to eq(true) - expect(json['ie.usePerProcessProxy']).to eq(true) - expect(json['ie.validateCookieDocumentType']).to eq(true) - expect(json[:foo]).to eq('bar') + options = Options.new(args: ['foo'], + browser_attach_timeout: 30000, + element_scroll_behavior: true, + full_page_screenshot: true, + ensure_clean_session: true, + file_upload_dialog_timeout: 30000, + force_create_process_api: true, + force_shell_windows_api: true, + ignore_protected_mode_settings: false, + ignore_zoom_level: false, + initial_browser_url: 'http://google.com', + native_events: false, + persistent_hover: false, + require_window_focus: true, + use_per_process_proxy: true, + validate_cookie_document_type: true) + options.add_option(:foo, 'bar') + + json = options.as_json['se:ieOptions'] + expect(json).to eq('ie.browserCommandLineSwitches' => 'foo', + 'browserAttachTimeout' => 30000, + 'elementScrollBehavior' => true, + 'ie.enableFullPageScreenshot' => true, + 'ie.ensureCleanSession' => true, + 'ie.fileUploadDialogTimeout' => 30000, + 'ie.forceCreateProcessApi' => true, + 'ie.forceShellWindowsApi' => true, + 'ignoreProtectedModeSettings' => false, + 'ignoreZoomSetting' => false, + 'initialBrowserUrl' => 'http://google.com', + 'nativeEvents' => false, + 'enablePersistentHover' => false, + 'requireWindowFocus' => true, + 'ie.usePerProcessProxy' => true, + 'ie.validateCookieDocumentType' => true, + 'foo' => 'bar') end end end # Options diff --git a/rb/spec/unit/selenium/webdriver/safari/options_spec.rb b/rb/spec/unit/selenium/webdriver/safari/options_spec.rb index f5cc12f0e636a..fada32925ad00 100644 --- a/rb/spec/unit/selenium/webdriver/safari/options_spec.rb +++ b/rb/spec/unit/selenium/webdriver/safari/options_spec.rb @@ -25,11 +25,12 @@ module Safari describe Options do describe '#as_json' do it 'returns JSON hash' do - options = Options.new(automatic_inspection: true, automatic_profiling: true) - expect(options.as_json).to eq( - 'safari:automaticInspection' => true, - 'safari:automaticProfiling' => true - ) + options = Options.new(automatic_inspection: true, + automatic_profiling: true) + + json = options.as_json + expect(json).to eq('safari:automaticInspection' => true, + 'safari:automaticProfiling' => true) end end end # Options