rudra 1.0.15 → 1.1.2

This diff has not been reviewed by any users.
Log in in order to be able to vote.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rudra.rb +148 -33
  3. metadata +22 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 18f80bbed760fbf34d622b60e647507bab5ddfea167a6d144430dae84ed35a98
4
- data.tar.gz: '04965c6ea61ea288861f22c6fabbb61240f384faf99b9a9402e51273d201caa4'
3
+ metadata.gz: f6485433a80329770ea6ce43647f1d10176c20fa1eefa825b51e222615e0b4fe
4
+ data.tar.gz: 980b66578597240fab1f2b0c68ee9fcc68be47b7466a8b5d99decf3dec6787c4
5
5
  SHA512:
6
- metadata.gz: 55a6791c2d89ecb33b3833ac41ef6f1514b482ac13525070aa246166bc5d530c7dc23bf09d353630f4205ab5959dc8202a49cee271e96554e485e19a5ca24f6e
7
- data.tar.gz: 1e9d5d7c2fd2cfa29aa3baa80145647e3088096a3af625f5e49d7baf931d2a72082d73abfeb7e12e44995a8d29607d08693e0533bbffdb5a34995e1182b7ee44
6
+ metadata.gz: f12e6ea46bb610708c6fa9cf13cd897bbd2e19ea645d7f5e748b1daccac7efdf00470b8333f16907401c9e63968f975f2c526188513862197db8771669e7c785
7
+ data.tar.gz: 7584799d278830b5912e6eb57e6582c3b2b7bb93cafff6c2bbc331137b06181674f5152e3cf179696ff3d1c6b66d0a91546fbd5800e2329662e5bb95357a8f40
@@ -1,10 +1,5 @@
1
1
  require 'selenium-webdriver'
2
- require 'webdrivers/chromedriver'
3
- require 'webdrivers/geckodriver'
4
- require 'webdrivers/iedriver'
5
-
6
- # Selenium::WebDriver::Chrome::Service.driver_path = './webdrivers/chromedriver'
7
- # Selenium::WebDriver::Firefox::Service.driver_path = './webdrivers/geckodriver'
2
+ require 'webdrivers'
8
3
 
9
4
  # Selenium IDE-like WebDriver based upon Ruby binding
10
5
  # @author Aaron Chen
@@ -13,8 +8,13 @@ require 'webdrivers/iedriver'
13
8
  # of the chosen browser
14
9
  # @attr_reader [String] install_dir The install directory of WebDrivers
15
10
  # @attr_reader [String] locale The browser locale
11
+ # @attr_reader [Boolean] headless Headless mode for Google Chrome
12
+ # @attr_reader [String] window_size Chrome window size when headless
13
+ # @attr_reader [String] screen_dir The screenshot directory of save_screenshot
14
+ # @attr_reader [String] log_prefix Prefix for logging descriptions and methods
16
15
  # @attr_reader [Integer] timeout The driver timeout
17
- # @attr_reader [Boolean] verbose Verbose mode
16
+ # @attr_reader [Boolean] verbose Turn on/off Verbose mode
17
+ # @attr_reader [Boolean] silent Turn off Turn on/off descriptions
18
18
  class Rudra
19
19
  # Supported Browsers
20
20
  BROWSERS = %i[chrome firefox ie safari].freeze
@@ -28,12 +28,13 @@ class Rudra
28
28
  # Attributes
29
29
  ATTRIBUTES = %i[
30
30
  browser driver install_dir locale
31
- headless log_prefix timeout verbose
31
+ headless window_size screen_dir
32
+ log_prefix timeout verbose silent
32
33
  ].freeze
33
34
 
34
35
  attr_reader :browser, :driver, :install_dir, :locale,
35
- :headless, :screen_dir, :log_prefix,
36
- :timeout, :verbose
36
+ :headless, :window_size, :screen_dir,
37
+ :log_prefix, :timeout, :verbose, :silent
37
38
 
38
39
  # Initialize an instance of Rudra
39
40
  # @param [Hash] options the options to initialize Rudra
@@ -43,18 +44,22 @@ class Rudra
43
44
  # directory of WebDrivers
44
45
  # @option options [Symbol] :locale (:en) the browser locale
45
46
  # @option options [Boolean] :headless (false) headless mode
