rudra 1.1.1 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rudra.rb +117 -14
  3. metadata +22 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff3f69221a8e01fb0c0bf5a517c11547872f475b4cdc7aa551a26f81929c8373
4
- data.tar.gz: e039db5f85576af890d9b58f8deed4f7f30cf09ea474d8b2226c6574cad9c115
3
+ metadata.gz: dd2c656d270051d403273294621ca5d21a9986b63ac082165d2453025e77abcf
4
+ data.tar.gz: 70eca0978aba2ee93fec2077e7999acf492b1083812d99ade02efc475a684ff7
5
5
  SHA512:
6
- metadata.gz: a632f5ee68fa9417a78e86642246c47d2b4480292ca4816471b8f948458d7c6444150ccb7eb1a65fe8d7167f25dca32e1271f97cd725dbc86643362d763d4361
7
- data.tar.gz: 9edc12b61b22302ef0d80698a682d859a124acaa7c3d121d87353f83c84fef948f9fa93971ce85074c4b7faf52b27bf9ebef4bdedcb14429a8ef7222b73854f3
6
+ metadata.gz: 1aa0e5fb07ad8b52d7e459bab2786f1a244a83cefa93ed41226dbbd58724e57c1e367b29aa425c85e52201595f36f02293d2c1edcfadecb96282437aada12aad
7
+ data.tar.gz: 47ef76f3d85928a7ba445a69d8e62a382db233f128cbc002e6c8a074b607b105a5a4b0043567156368103bf05d319041bf2789c35b3dc32c8b10775264bdedad
@@ -1,5 +1,9 @@
1
1
  require 'selenium-webdriver'
2
2
  require 'webdrivers'
3
+ require 'zip'
4
+ require 'base64'
5
+ require 'json'
6
+ require 'stringio'
3
7
 
4
8
  # Selenium IDE-like WebDriver based upon Ruby binding
5
9
  # @author Aaron Chen
@@ -15,6 +19,8 @@ require 'webdrivers'
15
19
  # @attr_reader [Integer] timeout The driver timeout
16
20
  # @attr_reader [Boolean] verbose Turn on/off Verbose mode
17
21
  # @attr_reader [Boolean] silent Turn off Turn on/off descriptions
22
+ # @attr_reader [String] auth_username username for Basic Access Authentication Extension (Chrome only)
23
+ # @attr_reader [String] auth_password password for Basic Access Authentication Extension (Chrome only)
18
24
  class Rudra
19
25
  # Supported Browsers
20
26
  BROWSERS = %i[chrome firefox ie safari].freeze
@@ -30,11 +36,13 @@ class Rudra
30
36
  browser driver install_dir locale
31
37
  headless window_size screen_dir
32
38
  log_prefix timeout verbose silent
39
+ auth_username auth_password
33
40
  ].freeze
34
41
 
35
42
  attr_reader :browser, :driver, :install_dir, :locale,
36
43
  :headless, :window_size, :screen_dir,
37
- :log_prefix, :timeout, :verbose, :silent
44
+ :log_prefix, :timeout, :verbose, :silent,
45
+ :auth_username, :auth_password
38
46
 
39
47
  # Initialize an instance of Rudra
40
48
  # @param [Hash] options the options to initialize Rudra
@@ -50,6 +58,8 @@ class Rudra
50
58
  # @option options [Integer] :timeout (30) implicit_wait timeout
51
59
  # @option options [Boolean] :verbose (false) Turn on/off verbose mode
52
60
  # @option options [Boolean] :silent (false) Turn on/off descriptions
61
+ # @option options [String] :auth_username ('') username for Basic Access Authentication extension
62
+ # @option options [String] :auth_password ('') password for Basic Access Authentication extension
53
63
  def initialize(options = {})
54
64
  self.browser = options.fetch(:browser, :chrome)
55
65
  self.install_dir = options.fetch(:install_dir, './webdrivers/')
@@ -60,6 +70,8 @@ class Rudra
60
70
  self.log_prefix = options.fetch(:log_prefix, ' - ')
61
71
  self.verbose = options.fetch(:verbose, false)
62
72
  self.silent = options.fetch(:silent, false)
