rudra 1.1.1 → 1.1.6

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 +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