rudra 1.0.14 → 1.1.1

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 +145 -28
  3. metadata +22 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f065383cc3c1a776dccc5708a77f627383aaa63f4198b087adad977271f713d6
4
- data.tar.gz: 9fc4e3d993f3d3a1b4fb53d57b146df87fe8fa5e561308b726a3c8c46dd5ac1d
3
+ metadata.gz: ff3f69221a8e01fb0c0bf5a517c11547872f475b4cdc7aa551a26f81929c8373
4
+ data.tar.gz: e039db5f85576af890d9b58f8deed4f7f30cf09ea474d8b2226c6574cad9c115
5
5
  SHA512:
6
- metadata.gz: 9f80dd1cc85e183b9ac7ac2be6831a2e1ac56be27ab884133fcbfc4b0f87e03a23d4d9443bd933cfef69292c881d968b2033d3af8cd5a72c909ba8474afcce03
7
- data.tar.gz: ad1f215b1ea9c9f6d16e387f95f1a5f9c087845c2db3239d0f64ea719e94241805578fe1a3589b69dafc0207fcc10b6589677259ecb87939752ab0fd0d5c9a52
6
+ metadata.gz: a632f5ee68fa9417a78e86642246c47d2b4480292ca4816471b8f948458d7c6444150ccb7eb1a65fe8d7167f25dca32e1271f97cd725dbc86643362d763d4361
7
+ data.tar.gz: 9edc12b61b22302ef0d80698a682d859a124acaa7c3d121d87353f83c84fef948f9fa93971ce85074c4b7faf52b27bf9ebef4bdedcb14429a8ef7222b73854f3
@@ -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,11 +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, :log_prefix, :timeout, :verbose
36
+ :headless, :window_size, :screen_dir,
37
+ :log_prefix, :timeout, :verbose, :silent
36
38
 
37
39
  # Initialize an instance of Rudra
38
40
  # @param [Hash] options the options to initialize Rudra
@@ -42,16 +44,22 @@ class Rudra
42
44
  # directory of WebDrivers
43
45
  # @option options [Symbol] :locale (:en) the browser locale
44
46
  # @option options [Boolean] :headless (false) headless mode
45
- # @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
46
50
  # @option options [Integer] :timeout (30) implicit_wait timeout
47
- # @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
48
53
  def initialize(options = {})
49
54
  self.browser = options.fetch(:browser, :chrome)
50
55
  self.install_dir = options.fetch(:install_dir, './webdrivers/')
51
56
  self.locale = options.fetch(:locale, :en)
52
57
  self.headless = options.fetch(:headless, false)
58
+ self.window_size = options.fetch(:window_size, '1280,720')
59
+ self.screen_dir = options.fetch(:screen_dir, './screens/')
53
60
  self.log_prefix = options.fetch(:log_prefix, ' - ')
54
- self.verbose = options.fetch(:verbose, true)
61
+ self.verbose = options.fetch(:verbose, false)
62
+ self.silent = options.fetch(:silent, false)
55
63
  self.main_label = caller_locations(2, 1).first.label
56
64
 
57
65
  initialize_driver
@@ -97,6 +105,7 @@ class Rudra
97
105
  end
98
106
 
99
107
  # Send keys to an alert
108
+ # @param [String] keys keystrokes to send
100
109
  def alert_send_keys(keys)
101
110
  switch_to_alert.send_keys(keys)
102
111
  end
@@ -168,7 +177,7 @@ class Rudra
168
177
 
169
178
  element ||= driver.find_element(how, what)
170
179
 
171
- abort("Failed to find element: #{locator}") unless element
180
+ raise Selenium::WebDriver::Error::NoSuchElementError, "Failed to find element: #{locator}" unless element
172
181
 
173
182
  wait_for { element.displayed? }
174
183
 
@@ -180,8 +189,11 @@ class Rudra
180
189
  # @return [Array<Selenium::WebDriver::Element>] the elements found
181
190
  def find_elements(locator)
182
191
  how, what = parse_locator(locator)
183
- driver.find_elements(how, what) ||
184
- 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
185
197
  end
186
198
 
187
199
  # Move forward a single entry in the browser's history
@@ -201,7 +213,7 @@ class Rudra
201
213
 
202
214
  # Maximize the current window
203
215
  def maximize
204
- driver.manage.window.maximize
216
+ driver.manage.window.maximize unless headless
205
217
  end
206
218
 
207
219
  # Maximize the current window to the size of the screen
@@ -259,6 +271,12 @@ class Rudra
259
271
  driver.page_source
260
272
  end
261
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
+
262
280
  # Refresh the current pagef
263
281
  def refresh
264
282
  driver.navigate.refresh