46
- # @option options [String] :screen_dir ('.//') the location of screenshots
47
- # @option options [String] :log_prefix (' - ') log prefix
47
+ # @option options [String] :window_size ('1280,720') window size when headless
48
+ # @option options [String] :screen_dir ('./screens/') the location of screenshots
49
+ # @option options [String] :log_prefix (' - ') prefix for logging descriptions and methods
48
50
  # @option options [Integer] :timeout (30) implicit_wait timeout
49
- # @option options [Boolean] :verbose (true) verbose mode
51
+ # @option options [Boolean] :verbose (false) Turn on/off verbose mode
52
+ # @option options [Boolean] :silent (false) Turn on/off descriptions
50
53
  def initialize(options = {})
51
54
  self.browser = options.fetch(:browser, :chrome)
52
55
  self.install_dir = options.fetch(:install_dir, './webdrivers/')
53
- self.locale = options.fetch(:locale, :enscreens)
56
+ self.locale = options.fetch(:locale, :en)
54
57
  self.headless = options.fetch(:headless, false)
58
+ self.window_size = options.fetch(:window_size, '1280,720')
55
59
  self.screen_dir = options.fetch(:screen_dir, './screens/')
56
60
  self.log_prefix = options.fetch(:log_prefix, ' - ')
57
- self.verbose = options.fetch(:verbose, true)
61
+ self.verbose = options.fetch(:verbose, false)
62
+ self.silent = options.fetch(:silent, false)
58
63
  self.main_label = caller_locations(2, 1).first.label
59
64
 
60
65
  initialize_driver
@@ -100,6 +105,7 @@ class Rudra
100
105
  end
101
106
 
102
107
  # Send keys to an alert
108
+ # @param [String] keys keystrokes to send
103
109
  def alert_send_keys(keys)
104
110
  switch_to_alert.send_keys(keys)
105
111
  end
@@ -171,7 +177,7 @@ class Rudra
171
177
 
172
178
  element ||= driver.find_element(how, what)
173
179
 
174
- abort("Failed to find element: #{locator}") unless element
180
+ raise Selenium::WebDriver::Error::NoSuchElementError, "Failed to find element: #{locator}" unless element
175
181
 
176
182
  wait_for { element.displayed? }
177
183
 
@@ -183,8 +189,11 @@ class Rudra
183
189
  # @return [Array<Selenium::WebDriver::Element>] the elements found
184
190
  def find_elements(locator)
185
191
  how, what = parse_locator(locator)
186
- driver.find_elements(how, what) ||
187
- abort("Failed to find elements: #{locator}")
192
+ elements = driver.find_elements(how, what)
193
+
194
+ raise Selenium::WebDriver::Error::NoSuchElementError, "Failed to find elements: #{locator}" if elements.empty?
195
+
196
+ elements
188
197
  end
189
198
 
190
199
  # Move forward a single entry in the browser's history
@@ -204,7 +213,7 @@ class Rudra
204
213
 
205
214
  # Maximize the current window
206
215
  def maximize
207
- driver.manage.window.maximize
216
+ driver.manage.window.maximize unless headless
208
217
  end
209
218
 
210
219
  # Maximize the current window to the size of the screen
@@ -262,6 +271,12 @@ class Rudra
262
271
  driver.page_source
263
272
  end
264
273
 
274
+ # Print description in the console
275
+ # @param [String] description description to show
276
+ def puts(description)
277
+ $stdout.puts "#{log_prefix}#{description.chomp}" unless silent
278
+ end
279
+
265
280
  # Refresh the current pagef
266
281
  def refresh
267
282
  driver.navigate.refresh
@@ -277,13 +292,16 @@ class Rudra
277
292
  # Save a PNG screenshot to file
278
293
  # @param [String] filename the filename of PNG screenshot
279
294
  def save_screenshot(filename)
