howitzer 2.1.1 → 2.4.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 +5 -5
- data/CHANGELOG.md +44 -1
- data/LICENSE +1 -1
- data/README.md +19 -17
- data/generators/base_generator.rb +5 -7
- data/generators/config/config_generator.rb +3 -4
- data/generators/config/templates/boot.rb +2 -2
- data/generators/config/templates/capybara.rb +4 -5
- data/generators/config/templates/default.yml +21 -11
- data/generators/config/templates/drivers/browserstack.rb +31 -4
- data/generators/config/templates/drivers/crossbrowsertesting.rb +9 -11
- data/generators/config/templates/drivers/headless_chrome.rb +1 -1
- data/generators/config/templates/drivers/headless_firefox.rb +23 -0
- data/generators/config/templates/drivers/lambdatest.rb +30 -0
- data/generators/config/templates/drivers/sauce.rb +30 -2
- data/generators/config/templates/drivers/selenium.rb +1 -1
- data/generators/config/templates/drivers/selenium_grid.rb +3 -3
- data/generators/config/templates/drivers/testingbot.rb +29 -2
- data/generators/cucumber/templates/cuke_sniffer.rake +2 -2
- data/generators/cucumber/templates/env.rb +8 -0
- data/generators/cucumber/templates/hooks.rb +9 -3
- data/generators/cucumber/templates/transformers.rb +1 -1
- data/generators/prerequisites/templates/factory_bot.rb +2 -1
- data/generators/root/root_generator.rb +1 -1
- data/generators/root/templates/Gemfile.erb +4 -10
- data/generators/rspec/templates/spec_helper.rb +6 -5
- data/generators/turnip/templates/spec_helper.rb +6 -5
- data/generators/web/templates/example_page.rb +1 -1
- data/lib/howitzer/cache.rb +20 -19
- data/lib/howitzer/capybara_helpers.rb +59 -14
- data/lib/howitzer/email.rb +3 -2
- data/lib/howitzer/exceptions.rb +21 -21
- data/lib/howitzer/gmail_api/client.rb +13 -4
- data/lib/howitzer/log.rb +6 -6
- data/lib/howitzer/mail_adapters/gmail.rb +3 -0
- data/lib/howitzer/mail_adapters/mailgun.rb +3 -1
- data/lib/howitzer/mail_adapters/mailtrap.rb +3 -0
- data/lib/howitzer/mailgun_api/client.rb +3 -2
- data/lib/howitzer/mailgun_api/connector.rb +1 -0
- data/lib/howitzer/mailgun_api/response.rb +1 -2
- data/lib/howitzer/mailtrap_api/client.rb +1 -1
- data/lib/howitzer/meta/actions.rb +35 -0
- data/lib/howitzer/meta/element.rb +40 -0
- data/lib/howitzer/meta/entry.rb +62 -0
- data/lib/howitzer/meta/iframe.rb +41 -0
- data/lib/howitzer/meta/section.rb +30 -0
- data/lib/howitzer/meta.rb +11 -0
- data/lib/howitzer/utils/string_extensions.rb +6 -2
- data/lib/howitzer/version.rb +1 -1
- data/lib/howitzer/web/base_section.rb +1 -1
- data/lib/howitzer/web/capybara_context_holder.rb +1 -0
- data/lib/howitzer/web/capybara_methods_proxy.rb +15 -6
- data/lib/howitzer/web/element_dsl.rb +104 -44
- data/lib/howitzer/web/iframe_dsl.rb +4 -2
- data/lib/howitzer/web/page.rb +14 -14
- data/lib/howitzer/web/page_dsl.rb +18 -6
- data/lib/howitzer/web/page_validator.rb +27 -26
- data/lib/howitzer/web/section.rb +13 -2
- data/lib/howitzer/web/section_dsl.rb +65 -30
- data/lib/howitzer.rb +40 -0
- metadata +31 -157
- data/.coveralls.yml +0 -1
- data/.gitignore +0 -14
- data/.rspec +0 -3
- data/.rubocop.yml +0 -51
- data/.ruby-gemset +0 -1
- data/.travis.yml +0 -7
- data/Gemfile +0 -14
- data/ISSUE_TEMPLATE.md +0 -16
- data/MAINTENANCE.md +0 -32
- data/Rakefile +0 -38
- data/features/cli_help.feature +0 -31
- data/features/cli_new.feature +0 -389
- data/features/cli_unknown.feature +0 -17
- data/features/cli_update.feature +0 -218
- data/features/cli_version.feature +0 -14
- data/features/step_definitions/common_steps.rb +0 -34
- data/features/support/env.rb +0 -1
- data/generators/config/templates/drivers/phantomjs.rb +0 -19
- data/generators/config/templates/drivers/poltergeist.rb +0 -11
- data/generators/config/templates/drivers/webkit.rb +0 -6
- data/generators/root/templates/.gitignore +0 -21
- data/generators/root/templates/.rubocop.yml +0 -35
- data/generators/turnip/templates/.rspec +0 -1
- data/howitzer.gemspec +0 -39
- data/lib/howitzer/mail_adapters/debugmail.rb +0 -0
- data/spec/config/custom.yml +0 -9
- data/spec/spec_helper.rb +0 -73
- data/spec/support/generator_helper.rb +0 -21
- data/spec/support/logger_helper.rb +0 -13
- data/spec/support/shared_examples/capybara_context_holder.rb +0 -33
- data/spec/support/shared_examples/capybara_methods_proxy.rb +0 -94
- data/spec/support/shared_examples/dynamic_section_methods.rb +0 -35
- data/spec/support/shared_examples/element_dsl.rb +0 -242
- data/spec/unit/generators/base_generator_spec.rb +0 -283
- data/spec/unit/generators/config_generator_spec.rb +0 -59
- data/spec/unit/generators/cucumber_generator_spec.rb +0 -62
- data/spec/unit/generators/emails_generator_spec.rb +0 -35
- data/spec/unit/generators/prerequisites_generator_spec.rb +0 -53
- data/spec/unit/generators/root_generator_spec.rb +0 -75
- data/spec/unit/generators/rspec_generator_spec.rb +0 -36
- data/spec/unit/generators/tasks_generator_spec.rb +0 -31
- data/spec/unit/generators/turnip_generator_spec.rb +0 -52
- data/spec/unit/generators/web_generator_spec.rb +0 -52
- data/spec/unit/lib/cache_spec.rb +0 -85
- data/spec/unit/lib/capybara_helpers_spec.rb +0 -697
- data/spec/unit/lib/email_spec.rb +0 -186
- data/spec/unit/lib/gmail_api/client_spec.rb +0 -26
- data/spec/unit/lib/howitzer_spec.rb +0 -69
- data/spec/unit/lib/init_spec.rb +0 -2
- data/spec/unit/lib/log_spec.rb +0 -122
- data/spec/unit/lib/mail_adapters/abstract_spec.rb +0 -62
- data/spec/unit/lib/mail_adapters/gmail_spec.rb +0 -128
- data/spec/unit/lib/mail_adapters/mailgun_spec.rb +0 -158
- data/spec/unit/lib/mail_adapters/mailtrap_spec.rb +0 -130
- data/spec/unit/lib/mailgun_api/client_spec.rb +0 -80
- data/spec/unit/lib/mailgun_api/connector_spec.rb +0 -54
- data/spec/unit/lib/mailgun_api/response_spec.rb +0 -28
- data/spec/unit/lib/mailtrap_api/client_spec.rb +0 -67
- data/spec/unit/lib/utils/string_extensions_spec.rb +0 -77
- data/spec/unit/lib/web/base_section_spec.rb +0 -43
- data/spec/unit/lib/web/element_dsl_spec.rb +0 -22
- data/spec/unit/lib/web/iframe_dsl_spec.rb +0 -203
- data/spec/unit/lib/web/page_dsl_spec.rb +0 -74
- data/spec/unit/lib/web/page_spec.rb +0 -378
- data/spec/unit/lib/web/page_validator_spec.rb +0 -276
- data/spec/unit/lib/web/section_dsl_spec.rb +0 -165
- data/spec/unit/lib/web/section_spec.rb +0 -63
- data/spec/unit/version_spec.rb +0 -8
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
Before do |scenario|
|
|
2
2
|
Capybara.use_default_driver
|
|
3
|
-
|
|
3
|
+
feature_name = \
|
|
4
|
+
if Gem::Requirement.new('>3').satisfied_by?(Gem::Version.new(Cucumber::VERSION))
|
|
5
|
+
File.read(scenario.location.file)[/Feature:\s(.+)/, 1]
|
|
6
|
+
else
|
|
7
|
+
scenario.feature.name
|
|
8
|
+
end
|
|
9
|
+
Howitzer::Log.print_feature_name(feature_name)
|
|
4
10
|
Howitzer::Log.print_scenario_name(scenario.name)
|
|
5
11
|
@session_start = CapybaraHelpers.duration(Time.now.utc - Howitzer::Cache.extract(:cloud, :start_time))
|
|
6
12
|
end
|
|
@@ -9,8 +15,8 @@ After do |scenario|
|
|
|
9
15
|
if CapybaraHelpers.cloud_driver?
|
|
10
16
|
Howitzer::Cache.store(:cloud, :status, false) if scenario.failed?
|
|
11
17
|
session_end = CapybaraHelpers.duration(Time.now.utc - Howitzer::Cache.extract(:cloud, :start_time))
|
|
12
|
-
Howitzer::Log.info "CLOUD VIDEO #{@session_start} - #{session_end}" \
|
|
13
|
-
|
|
18
|
+
Howitzer::Log.info "CLOUD VIDEO #{@session_start} - #{session_end} " \
|
|
19
|
+
"URL: #{CapybaraHelpers.cloud_resource_path(:video)}"
|
|
14
20
|
elsif CapybaraHelpers.ie_browser?
|
|
15
21
|
Howitzer::Log.info 'IE reset session'
|
|
16
22
|
Capybara.current_session.execute_script("void(document.execCommand('ClearAuthenticationCache', false));")
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# end
|
|
16
16
|
ParameterType(
|
|
17
17
|
name: 'factory',
|
|
18
|
-
regexp: /(?:factory|FACTORY)_([A-Za-z_]+)(\d*)(?:\[
|
|
18
|
+
regexp: /(?:factory|FACTORY)_([A-Za-z_]+)(\d*)(?:\[:(.+)\])?/,
|
|
19
19
|
transformer: lambda do |_, factory, num, property|
|
|
20
20
|
res = FactoryBot.given_by_number(factory.downcase, num)
|
|
21
21
|
res = res.send(property) if property
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @see
|
|
1
|
+
# @see https://www.rubydoc.info/gems/factory_bot/file/GETTING_STARTED.md
|
|
2
2
|
require 'factory_bot'
|
|
3
3
|
|
|
4
4
|
FactoryBot.definition_file_paths = [File.join(__dir__, 'factories')]
|
|
@@ -15,6 +15,7 @@ module FactoryBot
|
|
|
15
15
|
def self.given_by_number(factory, num)
|
|
16
16
|
data = Howitzer::Cache.extract(factory, num.to_i)
|
|
17
17
|
return data if data.present?
|
|
18
|
+
|
|
18
19
|
Howitzer::Cache.store(factory, num.to_i, build(factory))
|
|
19
20
|
end
|
|
20
21
|
end
|
|
@@ -7,11 +7,11 @@ module Howitzer
|
|
|
7
7
|
{ files:
|
|
8
8
|
[
|
|
9
9
|
{ source: '.gitignore', destination: '.gitignore' },
|
|
10
|
-
{ source: '.rubocop.yml', destination: '.rubocop.yml' },
|
|
11
10
|
{ source: 'Rakefile', destination: 'Rakefile' }
|
|
12
11
|
],
|
|
13
12
|
templates:
|
|
14
13
|
[
|
|
14
|
+
{ source: '.rubocop.yml.erb', destination: '.rubocop.yml' },
|
|
15
15
|
{ source: 'Gemfile.erb', destination: 'Gemfile' }
|
|
16
16
|
] }
|
|
17
17
|
end
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
source 'https://rubygems.org'
|
|
2
2
|
|
|
3
|
+
ruby '>=2.6.8'
|
|
4
|
+
|
|
3
5
|
gem 'capybara-screenshot'
|
|
4
|
-
<%= "gem 'cucumber', '
|
|
6
|
+
<%= "gem 'cucumber', '>=3.0', '<7'\n" if cucumber -%>
|
|
5
7
|
<%= "gem 'cuke_sniffer', require: false\n" if cucumber -%>
|
|
6
8
|
gem 'factory_bot'
|
|
7
9
|
gem 'howitzer'
|
|
@@ -11,14 +13,6 @@ gem 'repeater'
|
|
|
11
13
|
gem 'rest-client'
|
|
12
14
|
<%= "gem 'rspec', '~>3.2'\n" if rspec || turnip -%>
|
|
13
15
|
gem 'rubocop'
|
|
16
|
+
<%= "gem 'rubocop-rspec'\n" if rspec || turnip -%>
|
|
14
17
|
<%= "gem 'turnip'\n" if turnip -%>
|
|
15
18
|
<%= "gem 'syntax'\n" if cucumber -%>
|
|
16
|
-
|
|
17
|
-
# Uncomment it if you are going to use 'webkit' driver. QT library should be installed.
|
|
18
|
-
# See https://github.com/thoughtbot/capybara-webkit/wiki/Installing-Qt-and-compiling-capybara-webkit
|
|
19
|
-
#
|
|
20
|
-
# gem 'capybara-webkit'
|
|
21
|
-
|
|
22
|
-
# Uncomment it if you are going to use 'poltergeist' driver. PhantomJS should be installed.
|
|
23
|
-
# See https://github.com/jnicklas/capybara#poltergeist
|
|
24
|
-
# gem 'poltergeist', git: 'https://github.com/teampoltergeist/poltergeist.git', branch: :master
|
|
@@ -2,7 +2,7 @@ require 'capybara/rspec/features'
|
|
|
2
2
|
require_relative '../config/boot'
|
|
3
3
|
require_relative '../config/capybara'
|
|
4
4
|
|
|
5
|
-
Dir['./spec/support/**/*.rb'].each { |f| require f }
|
|
5
|
+
Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
|
|
6
6
|
|
|
7
7
|
RSpec.configure do |config|
|
|
8
8
|
Howitzer::Log.settings_as_formatted_text
|
|
@@ -15,8 +15,9 @@ RSpec.configure do |config|
|
|
|
15
15
|
config.disable_monkey_patching!
|
|
16
16
|
config.color = true
|
|
17
17
|
config.wait_timeout = Howitzer.rspec_wait_timeout
|
|
18
|
+
config.order = Howitzer.test_order.presence || :defined
|
|
18
19
|
|
|
19
|
-
config.before
|
|
20
|
+
config.before do
|
|
20
21
|
scenario_name =
|
|
21
22
|
if RSpec.current_example.description.blank?
|
|
22
23
|
RSpec.current_example.metadata[:full_description]
|
|
@@ -27,12 +28,12 @@ RSpec.configure do |config|
|
|
|
27
28
|
@session_start = CapybaraHelpers.duration(Time.now.utc - Howitzer::Cache.extract(:cloud, :start_time))
|
|
28
29
|
end
|
|
29
30
|
|
|
30
|
-
config.after
|
|
31
|
+
config.after do
|
|
31
32
|
Howitzer::Cache.clear_all_ns
|
|
32
33
|
if CapybaraHelpers.cloud_driver?
|
|
33
34
|
session_end = CapybaraHelpers.duration(Time.now.utc - Howitzer::Cache.extract(:cloud, :start_time))
|
|
34
|
-
Howitzer::Log.info "CLOUD VIDEO #{@session_start} - #{session_end}" \
|
|
35
|
-
|
|
35
|
+
Howitzer::Log.info "CLOUD VIDEO #{@session_start} - #{session_end} " \
|
|
36
|
+
"URL: #{CapybaraHelpers.cloud_resource_path(:video)}"
|
|
36
37
|
elsif CapybaraHelpers.ie_browser?
|
|
37
38
|
Howitzer::Log.info 'IE reset session'
|
|
38
39
|
Capybara.current_session.execute_script("void(document.execCommand('ClearAuthenticationCache', false));")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require_relative '../config/boot'
|
|
2
2
|
require_relative '../config/capybara'
|
|
3
3
|
|
|
4
|
-
Dir['./spec/support/**/*.rb'].each { |f| require f }
|
|
4
|
+
Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
|
|
5
5
|
|
|
6
6
|
RSpec.configure do |config|
|
|
7
7
|
Howitzer::Log.settings_as_formatted_text
|
|
@@ -14,8 +14,9 @@ RSpec.configure do |config|
|
|
|
14
14
|
config.disable_monkey_patching!
|
|
15
15
|
config.color = true
|
|
16
16
|
config.wait_timeout = Howitzer.rspec_wait_timeout
|
|
17
|
+
config.order = Howitzer.test_order.presence || :defined
|
|
17
18
|
|
|
18
|
-
config.before
|
|
19
|
+
config.before do
|
|
19
20
|
scenario_name =
|
|
20
21
|
if RSpec.current_example.description.blank?
|
|
21
22
|
RSpec.current_example.metadata[:full_description]
|
|
@@ -26,12 +27,12 @@ RSpec.configure do |config|
|
|
|
26
27
|
@session_start = CapybaraHelpers.duration(Time.now.utc - Howitzer::Cache.extract(:cloud, :start_time))
|
|
27
28
|
end
|
|
28
29
|
|
|
29
|
-
config.after
|
|
30
|
+
config.after do
|
|
30
31
|
Howitzer::Cache.clear_all_ns
|
|
31
32
|
if CapybaraHelpers.cloud_driver?
|
|
32
33
|
session_end = CapybaraHelpers.duration(Time.now.utc - Howitzer::Cache.extract(:cloud, :start_time))
|
|
33
|
-
Howitzer::Log.info "CLOUD VIDEO #{@session_start} - #{session_end}" \
|
|
34
|
-
|
|
34
|
+
Howitzer::Log.info "CLOUD VIDEO #{@session_start} - #{session_end} " \
|
|
35
|
+
"URL: #{CapybaraHelpers.cloud_resource_path(:video)}"
|
|
35
36
|
elsif CapybaraHelpers.ie_browser?
|
|
36
37
|
Howitzer::Log.info 'IE reset session'
|
|
37
38
|
Capybara.current_session.execute_script("void(document.execCommand('ClearAuthenticationCache', false));")
|
data/lib/howitzer/cache.rb
CHANGED
|
@@ -4,7 +4,7 @@ module Howitzer
|
|
|
4
4
|
# Data can be stored in memory using this class
|
|
5
5
|
#
|
|
6
6
|
module Cache
|
|
7
|
-
SPECIAL_NS_LIST = [:cloud].freeze
|
|
7
|
+
SPECIAL_NS_LIST = [:cloud].freeze # :nodoc:
|
|
8
8
|
@data ||= {}
|
|
9
9
|
|
|
10
10
|
class << self
|
|
@@ -12,35 +12,35 @@ module Howitzer
|
|
|
12
12
|
|
|
13
13
|
# Saves data into memory. Marking by a namespace and a key
|
|
14
14
|
#
|
|
15
|
-
# @param
|
|
15
|
+
# @param namespace [String] a namespace
|
|
16
16
|
# @param key [String] a key that should be uniq within the namespace
|
|
17
17
|
# @param value [Object] everything you want to store in Memory
|
|
18
18
|
# @raise [NoDataError] if the namespace missing
|
|
19
19
|
|
|
20
|
-
def store(
|
|
21
|
-
check_ns(
|
|
22
|
-
@data[
|
|
20
|
+
def store(namespace, key, value)
|
|
21
|
+
check_ns(namespace)
|
|
22
|
+
@data[namespace][key] = value
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
# Gets data from memory. Can get all namespace or single data value in namespace using key
|
|
26
26
|
#
|
|
27
|
-
# @param
|
|
27
|
+
# @param namespace [String] a namespace
|
|
28
28
|
# @param key [String] key that isn't necessary required
|
|
29
29
|
# @return [Object, Hash] all data from the namespace if the key is ommited, otherwise returs
|
|
30
30
|
# all data for the namespace
|
|
31
31
|
# @raise [NoDataError] if the namespace missing
|
|
32
32
|
|
|
33
|
-
def extract(
|
|
34
|
-
check_ns(
|
|
35
|
-
key ? @data[
|
|
33
|
+
def extract(namespace, key = nil)
|
|
34
|
+
check_ns(namespace)
|
|
35
|
+
key ? @data[namespace][key] : @data[namespace]
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
# Deletes all data from a namespace
|
|
39
39
|
#
|
|
40
|
-
# @param
|
|
40
|
+
# @param namespace [String] a namespace
|
|
41
41
|
|
|
42
|
-
def clear_ns(
|
|
43
|
-
init_ns(
|
|
42
|
+
def clear_ns(namespace)
|
|
43
|
+
init_ns(namespace)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
# Deletes all namespaces with data
|
|
@@ -53,17 +53,18 @@ module Howitzer
|
|
|
53
53
|
|
|
54
54
|
private
|
|
55
55
|
|
|
56
|
-
def check_ns(
|
|
57
|
-
raise Howitzer::NoDataError, 'Data storage namespace can not be empty' unless
|
|
58
|
-
|
|
56
|
+
def check_ns(namespace)
|
|
57
|
+
raise Howitzer::NoDataError, 'Data storage namespace can not be empty' unless namespace
|
|
58
|
+
|
|
59
|
+
init_ns(namespace) if ns_absent?(namespace)
|
|
59
60
|
end
|
|
60
61
|
|
|
61
|
-
def ns_absent?(
|
|
62
|
-
!@data.key?(
|
|
62
|
+
def ns_absent?(namespace)
|
|
63
|
+
!@data.key?(namespace)
|
|
63
64
|
end
|
|
64
65
|
|
|
65
|
-
def init_ns(
|
|
66
|
-
@data[
|
|
66
|
+
def init_ns(namespace)
|
|
67
|
+
@data[namespace] = {}
|
|
67
68
|
end
|
|
68
69
|
end
|
|
69
70
|
end
|
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
require 'rest-client'
|
|
2
2
|
require 'howitzer/exceptions'
|
|
3
3
|
|
|
4
|
+
# There is an issue with supporting Ruby 3 by Selenium Webdriver 3.x version
|
|
5
|
+
# https://github.com/SeleniumHQ/selenium/issues/9001
|
|
6
|
+
# Migration to Selenium Webdriver 4 is planned when it will be released without alfa, beta stages.
|
|
7
|
+
# :nocov:
|
|
8
|
+
if Gem::Requirement.new('>=3').satisfied_by?(Gem::Version.new(RUBY_VERSION)) &&
|
|
9
|
+
Gem::Requirement.new(['>=3', '<4']).satisfied_by?(Gem::Version.new(Selenium::WebDriver::VERSION))
|
|
10
|
+
module Selenium
|
|
11
|
+
module WebDriver
|
|
12
|
+
module Remote
|
|
13
|
+
class Bridge # rubocop:disable Style/Documentation
|
|
14
|
+
class << self
|
|
15
|
+
alias original_handshake handshake
|
|
16
|
+
|
|
17
|
+
def handshake(opts = {})
|
|
18
|
+
original_handshake(**opts)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
# :nocov:
|
|
27
|
+
|
|
4
28
|
module Howitzer
|
|
5
29
|
# This module holds capybara helpers methods
|
|
6
30
|
module CapybaraHelpers
|
|
7
|
-
CHECK_YOUR_SETTINGS_MSG = 'Please check your settings'.freeze
|
|
8
|
-
HOWITZER_KNOWN_BROWSERS = [
|
|
31
|
+
CHECK_YOUR_SETTINGS_MSG = 'Please check your settings'.freeze # :nodoc:
|
|
32
|
+
HOWITZER_KNOWN_BROWSERS = [ # :nodoc:
|
|
9
33
|
CLOUD_BROWSERS = [
|
|
10
34
|
SAUCE = :sauce,
|
|
11
35
|
TESTINGBOT = :testingbot,
|
|
@@ -14,11 +38,9 @@ module Howitzer
|
|
|
14
38
|
].freeze,
|
|
15
39
|
LOCAL_BROWSERS = [
|
|
16
40
|
HEADLESS_CHROME = :headless_chrome,
|
|
17
|
-
|
|
18
|
-
POLTERGEIST = :poltergeist,
|
|
41
|
+
HEADLESS_FIREFOX = :headless_firefox,
|
|
19
42
|
SELENIUM = :selenium,
|
|
20
|
-
SELENIUM_GRID = :selenium_grid
|
|
21
|
-
WEBKIT = :webkit
|
|
43
|
+
SELENIUM_GRID = :selenium_grid
|
|
22
44
|
].freeze
|
|
23
45
|
].freeze
|
|
24
46
|
|
|
@@ -51,7 +73,7 @@ module Howitzer
|
|
|
51
73
|
# @raise [SelBrowserNotSpecifiedError] if selenium driver and missing browser name
|
|
52
74
|
|
|
53
75
|
def chrome_browser?
|
|
54
|
-
browser?
|
|
76
|
+
browser? :chrome
|
|
55
77
|
end
|
|
56
78
|
|
|
57
79
|
# @return [Boolean] whether or not current browser is Safari.
|
|
@@ -110,6 +132,21 @@ module Howitzer
|
|
|
110
132
|
}
|
|
111
133
|
end
|
|
112
134
|
|
|
135
|
+
# @return [Hash] selenium W3C capabilities required for a cloud driver
|
|
136
|
+
|
|
137
|
+
def required_w3c_cloud_caps
|
|
138
|
+
{
|
|
139
|
+
browserName: Howitzer.cloud_browser_name,
|
|
140
|
+
browserVersion: Howitzer.cloud_browser_version
|
|
141
|
+
}
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @return [Boolean] whether or not Selenium is W3C compatible.
|
|
145
|
+
|
|
146
|
+
def w3c_selenium?
|
|
147
|
+
Gem::Requirement.new('>=4').satisfied_by?(Gem::Version.new(Selenium::WebDriver::VERSION))
|
|
148
|
+
end
|
|
149
|
+
|
|
113
150
|
# Buids selenium driver for a cloud service
|
|
114
151
|
# @param app [<Rack>] a rack application that this server will contain
|
|
115
152
|
# @param caps [Hash] remote capabilities
|
|
@@ -120,14 +157,14 @@ module Howitzer
|
|
|
120
157
|
http_client = ::Selenium::WebDriver::Remote::Http::Default.new
|
|
121
158
|
http_client.read_timeout = Howitzer.cloud_http_idle_timeout
|
|
122
159
|
http_client.open_timeout = Howitzer.cloud_http_idle_timeout
|
|
123
|
-
|
|
124
160
|
options = {
|
|
125
161
|
url: url,
|
|
126
|
-
desired_capabilities: ::Selenium::WebDriver::Remote::Capabilities.new(caps),
|
|
127
162
|
http_client: http_client,
|
|
128
163
|
browser: :remote
|
|
129
164
|
}
|
|
130
|
-
|
|
165
|
+
options[w3c_selenium? ? :capabilities : :desired_capabilities] =
|
|
166
|
+
::Selenium::WebDriver::Remote::Capabilities.new(caps)
|
|
167
|
+
driver = Capybara::Selenium::Driver.new(app, **options)
|
|
131
168
|
driver.browser.file_detector = remote_file_detector
|
|
132
169
|
driver
|
|
133
170
|
end
|
|
@@ -155,13 +192,13 @@ module Howitzer
|
|
|
155
192
|
unless Howitzer.cloud_browser_name.nil?
|
|
156
193
|
return browser_aliases.include?(Howitzer.cloud_browser_name.to_s.downcase.to_sym)
|
|
157
194
|
end
|
|
195
|
+
|
|
158
196
|
raise Howitzer::CloudBrowserNotSpecifiedError, CHECK_YOUR_SETTINGS_MSG
|
|
159
197
|
end
|
|
160
198
|
|
|
161
199
|
def selenium_browser?(*browser_aliases)
|
|
162
|
-
unless Howitzer.selenium_browser.nil?
|
|
163
|
-
|
|
164
|
-
end
|
|
200
|
+
return browser_aliases.include?(Howitzer.selenium_browser.to_s.to_sym) unless Howitzer.selenium_browser.nil?
|
|
201
|
+
|
|
165
202
|
raise Howitzer::SelBrowserNotSpecifiedError, CHECK_YOUR_SETTINGS_MSG
|
|
166
203
|
end
|
|
167
204
|
|
|
@@ -169,6 +206,14 @@ module Howitzer
|
|
|
169
206
|
Howitzer.driver.to_sym == SELENIUM
|
|
170
207
|
end
|
|
171
208
|
|
|
209
|
+
def headless_chrome_driver?
|
|
210
|
+
Howitzer.driver.to_sym == HEADLESS_CHROME
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def headless_firefox_driver?
|
|
214
|
+
Howitzer.driver.to_sym == HEADLESS_FIREFOX
|
|
215
|
+
end
|
|
216
|
+
|
|
172
217
|
def selenium_grid_driver?
|
|
173
218
|
Howitzer.driver.to_sym == SELENIUM_GRID
|
|
174
219
|
end
|
|
@@ -191,7 +236,7 @@ module Howitzer
|
|
|
191
236
|
end
|
|
192
237
|
|
|
193
238
|
def update_sauce_job_status(json_data = {})
|
|
194
|
-
host = "
|
|
239
|
+
host = "https://#{Howitzer.cloud_auth_login}:#{Howitzer.cloud_auth_pass}@saucelabs.com"
|
|
195
240
|
path = "/rest/v1/#{Howitzer.cloud_auth_login}/jobs/#{session_id}"
|
|
196
241
|
url = "#{host}#{path}"
|
|
197
242
|
::RestClient.put url, json_data.to_json, content_type: :json, accept: :json
|
data/lib/howitzer/email.rb
CHANGED
|
@@ -12,6 +12,7 @@ module Howitzer
|
|
|
12
12
|
|
|
13
13
|
def self.adapter
|
|
14
14
|
return @adapter if @adapter
|
|
15
|
+
|
|
15
16
|
self.adapter = Howitzer.mail_adapter.to_sym
|
|
16
17
|
@adapter
|
|
17
18
|
end
|
|
@@ -78,8 +79,8 @@ module Howitzer
|
|
|
78
79
|
def self.find_by_recipient(recipient, params = {})
|
|
79
80
|
if defined?(subject_value).nil? || subject_value.nil?
|
|
80
81
|
raise Howitzer::NoEmailSubjectError, "Please specify email subject. For example:\n" \
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
"class SomeEmail < Howitzer::Email\n " \
|
|
83
|
+
"subject ‘some subject text’\nend"
|
|
83
84
|
end
|
|
84
85
|
new(adapter.find(recipient, expand_subject(params), wait: wait_time_value))
|
|
85
86
|
end
|
data/lib/howitzer/exceptions.rb
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
# This module holds all custom howitzer exceptions
|
|
2
2
|
module Howitzer
|
|
3
|
-
CommunicationError = Class.new(StandardError)
|
|
4
|
-
ParseError = Class.new(StandardError)
|
|
5
|
-
InvalidApiKeyError = Class.new(StandardError)
|
|
6
|
-
BadElementParamsError = Class.new(StandardError)
|
|
7
|
-
NoValidationError = Class.new(StandardError)
|
|
8
|
-
UnknownValidationError = Class.new(StandardError)
|
|
9
|
-
EmailNotFoundError = Class.new(StandardError)
|
|
10
|
-
NoAttachmentsError = Class.new(StandardError)
|
|
11
|
-
DriverNotSpecifiedError = Class.new(StandardError)
|
|
12
|
-
UnknownDriverError = Class.new(StandardError)
|
|
13
|
-
CloudBrowserNotSpecifiedError = Class.new(StandardError)
|
|
14
|
-
SelBrowserNotSpecifiedError = Class.new(StandardError)
|
|
15
|
-
UnknownBrowserError = Class.new(StandardError)
|
|
16
|
-
IncorrectPageError = Class.new(StandardError)
|
|
17
|
-
AmbiguousPageMatchingError = Class.new(StandardError)
|
|
18
|
-
NoMailAdapterError = Class.new(StandardError)
|
|
19
|
-
NoPathForPageError = Class.new(StandardError)
|
|
20
|
-
NoEmailSubjectError = Class.new(StandardError)
|
|
21
|
-
NoDataError = Class.new(StandardError)
|
|
22
|
-
UndefinedElementError = Class.new(StandardError)
|
|
23
|
-
UndefinedSexySettingError = Class.new(StandardError)
|
|
3
|
+
CommunicationError = Class.new(StandardError) # :nodoc:
|
|
4
|
+
ParseError = Class.new(StandardError) # :nodoc:
|
|
5
|
+
InvalidApiKeyError = Class.new(StandardError) # :nodoc:
|
|
6
|
+
BadElementParamsError = Class.new(StandardError) # :nodoc:
|
|
7
|
+
NoValidationError = Class.new(StandardError) # :nodoc:
|
|
8
|
+
UnknownValidationError = Class.new(StandardError) # :nodoc:
|
|
9
|
+
EmailNotFoundError = Class.new(StandardError) # :nodoc:
|
|
10
|
+
NoAttachmentsError = Class.new(StandardError) # :nodoc:
|
|
11
|
+
DriverNotSpecifiedError = Class.new(StandardError) # :nodoc:
|
|
12
|
+
UnknownDriverError = Class.new(StandardError) # :nodoc:
|
|
13
|
+
CloudBrowserNotSpecifiedError = Class.new(StandardError) # :nodoc:
|
|
14
|
+
SelBrowserNotSpecifiedError = Class.new(StandardError) # :nodoc:
|
|
15
|
+
UnknownBrowserError = Class.new(StandardError) # :nodoc:
|
|
16
|
+
IncorrectPageError = Class.new(StandardError) # :nodoc:
|
|
17
|
+
AmbiguousPageMatchingError = Class.new(StandardError) # :nodoc:
|
|
18
|
+
NoMailAdapterError = Class.new(StandardError) # :nodoc:
|
|
19
|
+
NoPathForPageError = Class.new(StandardError) # :nodoc:
|
|
20
|
+
NoEmailSubjectError = Class.new(StandardError) # :nodoc:
|
|
21
|
+
NoDataError = Class.new(StandardError) # :nodoc:
|
|
22
|
+
UndefinedElementError = Class.new(StandardError) # :nodoc:
|
|
23
|
+
UndefinedSexySettingError = Class.new(StandardError) # :nodoc:
|
|
24
24
|
end
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
require 'gmail'
|
|
2
|
-
|
|
3
1
|
module Howitzer
|
|
4
2
|
module GmailApi
|
|
5
3
|
# A GmailApi::Client object is used to communicate with the Gmail API.
|
|
6
4
|
class Client
|
|
5
|
+
def self.load_gmail_gem!
|
|
6
|
+
require 'gmail'
|
|
7
|
+
rescue LoadError
|
|
8
|
+
raise LoadError, "Unable to load `gmail` library, please add following code to your Gemfile:\n\ngem 'gmail'"
|
|
9
|
+
end
|
|
10
|
+
load_gmail_gem!
|
|
11
|
+
|
|
7
12
|
def initialize
|
|
8
|
-
|
|
13
|
+
self.client = Gmail.connect(Howitzer.gmail_login, Howitzer.gmail_password)
|
|
9
14
|
end
|
|
10
15
|
|
|
11
16
|
# Finds message according to given parameters
|
|
@@ -15,8 +20,12 @@ module Howitzer
|
|
|
15
20
|
# @return [Gmail::Message] gmail message object
|
|
16
21
|
|
|
17
22
|
def find_message(recipient, subject)
|
|
18
|
-
|
|
23
|
+
client.inbox.emails(to: recipient, subject: subject).last
|
|
19
24
|
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_accessor :client
|
|
20
29
|
end
|
|
21
30
|
end
|
|
22
31
|
end
|
data/lib/howitzer/log.rb
CHANGED
|
@@ -80,13 +80,13 @@ module Howitzer
|
|
|
80
80
|
Logger['ruby_log'].trace = true
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
# :nocov:
|
|
84
84
|
def log_without_formatting
|
|
85
85
|
self.base_formatter = blank_formatter
|
|
86
86
|
yield
|
|
87
87
|
self.base_formatter = default_formatter
|
|
88
88
|
end
|
|
89
|
-
|
|
89
|
+
# :nocov:
|
|
90
90
|
|
|
91
91
|
def console_log
|
|
92
92
|
StdoutOutputter.new(:console).tap { |o| o.only_at(INFO, DEBUG, WARN) }
|
|
@@ -96,13 +96,13 @@ module Howitzer
|
|
|
96
96
|
StderrOutputter.new(:error, 'level' => ERROR)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
# :nocov:
|
|
100
100
|
def blank_formatter
|
|
101
101
|
PatternFormatter.new(pattern: '%m')
|
|
102
102
|
end
|
|
103
|
-
|
|
103
|
+
# :nocov:
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
# :nocov:
|
|
106
106
|
def default_formatter
|
|
107
107
|
params = if Howitzer.hide_datetime_from_log
|
|
108
108
|
{ pattern: '[%l] %m' }
|
|
@@ -111,7 +111,7 @@ module Howitzer
|
|
|
111
111
|
end
|
|
112
112
|
PatternFormatter.new(params)
|
|
113
113
|
end
|
|
114
|
-
|
|
114
|
+
# :nocov:
|
|
115
115
|
|
|
116
116
|
def base_formatter=(formatter)
|
|
117
117
|
@logger.outputters.each { |outputter| outputter.formatter = formatter }
|
|
@@ -16,6 +16,7 @@ module Howitzer
|
|
|
16
16
|
message = {}
|
|
17
17
|
retryable(find_retry_params(wait)) { message = get_message(recipient, subject) }
|
|
18
18
|
return new(message) if message.present?
|
|
19
|
+
|
|
19
20
|
raise Howitzer::EmailNotFoundError,
|
|
20
21
|
"Message with subject '#{subject}' for recipient '#{recipient}' was not found."
|
|
21
22
|
end
|
|
@@ -68,12 +69,14 @@ module Howitzer
|
|
|
68
69
|
def mime_part!
|
|
69
70
|
files = mime_part
|
|
70
71
|
return files if files.present?
|
|
72
|
+
|
|
71
73
|
raise Howitzer::NoAttachmentsError, 'No attachments were found.'
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
def self.get_message(recipient, subject)
|
|
75
77
|
message = Howitzer::GmailApi::Client.new.find_message(recipient, subject)
|
|
76
78
|
raise Howitzer::EmailNotFoundError if message.blank?
|
|
79
|
+
|
|
77
80
|
message
|
|
78
81
|
end
|
|
79
82
|
private_class_method :get_message
|
|
@@ -17,6 +17,7 @@ module Howitzer
|
|
|
17
17
|
message = {}
|
|
18
18
|
retryable(find_retry_params(wait)) { message = retrieve_message(recipient, subject) }
|
|
19
19
|
return new(message) if message.present?
|
|
20
|
+
|
|
20
21
|
raise Howitzer::EmailNotFoundError,
|
|
21
22
|
"Message with subject '#{subject}' for recipient '#{recipient}' was not found."
|
|
22
23
|
end
|
|
@@ -75,6 +76,7 @@ module Howitzer
|
|
|
75
76
|
def mime_part!
|
|
76
77
|
files = mime_part
|
|
77
78
|
return files if files.present?
|
|
79
|
+
|
|
78
80
|
raise Howitzer::NoAttachmentsError, 'No attachments were found.'
|
|
79
81
|
end
|
|
80
82
|
|
|
@@ -87,7 +89,7 @@ module Howitzer
|
|
|
87
89
|
|
|
88
90
|
def self.event_by(recipient, subject)
|
|
89
91
|
events.to_h['items'].find do |hash|
|
|
90
|
-
hash['message']['recipients'].first == recipient && hash['message']['headers']['subject']
|
|
92
|
+
hash['message']['recipients'].first == recipient && subject === hash['message']['headers']['subject']
|
|
91
93
|
end
|
|
92
94
|
end
|
|
93
95
|
private_class_method :event_by
|
|
@@ -16,6 +16,7 @@ module Howitzer
|
|
|
16
16
|
message = {}
|
|
17
17
|
retryable(find_retry_params(wait)) { message = retrieve_message(recipient, subject) }
|
|
18
18
|
return new(message) if message.present?
|
|
19
|
+
|
|
19
20
|
raise Howitzer::EmailNotFoundError,
|
|
20
21
|
"Message with subject '#{subject}' for recipient '#{recipient}' was not found."
|
|
21
22
|
end
|
|
@@ -74,6 +75,7 @@ module Howitzer
|
|
|
74
75
|
def mime_part!
|
|
75
76
|
files = mime_part
|
|
76
77
|
return files if files.present?
|
|
78
|
+
|
|
77
79
|
raise Howitzer::NoAttachmentsError, 'No attachments were found.'
|
|
78
80
|
end
|
|
79
81
|
|
|
@@ -91,6 +93,7 @@ module Howitzer
|
|
|
91
93
|
def self.retrieve_message(recipient, subject)
|
|
92
94
|
message = Howitzer::MailtrapApi::Client.new.find_message(recipient, subject)
|
|
93
95
|
raise Howitzer::EmailNotFoundError, 'Message not received yet, retry...' unless message
|
|
96
|
+
|
|
94
97
|
message
|
|
95
98
|
end
|
|
96
99
|
private_class_method :retrieve_message
|
|
@@ -9,9 +9,10 @@ module Howitzer
|
|
|
9
9
|
# wrapper around RestClient so you don't have to worry about the HTTP aspect
|
|
10
10
|
# of communicating with Mailgun API.
|
|
11
11
|
class Client
|
|
12
|
-
USER_AGENT = 'mailgun-sdk-ruby'.freeze
|
|
12
|
+
USER_AGENT = 'mailgun-sdk-ruby'.freeze # :nodoc:
|
|
13
13
|
attr_reader :api_user, :api_key, :api_host, :api_version, :ssl
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
def initialize(api_user: 'api', api_key: 'key', api_host: 'api.mailgun.net', api_version: 'v3', ssl: true)
|
|
15
16
|
@api_user = api_user
|
|
16
17
|
@api_key = api_key
|
|
17
18
|
@api_host = api_host
|
|
@@ -5,7 +5,7 @@ module Howitzer
|
|
|
5
5
|
module MailtrapApi
|
|
6
6
|
# A Mailtrap::Client object is used to communicate with the Mailtrap API.
|
|
7
7
|
class Client
|
|
8
|
-
BASE_URL = "https://mailtrap.io/api/v1/inboxes/#{Howitzer.mailtrap_inbox_id}".freeze
|
|
8
|
+
BASE_URL = "https://mailtrap.io/api/v1/inboxes/#{Howitzer.mailtrap_inbox_id}".freeze # :nodoc:
|
|
9
9
|
|
|
10
10
|
def initialize
|
|
11
11
|
@api_token = Howitzer.mailtrap_api_token
|