Skip to content

Commit 38a7502

Browse files
committed
[rb] update chrome extensions & firefox profile behavior to evaluate validity when assigned rather than when used
1 parent 03d5b56 commit 38a7502

File tree

7 files changed

+71
-47
lines changed

7 files changed

+71
-47
lines changed

rb/.rubocop.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Metrics/ClassLength:
6262
- 'lib/selenium/webdriver/remote/capabilities.rb'
6363

6464
Metrics/CyclomaticComplexity:
65-
Max: 10
65+
Max: 9
6666
Exclude:
6767
- 'lib/selenium/webdriver/remote/capabilities.rb'
6868
- 'lib/selenium/webdriver/support/color.rb'

rb/lib/selenium/webdriver/chrome/options.rb

+43-23
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ class Options < WebDriver::Options
2929
# see: http://chromedriver.chromium.org/capabilities
3030
CAPABILITIES = {args: 'args',
3131
binary: 'binary',
32-
extensions: 'extensions',
3332
local_state: 'localState',
3433
prefs: 'prefs',
3534
detach: 'detach',
@@ -40,6 +39,9 @@ class Options < WebDriver::Options
4039
perf_logging_prefs: 'perfLoggingPrefs',
4140
window_types: 'windowTypes'}.freeze
4241

42+
# NOTE: special handling of 'extensions' to validate when set instead of when used
43+
attr_reader :extensions
44+
4345
# Create a new Options instance.
4446
#
4547
# @example
@@ -64,21 +66,23 @@ class Options < WebDriver::Options
6466
# @option opts [Array<String>] :window_types A list of window types to appear in the list of window handles
6567
#
6668

67-
def initialize(profile: nil, encoded_extensions: [], **opts)
69+
def initialize(profile: nil, **opts)
6870
super(**opts)
6971

7072
@profile = profile
71-
@options[:encoded_extensions] = encoded_extensions
72-
73-
@options[:args] ||= []
74-
@options[:prefs] ||= {}
75-
@options[:emulation] ||= {}
76-
@options[:local_state] ||= {}
77-
@options[:exclude_switches] ||= []
78-
@options[:perf_logging_prefs] ||= {}
79-
@options[:window_types] ||= []
80-
@options[:extensions] ||= []
81-
@options[:extensions].each(&method(:validate_extension))
73+
74+
@options = {args: [],
75+
prefs: {},
76+
emulation: {},
77+
extensions: [],
78+
local_state: {},
79+
exclude_switches: [],
80+
perf_logging_prefs: {},
81+
window_types: []}.merge(@options)
82+
83+
@encoded_extensions = @options.delete(:encoded_extensions) || []
84+
@extensions = []
85+
(@options.delete(:extensions)).each(&method(:validate_extension))
8286
end
8387

8488
#
@@ -93,7 +97,21 @@ def initialize(profile: nil, encoded_extensions: [], **opts)
9397

9498
def add_extension(path)
9599
validate_extension(path)
96-
@options[:extensions] << path
100+
end
101+
102+
#
103+
# Add an extension by local path.
104+
#
105+
# @example
106+
# extensions = ['/path/to/extension.crx', '/path/to/other.crx']
107+
# options = Selenium::WebDriver::Chrome::Options.new
108+
# options.extensions = extensions
109+
#
110+
# @param [Array<String>] :extensions A list of paths to (.crx) Chrome extensions to install on startup
111+
#
112+
113+
def extensions=(extensions)
114+
extensions.each(&method(:validate_extension))
97115
end
98116

99117
#
@@ -107,9 +125,8 @@ def add_extension(path)
107125
#
108126

109127
def add_encoded_extension(encoded)
110-
@options[:encoded_extensions] << encoded
128+
@encoded_extensions << encoded
111129
end
112-
alias_method :encoded_extension=, :add_encoded_extension
113130

114131
#
115132
# Add a command-line argument to use when starting Chrome.
@@ -178,15 +195,16 @@ def add_emulation(**opts)
178195
private
179196

180197
def process_browser_options(browser_options)
181-
options = browser_options[KEY]
198+
options = browser_options[self.class::KEY]
182199
options['binary'] ||= binary_path if binary_path
183-
options['args'] << "--user-data-dir=#{@profile.directory}" if @profile
184-
merge_extensions(options)
185-
end
200+
if @profile
201+
options['args'] ||= []
202+
options['args'] << "--user-data-dir=#{@profile.directory}"
203+
end
204+
205+
return if (@encoded_extensions + @extensions).empty?
186206

187-
def merge_extensions(browser_options)
188-
encoded_extensions = browser_options.delete(:encoded_extensions)
189-
browser_options[:extensions] = extensions.map(&method(:encode_extension)) + encoded_extensions
207+
options['extensions'] = @encoded_extensions + @extensions.map(&method(:encode_extension))
190208
end
191209

192210
def binary_path
@@ -200,6 +218,8 @@ def encode_extension(path)
200218
def validate_extension(path)
201219
raise Error::WebDriverError, "could not find extension at #{path.inspect}" unless File.file?(path)
202220
raise Error::WebDriverError, "file was not an extension #{path.inspect}" unless File.extname(path) == '.crx'
221+
222+
@extensions << path
203223
end
204224

205225
def camelize?(key)

rb/lib/selenium/webdriver/common/options.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,16 @@ def as_json(*)
8282
end
8383
browser_options = defined?(self.class::KEY) ? {self.class::KEY => options} : options
8484