@@ -271,11 +289,15 @@ class Rudra
271
289
  driver.manage.window.resize_to(width, height)
272
290
  end
273
291
 
274
- # Save a PNG screenshot to the given path
275
- # @param [String] png_path the path of PNG screenshot
276
- def save_screenshot(png_path)
292
+ # Save a PNG screenshot to file
293
+ # @param [String] filename the filename of PNG screenshot
294
+ def save_screenshot(filename)
295
+ mkdir(@screen_dir) unless Dir.exist?(@screen_dir)
277
296
  driver.save_screenshot(
278
- png_path.end_with?('.png') ? png_path : "#{png_path}.png"
297
+ File.join(
298
+ @screen_dir,
299
+ filename.end_with?('.png') ? filename : "#{filename}.png"
300
+ )
279
301
  )
280
302
  end
281
303
 
@@ -291,6 +313,7 @@ class Rudra
291
313
  end
292
314
 
293
315
  # Switch to the frame with the given id
316
+ # @param [String] id the frame id
294
317
  def switch_to_frame(id)
295
318
  driver.switch_to.frame(id)
296
319
  end
@@ -326,6 +349,48 @@ class Rudra
326
349
  wait_for { find_element(locator).enabled? }
327
350
  end
328
351
 
352
+ # Wait until the element, identified by locator, is found in frame
353
+ # @param [String] frame_id the frame id
354
+ # @param [String] locator the locator to identify the element
355
+ def wait_for_element_found_in_frame(frame_id, locator)
356
+ switch_to_frame frame_id
357
+
358
+ how, what = parse_locator(locator)
359
+
360
+ wait_for do
361
+ begin
362
+ driver.find_element(how, what)
363
+ rescue Selenium::WebDriver::Error::NoSuchWindowError
364
+ false
365
+ end
366
+ end
367
+ end
368
+
369
+ # Wait (in seconds) until the element is not displayed
370
+ # @param [String, Selenium::WebDriver::Element] locator the locator to
371
+ # identify the element or Selenium::WebDriver::Element
372
+ # @param [Integer] seconds seconds before timed out
373
+ def wait_for_not_visible(locator, seconds = 2)
374
+ how, what = parse_locator(locator)
375
+
376
+ begin
377
+ wait_for(seconds) do
378
+ begin
379
+ elements = driver.find_elements(how, what)
380
+ elements.empty? || elements.map(&:displayed?).none?
381
+ rescue Selenium::WebDriver::Error::NoSuchElementError
382
+ true
383
+ rescue Selenium::WebDriver::Error::StaleElementReferenceError
384
+ false
385
+ end
386
+ end
387
+ rescue Selenium::WebDriver::Error::TimeoutError
388
+ true
389
+ rescue Net::ReadTimeout
390
+ true
391
+ end
392
+ end
393
+
329
394
  # Wait until the title of the page including the given string
330
395
  # @param [String] string the string to compare
331
396
  def wait_for_title(string)
@@ -374,7 +439,7 @@ class Rudra
374
439
  # @param [String] attribute the name of the attribute
375
440
  # @return [String, nil] attribute value
376
441
  def attribute(locator, attribute)
377
- find_element(locator).property(attribute)
442
+ find_element(locator).attribute(attribute)
378
443
  end
379
444
 
380
445
  # If the element, identified by locator, has the given attribute
@@ -409,7 +474,13 @@ class Rudra
409
474
  # @param [String, Selenium::WebDriver::Element] locator the locator to
410
475
  # identify the element or Selenium::WebDriver::Element
411
476
  def click(locator)
412
- find_element(locator).click
477
+ wait_for do
478
+ begin
479
+ find_element(locator).click.nil?
480
+ rescue Selenium::WebDriver::Error::ElementClickInterceptedError
481
+ false
482
+ end
483
+ end
413
484
  end
414
485
 
415
486
  # Click the given element, identified by locator, with an offset
@@ -722,6 +793,38 @@ class Rudra
722
793
  ), find_element(locator), event)
723
794
  end
724
795
 