280
- mkdir(@screen_dir) unless Dir.exist?(@screen_dir)
281
- driver.save_screenshot(
282
- File.join(
283
- @screen_dir,
284
- filename.end_with?('.png') ? filename : "#{filename}.png"
285
- )
295
+ file = File.join(
296
+ @screen_dir,
297
+ sanitize(filename.end_with?('.png') ? filename : "#{filename}.png")
286
298
  )
299
+
300
+ dir = File.dirname(file)
301
+
302
+ mkdir(dir) unless Dir.exist?(dir)
303
+
304
+ driver.save_screenshot(file)
287
305
  end
288
306
 
289
307
  # Switch to the currently active modal dialog
@@ -298,6 +316,7 @@ class Rudra
298
316
  end
299
317
 
300
318
  # Switch to the frame with the given id
319
+ # @param [String] id the frame id
301
320
  def switch_to_frame(id)
302
321
  driver.switch_to.frame(id)
303
322
  end
@@ -333,6 +352,46 @@ class Rudra
333
352
  wait_for { find_element(locator).enabled? }
334
353
  end
335
354
 
355
+ # Wait until the element, identified by locator, is found in frame
356
+ # @param [String] frame_id the frame id
357
+ # @param [String] locator the locator to identify the element
358
+ def wait_for_element_found_in_frame(frame_id, locator)
359
+ switch_to_frame frame_id
360
+
361
+ how, what = parse_locator(locator)
362
+
363
+ wait_for do
364
+ begin
365
+ driver.find_element(how, what)
366
+ rescue Selenium::WebDriver::Error::NoSuchWindowError
367
+ false
368
+ end
369
+ end
370
+ end
371
+
372
+ # Wait (in seconds) until the element is not displayed
373
+ # @param [String, Selenium::WebDriver::Element] locator the locator to
374
+ # identify the element or Selenium::WebDriver::Element
375
+ # @param [Integer] seconds seconds before timed out
376
+ def wait_for_not_visible(locator, seconds = 3)
377
+ how, what = parse_locator(locator)
378
+
379
+ implicit_wait(seconds)
380
+
381
+ begin
382
+ wait_for(seconds) do
383
+ elements = driver.find_elements(how, what)
384
+ elements.empty? || elements.map(&:displayed?).none?
385
+ end
386
+ rescue Selenium::WebDriver::Error::TimeoutError
387
+ true
388
+ rescue Net::ReadTimeout
389
+ true
390
+ ensure
391
+ implicit_wait(timeout)
392
+ end
393
+ end
394
+
336
395
  # Wait until the title of the page including the given string
337
396
  # @param [String] string the string to compare
338
397
  def wait_for_title(string)
@@ -381,7 +440,7 @@ class Rudra
381
440
  # @param [String] attribute the name of the attribute
382
441
  # @return [String, nil] attribute value
383
442
  def attribute(locator, attribute)
384
- find_element(locator).property(attribute)
443
+ find_element(locator).attribute(attribute)
385
444
  end
386
445
 
387
446
  # If the element, identified by locator, has the given attribute
@@ -416,7 +475,13 @@ class Rudra
416
475
  # @param [String, Selenium::WebDriver::Element] locator the locator to
417
476
  # identify the element or Selenium::WebDriver::Element
418
477
  def click(locator)
419
- find_element(locator).click
478
+ wait_for do
479
+ begin
480
+ find_element(locator).click.nil?
481
+ rescue Selenium::WebDriver::Error::ElementClickInterceptedError
482
+ false
483
+ end
484
+ end
420
485
  end
421
486
 
422
487
  # Click the given element, identified by locator, with an offset
@@ -729,6 +794,38 @@ class Rudra
729
794
  ), find_element(locator), event)
730
795
  end
731
796
 
797
+ # Wait until the element, identified by locator, attribute has value
798
+ # @param [String, Selenium::WebDriver::Element] locator the locator to identify the element
799
+ # @param [String] attribute the name of the attribute
800
+ # @param [String] value the value of the attribute
801
+ def wait_for_attribute_to_include(locator, attribute, value)
802
+ how, what = parse_locator(locator)
803
+
804
+ wait_for do
805
+ begin
806
+ driver.find_element(how, what)&.attribute(attribute)&.downcase&.include?(value.downcase)
807
+ rescue Selenium::WebDriver::Error::StaleElementReferenceError
808
+ false
809
+ end
810
+ end
811
+ end
812
+
813
+ # Wait until the element, identified by locator, excluding string in text
814
+ # @param [String, Selenium::WebDriver::Element] locator the locator to
815
+ # identify the element or Selenium::WebDriver::Element
816
+ # @param [String] string the string to exclude
817
+ def wait_for_text_to_exclude(locator, string)
818
+ wait_for { text(locator).exclude?(string) }
819
+ end
820
+
821
+ # Wait until the element, identified by locator, including string in text
822
+ # @param [String, Selenium::WebDriver::Element] locator the locator to
823
+ # identify the element or Selenium::WebDriver::Element
824
+ # @param [String] string the string to compare
825
+ def wait_for_text_to_include(locator, string)
826
+ wait_for { text(locator).include?(string) }
827
+ end
828
+
732
829
  #
