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.
Files changed (129) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +44 -1
  3. data/LICENSE +1 -1
  4. data/README.md +19 -17
  5. data/generators/base_generator.rb +5 -7
  6. data/generators/config/config_generator.rb +3 -4
  7. data/generators/config/templates/boot.rb +2 -2
  8. data/generators/config/templates/capybara.rb +4 -5
  9. data/generators/config/templates/default.yml +21 -11
  10. data/generators/config/templates/drivers/browserstack.rb +31 -4
  11. data/generators/config/templates/drivers/crossbrowsertesting.rb +9 -11
  12. data/generators/config/templates/drivers/headless_chrome.rb +1 -1
  13. data/generators/config/templates/drivers/headless_firefox.rb +23 -0
  14. data/generators/config/templates/drivers/lambdatest.rb +30 -0
  15. data/generators/config/templates/drivers/sauce.rb +30 -2
  16. data/generators/config/templates/drivers/selenium.rb +1 -1
  17. data/generators/config/templates/drivers/selenium_grid.rb +3 -3
  18. data/generators/config/templates/drivers/testingbot.rb +29 -2
  19. data/generators/cucumber/templates/cuke_sniffer.rake +2 -2
  20. data/generators/cucumber/templates/env.rb +8 -0
  21. data/generators/cucumber/templates/hooks.rb +9 -3
  22. data/generators/cucumber/templates/transformers.rb +1 -1
  23. data/generators/prerequisites/templates/factory_bot.rb +2 -1
  24. data/generators/root/root_generator.rb +1 -1
  25. data/generators/root/templates/Gemfile.erb +4 -10
  26. data/generators/rspec/templates/spec_helper.rb +6 -5
  27. data/generators/turnip/templates/spec_helper.rb +6 -5
  28. data/generators/web/templates/example_page.rb +1 -1
  29. data/lib/howitzer/cache.rb +20 -19
  30. data/lib/howitzer/capybara_helpers.rb +59 -14
  31. data/lib/howitzer/email.rb +3 -2
  32. data/lib/howitzer/exceptions.rb +21 -21
  33. data/lib/howitzer/gmail_api/client.rb +13 -4
  34. data/lib/howitzer/log.rb +6 -6
  35. data/lib/howitzer/mail_adapters/gmail.rb +3 -0
  36. data/lib/howitzer/mail_adapters/mailgun.rb +3 -1
  37. data/lib/howitzer/mail_adapters/mailtrap.rb +3 -0
  38. data/lib/howitzer/mailgun_api/client.rb +3 -2
  39. data/lib/howitzer/mailgun_api/connector.rb +1 -0
  40. data/lib/howitzer/mailgun_api/response.rb +1 -2
  41. data/lib/howitzer/mailtrap_api/client.rb +1 -1
  42. data/lib/howitzer/meta/actions.rb +35 -0
  43. data/lib/howitzer/meta/element.rb +40 -0
  44. data/lib/howitzer/meta/entry.rb +62 -0
  45. data/lib/howitzer/meta/iframe.rb +41 -0
  46. data/lib/howitzer/meta/section.rb +30 -0
  47. data/lib/howitzer/meta.rb +11 -0
  48. data/lib/howitzer/utils/string_extensions.rb +6 -2
  49. data/lib/howitzer/version.rb +1 -1
  50. data/lib/howitzer/web/base_section.rb +1 -1
  51. data/lib/howitzer/web/capybara_context_holder.rb +1 -0
  52. data/lib/howitzer/web/capybara_methods_proxy.rb +15 -6
  53. data/lib/howitzer/web/element_dsl.rb +104 -44
  54. data/lib/howitzer/web/iframe_dsl.rb +4 -2
  55. data/lib/howitzer/web/page.rb +14 -14
  56. data/lib/howitzer/web/page_dsl.rb +18 -6
  57. data/lib/howitzer/web/page_validator.rb +27 -26
  58. data/lib/howitzer/web/section.rb +13 -2
  59. data/lib/howitzer/web/section_dsl.rb +65 -30
  60. data/lib/howitzer.rb +40 -0
  61. metadata +31 -157
  62. data/.coveralls.yml +0 -1
  63. data/.gitignore +0 -14
  64. data/.rspec +0 -3
  65. data/.rubocop.yml +0 -51
  66. data/.ruby-gemset +0 -1
  67. data/.travis.yml +0 -7
  68. data/Gemfile +0 -14
  69. data/ISSUE_TEMPLATE.md +0 -16
  70. data/MAINTENANCE.md +0 -32
  71. data/Rakefile +0 -38
  72. data/features/cli_help.feature +0 -31
  73. data/features/cli_new.feature +0 -389
  74. data/features/cli_unknown.feature +0 -17
  75. data/features/cli_update.feature +0 -218
  76. data/features/cli_version.feature +0 -14
  77. data/features/step_definitions/common_steps.rb +0 -34
  78. data/features/support/env.rb +0 -1
  79. data/generators/config/templates/drivers/phantomjs.rb +0 -19
  80. data/generators/config/templates/drivers/poltergeist.rb +0 -11
  81. data/generators/config/templates/drivers/webkit.rb +0 -6
  82. data/generators/root/templates/.gitignore +0 -21
  83. data/generators/root/templates/.rubocop.yml +0 -35
  84. data/generators/turnip/templates/.rspec +0 -1
  85. data/howitzer.gemspec +0 -39
  86. data/lib/howitzer/mail_adapters/debugmail.rb +0 -0
  87. data/spec/config/custom.yml +0 -9
  88. data/spec/spec_helper.rb +0 -73
  89. data/spec/support/generator_helper.rb +0 -21
  90. data/spec/support/logger_helper.rb +0 -13
  91. data/spec/support/shared_examples/capybara_context_holder.rb +0 -33
  92. data/spec/support/shared_examples/capybara_methods_proxy.rb +0 -94
  93. data/spec/support/shared_examples/dynamic_section_methods.rb +0 -35
  94. data/spec/support/shared_examples/element_dsl.rb +0 -242
  95. data/spec/unit/generators/base_generator_spec.rb +0 -283
  96. data/spec/unit/generators/config_generator_spec.rb +0 -59
  97. data/spec/unit/generators/cucumber_generator_spec.rb +0 -62
  98. data/spec/unit/generators/emails_generator_spec.rb +0 -35
  99. data/spec/unit/generators/prerequisites_generator_spec.rb +0 -53
  100. data/spec/unit/generators/root_generator_spec.rb +0 -75
  101. data/spec/unit/generators/rspec_generator_spec.rb +0 -36
  102. data/spec/unit/generators/tasks_generator_spec.rb +0 -31
  103. data/spec/unit/generators/turnip_generator_spec.rb +0 -52
  104. data/spec/unit/generators/web_generator_spec.rb +0 -52
  105. data/spec/unit/lib/cache_spec.rb +0 -85
  106. data/spec/unit/lib/capybara_helpers_spec.rb +0 -697
  107. data/spec/unit/lib/email_spec.rb +0 -186
  108. data/spec/unit/lib/gmail_api/client_spec.rb +0 -26
  109. data/spec/unit/lib/howitzer_spec.rb +0 -69
  110. data/spec/unit/lib/init_spec.rb +0 -2
  111. data/spec/unit/lib/log_spec.rb +0 -122
  112. data/spec/unit/lib/mail_adapters/abstract_spec.rb +0 -62
  113. data/spec/unit/lib/mail_adapters/gmail_spec.rb +0 -128
  114. data/spec/unit/lib/mail_adapters/mailgun_spec.rb +0 -158
  115. data/spec/unit/lib/mail_adapters/mailtrap_spec.rb +0 -130
  116. data/spec/unit/lib/mailgun_api/client_spec.rb +0 -80
  117. data/spec/unit/lib/mailgun_api/connector_spec.rb +0 -54
  118. data/spec/unit/lib/mailgun_api/response_spec.rb +0 -28
  119. data/spec/unit/lib/mailtrap_api/client_spec.rb +0 -67
  120. data/spec/unit/lib/utils/string_extensions_spec.rb +0 -77
  121. data/spec/unit/lib/web/base_section_spec.rb +0 -43
  122. data/spec/unit/lib/web/element_dsl_spec.rb +0 -22
  123. data/spec/unit/lib/web/iframe_dsl_spec.rb +0 -203
  124. data/spec/unit/lib/web/page_dsl_spec.rb +0 -74
  125. data/spec/unit/lib/web/page_spec.rb +0 -378
  126. data/spec/unit/lib/web/page_validator_spec.rb +0 -276
  127. data/spec/unit/lib/web/section_dsl_spec.rb +0 -165
  128. data/spec/unit/lib/web/section_spec.rb +0 -63
  129. data/spec/unit/version_spec.rb +0 -8
