howitzer 2.2.0 → 2.5.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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -1
  3. data/LICENSE +1 -1
  4. data/README.md +16 -17
  5. data/generators/base_generator.rb +4 -6
  6. data/generators/config/config_generator.rb +2 -4
  7. data/generators/config/templates/boot.rb +1 -1
  8. data/generators/config/templates/capybara.rb +3 -5
  9. data/generators/config/templates/default.yml +19 -20
  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 +1 -1
  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/env.rb +1 -1
  20. data/generators/cucumber/templates/hooks.rb +9 -3
  21. data/generators/cucumber/templates/transformers.rb +1 -1
  22. data/generators/prerequisites/templates/factory_bot.rb +1 -1
  23. data/generators/root/templates/Gemfile.erb +4 -14
  24. data/generators/rspec/templates/spec_helper.rb +5 -5
  25. data/generators/turnip/templates/spec_helper.rb +5 -5
  26. data/generators/web/templates/example_page.rb +1 -1
  27. data/lib/howitzer/cache.rb +1 -1
  28. data/lib/howitzer/capybara_helpers.rb +46 -9
  29. data/lib/howitzer/email.rb +2 -2
  30. data/lib/howitzer/exceptions.rb +21 -21
  31. data/lib/howitzer/gmail_api/client.rb +13 -4
  32. data/lib/howitzer/log.rb +6 -6
  33. data/lib/howitzer/mail_adapters/mailgun.rb +1 -1
  34. data/lib/howitzer/mail_adapters/mailtrap.rb +3 -3
  35. data/lib/howitzer/mail_adapters/onesecmail.rb +80 -0
  36. data/lib/howitzer/mail_adapters/testmail.rb +102 -0
  37. data/lib/howitzer/mailgun_api/client.rb +3 -2
  38. data/lib/howitzer/mailgun_api/response.rb +1 -2
  39. data/lib/howitzer/mailtrap_api/client.rb +19 -1
  40. data/lib/howitzer/meta/actions.rb +13 -16
  41. data/lib/howitzer/meta/element.rb +12 -10
  42. data/lib/howitzer/onesecmail_api/client.rb +44 -0
  43. data/lib/howitzer/onesecmail_api.rb +7 -0
  44. data/lib/howitzer/testmail_api/client.rb +44 -0
  45. data/lib/howitzer/testmail_api.rb +7 -0
  46. data/lib/howitzer/utils/string_extensions.rb +6 -2
  47. data/lib/howitzer/version.rb +1 -1
  48. data/lib/howitzer/web/base_section.rb +1 -1
  49. data/lib/howitzer/web/capybara_methods_proxy.rb +11 -5
  50. data/lib/howitzer/web/element_dsl.rb +104 -45
  51. data/lib/howitzer/web/iframe_dsl.rb +2 -2
  52. data/lib/howitzer/web/page.rb +4 -14
  53. data/lib/howitzer/web/page_dsl.rb +15 -6
  54. data/lib/howitzer/web/page_validator.rb +25 -26
  55. data/lib/howitzer/web/section.rb +5 -2
  56. data/lib/howitzer/web/section_dsl.rb +64 -30
  57. data/lib/howitzer.rb +2 -2
  58. metadata +29 -165
  59. data/.coveralls.yml +0 -1
  60. data/.gitignore +0 -14
  61. data/.rspec +0 -3
  62. data/.rubocop.yml +0 -60
  63. data/.ruby-gemset +0 -1
  64. data/.travis.yml +0 -8
  65. data/Gemfile +0 -14
  66. data/ISSUE_TEMPLATE.md +0 -16
  67. data/MAINTENANCE.md +0 -32
  68. data/Rakefile +0 -38
  69. data/features/cli_help.feature +0 -31
  70. data/features/cli_new.feature +0 -393
  71. data/features/cli_unknown.feature +0 -17
  72. data/features/cli_update.feature +0 -223
  73. data/features/cli_version.feature +0 -14
  74. data/features/step_definitions/common_steps.rb +0 -34
  75. data/features/support/env.rb +0 -1
  76. data/generators/config/templates/drivers/appium.rb +0 -25
  77. data/generators/config/templates/drivers/poltergeist.rb +0 -11
  78. data/generators/config/templates/drivers/webkit.rb +0 -6
  79. data/generators/root/templates/.gitignore +0 -21
  80. data/generators/root/templates/.rubocop.yml.erb +0 -56
  81. data/generators/turnip/templates/.rspec +0 -1
  82. data/howitzer.gemspec +0 -39
  83. data/lib/howitzer/mail_adapters/debugmail.rb +0 -0
  84. data/spec/config/custom.yml +0 -9
  85. data/spec/spec_helper.rb +0 -73
  86. data/spec/support/generator_helper.rb +0 -21
  87. data/spec/support/logger_helper.rb +0 -13
  88. data/spec/support/shared_examples/capybara_context_holder.rb +0 -33
  89. data/spec/support/shared_examples/capybara_methods_proxy.rb +0 -94
  90. data/spec/support/shared_examples/dynamic_section_methods.rb +0 -35
  91. data/spec/support/shared_examples/element_dsl.rb +0 -242
  92. data/spec/support/shared_examples/meta_highlight_xpath.rb +0 -41
  93. data/spec/unit/generators/base_generator_spec.rb +0 -283
  94. data/spec/unit/generators/config_generator_spec.rb +0 -61
  95. data/spec/unit/generators/cucumber_generator_spec.rb +0 -62
  96. data/spec/unit/generators/emails_generator_spec.rb +0 -35
  97. data/spec/unit/generators/prerequisites_generator_spec.rb +0 -53
  98. data/spec/unit/generators/root_generator_spec.rb +0 -86
  99. data/spec/unit/generators/rspec_generator_spec.rb +0 -36
  100. data/spec/unit/generators/tasks_generator_spec.rb +0 -31
  101. data/spec/unit/generators/templates/cucumber_spec.rb +0 -97
  102. data/spec/unit/generators/templates/rspec_spec.rb +0 -88
  103. data/spec/unit/generators/templates/turnip_spec.rb +0 -98
  104. data/spec/unit/generators/turnip_generator_spec.rb +0 -52
  105. data/spec/unit/generators/web_generator_spec.rb +0 -52
  106. data/spec/unit/lib/cache_spec.rb +0 -85
  107. data/spec/unit/lib/capybara_helpers_spec.rb +0 -730
  108. data/spec/unit/lib/email_spec.rb +0 -186
  109. data/spec/unit/lib/gmail_api/client_spec.rb +0 -26
  110. data/spec/unit/lib/howitzer_spec.rb +0 -92
  111. data/spec/unit/lib/init_spec.rb +0 -2
  112. data/spec/unit/lib/log_spec.rb +0 -122
  113. data/spec/unit/lib/mail_adapters/abstract_spec.rb +0 -62
  114. data/spec/unit/lib/mail_adapters/gmail_spec.rb +0 -128
  115. data/spec/unit/lib/mail_adapters/mailgun_spec.rb +0 -158
  116. data/spec/unit/lib/mail_adapters/mailtrap_spec.rb +0 -130
  117. data/spec/unit/lib/mailgun_api/client_spec.rb +0 -80
  118. data/spec/unit/lib/mailgun_api/connector_spec.rb +0 -54
  119. data/spec/unit/lib/mailgun_api/response_spec.rb +0 -28
  120. data/spec/unit/lib/mailtrap_api/client_spec.rb +0 -67
  121. data/spec/unit/lib/meta/element_spec.rb +0 -59
  122. data/spec/unit/lib/meta/entry_spec.rb +0 -77
  123. data/spec/unit/lib/meta/iframe_spec.rb +0 -66
  124. data/spec/unit/lib/meta/section_spec.rb +0 -43
  125. data/spec/unit/lib/utils/string_extensions_spec.rb +0 -77
  126. data/spec/unit/lib/web/base_section_spec.rb +0 -43
  127. data/spec/unit/lib/web/element_dsl_spec.rb +0 -31
  128. data/spec/unit/lib/web/iframe_dsl_spec.rb +0 -203
  129. data/spec/unit/lib/web/page_dsl_spec.rb +0 -74
  130. data/spec/unit/lib/web/page_spec.rb +0 -385
  131. data/spec/unit/lib/web/page_validator_spec.rb +0 -276
  132. data/spec/unit/lib/web/section_dsl_spec.rb +0 -165
  133. data/spec/unit/lib/web/section_spec.rb +0 -70
  134. data/spec/unit/version_spec.rb +0 -8
