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.
- checksums.yaml +4 -4
- data/lib/rudra.rb +117 -14
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd2c656d270051d403273294621ca5d21a9986b63ac082165d2453025e77abcf
|
4
|
+
data.tar.gz: 70eca0978aba2ee93fec2077e7999acf492b1083812d99ade02efc475a684ff7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1aa0e5fb07ad8b52d7e459bab2786f1a244a83cefa93ed41226dbbd58724e57c1e367b29aa425c85e52201595f36f02293d2c1edcfadecb96282437aada12aad
|
7
|
+
data.tar.gz: 47ef76f3d85928a7ba445a69d8e62a382db233f128cbc002e6c8a074b607b105a5a4b0043567156368103bf05d319041bf2789c35b3dc32c8b10775264bdedad
|
data/lib/rudra.rb
CHANGED
@@ -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
|
-
|
296
|
-
|
297
|
-
|
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
|
-
#
|
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
|
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 =
|
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)
|
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.
|
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-
|
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
|