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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/lib/capybara/core_ext.rb +7 -0
  3. data/lib/capybara/core_ext/capybara_error.rb +14 -0
  4. data/lib/capybara/core_ext/node/element.rb +35 -0
  5. data/lib/capybara/core_ext/selenium/node.rb +75 -0
  6. data/lib/headless/core_ext/random_display.rb +15 -0
  7. data/lib/qat/cli/plugins/web.rb +7 -0
  8. data/lib/qat/web.rb +12 -0
  9. data/lib/qat/web/browser.rb +21 -0
  10. data/lib/qat/web/browser/autoload.rb +22 -0
  11. data/lib/qat/web/browser/factory.rb +39 -0
  12. data/lib/qat/web/browser/firefox/harexporttrigger-0.5.0-beta.10.xpi +0 -0
  13. data/lib/qat/web/browser/firefox/loader/helper.rb +49 -0
  14. data/lib/qat/web/browser/html_dump.rb +46 -0
  15. data/lib/qat/web/browser/loader.rb +75 -0
  16. data/lib/qat/web/browser/profile.rb +92 -0
  17. data/lib/qat/web/browser/screenshot.rb +46 -0
  18. data/lib/qat/web/configuration.rb +46 -0
  19. data/lib/qat/web/cucumber.rb +19 -0
  20. data/lib/qat/web/drivers.rb +3 -0
  21. data/lib/qat/web/drivers/chrome.rb +5 -0
  22. data/lib/qat/web/drivers/default.rb +25 -0
  23. data/lib/qat/web/drivers/firefox.rb +6 -0
  24. data/lib/qat/web/drivers/firefox/har_exporter.rb +16 -0
  25. data/lib/qat/web/elements.rb +78 -0
  26. data/lib/qat/web/elements/base.rb +50 -0
  27. data/lib/qat/web/elements/collection.rb +16 -0
  28. data/lib/qat/web/elements/config.rb +19 -0
  29. data/lib/qat/web/elements/element.rb +16 -0
  30. data/lib/qat/web/elements/selector.rb +108 -0
  31. data/lib/qat/web/elements/waiters.rb +103 -0
  32. data/lib/qat/web/error.rb +14 -0
  33. data/lib/qat/web/error/enrichment.rb +14 -0
  34. data/lib/qat/web/exceptions.rb +15 -0
  35. data/lib/qat/web/finders.rb +49 -0
  36. data/lib/qat/web/hooks/common.rb +17 -0
  37. data/lib/qat/web/hooks/har_exporter.rb +32 -0
  38. data/lib/qat/web/hooks/html_dump.rb +21 -0
  39. data/lib/qat/web/hooks/screenshot.rb +20 -0
  40. data/lib/qat/web/page.rb +158 -0
  41. data/lib/qat/web/page/validators.rb +37 -0
  42. data/lib/qat/web/page_manager.rb +71 -0
  43. data/lib/qat/web/screen.rb +2 -0
  44. data/lib/qat/web/screen/autoload.rb +22 -0
  45. data/lib/qat/web/screen/factory.rb +68 -0
  46. data/lib/qat/web/screen/loader.rb +93 -0
  47. data/lib/qat/web/screen/wrapper.rb +96 -0
  48. data/lib/qat/web/version.rb +9 -0
  49. metadata +278 -0
@@ -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,7 @@
1
+ require 'capybara'
2
+ require_relative 'core_ext/capybara_error'
3
+ require_relative 'core_ext/node/element'
4
+
5
+ if defined?(Selenium::WebDriver)
6
+ require_relative 'core_ext/selenium/node'
7
+ end
@@ -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
@@ -0,0 +1,7 @@
1
+ require_relative '../../web/version'
2
+
3
+ #Plugin for CLI functions
4
+ #@since 1.0.0
5
+ module QAT::CLI::Plugins::Web
6
+
7
+ end
@@ -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
@@ -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