@@ -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,18 +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 'appium' driver. Appium and Android SDK should be installed.
18
- # See https://appium.io/docs/en/about-appium/getting-started/
19
- # gem 'appium_capybara'
20
-
21
- # Uncomment it if you are going to use 'webkit' driver. QT library should be installed.
22
- # See https://github.com/thoughtbot/capybara-webkit/wiki/Installing-Qt-and-compiling-capybara-webkit
23
- #
24
- # gem 'capybara-webkit'
25
-
26
- # Uncomment it if you are going to use 'poltergeist' driver. PhantomJS should be installed.
27
- # See https://github.com/jnicklas/capybara#poltergeist
28
- # 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
@@ -17,7 +17,7 @@ RSpec.configure do |config|
17
17
  config.wait_timeout = Howitzer.rspec_wait_timeout
18
18
  config.order = Howitzer.test_order.presence || :defined
19
19
 
20
- config.before(:each) do
20
+ config.before do
21
21
  scenario_name =
22
22
  if RSpec.current_example.description.blank?
23
23
  RSpec.current_example.metadata[:full_description]
@@ -28,12 +28,12 @@ RSpec.configure do |config|
28
28
  @session_start = CapybaraHelpers.duration(Time.now.utc - Howitzer::Cache.extract(:cloud, :start_time))
