sauce_bindings 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 911fcc77b89278c32496a2c1e29a8076494208a2133fa4fa854e949d5db8437d
4
- data.tar.gz: c8a91543d40f08b14fd3253e7ca32ecd639c9d2c24833f63c4668da51699ed27
3
+ metadata.gz: 1ac45f63a4a484e6d4e5a60a31d5134a523533eabb46ac587517384307a1f84f
4
+ data.tar.gz: 43a328c5b629db206a6af37c77208e5370e547c6ee09239f112a45e77bc6c460
5
5
  SHA512:
6
- metadata.gz: ce6d3809d1efd72a5b89b0130a659b4d82863b16cf14377480bdfc3989ddf6f4c4e4bf2d9105968a03ee378c295366982a00b008fe2d9a91186ca107c1ea6231
7
- data.tar.gz: 6f9a7311e6c206e3ac8689d402bed4dfb7ec8f19e2380b4543e64ddcfc5ed2dbf673da00c9788b6cea8aa3f20a432ff08cf8235d9a22c72f1d585445e3e7c82d
6
+ metadata.gz: c26b2b21b1550daedae332c11d5e7ca3efb1f90c349b60ea2e06c1f4f869bdf1908b4405ec8d3213c1f7160f6b077602847951f2ef5d6a30e7af6631bb2c0741
7
+ data.tar.gz: 3f911b1b2335fb00e7bb8fbe2d406907d40a3989edaf2860bccb5e2ab9de675185af71a8015ce96a4c48e12d393b5baf5c1f89bcb67458135be308fca948bd91
data/.rubocop.yml CHANGED
@@ -16,10 +16,10 @@ Metrics/BlockLength:
16
16
  - "**/*_spec.rb"
17
17
 
18
18
  Metrics/CyclomaticComplexity:
19
- Max: 8
19
+ Max: 10
20
20
 
21
21
  Metrics/PerceivedComplexity:
22
- Max: 9
22
+ Max: 11
23
23
 
24
24
  Metrics/ClassLength:
25
25
  Exclude:
@@ -3,3 +3,10 @@
3
3
  require 'sauce_bindings/version'
4
4
  require 'sauce_bindings/options'
5
5
  require 'sauce_bindings/session'
6
+ require 'sauce_bindings/base_configurations'
7
+ require 'sauce_bindings/vdc_configurations'
8
+ require 'sauce_bindings/chrome_configurations'
9
+ require 'sauce_bindings/edge_configurations'
10
+ require 'sauce_bindings/firefox_configurations'
11
+ require 'sauce_bindings/ie_configurations'
12
+ require 'sauce_bindings/safari_configurations'
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SauceBindings
4
+ class BaseConfigurations
5
+ def self.valid_options
6
+ %i[platform_name name build tags custom_data public tunnel_identifier parent_tunnel]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SauceBindings
4
+ class ChromeConfigurations < VDCConfigurations
5
+ def self.valid_options
6
+ super + %i[chromedriver_version extended_debugging capture_performance set_window_rect]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SauceBindings
4
+ class EdgeConfigurations < VDCConfigurations
5
+ def self.valid_options
6
+ super + %i[edgedriver_version selenium_version set_window_rect]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SauceBindings
4
+ class FirefoxConfigurations < VDCConfigurations
5
+ def self.valid_options
6
+ super + %i[geckodriver_version extended_debugging selenium_version set_window_rect]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SauceBindings
4
+ class IEConfigurations < VDCConfigurations
5
+ def self.valid_options
6
+ super + %i[iedriver_version avoid_proxy selenium_version set_window_rect]
7
+ end
8
+ end
9
+ end
@@ -11,26 +11,36 @@ module SauceBindings
11
11
 
12
12
  def chrome(**opts)
13
13
  opts[:browser_name] = 'chrome'
14
+ opts[:valid_options] = ChromeConfigurations.valid_options
14
15
  Options.new(**opts)
15
16
  end
16
17
 
17
18
  def edge(**opts)
19
+ if Selenium::WebDriver::VERSION[0] == '3'
20
+ raise ArgumentError, 'Selenium 3 is not compatible with the Chromium based Microsoft Edge.'
21
+ end
22
+
18
23
  opts[:browser_name] = 'MicrosoftEdge'
24
+ opts[:valid_options] = EdgeConfigurations.valid_options
19
25
  Options.new(**opts)
20
26
  end
21
27
 
22
28
  def firefox(**opts)
23
29
  opts[:browser_name] = 'firefox'
30
+ opts[:valid_options] = FirefoxConfigurations.valid_options
24
31
  Options.new(**opts)
25
32
  end
26
33
 