796
+ # Wait until the element, identified by locator, attribute has value
797
+ # @param [String, Selenium::WebDriver::Element] locator the locator to identify the element
798
+ # @param [String] attribute the name of the attribute
799
+ # @param [String] value the value of the attribute
800
+ def wait_for_attribute_to_include(locator, attribute, value)
801
+ how, what = parse_locator(locator)
802
+
803
+ wait_for do
804
+ begin
805
+ driver.find_element(how, what)&.attribute(attribute)&.downcase&.include?(value.downcase)
806
+ rescue Selenium::WebDriver::Error::StaleElementReferenceError
807
+ false
808
+ end
809
+ end
810
+ end
811
+
812
+ # Wait until the element, identified by locator, excluding string in text
813
+ # @param [String, Selenium::WebDriver::Element] locator the locator to
814
+ # identify the element or Selenium::WebDriver::Element
815
+ # @param [String] string the string to exclude
816
+ def wait_for_text_to_exclude(locator, string)
817
+ wait_for { text(locator).exclude?(string) }
818
+ end
819
+
820
+ # Wait until the element, identified by locator, including string in text
821
+ # @param [String, Selenium::WebDriver::Element] locator the locator to
822
+ # identify the element or Selenium::WebDriver::Element
823
+ # @param [String] string the string to compare
824
+ def wait_for_text_to_include(locator, string)
825
+ wait_for { text(locator).include?(string) }
826
+ end
827
+
725
828
  #
726
829
  # Tool Functions
727
830
  #
@@ -1059,7 +1162,7 @@ class Rudra
1059
1162
  end
1060
1163
 
1061
1164
  (instance_methods - superclass.instance_methods).map do |method_name|
1062
- next if private_method_defined?(method_name) || ATTRIBUTES.include?(method_name)
1165
+ next if private_method_defined?(method_name) || ATTRIBUTES.include?(method_name) || method_name == :puts
1063
1166
 
1064
1167
  original_method = instance_method(method_name)
1065
1168
 
@@ -1071,7 +1174,8 @@ class Rudra
1071
1174
 
1072
1175
  private
1073
1176
 
1074
- attr_writer :main_label
1177
+ attr_accessor :main_label
1178
+ attr_writer :silent, :window_size
1075
1179
 
1076
1180
  def browser=(brw)
1077
1181
  unless BROWSERS.include?(brw)
@@ -1098,6 +1202,10 @@ class Rudra
1098
1202
  @headless = true?(mode)
1099
1203
  end
1100
1204
 
1205
+ def screen_dir=(path)
1206
+ @screen_dir = File.join(path, @locale.to_s)
1207
+ end
1208
+
1101
1209
  def log_prefix=(prefix)
1102
1210
  @log_prefix = prefix.chomp
1103
1211
  end
@@ -1120,6 +1228,8 @@ class Rudra
1120
1228
  def initialize_driver
1121
1229
  @driver = if browser == :chrome
1122
1230
  Selenium::WebDriver.for(:chrome, options: chrome_options)
1231
+ # elsif browser == :edge
1232
+ # Selenium::WebDriver.for(:edge, options: edge_options)
1123
1233
  elsif browser == :firefox
1124
1234
  Selenium::WebDriver.for(:firefox, options: firefox_options)
1125
1235
  elsif browser == :ie
@@ -1132,7 +1242,10 @@ class Rudra
1132
1242
  def chrome_options
1133
1243
  options = Selenium::WebDriver::Chrome::Options.new
1134
1244
  options.add_argument('--disable-notifications')
1135
- options.add_argument('--headless') if headless
1245
+ if headless
1246
+ options.add_argument('--headless')
1247
+ options.add_argument("--window-size=#{window_size}")
1248
+ end
1136
1249
  options.add_option(
1137
1250
  'excludeSwitches',
1138
1251
  %w[enable-automation enable-logging]
@@ -1141,6 +1254,10 @@ class Rudra
1141
1254
  options
1142
1255
  end
1143
1256
 
1257
+ # def edge_options
1258
+ # Selenium::WebDriver::Edge::Options.new
1259
+ # end
1260
+
1144
1261
  def firefox_options
1145
1262
  options = Selenium::WebDriver::Firefox::Options.new
1146
1263
  options.add_preference('intl.accept_languages', locale)
@@ -1173,17 +1290,17 @@ class Rudra
1173
1290
  how.to_sym
1174
1291
  end
1175
1292
 
1176
- abort("Cannot parse locator: #{locator}") unless HOWS.include?(how)
1293
+ raise Selenium::WebDriver::Error::InvalidSelectorError, "Cannot parse locator: #{locator}" unless HOWS.include?(how)
1177
1294
 
1178
1295
  [how, what]
1179
1296
  end
1180
1297
 
1181
1298
  def log(method_name, *args)
1182
- return unless @verbose && caller_locations(2, 1).first.label == main_label
1299
+ return unless verbose && caller_locations(2, 1).first.label == main_label
1183
1300
 
1184
1301
  arguments = args.map(&:to_s).join(', ')
1185
1302
 
1186
- puts @log_prefix + (
1303
+ puts log_prefix + (
1187
1304
  arguments.empty? ? method_name.to_s : "#{method_name}(#{arguments})"
1188
1305
  )
1189
1306
  end
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.14
4
+ version: 1.1.1
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-01 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