73
+ self.auth_username = options.fetch(:auth_username, '')
74
+ self.auth_password = options.fetch(:auth_password, '')
63
75
  self.main_label = caller_locations(2, 1).first.label
64
76
 
65
77
  initialize_driver
@@ -149,6 +161,26 @@ class Rudra
149
161
  driver.manage.delete_cookie(name)
150
162
  end
151
163
 
164
+ # Check if an element is found
165
+ # @param [String, Selenium::WebDriver::Element] locator the locator to
166
+ # identify the element or Selenium::WebDriver::Element
167
+ # @param [Integer] seconds seconds before timed out
168
+ def element_found?(locator, seconds = 1)
169
+ how, what = parse_locator(locator)
170
+
171
+ implicit_wait(seconds)
172
+
173
+ begin
174
+ wait_for(seconds) { driver.find_element(how, what).displayed? }
175
+ rescue Selenium::WebDriver::Error::TimeoutError
176
+ false
177
+ rescue Net::ReadTimeout
178
+ false
179
+ ensure
180
+ implicit_wait(timeout)
181
+ end
182
+ end
183
+
152
184
  # Execute the given JavaScript
153
185
  # @param [String] script JavaScript source to execute
154
186
  # @param [Selenium::WebDriver::Element, Integer, Float, Boolean, NilClass,
@@ -292,13 +324,16 @@ class Rudra
292
324
  # Save a PNG screenshot to file
293
325
  # @param [String] filename the filename of PNG screenshot
294
326
  def save_screenshot(filename)