29
29
  end
30
30
 
31
- config.after(:each) do
31
+ config.after do
32
32
  Howitzer::Cache.clear_all_ns
33
33
  if CapybaraHelpers.cloud_driver?
34
34
  session_end = CapybaraHelpers.duration(Time.now.utc - Howitzer::Cache.extract(:cloud, :start_time))
35
- Howitzer::Log.info "CLOUD VIDEO #{@session_start} - #{session_end}" \
36
- " URL: #{CapybaraHelpers.cloud_resource_path(:video)}"
35
+ Howitzer::Log.info "CLOUD VIDEO #{@session_start} - #{session_end} " \
36
+ "URL: #{CapybaraHelpers.cloud_resource_path(:video)}"
37
37
  elsif CapybaraHelpers.ie_browser?
38
38
  Howitzer::Log.info 'IE reset session'
39
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
@@ -16,7 +16,7 @@ RSpec.configure do |config|
16
16
  config.wait_timeout = Howitzer.rspec_wait_timeout
17
17
  config.order = Howitzer.test_order.presence || :defined
18
18
 
19
- config.before(:each) do
19
+ config.before do
20
20
  scenario_name =
21
21
  if RSpec.current_example.description.blank?
22
22
  RSpec.current_example.metadata[:full_description]
@@ -27,12 +27,12 @@ RSpec.configure do |config|
27
27
  @session_start = CapybaraHelpers.duration(Time.now.utc - Howitzer::Cache.extract(:cloud, :start_time))
28
28
  end
29
29
 
30
- config.after(:each) do
30
+ config.after do
31
31
  Howitzer::Cache.clear_all_ns
32
32
  if CapybaraHelpers.cloud_driver?
33
33
  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)}"
34
+ Howitzer::Log.info "CLOUD VIDEO #{@session_start} - #{session_end} " \
35
+ "URL: #{CapybaraHelpers.cloud_resource_path(:video)}"
36
36
  elsif CapybaraHelpers.ie_browser?
37
37
  Howitzer::Log.info 'IE reset session'
38
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
@@ -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,
@@ -15,10 +39,8 @@ module Howitzer
15
39
  LOCAL_BROWSERS = [
16
40
  HEADLESS_CHROME = :headless_chrome,
17
41
  HEADLESS_FIREFOX = :headless_firefox,
18
- POLTERGEIST = :poltergeist,
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
 
@@ -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
@@ -199,7 +236,7 @@ module Howitzer
199
236
  end
200
237
 
201
238
  def update_sauce_job_status(json_data = {})
202
- 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"
203
240
  path = "/rest/v1/#{Howitzer.cloud_auth_login}/jobs/#{session_id}"
204
241
  url = "#{host}#{path}"
205
242
  ::RestClient.put url, json_data.to_json, content_type: :json, accept: :json
@@ -79,8 +79,8 @@ module Howitzer
79
79
  def self.find_by_recipient(recipient, params = {})
80
80
  if defined?(subject_value).nil? || subject_value.nil?
81
81
  raise Howitzer::NoEmailSubjectError, "Please specify email subject. For example:\n" \
82
- "class SomeEmail < Howitzer::Email\n" \
83
- " subject ‘some subject text’\nend"
82
+ "class SomeEmail < Howitzer::Email\n " \
83
+ "subject ‘some subject text’\nend"
84
84
  end
85
85
  new(adapter.find(recipient, expand_subject(params), wait: wait_time_value))
86
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 }
@@ -89,7 +89,7 @@ module Howitzer
89
89
 