733
830
  # Tool Functions
734
831
  #
@@ -1066,7 +1163,7 @@ class Rudra
1066
1163
  end
1067
1164
 
1068
1165
  (instance_methods - superclass.instance_methods).map do |method_name|
1069
- next if private_method_defined?(method_name) || ATTRIBUTES.include?(method_name)
1166
+ next if private_method_defined?(method_name) || ATTRIBUTES.include?(method_name) || method_name == :puts
1070
1167
 
1071
1168
  original_method = instance_method(method_name)
1072
1169
 
@@ -1078,7 +1175,8 @@ class Rudra
1078
1175
 
1079
1176
  private
1080
1177
 
1081
- attr_writer :main_label
1178
+ attr_accessor :main_label
1179
+ attr_writer :silent, :window_size
1082
1180
 
1083
1181
  def browser=(brw)
1084
1182
  unless BROWSERS.include?(brw)
@@ -1131,6 +1229,8 @@ class Rudra
1131
1229
  def initialize_driver
1132
1230
  @driver = if browser == :chrome
1133
1231
  Selenium::WebDriver.for(:chrome, options: chrome_options)
1232
+ # elsif browser == :edge
1233
+ # Selenium::WebDriver.for(:edge, options: edge_options)
1134
1234
  elsif browser == :firefox
1135
1235
  Selenium::WebDriver.for(:firefox, options: firefox_options)
1136
1236
  elsif browser == :ie
@@ -1143,7 +1243,10 @@ class Rudra
1143
1243
  def chrome_options
1144
1244
  options = Selenium::WebDriver::Chrome::Options.new
1145
1245
  options.add_argument('--disable-notifications')
1146
- options.add_argument('--headless') if headless
1246
+ if headless
1247
+ options.add_argument('--headless')
1248
+ options.add_argument("--window-size=#{window_size}")
1249
+ end
1147
1250
  options.add_option(
1148
1251
  'excludeSwitches',
1149
1252
  %w[enable-automation enable-logging]
@@ -1152,6 +1255,10 @@ class Rudra
1152
1255
  options
1153
1256
  end
1154
1257
 
1258
+ # def edge_options
1259
+ # Selenium::WebDriver::Edge::Options.new
1260
+ # end
1261
+
1155
1262
  def firefox_options
1156
1263
  options = Selenium::WebDriver::Firefox::Options.new
1157
1264
  options.add_preference('intl.accept_languages', locale)
@@ -1184,21 +1291,29 @@ class Rudra
1184
1291
  how.to_sym
1185
1292
  end
1186
1293
 
1187
- abort("Cannot parse locator: #{locator}") unless HOWS.include?(how)
1294
+ raise Selenium::WebDriver::Error::InvalidSelectorError, "Cannot parse locator: #{locator}" unless HOWS.include?(how)
1188
1295
 
1189
1296
  [how, what]
1190
1297
  end
1191
1298
 
1192
1299
  def log(method_name, *args)
1193
- return unless @verbose && caller_locations(2, 1).first.label == @main_label
1300
+ return unless verbose && caller_locations(2, 1).first.label == main_label
1194
1301
 
1195
1302
  arguments = args.map(&:to_s).join(', ')
1196
1303
 
1197
- puts @log_prefix + (
1304
+ puts log_prefix + (
1198
1305
  arguments.empty? ? method_name.to_s : "#{method_name}(#{arguments})"
1199
1306
  )
1200
1307
  end
1201
1308
 
1309
+ def sanitize(filename)
1310
+ invalid_characters = ['/', '\\', '?', '%', '*', ':', '|', '"', '<', '>']
1311
+ invalid_characters.each do |character|
1312
+ filename.gsub!(character, '')
1313
+ end
1314
+ filename
1315
+ end
1316
+
1202
1317
  def random_id(length = 8)
1203
1318
  charset = [(0..9), ('a'..'z')].flat_map(&:to_a)
1204
1319
  id = Array.new(length) { charset.sample }.join
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rudra
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.15
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Chen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-02 00:00:00.000000000 Z
11
+ date: 2020-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yard
@@ -24,6 +24,26 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.9.25
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 3.9.0
34
+ - - "~>"
35
+ - !ruby/object:Gem::Version
36
+ version: '3.9'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 3.9.0
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.9'
27
47
  - !ruby/object:Gem::Dependency
28
48
  name: selenium-webdriver
29
49
  requirement: !ruby/object:Gem::Requirement