295
- mkdir(@screen_dir) unless Dir.exist?(@screen_dir)
296
- driver.save_screenshot(
297
- File.join(
298
- @screen_dir,
299
- filename.end_with?('.png') ? filename : "#{filename}.png"
300
- )
327
+ file = File.join(
328
+ @screen_dir,
329
+ sanitize(filename.end_with?('.png') ? filename : "#{filename}.png")
301
330
  )
331
+
332
+ dir = File.dirname(file)
333
+
334
+ mkdir(dir) unless Dir.exist?(dir)
335
+
336
+ driver.save_screenshot(file)
302
337
  end
303
338
 
304
339
  # Switch to the currently active modal dialog
@@ -349,10 +384,10 @@ class Rudra
349
384
  wait_for { find_element(locator).enabled? }
350
385
  end
351
386
 
352
- # Wait until the element, identified by locator, is found in frame
387
+ # Switch to a frame and wait until the element, identified by locator, is found
353
388
  # @param [String] frame_id the frame id
354
389
  # @param [String] locator the locator to identify the element
355
- def wait_for_element_found_in_frame(frame_id, locator)
390
+ def switch_to_frame_and_wait_for_element_found(frame_id, locator)
356
391
  switch_to_frame frame_id
357
392
 
358
393
  how, what = parse_locator(locator)
@@ -370,16 +405,16 @@ class Rudra
370
405
  # @param [String, Selenium::WebDriver::Element] locator the locator to
371
406
  # identify the element or Selenium::WebDriver::Element
372
407
  # @param [Integer] seconds seconds before timed out
373
- def wait_for_not_visible(locator, seconds = 2)
408
+ def wait_for_not_visible(locator, seconds = 3)
374
409
  how, what = parse_locator(locator)
375
410
 
411
+ implicit_wait(seconds)
412
+
376
413
  begin
377
414
  wait_for(seconds) do
378
415
  begin
379
416
  elements = driver.find_elements(how, what)
380
417
  elements.empty? || elements.map(&:displayed?).none?
381
- rescue Selenium::WebDriver::Error::NoSuchElementError
382
- true
383
418
  rescue Selenium::WebDriver::Error::StaleElementReferenceError
384
419
  false
385
420
  end
@@ -388,6 +423,8 @@ class Rudra
388
423
  true
389
424
  rescue Net::ReadTimeout
390
425
  true
426
+ ensure
427
+ implicit_wait(timeout)
391
428
  end
392
429
  end
393
430
 
@@ -476,7 +513,8 @@ class Rudra
476
513
  def click(locator)
477
514
  wait_for do
478
515
  begin
479
- find_element(locator).click.nil?
516
+ element = find_element(locator)
517
+ element.enabled? && element.click.nil?
480
518
  rescue Selenium::WebDriver::Error::ElementClickInterceptedError
481
519
  false
482
520
  end
@@ -1175,7 +1213,7 @@ class Rudra
1175
1213
  private
1176
1214
 
1177
1215
  attr_accessor :main_label
1178
- attr_writer :silent, :window_size
1216
+ attr_writer :silent, :window_size, :auth_username, :auth_password
1179
1217
 
1180
1218
  def browser=(brw)
1181
1219
  unless BROWSERS.include?(brw)
@@ -1242,10 +1280,23 @@ class Rudra
1242
1280
  def chrome_options
1243
1281
  options = Selenium::WebDriver::Chrome::Options.new
1244
1282
  options.add_argument('--disable-notifications')
1283
+ options.add_argument('--ignore-ssl-errors=yes')
1284
+ options.add_argument('--ignore-certificate-errors')
1285
+
1245
1286
  if headless
1246
1287
  options.add_argument('--headless')
1247
1288
  options.add_argument("--window-size=#{window_size}")
1248
1289
  end
1290
+
1291
+ if auth_username
1292
+ if headless
1293
+ $stdout.puts('Basic Access Authentication Extension cannot be installed while headless')
1294
+ else
1295
+ encoded = chrome_basic_auth_extension(auth_username, auth_password)
1296
+ options.add_encoded_extension(encoded)
1297
+ end
1298
+ end
1299
+
1249
1300
  options.add_option(
1250
1301
  'excludeSwitches',
1251
1302
  %w[enable-automation enable-logging]
@@ -1305,9 +1356,61 @@ class Rudra
1305
1356
  )
1306
1357
  end
1307
1358
 
1359
+ def sanitize(filename)
1360
+ invalid_characters = ['/', '\\', '?', '%', '*', ':', '|', '"', '<', '>']
1361
+ invalid_characters.each do |character|
1362
+ filename.gsub!(character, '')
1363
+ end
1364
+ filename
1365
+ end
1366
+
1308
1367
  def random_id(length = 8)
1309
1368
  charset = [(0..9), ('a'..'z')].flat_map(&:to_a)
1310
1369
  id = Array.new(length) { charset.sample }.join
1311
1370
  "rudra_#{id}"
1312
1371
  end
1372
+
1373
+ def chrome_basic_auth_extension(username, password)
1374
+ manifest = {
1375
+ "manifest_version": 2,
1376
+ "name": 'Rudra Basic Access Authentication Extension',
1377
+ "version": '1.0.0',
1378
+ "permissions": ['*://*/*', 'webRequest', 'webRequestBlocking'],
1379
+ "background": {
1380
+ "scripts": ['background.js']
1381
+ }
1382
+ }
1383
+
1384
+ background = <<~JAVASCRIPT
1385
+ var username = '#{username}';
1386
+ var password = '#{password}';
1387
+
1388
+ chrome.webRequest.onAuthRequired.addListener(
1389
+ function handler(details) {
1390
+ if (username == null) {
1391
+ return { cancel: true };
1392
+ }
1393
+
1394
+ var authCredentials = { username: username, password: username };
1395
+ username = password = null;
1396
+
1397
+ return { authCredentials: authCredentials };
1398
+ },
1399
+ { urls: ['<all_urls>'] },
1400
+ ['blocking']
1401
+ );
1402
+ JAVASCRIPT
1403
+
1404
+ stringio = Zip::OutputStream.write_buffer do |zos|
1405
+ zos.put_next_entry('manifest.json')
1406
+ zos.write manifest.to_json
1407
+ zos.put_next_entry('background.js')
1408
+ zos.write background
1409
+ end
1410
+ # File.open('basic_auth.crx', 'wb') do |f|
1411
+ # f << stringio.string
1412
+ # end
1413
+
1414
+ Base64.strict_encode64(stringio.string)
1415
+ end
1313
1416
  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.1.1
4
+ version: 1.1.6
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-12 00:00:00.000000000 Z
11
+ date: 2020-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yard
@@ -44,6 +44,26 @@ dependencies:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '3.9'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rubyzip
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 2.3.0
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '2.3'
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 2.3.0
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '2.3'
47
67
  - !ruby/object:Gem::Dependency
48
68
  name: selenium-webdriver
49
69
  requirement: !ruby/object:Gem::Requirement