85-
process_browser_options(browser_options) if private_methods(false).include?(:process_browser_options)
85+
process_browser_options(browser_options)
8686
generate_as_json(w3c_options.merge(browser_options))
8787
end
8888

8989
private
9090

91+
def process_browser_options(_browser_options)
92+
nil
93+
end
94+
9195
def camelize?(_key)
9296
true
9397
end

rb/lib/selenium/webdriver/firefox/options.rb

+14-14
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ class Options < WebDriver::Options
2424
KEY = 'moz:firefoxOptions'
2525

2626
# see: https://firefox-source-docs.mozilla.org/testing/geckodriver/Capabilities.html
27-
# NOTE: special handling of 'profile' to validate on construction instead of use
2827
CAPABILITIES = {binary: 'binary',
2928
args: 'args',
3029
log: 'log',
3130
prefs: 'prefs'}.freeze
3231
BROWSER = 'firefox'
3332

33+
# NOTE: special handling of 'profile' to validate when set instead of when used
34+
attr_reader :profile
35+
3436
#
3537
# Create a new Options instance, only for W3C-capable versions of Firefox.
3638
#
@@ -53,7 +55,8 @@ def initialize(log_level: nil, **opts)
5355
@options[:args] ||= []
5456
@options[:prefs] ||= {}
5557
@options[:log] ||= {level: log_level} if log_level
56-
process_profile(@options[:profile]) if @options.key?(:profile)
58+
59+
process_profile(@options.delete(:profile))
5760
end
5861

5962
#
@@ -116,10 +119,6 @@ def profile=(profile)
116119
process_profile(profile)
117120
end
118121

119-
def profile
120-
@options[:profile]
121-
end
122-
123122
def log_level
124123
@options.dig(:log, :level)
125124
end
@@ -133,17 +132,18 @@ def log_level=(level)
133132
def process_browser_options(browser_options)
134133
options = browser_options[KEY]
135134
options['binary'] ||= Firefox.path if Firefox.path
136-
options['profile'] = options.delete(:profile) if profile
135+
options['profile'] = @profile if @profile
137136
end
138137

139138
def process_profile(profile)
140-
@options[:profile] = if profile.nil?
141-
nil
142-
elsif profile.is_a? Profile
143-
profile
144-
else
145-
Profile.from_name(profile)
146-
end
139+
@profile = case profile
140+
when nil
141+
nil
142+
when Profile
143+
profile
144+
else
145+
Profile.from_name(profile)
146+
end
147147
end
148148
end # Options
149149
end # Firefox

rb/spec/unit/selenium/webdriver/chrome/options_spec.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ module Chrome
158158
describe '#add_encoded_extension' do
159159
it 'adds an encoded extension' do
160160
options.add_encoded_extension('foo')
161-
expect(options.instance_variable_get('@options')[:encoded_extensions]).to include('foo')
161+
expect(options.instance_variable_get('@encoded_extensions')).to include('foo')
162162
end
163163
end
164164

@@ -264,7 +264,7 @@ module Chrome
264264
'prefs' => {'foo' => 'bar',
265265
'key_that_should_not_be_camelcased' => 'baz'},
266266
'binary' => '/foo/bar',
267-
'extensions' => %w[encoded_foo encoded_bar encoded_foobar],
267+
'extensions' => %w[encoded_foobar encoded_foo encoded_bar],
268268
'foo' => 'bar',
269269
'mobileEmulation' => {'deviceName' => 'mine'},
270270
'localState' => {'foo' => 'bar'},

rb/spec/unit/selenium/webdriver/edge_chrome/driver_spec.rb

+4-1
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,11 @@ def as_json(*)
210210

211211
it 'with Options instance with profile' do
212212
profile = Profile.new.tap(&:layout_on_disk)
213+
allow(profile).to receive(:directory).and_return("PROF_DIR")
213214
options = Options.new(profile: profile)
214-
expect_request(body: {capabilities: {firstMatch: [browserName: "MicrosoftEdge", 'ms:edgeOptions': {}]}})
215+
expect_request(body: {capabilities:
216+
{firstMatch: [browserName: "MicrosoftEdge",
217+
'ms:edgeOptions': {"args": ["--user-data-dir=PROF_DIR"]}]}})
215218

216219
expect { Driver.new(capabilities: [options]) }.not_to raise_exception
217220
end

rb/spec/unit/selenium/webdriver/edge_chrome/options_spec.rb

+2-5
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ module EdgeChrome
107107
describe '#add_encoded_extension' do
108108
it 'adds an encoded extension' do
109109
options.add_encoded_extension('foo')
110-
expect(options.instance_variable_get('@options')[:encoded_extensions]).to include('foo')
110+
expect(options.instance_variable_get('@encoded_extensions')).to include('foo')
111111
end
112112
end
113113

@@ -220,10 +220,7 @@ module EdgeChrome
220220
'prefs' => {'foo' => 'bar',
221221
'key_that_should_not_be_camelcased' => 'baz'},
222222
'binary' => '/foo/bar',
223-
# TODO: verify this is correct behavior;
224-
# I would expect extensions to come back encoded
225-
'extensions' => %w[foo.crx bar.crx],
226-
'encodedExtensions' => %w[encoded_foobar],
223+
'extensions' => %w[encoded_foobar encoded_foo encoded_bar],
227224
'foo' => 'bar',
228225
'mobileEmulation' => {'deviceName' => 'mine'},
229226
'localState' => {'foo' => 'bar'},

0 commit comments

Comments
 (0)