27
34
  def ie(**opts)
28
35
  opts[:browser_name] = 'internet explorer'
36
+ opts[:valid_options] = IEConfigurations.valid_options
29
37
  Options.new(**opts)
30
38
  end
31
39
 
32
40
  def safari(**opts)
33
41
  opts[:browser_name] = 'safari'
42
+ opts[:platform_name] ||= 'macOS 11.00'
43
+ opts[:valid_options] = SafariConfigurations.valid_options
34
44
  Options.new(**opts)
35
45
  end
36
46
  end
@@ -49,17 +59,20 @@ module SauceBindings
49
59
  record_video screen_resolution selenium_version tags time_zone tunnel_identifier video_upload_on_pass
50
60
  capture_performance].freeze
51
61
 
52
- attr_accessor :browser_name, :browser_version, :platform_name, :accept_insecure_certs, :page_load_strategy, :proxy,
53
- :set_window_rect, :timeouts, :unhandled_prompt_behavior, :strict_file_interactability, :avoid_proxy,
54
- :build, :chromedriver_version, :command_timeout, :custom_data, :extended_debugging, :idle_timeout,
55
- :iedriver_version, :max_duration, :name, :parent_tunnel, :prerun, :priority, :public, :record_logs,
56
- :record_screenshots, :record_video, :screen_resolution, :selenium_version, :tags, :time_zone,
57
- :tunnel_identifier, :video_upload_on_pass, :capture_performance
58
- attr_reader :selenium_options
62
+ attr_reader :selenium_options, :timeouts
59
63
 
60
64
  def initialize(**opts)
61
- parse_selenium_options(opts.delete(:selenium_options))
62
- create_variables(SAUCE + W3C, opts)
65
+ se_options = Array(opts.delete(:selenium_options))
66
+ valid_options = opts.delete(:valid_options)
67
+ if valid_options.nil?
68
+ valid_options = SAUCE + W3C
69
+ warn 'Using `Options.new(opts)` directly is deprecated, use static methods for desired browser instead; ' \
70
+ 'e.g., `Options.chrome(opts)` or `Options.safari(opts)'
71
+ end
72
+
73
+ create_variables(valid_options, opts)
74
+ @selenium_options = se_options.map(&:as_json).inject(:merge) || {}
75
+ parse_selenium_options(se_options)
63
76
  @build ||= build_name
64
77
 
65
78
  @browser_name ||= selenium_options['browserName'] || 'chrome'
@@ -70,17 +83,13 @@ module SauceBindings
70
83
  def capabilities
71
84
  caps = selenium_options.dup
72
85
  W3C.each do |key|
73
- value = send(key)
74
- key = self.class.camel_case(key)
75
- value = parse_w3c_key(key, value)
76
- caps[key] = value unless value.nil?
86
+ value = parse_w3c_key(key)
87
+ caps[self.class.camel_case(key)] = value unless value.nil?
77
88
  end
78
89
  caps['sauce:options'] = {}
79
90
  SAUCE.each do |key|
80
- value = send(key)
81
- key = self.class.camel_case(key)
82
- value = parse_sauce_key(key, value)
83
- caps['sauce:options'][key] = value unless value.nil?
91
+ value = parse_sauce_key(key)
92
+ caps['sauce:options'][self.class.camel_case(key)] = value unless value.nil?
84
93
  end
85
94
  caps
86
95
  end
@@ -90,11 +99,7 @@ module SauceBindings
90
99
  opts.each do |key, value|
91
100
  raise ArgumentError, "#{key} is not a valid parameter for Options class" unless respond_to?("#{key}=")
92
101
 
93
- if value.is_a?(Hash)
94
- value = value.each_with_object({}) do |(old_key, val), updated|
95
- updated[old_key.to_sym] = val
96
- end
97
- end
102
+ value = value.transform_keys(&:to_sym) if value.is_a?(Hash)
98
103
 
99
104
  send("#{key}=", value)
100
105
  end
@@ -102,59 +107,124 @@ module SauceBindings
102
107
 
103
108
  private
104
109
 
105
- def parse_w3c_key(key, value)
106
- if key == 'proxy' && value
110
+ def key_value(key)
111
+ send(key)
112
+ rescue NoMethodError
113
+ # Ignored
114
+ end
115
+
116
+ def parse_w3c_key(key)
117
+ value = send(key)
118
+
119
+ if key == :proxy && value
107
120
  value.as_json
