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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -1
- data/LICENSE +1 -1
- data/README.md +16 -17
- data/generators/base_generator.rb +4 -6
- data/generators/config/config_generator.rb +2 -4
- data/generators/config/templates/boot.rb +1 -1
- data/generators/config/templates/capybara.rb +3 -5
- data/generators/config/templates/default.yml +19 -20
- 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 +1 -1
- 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/env.rb +1 -1
- data/generators/cucumber/templates/hooks.rb +9 -3
- data/generators/cucumber/templates/transformers.rb +1 -1
- data/generators/prerequisites/templates/factory_bot.rb +1 -1
- data/generators/root/templates/Gemfile.erb +4 -14
- data/generators/rspec/templates/spec_helper.rb +5 -5
- data/generators/turnip/templates/spec_helper.rb +5 -5
- data/generators/web/templates/example_page.rb +1 -1
- data/lib/howitzer/cache.rb +1 -1
- data/lib/howitzer/capybara_helpers.rb +46 -9
- data/lib/howitzer/email.rb +2 -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/mailgun.rb +1 -1
- data/lib/howitzer/mail_adapters/mailtrap.rb +3 -3
- data/lib/howitzer/mail_adapters/onesecmail.rb +80 -0
- data/lib/howitzer/mail_adapters/testmail.rb +102 -0
- data/lib/howitzer/mailgun_api/client.rb +3 -2
- data/lib/howitzer/mailgun_api/response.rb +1 -2
- data/lib/howitzer/mailtrap_api/client.rb +19 -1
- data/lib/howitzer/meta/actions.rb +13 -16
- data/lib/howitzer/meta/element.rb +12 -10
- data/lib/howitzer/onesecmail_api/client.rb +44 -0
- data/lib/howitzer/onesecmail_api.rb +7 -0
- data/lib/howitzer/testmail_api/client.rb +44 -0
- data/lib/howitzer/testmail_api.rb +7 -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_methods_proxy.rb +11 -5
- data/lib/howitzer/web/element_dsl.rb +104 -45
- data/lib/howitzer/web/iframe_dsl.rb +2 -2
- data/lib/howitzer/web/page.rb +4 -14
- data/lib/howitzer/web/page_dsl.rb +15 -6
- data/lib/howitzer/web/page_validator.rb +25 -26
- data/lib/howitzer/web/section.rb +5 -2
- data/lib/howitzer/web/section_dsl.rb +64 -30
- data/lib/howitzer.rb +2 -2
- metadata +29 -165
- data/.coveralls.yml +0 -1
- data/.gitignore +0 -14
- data/.rspec +0 -3
- data/.rubocop.yml +0 -60
- data/.ruby-gemset +0 -1
- data/.travis.yml +0 -8
- 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 -393
- data/features/cli_unknown.feature +0 -17
- data/features/cli_update.feature +0 -223
- 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/appium.rb +0 -25
- 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.erb +0 -56
- 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/support/shared_examples/meta_highlight_xpath.rb +0 -41
- data/spec/unit/generators/base_generator_spec.rb +0 -283
- data/spec/unit/generators/config_generator_spec.rb +0 -61
- 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 -86
- data/spec/unit/generators/rspec_generator_spec.rb +0 -36
- data/spec/unit/generators/tasks_generator_spec.rb +0 -31
- data/spec/unit/generators/templates/cucumber_spec.rb +0 -97
- data/spec/unit/generators/templates/rspec_spec.rb +0 -88
- data/spec/unit/generators/templates/turnip_spec.rb +0 -98
- 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 -730
- 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 -92
- 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/meta/element_spec.rb +0 -59
- data/spec/unit/lib/meta/entry_spec.rb +0 -77
- data/spec/unit/lib/meta/iframe_spec.rb +0 -66
- data/spec/unit/lib/meta/section_spec.rb +0 -43
- 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 -31
- 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 -385
- 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 -70
- 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', '
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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));")
|
data/lib/howitzer/cache.rb
CHANGED
|
@@ -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,
|
|
@@ -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
|
-
|
|
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 = "
|
|
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
|
data/lib/howitzer/email.rb
CHANGED
|
@@ -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
|
-
|
|
83
|
-
|
|
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
|
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 }
|
|
@@ -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']
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
@@ -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)
|