@@ -1,6 +1,12 @@
1
1
  Before do |scenario|
2
2
  Capybara.use_default_driver
3
- Howitzer::Log.print_feature_name(scenario.feature.name)
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
- " URL: #{CapybaraHelpers.cloud_resource_path(:video)}"
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 http://www.rubydoc.info/gems/factory_bot/file/GETTING_STARTED.md
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', '~>3.0'\n" if 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(:each) do
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(:each) do
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
- " URL: #{CapybaraHelpers.cloud_resource_path(:video)}"
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(:each) do
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(:each) do
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
- " URL: #{CapybaraHelpers.cloud_resource_path(:video)}"
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));")
@@ -1,7 +1,7 @@
1
1
  # This class is example of web page
2
2
  class ExamplePage < Howitzer::Web::Page
3
3
  path '/'
4
- validate :url, %r{\A(?:.*?:\/\/)?[^\/]*\/?\z}
4
+ validate :url, %r{\A(?:.*?://)?[^/]*/?\z}
5
5
 
6
6
  section :menu
7
7
 
@@ -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 #:nodoc:
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 ns [String] a namespace
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(ns, key, value)
21
- check_ns(ns)
22
- @data[ns][key] = value
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 ns [String] a namespace
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(ns, key = nil)
34
- check_ns(ns)
35
- key ? @data[ns][key] : @data[ns]
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 ns [String] a namespace
40
+ # @param namespace [String] a namespace
41
41
 
42
- def clear_ns(ns)
43
- init_ns(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(ns)
57
- raise Howitzer::NoDataError, 'Data storage namespace can not be empty' unless ns
58
- init_ns(ns) if ns_absent?(ns)
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?(ns)
62
- !@data.key?(ns)
62
+ def ns_absent?(namespace)
63
+ !@data.key?(namespace)
63
64
  end
64
65
 
65
- def init_ns(ns)
66
- @data[ns] = {}
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 #:nodoc:
8
- HOWITZER_KNOWN_BROWSERS = [ #:nodoc:
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
- PHANTOMJS = :phantomjs,
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?(:chrome) || Howitzer.driver == HEADLESS_CHROME.to_s
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
- driver = Capybara::Selenium::Driver.new(app, options)
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
- return browser_aliases.include?(Howitzer.selenium_browser.to_s.to_sym)
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 = "http://#{Howitzer.cloud_auth_login}:#{Howitzer.cloud_auth_pass}@saucelabs.com"
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
@@ -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
- "class SomeEmail < Howitzer::Email\n" \
82
- " subject ‘some subject text’\nend"
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
@@ -1,24 +1,24 @@
1
1
  # This module holds all custom howitzer exceptions
2
2
  module Howitzer
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:
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
- @client = Gmail.connect(Howitzer.gmail_login, Howitzer.gmail_password)
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
- @client.inbox.emails(to: recipient, subject: subject).last
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
- #:nocov:
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
- #:nocov:
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
- #:nocov:
99
+ # :nocov:
100
100
  def blank_formatter
101
101
  PatternFormatter.new(pattern: '%m')
102
102
  end
103
- #:nocov:
103
+ # :nocov:
104
104
 
105
- #:nocov:
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
- #:nocov:
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'] == 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 #:nodoc:
12
+ USER_AGENT = 'mailgun-sdk-ruby'.freeze # :nodoc:
13
13
  attr_reader :api_user, :api_key, :api_host, :api_version, :ssl
14
- def initialize(api_user: 'api', api_key:, api_host: 'api.mailgun.net', api_version: 'v3', ssl: true)
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
@@ -23,6 +23,7 @@ module Howitzer
23
23
  def client(api_key = Howitzer.mailgun_key)
24
24
  check_api_key(api_key)
25
25
  return @client if @api_key == api_key && @api_key
26
+
26
27
  @api_key = api_key
27
28
  @client = Client.new(api_key: @api_key)
28
29
  end
@@ -6,8 +6,7 @@ module Howitzer
6
6
  # by the Client request. The Response object supports deserialization of
7
7
  # the JSON result.
8
8
  class Response
9
- attr_accessor :body
10
- attr_accessor :code
9
+ attr_accessor :body, :code
11
10
 
12
11
  def initialize(response)
13
12
  @body = response.body
@@ -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 #:nodoc:
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