qat-web 6.0.0
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 +7 -0
- data/lib/capybara/core_ext.rb +7 -0
- data/lib/capybara/core_ext/capybara_error.rb +14 -0
- data/lib/capybara/core_ext/node/element.rb +35 -0
- data/lib/capybara/core_ext/selenium/node.rb +75 -0
- data/lib/headless/core_ext/random_display.rb +15 -0
- data/lib/qat/cli/plugins/web.rb +7 -0
- data/lib/qat/web.rb +12 -0
- data/lib/qat/web/browser.rb +21 -0
- data/lib/qat/web/browser/autoload.rb +22 -0
- data/lib/qat/web/browser/factory.rb +39 -0
- data/lib/qat/web/browser/firefox/harexporttrigger-0.5.0-beta.10.xpi +0 -0
- data/lib/qat/web/browser/firefox/loader/helper.rb +49 -0
- data/lib/qat/web/browser/html_dump.rb +46 -0
- data/lib/qat/web/browser/loader.rb +75 -0
- data/lib/qat/web/browser/profile.rb +92 -0
- data/lib/qat/web/browser/screenshot.rb +46 -0
- data/lib/qat/web/configuration.rb +46 -0
- data/lib/qat/web/cucumber.rb +19 -0
- data/lib/qat/web/drivers.rb +3 -0
- data/lib/qat/web/drivers/chrome.rb +5 -0
- data/lib/qat/web/drivers/default.rb +25 -0
- data/lib/qat/web/drivers/firefox.rb +6 -0
- data/lib/qat/web/drivers/firefox/har_exporter.rb +16 -0
- data/lib/qat/web/elements.rb +78 -0
- data/lib/qat/web/elements/base.rb +50 -0
- data/lib/qat/web/elements/collection.rb +16 -0
- data/lib/qat/web/elements/config.rb +19 -0
- data/lib/qat/web/elements/element.rb +16 -0
- data/lib/qat/web/elements/selector.rb +108 -0
- data/lib/qat/web/elements/waiters.rb +103 -0
- data/lib/qat/web/error.rb +14 -0
- data/lib/qat/web/error/enrichment.rb +14 -0
- data/lib/qat/web/exceptions.rb +15 -0
- data/lib/qat/web/finders.rb +49 -0
- data/lib/qat/web/hooks/common.rb +17 -0
- data/lib/qat/web/hooks/har_exporter.rb +32 -0
- data/lib/qat/web/hooks/html_dump.rb +21 -0
- data/lib/qat/web/hooks/screenshot.rb +20 -0
- data/lib/qat/web/page.rb +158 -0
- data/lib/qat/web/page/validators.rb +37 -0
- data/lib/qat/web/page_manager.rb +71 -0
- data/lib/qat/web/screen.rb +2 -0
- data/lib/qat/web/screen/autoload.rb +22 -0
- data/lib/qat/web/screen/factory.rb +68 -0
- data/lib/qat/web/screen/loader.rb +93 -0
- data/lib/qat/web/screen/wrapper.rb +96 -0
- data/lib/qat/web/version.rb +9 -0
- metadata +278 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e92379991eb1d96103670c226b80c22ed8bc8f10d6eda381be8a0b61bd336b33
|
4
|
+
data.tar.gz: 1bf523ec09958f3b5a43815ef178974b858967a69a306fe8cd3b441c584e581f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fc9bc0ccb6e9fc2f49778ccb9840927fea4d8040f53867ef2781817628b8ffad45f585762653274cded93d8fad2e1ae577dab9aaa4c51aaf8f8f806269191fd8
|
7
|
+
data.tar.gz: '0268ac6f4b106cc85951e55f5877c67d81e3b1656b9359c70233fd97ae031c5939c07b47d5379f0beb25999aea4d6b6a91cf2090858c86724a6898b3f068839e'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
require_relative '../../../lib/qat/web/error/enrichment'
|
3
|
+
# Capybara extension
|
4
|
+
module Capybara
|
5
|
+
# Capybara::CapybaraError extension
|
6
|
+
class CapybaraError
|
7
|
+
include Enrichment
|
8
|
+
|
9
|
+
#@api private
|
10
|
+
def initialize(msg)
|
11
|
+
super(rich_msg(msg))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'capybara/node/element'
|
2
|
+
|
3
|
+
# Capybara namespace
|
4
|
+
module Capybara
|
5
|
+
# Capybara::Node namespace
|
6
|
+
module Node
|
7
|
+
# Capybara::Node::Element namespace
|
8
|
+
class Element < Base
|
9
|
+
# Scrolls an element into view and return the element to allow method chaining
|
10
|
+
#@return [Capybara::Node::Element]
|
11
|
+
def scroll_into_view!
|
12
|
+
synchronize { base.scroll_into_view! }
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
# Validates if the element on the displayed part of the page (screen!)
|
17
|
+
#@return [Boolean]
|
18
|
+
def on_screen?(fully: false)
|
19
|
+
synchronize { base.on_screen?(fully) }
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the element absolute location on the page
|
23
|
+
#@return [Selenium::WebDriver::Point]
|
24
|
+
def location
|
25
|
+
synchronize { base.location }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the size of this element
|
29
|
+
# @return [Selenium::WebDriver::Dimension]
|
30
|
+
def size
|
31
|
+
synchronize { base.size }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'capybara/selenium/node'
|
2
|
+
|
3
|
+
# Selenium specific implementation of the Capybara::Driver::Node API
|
4
|
+
class Capybara::Selenium::Node < Capybara::Driver::Node
|
5
|
+
# Scrolls an element into view and return the element to allow method chaining
|
6
|
+
#@return [Nil]
|
7
|
+
def scroll_into_view!
|
8
|
+
script = <<-JS
|
9
|
+
arguments[0].scrollIntoView(false);
|
10
|
+
JS
|
11
|
+
|
12
|
+
driver.execute_script(script, native)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Validates if the element on the displayed part of the page (screen!)
|
16
|
+
#@return [Boolean]
|
17
|
+
def on_screen?(fully)
|
18
|
+
raise ArgumentError, 'on_screen argument should be true or false' unless [true, false].include?(fully)
|
19
|
+
|
20
|
+
screen_position_x = driver.execute_script('return window.scrollX;')
|
21
|
+
screen_position_y = driver.execute_script('return window.scrollY;')
|
22
|
+
|
23
|
+
window_size = driver.browser.manage.window.size
|
24
|
+
|
25
|
+
screen_size_width = window_size.width
|
26
|
+
screen_size_height = window_size.height
|
27
|
+
|
28
|
+
if fully
|
29
|
+
on_screen_x = (x_origin < (screen_position_x + screen_size_width) and x_end < (screen_position_x + screen_size_width))
|
30
|
+
on_screen_y = (y_origin < (screen_position_y + screen_size_height) and y_end < (screen_position_y + screen_size_height))
|
31
|
+
else #partially
|
32
|
+
on_screen_x = location.x < (screen_position_x + screen_size_width)
|
33
|
+
on_screen_y = location.y < (screen_position_y + screen_size_height)
|
34
|
+
end
|
35
|
+
|
36
|
+
on_screen_x and on_screen_y
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the element absolute location on the page
|
40
|
+
#@return [Selenium::WebDriver::Point]
|
41
|
+
def location
|
42
|
+
native.location
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the size of this element
|
46
|
+
# @return [Selenium::WebDriver::Dimension]
|
47
|
+
def size
|
48
|
+
native.size
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the element X location on the page
|
52
|
+
#@return Integer
|
53
|
+
def x_origin
|
54
|
+
@x_origin ||= (location.x).to_i
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns the end of the X element location on the page
|
58
|
+
#@return Integer
|
59
|
+
def x_end
|
60
|
+
@x_end ||= (x_origin + size.width).to_i
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the element Y location on the page
|
64
|
+
#@return Integer
|
65
|
+
def y_origin
|
66
|
+
@y_origin ||= (location.y).to_i
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the end of the Y element location on the page
|
70
|
+
#@return Integer
|
71
|
+
def y_end
|
72
|
+
@y_end ||= (y_origin + size.height).to_i
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'headless'
|
2
|
+
|
3
|
+
#Redifinition of the Headless class, which works as a wrapper arround Xvfb.
|
4
|
+
#@since 1.1.0
|
5
|
+
class Headless
|
6
|
+
|
7
|
+
#Link to original implemenmtarion of Headless#pick_available_display
|
8
|
+
alias_method :old_pick_available_display, :pick_available_display
|
9
|
+
|
10
|
+
#Shuffles the original display set generated by Headless.
|
11
|
+
#This makes the display picking random while still using the original avalability check algorithm.
|
12
|
+
def pick_available_display(display_set, can_reuse)
|
13
|
+
old_pick_available_display display_set.to_a.shuffle, can_reuse
|
14
|
+
end
|
15
|
+
end
|
data/lib/qat/web.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'web/version'
|
2
|
+
require_relative 'web/drivers'
|
3
|
+
require_relative 'web/browser'
|
4
|
+
require_relative 'web/browser/autoload'
|
5
|
+
require_relative 'web/finders'
|
6
|
+
require_relative 'web/screen'
|
7
|
+
require_relative 'web/screen/autoload'
|
8
|
+
require_relative 'web/error'
|
9
|
+
require_relative 'web/exceptions'
|
10
|
+
require_relative 'web/page'
|
11
|
+
require_relative 'web/page_manager'
|
12
|
+
require_relative '../capybara/core_ext'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'version'
|
2
|
+
require_relative 'drivers'
|
3
|
+
require_relative 'browser/factory'
|
4
|
+
require_relative 'browser/loader'
|
5
|
+
require_relative 'browser/screenshot'
|
6
|
+
require_relative 'browser/html_dump'
|
7
|
+
require_relative 'browser/profile'
|
8
|
+
|
9
|
+
require 'qat/logger'
|
10
|
+
|
11
|
+
module QAT::Web::Browser
|
12
|
+
include QAT::Logger
|
13
|
+
|
14
|
+
class << self
|
15
|
+
#Prints the current browser URL
|
16
|
+
#@since 1.2.0
|
17
|
+
def print_url
|
18
|
+
log.info "The current URL is #{Capybara.current_session.current_url}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'loader'
|
2
|
+
|
3
|
+
module QAT
|
4
|
+
module Web
|
5
|
+
module Browser
|
6
|
+
# Helper methods for configuration auto-loading
|
7
|
+
module AutoLoad
|
8
|
+
include QAT::Logger
|
9
|
+
|
10
|
+
# Loads all screens from QAT cconfiguration cache
|
11
|
+
def self.load_browsers!
|
12
|
+
if QAT.respond_to?(:configuration) && QAT.configuration[:browsers]
|
13
|
+
QAT::Web::Browser::Loader.load_config(QAT.configuration[:browsers])
|
14
|
+
log.debug { "Browser controllers loaded in cache: [#{Capybara.drivers.keys.join(', ')}]" }
|
15
|
+
else
|
16
|
+
log.debug { "Browser controllers aren't loaded in cache, load screens manually from file using QAT::Web::Browser::Loader#load" }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
require 'qat/logger'
|
3
|
+
|
4
|
+
module QAT::Web
|
5
|
+
# Browser namespace
|
6
|
+
module Browser
|
7
|
+
# Module to provide browsers and drivers for web control.
|
8
|
+
#@since 1.0.0
|
9
|
+
module Factory
|
10
|
+
include QAT::Logger
|
11
|
+
|
12
|
+
#Method to ask for a browser. It will be provided if Capybara has a driver with that name
|
13
|
+
#@param browser [String/Symbol] Name of the Capybara::Driver to use
|
14
|
+
#@raise [ArgumentError] When a given driver does not exist.
|
15
|
+
#@since 1.0.0
|
16
|
+
def self.for browser
|
17
|
+
browser = browser.to_sym
|
18
|
+
|
19
|
+
unless Capybara.drivers.has_key? browser
|
20
|
+
log.error { "No driver with name #{browser} available" }
|
21
|
+
log.debug { 'Available drivers are:' }
|
22
|
+
log.debug { Capybara.drivers.keys }
|
23
|
+
raise ArgumentError.new "No driver with name #{browser} available"
|
24
|
+
end
|
25
|
+
|
26
|
+
if Capybara.current_driver != browser
|
27
|
+
log.info { "Switching from #{Capybara.current_driver} to #{browser}" }
|
28
|
+
Capybara.current_driver = browser
|
29
|
+
Capybara.default_driver = browser
|
30
|
+
Capybara.javascript_driver = browser
|
31
|
+
end
|
32
|
+
#Force driver start
|
33
|
+
Capybara.current_session.driver
|
34
|
+
Capybara.current_session
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
Binary file
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module QAT::Web
|
2
|
+
module Browser
|
3
|
+
module Loader
|
4
|
+
# Module with helper methods to load browsers and drivers from configuration files.
|
5
|
+
#@since 2.0.1
|
6
|
+
module Helper
|
7
|
+
# Creates a generic Capybara driver
|
8
|
+
# @param browser [String] Expected browser
|
9
|
+
# @param controller [String] Expected controller
|
10
|
+
# @param screen [String] Expected screen properties
|
11
|
+
# @param driver [String] Expected driver
|
12
|
+
# @param properties [String] Expected driver properties
|
13
|
+
# @param addons [String] Expected driver/browser addons
|
14
|
+
# @param hooks [String] Cucumber hooks to use
|
15
|
+
# @return [Capybara::RackTest::Driver||Capybara::Selenium::Driver]
|
16
|
+
def load_generic_driver(browser, controller, screen, driver, properties, addons, hooks)
|
17
|
+
Capybara.register_driver controller do |app|
|
18
|
+
loaded_screen = QAT::Web::Screen::Factory.for screen
|
19
|
+
loaded_driver = nil
|
20
|
+
Retriable.retriable on: [Net::ReadTimeout, ::Selenium::WebDriver::Error::WebDriverError],
|
21
|
+
tries: 3,
|
22
|
+
base_interval: 5,
|
23
|
+
multiplier: 1.0,
|
24
|
+
rand_factor: 0.0 do
|
25
|
+
|
26
|
+
options = { browser: browser }
|
27
|
+
if properties
|
28
|
+
customized_profile = create_profile(driver, browser, properties, addons)
|
29
|
+
options.merge!(customized_profile) if customized_profile
|
30
|
+
end
|
31
|
+
loaded_driver = Capybara.const_get(driver.capitalize)::Driver.new(app, options)
|
32
|
+
loaded_driver.browser
|
33
|
+
end
|
34
|
+
|
35
|
+
if loaded_screen.xvfb
|
36
|
+
loaded_driver.resize_window_to(loaded_driver.current_window_handle, loaded_screen.width, loaded_screen.height)
|
37
|
+
else
|
38
|
+
loaded_driver.maximize_window(loaded_driver.current_window_handle) if loaded_driver.respond_to? :maximize_window
|
39
|
+
end
|
40
|
+
|
41
|
+
require_hooks(hooks)
|
42
|
+
|
43
|
+
loaded_driver
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative '../version'
|
2
|
+
require 'capybara'
|
3
|
+
require 'qat/logger'
|
4
|
+
|
5
|
+
module QAT::Web
|
6
|
+
# Browser namespace
|
7
|
+
module Browser
|
8
|
+
# Module to handle browser HTML dumps.
|
9
|
+
#@since 1.0.0
|
10
|
+
module HTMLDump
|
11
|
+
include QAT::Logger
|
12
|
+
extend self
|
13
|
+
|
14
|
+
# Function to take a browser HTML dump. Will handle the usage of driver that don't support HTML dumps.
|
15
|
+
#@param page [Capybara::Session] Browser to take HTML dump from
|
16
|
+
#@param path [String] File path to save HTML dump file
|
17
|
+
#@return [String/NilClass] File path to where the HTML dump file was saved or nil if the browser doesn't support HTML dumps
|
18
|
+
#@since 1.0.0
|
19
|
+
def take_html_dump(page=Capybara.current_session, path=html_dump_path)
|
20
|
+
log.info { "Saving HTML dump to #{path}" }
|
21
|
+
raise ArgumentError.new "File #{path} already exists! Choose another filename" if ::File.exists? path
|
22
|
+
path = page.save_page path
|
23
|
+
log.info { "HTML dump available" }
|
24
|
+
::File.basename(path)
|
25
|
+
rescue Capybara::NotSupportedByDriverError
|
26
|
+
log.warn { "Driver #{page.mode} does not support HTML dumps!" }
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
#Default HTML dump path. Can be set with {#html_dump_path=}.
|
31
|
+
#@return [String] HTML dump path
|
32
|
+
#@since 1.0.0
|
33
|
+
def html_dump_path
|
34
|
+
@html_dump_path || ::File.join('public', "browser_#{Time.new.strftime("%H%M%S%L")}.html")
|
35
|
+
end
|
36
|
+
|
37
|
+
#Set new default HTML dump path.
|
38
|
+
#@param path [String] HTML dump path
|
39
|
+
#@since 1.0.0
|
40
|
+
def html_dump_path=(path)
|
41
|
+
@html_dump_path = path
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
require_relative '../version'
|
3
|
+
require_relative '../drivers/default'
|
4
|
+
require_relative 'profile'
|
5
|
+
require_relative 'firefox/loader/helper'
|
6
|
+
require 'retriable'
|
7
|
+
require 'erb'
|
8
|
+
require 'active_support'
|
9
|
+
require 'active_support/hash_with_indifferent_access'
|
10
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
11
|
+
|
12
|
+
module QAT::Web
|
13
|
+
module Browser
|
14
|
+
# Module to load browsers and drivers from configuration files.
|
15
|
+
#@since 1.0.0
|
16
|
+
module Loader
|
17
|
+
include Drivers::Default
|
18
|
+
include QAT::Web::Browser::Profile
|
19
|
+
include Helper
|
20
|
+
extend self
|
21
|
+
|
22
|
+
# Registers browser drivers in Capybara from a YAML file
|
23
|
+
#@param file_path [String] file containing browser drivers
|
24
|
+
#@since 1.0.0
|
25
|
+
def load(file_path)
|
26
|
+
controllers = HashWithIndifferentAccess.new(YAML::load(ERB.new(File.read(file_path)).result)) || {}
|
27
|
+
load_config(controllers)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Registers browser drivers in Capybara from a configuration hash
|
31
|
+
#@param config [String] configuration hash containing browser drivers
|
32
|
+
#@since 2.1.0
|
33
|
+
def load_config(config)
|
34
|
+
config.each do |controller, options|
|
35
|
+
raise InvalidConfigurationError.new "No browser defined for controller #{controller}" unless options['browser']
|
36
|
+
register_controller(controller.to_sym, options)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def register_controller(controller, options)
|
43
|
+
browser = options['browser'].to_sym
|
44
|
+
driver = options['driver'] || mapping[browser]
|
45
|
+
screen = options['screen']
|
46
|
+
properties = options['properties']
|
47
|
+
addons = options['addons']
|
48
|
+
hooks = options['hooks']
|
49
|
+
|
50
|
+
if driver.to_sym == :poltergeist
|
51
|
+
load_poltergeist_driver(browser, controller, screen)
|
52
|
+
else
|
53
|
+
load_generic_driver(browser, controller, screen, driver, properties, addons, hooks)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def require_hooks(hooks)
|
58
|
+
if hooks&.any?
|
59
|
+
if defined?(Cucumber)
|
60
|
+
hooks.each do |hook|
|
61
|
+
log.debug "Loading cucumber hook: qat/web/hooks/#{hook}"
|
62
|
+
require "qat/web/hooks/#{hook}"
|
63
|
+
end
|
64
|
+
else
|
65
|
+
log.debug "Running in a non-Cucumber runtime, skipping hooks!"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#Configuration load error class.
|
71
|
+
class InvalidConfigurationError < StandardError
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|