90
90
  def self.event_by(recipient, subject)
91
91
  events.to_h['items'].find do |hash|
92
- hash['message']['recipients'].first == recipient && hash['message']['headers']['subject'] == subject
92
+ hash['message']['recipients'].first == recipient && subject === hash['message']['headers']['subject']
93
93
  end
94
94
  end
95
95
  private_class_method :event_by
@@ -24,19 +24,19 @@ module Howitzer
24
24
  # @return [String] plain text body of the email message
25
25
 
26
26
  def plain_text_body
27
- message['text_body']
27
+ Howitzer::MailtrapApi::Client.new.get_txt_body(message)
28
28
  end
29
29
 
30
30
  # @return [String] html body of the email message
31
31
 
32
32
  def html_body
33
- message['html_body']
33
+ Howitzer::MailtrapApi::Client.new.get_html_body(message)
34
34
  end
35
35
 
36
36
  # @return [String] stripped text
37
37
 
38
38
  def text
39
- message['text_body']
39
+ Howitzer::MailtrapApi::Client.new.get_raw_body(message)
40
40
  end
41
41
 
42
42
  # @return [String] an email address specified in `From` field
@@ -0,0 +1,80 @@
1
+ require 'howitzer/exceptions'
2
+ require 'howitzer/mail_adapters/abstract'
3
+ require 'howitzer/onesecmail_api/client'
4
+
5
+ module Howitzer
6
+ module MailAdapters
7
+ # This class represents 1secMail mail adapter
8
+ class Onesecmail < Abstract
9
+ # Finds an email in storage
10
+ # @param recipient [String] an email
11
+ # @param subject [String]
12
+ # @param wait [Integer] how much time is required to wait an email
13
+ # @raise [EmailNotFoundError] if blank message
14
+
15
+ def self.find(recipient, subject, wait:)
16
+ message = {}
17
+ retryable(find_retry_params(wait)) { message = retrieve_message(recipient, subject) }
18
+ return new(message) if message.present?
19
+
20
+ raise Howitzer::EmailNotFoundError,
21
+ "Message with subject '#{subject}' for recipient '#{recipient}' was not found."
22
+ end
23
+
24
+ # @return [String] plain text body of the email message
25
+
26
+ def plain_text_body
27
+ message['body']
28
+ end
29
+
30
+ # @return [String] html body of the email message
31
+
32
+ def html_body
33
+ message['htmlBody']
34
+ end
35
+
36
+ # @return [String] stripped text
37
+
38
+ def text
39
+ message['textBody']
40
+ end
41
+
42
+ # @return [String] an email address specified in `From` field
43
+
44
+ def mail_from
45
+ message['from']
46
+ end
47
+
48
+ # @return [String] when email was received
49
+
50
+ def received_time
51
+ Time.parse(message['date']).to_s
52
+ end
53
+
54
+ # @return [String] a real sender email address
55
+
56
+ def sender_email
57
+ message['from']
58
+ end
59
+
60
+ def self.find_retry_params(wait)
61
+ {
62
+ timeout: wait,
63
+ sleep: Howitzer.mail_sleep_time,
64
+ silent: true,
65
+ logger: Howitzer::Log,
66
+ on: Howitzer::EmailNotFoundError
67
+ }
68
+ end
69
+ private_class_method :find_retry_params
70
+
71
+ def self.retrieve_message(recipient, subject)
72
+ message = Howitzer::OnesecmailApi::Client.new.find_message(recipient, subject)
73
+ raise Howitzer::EmailNotFoundError, 'Message not received yet, retry...' unless message
74
+
75
+ message
76
+ end
77
+ private_class_method :retrieve_message
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,102 @@
1
+ require 'howitzer/exceptions'
2
+ require 'howitzer/mail_adapters/abstract'
3
+ require 'howitzer/testmail_api/client'
4
+
5
+ module Howitzer
6
+ module MailAdapters
7
+ # This class represents testmail.app mail adapter
8
+ class Testmail < Abstract
9
+ # Finds an email in storage
10
+ # @param recipient [String] an email
11
+ # @param subject [String]
12
+ # @param wait [Integer] how much time is required to wait an email
13
+ # @raise [EmailNotFoundError] if blank message
14
+
15
+ def self.find(recipient, subject, wait:)
16
+ message = {}
17
+ retryable(find_retry_params(wait)) { message = retrieve_message(recipient, subject) }
18
+ return new(message) if message.present?
19
+
20
+ raise Howitzer::EmailNotFoundError,
21
+ "Message with subject '#{subject}' for recipient '#{recipient}' was not found."
22
+ end
23
+
24
+ # @return [String] plain text body of the email message
25
+
26
+ def plain_text_body
27
+ message['text']
28
+ end
29
+
30
+ # @return [String] html body of the email message
31
+
32
+ def html_body
33
+ message['html']
34
+ end
35
+
36
+ # @return [String] stripped text
37
+
38
+ def text
39
+ message['text']
40
+ end
41
+
42
+ # @return [String] an email address specified in `From` field
43
+
44
+ def mail_from
45
+ message['from']
46
+ end
47
+
48
+ # @return [String] recipient emails separated with `, `
49
+
50
+ def recipients
51
+ message['to'].split ', '
52
+ end
53
+
54
+ # @return [String] when email was received
55
+
56
+ def received_time
57
+ Time.parse(message['timestamp']).to_s
58
+ end
59
+
60
+ # @return [String] a real sender email address
61
+
62
+ def sender_email
63
+ message['from']
64
+ end
65
+
66
+ # @return [Array] attachments
67
+
68
+ def mime_part
69
+ message['attachments']
70
+ end
71
+
72
+ # @raise [NoAttachmentsError] if no attachments present
73
+ # @return [Array] attachments
74
+
75
+ def mime_part!
76
+ files = mime_part
77
+ return files if files.present?
78
+
79
+ raise Howitzer::NoAttachmentsError, 'No attachments were found.'
80
+ end
81
+
82
+ def self.find_retry_params(wait)
83
+ {
84
+ timeout: wait,
85
+ sleep: Howitzer.mail_sleep_time,
86
+ silent: true,
87
+ logger: Howitzer::Log,
88
+ on: Howitzer::EmailNotFoundError
89
+ }
90
+ end
91
+ private_class_method :find_retry_params
92
+
93
+ def self.retrieve_message(recipient, subject)
94
+ message = Howitzer::TestmailApi::Client.new.find_message(recipient, subject)
95
+ raise Howitzer::EmailNotFoundError, 'Message not received yet, retry...' unless message
96
+
97
+ message
98
+ end
99
+ private_class_method :retrieve_message
100
+ end
101
+ end
102
+ end
@@ -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
@@ -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
@@ -32,6 +32,24 @@ module Howitzer
32
32
  JSON.parse(RestClient.get("#{BASE_URL}/messages/#{message['id']}/attachments", 'Api-Token' => @api_token))
33
33
  end
34
34
 
35
+ def get_html_body(message)
36
+ RestClient.get("#{BASE_URL}/messages/#{message['id']}/body.html", 'Api-Token' => @api_token).body
37
+ rescue => e
38
+ raise Howitzer::CommunicationError, e.message
39
+ end
40
+
41
+ def get_txt_body(message)
42
+ RestClient.get("#{BASE_URL}/messages/#{message['id']}/body.txt", 'Api-Token' => @api_token).body
43
+ rescue => e
44
+ raise Howitzer::CommunicationError, e.message
45
+ end
46
+
47
+ def get_raw_body(message)
48
+ RestClient.get("#{BASE_URL}/messages/#{message['id']}/body.raw", 'Api-Token' => @api_token).body
49
+ rescue => e
50
+ raise Howitzer::CommunicationError, e.message
51
+ end
52
+
35
53
  private
36
54
 
37
55
  def messages(recipient)