108
- elsif key == 'timeouts' && value
109
- value.each_with_object({}) do |(old_key, val), updated|
110
- updated[self.class.camel_case(old_key)] = val
121
+ elsif key == :timeouts
122
+ if value
123
+ warn ':timeouts is deprecated, use :implicit_wait_timeout, :page_load_timeout or :script_timeout directly; ' \
124
+ '(ensure the values are set as seconds not milliseconds)'
125
+ value.transform_keys do |old_key|
126
+ self.class.camel_case(old_key)
127
+ end
128
+ else
129
+ manage_timeouts
111
130
  end
112
131
  else
113
132
  value
114
133
  end
115
134
  end
116
135
 
117
- def parse_sauce_key(key, value)
118
- if key == 'prerun' && value.is_a?(Hash)
119
- value.each_with_object({}) do |(old_key, val), updated|
120
- updated[self.class.camel_case(old_key)] = val
121
- end
122
- elsif key == 'customData' && value.is_a?(Hash)
123
- value.each_with_object({}) do |(old_key, val), updated|
124
- updated[self.class.camel_case(old_key)] = val
125
- end
136
+ def manage_timeouts
137
+ timeouts = {}
138
+ timeouts['implicit'] = ms_multiplier(@implicit_wait_timeout) if @implicit_wait_timeout
139
+ timeouts['pageLoad'] = ms_multiplier(@page_load_timeout) if @page_load_timeout
140
+ timeouts['script'] = ms_multiplier(@script_timeout) if @script_timeout
141
+ timeouts unless timeouts.empty?
142
+ end
143
+
144
+ def ms_multiplier(int)
145
+ raise(ArgumentError, 'Timeouts need to be entered as seconds not milliseconds') if int > 600
146
+
147
+ int * 1000
148
+ end
149
+
150
+ def parse_sauce_key(key)
151
+ value = key_value(key)
152
+
153
+ case key
154
+ when :prerun
155
+ camelize_keys(value)
156
+ when :custom_data
157
+ camelize_keys(value)
158
+ when :disable_record_video
159
+ !send(:record_video)
160
+ when :disable_video_upload_on_pass
161
+ !send(:video_upload_on_pass)
162
+ when :disable_record_screenshots
163
+ !send(:record_screenshots)
164
+ when :disable_record_logs
165
+ !send(:record_logs)
126
166
  else
127
167
  value
128
168
  end
129
169
  end
130
170
 
171
+ def camelize_keys(hash)
172
+ hash&.transform_keys do |old_key|
173
+ self.class.camel_case(old_key)
174
+ end
175
+ end
176
+
131
177
  def parse_selenium_options(selenium_opts)
132
- opts = Array(selenium_opts)
178
+ selenium_opts.each do |opt|
179
+ W3C.each do |capability|
180
+ value = option_value(opt, capability)
181
+ next if capability == :timeouts && value&.empty?
133
182
 
134
- opts.each do |opt|
135
- browser = BROWSER_NAMES[opt.class]
136
- if browser
137
- @browser_name = browser
138
- else
139
- W3C.each do |capability|
140
- send("#{capability}=", opt[capability]) if opt[capability]
183
+ if capability == :browser_name
184
+ @browser_name ||= BROWSER_NAMES[opt.class]
185
+ validate_browser_name(value || BROWSER_NAMES[opt.class])
186
+ elsif value
187
+ send("#{capability}=", value)
141
188
  end
142
189
  end
143
190
  end
191
+ end
192
+
193
+ def option_value(opt, capability)
194
+ if opt.respond_to?(capability)
195
+ begin
196
+ opt.send(capability)
197
+ rescue KeyError
198
+ # Ignored
199
+ end
200
+ elsif opt.respond_to?(:[])
201
+ opt[capability]
202
+ end
203
+ end
144
204
 
145
- @selenium_options = opts.map(&:as_json).inject(:merge) || {}
205
+ def validate_browser_name(browser)
206
+ return if @browser_name.nil? || browser == @browser_name
207
+
208
+ raise ArgumentError, "Selenium class identifies capabilities for #{browser}, which does not match the " \
209
+ "provided browser name: #{@browser_name}"
146
210
  end
147
211
 
148
212
  def create_variables(key, opts)
149
213
  key.each do |option|
150
- self.class.__send__(:attr_accessor, option)
214
+ singleton_class.class_eval { attr_accessor option }
151
215
  next unless opts.key?(option)
152
216
 
153
217
  instance_variable_set("@#{option}", opts.delete(option))
154
218
  end
219
+
220
+ if opts.key?(:browser_name)
221
+ singleton_class.class_eval { attr_reader :browser_name }
222
+ @browser_name = opts.delete(:browser_name)
223
+ end
224
+
155
225
  return if opts.empty?
156
226
 
157
- raise ArgumentError, "#{opts.inspect} are not valid parameters for Options class"
227
+ raise ArgumentError, "#{opts.inspect} are not valid parameters for Options class with #{@browser_name}"
158
228
  end
159
229
 
160
230
  def build_name
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SauceBindings
4
+ class SafariConfigurations < VDCConfigurations
5
+ def self.valid_options
6
+ super + %i[avoid_proxy selenium_version set_window_rect]
7
+ end
8
+ end
9
+ end
@@ -15,7 +15,7 @@ module SauceBindings
15
15
  attr_accessor :http_client, :listener
16
16
 
17
17
  def initialize(options = nil, data_center: nil, http_client: nil, listener: nil)
18
- @options = options || Options.new
18
+ @options = options || Options.chrome
19
19
  @http_client = http_client
20
20
  @listener = listener
21
21
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SauceBindings
4
+ class VDCConfigurations < BaseConfigurations
5
+ def self.valid_options
6
+ super + %i[browser_version page_load_strategy accept_insecure_certs proxy
7
+ strict_file_interactability unhandled_prompt_behavior implicit_wait_timeout
8
+ page_load_timeout script_timeout record_video video_upload_on_pass
9
+ record_screenshots record_logs max_duration command_timeout
10
+ idle_timeout prerun priority screen_resolution time_zone]
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SauceBindings
4
- VERSION = '1.1.0'
4
+ VERSION = '1.1.1'
5
5
  end
@@ -9,6 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.version = SauceBindings::VERSION
10
10
  spec.authors = ['Titus Fortner']
11
11
  spec.email = ['titusfortner@gmail.com']
12
+ spec.required_ruby_version = '>= 2.5.0'
12
13
 
13
14
  spec.summary = 'Simple interface for interacting with Sauce Labs.'
14
15
  spec.description = 'Reduces complexity in user code for running Selenium tests on Sauce Labs'
@@ -23,11 +24,11 @@ Gem::Specification.new do |spec|
23
24
  spec.add_development_dependency 'capybara', '~> 3.16'
24
25
  spec.add_development_dependency 'rake', '>= 12.3.3'
25
26
  spec.add_development_dependency 'rspec', '~> 3.0'
26
- spec.add_development_dependency 'rubocop', '~>0.66'
27
+ spec.add_development_dependency 'rubocop', '~> 1.0'
27
28
  spec.add_development_dependency 'rubocop-performance'
28
- spec.add_development_dependency 'rubocop-rspec', '~>1.32'
29
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.0'
29
30
  spec.add_development_dependency 'webmock', '~> 3.5'
30
31
 
31
32
  spec.add_runtime_dependency 'sauce_whisk'
32
- spec.add_runtime_dependency 'selenium-webdriver', '~> 3.142.0', '>= 3.142.7'
33
+ spec.add_runtime_dependency 'selenium-webdriver', '>= 3.142.7'
33
34
  end
@@ -0,0 +1,56 @@
1
+ example_values:
2
+ browser_name: 'firefox'
3
+ browser_version: '123'
4
+ platform_name: 'Mac'
5
+ accept_insecure_certs: true
6
+ page_load_strategy: 'eager'
7
+ set_window_rect: true
8
+ unhandled_prompt_behavior: "accept"
9
+ strict_file_interactability: true
10
+ timeouts:
11
+ implicit: 1
12
+ page_load: 59
13
+ script: 29
14
+ avoid_proxy: true
15
+ build: 'Sample Build Name'
16
+ capture_performance: true
17
+ chromedriver_version: '71'
18
+ command_timeout: 2
19
+ custom_data:
20
+ foo: 'foo'
21
+ bar: 'bar'
22
+ extended_debugging: true
23
+ idle_timeout: 3
24
+ iedriver_version: '3.141.0'
25
+ max_duration: 300
26
+ name: 'Sample Test Name'
27
+ parent_tunnel: 'Mommy'
28
+ prerun:
29
+ executable: "http://url.to/your/executable.exe"
30
+ args:
31
+ - --silent
32
+ - -a
33
+ - -q
34
+ background: false
35
+ timeout: 120
36
+ priority: 0
37
+ public: 'team'
38
+ record_logs: false
39
+ record_screenshots: false
40
+ record_video: false
41
+ screen_resolution: '10x10'
42
+ selenium_version: '3.141.59'
43
+ tags:
44
+ - foo
45
+ - bar
46
+ - foobar
47
+ time_zone: 'San Francisco'
48
+ tunnel_identifier: 'tunnelname'
49
+ video_upload_on_pass: false
50
+
51
+ invalid_option:
52
+ foo: "bar"
53
+ browser_name: "firefox"
54
+ browser_version: "70"
55
+ platform_name: "MacOS 10.12"
56
+ record_screenshots: false