howitzer 2.0.3 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +69 -11
- data/LICENSE +1 -1
- data/README.md +21 -17
- data/bin/howitzer +7 -6
- data/generators/base_generator.rb +31 -17
- data/generators/config/config_generator.rb +11 -3
- data/generators/config/templates/boot.rb +3 -3
- data/generators/config/templates/capybara.rb +6 -131
- data/generators/config/templates/default.yml +34 -13
- data/generators/config/templates/drivers/appium.rb +25 -0
- data/generators/config/templates/drivers/browserstack.rb +23 -0
- data/generators/config/templates/drivers/crossbrowsertesting.rb +29 -0
- data/generators/config/templates/drivers/headless_chrome.rb +15 -0
- data/generators/config/templates/drivers/headless_firefox.rb +23 -0
- data/generators/config/templates/drivers/sauce.rb +25 -0
- data/generators/config/templates/drivers/selenium.rb +24 -0
- data/generators/config/templates/drivers/selenium_grid.rb +31 -0
- data/generators/config/templates/drivers/testingbot.rb +24 -0
- data/generators/cucumber/cucumber_generator.rb +2 -2
- data/generators/cucumber/templates/common_steps.rb +3 -3
- data/generators/cucumber/templates/cucumber.rake +5 -13
- data/generators/cucumber/templates/cuke_sniffer.rake +2 -2
- data/generators/cucumber/templates/env.rb +9 -1
- data/generators/cucumber/templates/hooks.rb +8 -2
- data/generators/cucumber/templates/transformers.rb +11 -25
- data/generators/emails/emails_generator.rb +2 -2
- data/generators/emails/templates/example_email.rb +1 -1
- data/generators/prerequisites/prerequisites_generator.rb +3 -3
- data/generators/prerequisites/templates/base.rb +1 -1
- data/generators/prerequisites/templates/{factory_girl.rb → factory_bot.rb} +7 -6
- data/generators/prerequisites/templates/users.rb +1 -1
- data/generators/root/root_generator.rb +3 -3
- data/generators/root/templates/Gemfile.erb +16 -22
- data/generators/rspec/rspec_generator.rb +2 -2
- data/generators/rspec/templates/rspec.rake +8 -8
- data/generators/rspec/templates/spec_helper.rb +6 -5
- data/generators/tasks/tasks_generator.rb +2 -2
- data/generators/turnip/templates/spec_helper.rb +6 -5
- data/generators/turnip/turnip_generator.rb +2 -2
- data/generators/web/templates/example_page.rb +1 -1
- data/generators/web/web_generator.rb +2 -2
- data/lib/howitzer/cache.rb +20 -19
- data/lib/howitzer/capybara_helpers.rb +58 -13
- data/lib/howitzer/email.rb +3 -2
- data/lib/howitzer/exceptions.rb +21 -20
- data/lib/howitzer/gmail_api/client.rb +31 -0
- data/lib/howitzer/gmail_api.rb +7 -0
- data/lib/howitzer/log.rb +6 -6
- data/lib/howitzer/mail_adapters/gmail.rb +96 -0
- data/lib/howitzer/mail_adapters/mailgun.rb +4 -2
- data/lib/howitzer/mail_adapters/mailtrap.rb +108 -0
- data/lib/howitzer/mailgun_api/client.rb +3 -2
- data/lib/howitzer/mailgun_api/connector.rb +1 -0
- data/lib/howitzer/mailgun_api/response.rb +1 -2
- data/lib/howitzer/mailtrap_api/client.rb +52 -0
- data/lib/howitzer/mailtrap_api.rb +7 -0
- data/lib/howitzer/meta/actions.rb +35 -0
- data/lib/howitzer/meta/element.rb +40 -0
- data/lib/howitzer/meta/entry.rb +62 -0
- data/lib/howitzer/meta/iframe.rb +41 -0
- data/lib/howitzer/meta/section.rb +30 -0
- data/lib/howitzer/meta.rb +11 -0
- data/lib/howitzer/utils/string_extensions.rb +6 -2
- data/lib/howitzer/version.rb +1 -1
- data/lib/howitzer/web/base_section.rb +1 -1
- data/lib/howitzer/web/capybara_context_holder.rb +1 -0
- data/lib/howitzer/web/capybara_methods_proxy.rb +15 -6
- data/lib/howitzer/web/element_dsl.rb +104 -44
- data/lib/howitzer/web/iframe_dsl.rb +23 -3
- data/lib/howitzer/web/page.rb +16 -4
- data/lib/howitzer/web/page_dsl.rb +19 -7
- data/lib/howitzer/web/page_validator.rb +27 -26
- data/lib/howitzer/web/section.rb +13 -2
- data/lib/howitzer/web/section_dsl.rb +65 -30
- data/lib/howitzer.rb +66 -10
- metadata +67 -133
- data/.coveralls.yml +0 -1
- data/.gitignore +0 -14
- data/.rspec +0 -3
- data/.rubocop.yml +0 -44
- data/.ruby-gemset +0 -1
- data/.travis.yml +0 -7
- data/Gemfile +0 -13
- data/MAINTENANCE.md +0 -32
- data/Rakefile +0 -22
- data/features/cli_help.feature +0 -31
- data/features/cli_new.feature +0 -349
- data/features/cli_unknown.feature +0 -17
- data/features/cli_update.feature +0 -178
- data/features/cli_version.feature +0 -14
- data/features/step_definitions/common_steps.rb +0 -29
- data/features/support/env.rb +0 -1
- data/features/support/transformers.rb +0 -3
- data/generators/root/templates/.gitignore +0 -21
- data/generators/root/templates/.rubocop.yml +0 -35
- data/generators/turnip/templates/.rspec +0 -1
- data/howitzer.gemspec +0 -37
- data/lib/howitzer/mail_adapters/debugmail.rb +0 -0
- data/spec/config/custom.yml +0 -9
- data/spec/spec_helper.rb +0 -72
- data/spec/support/generator_helper.rb +0 -21
- data/spec/support/logger_helper.rb +0 -13
- data/spec/support/mailgun_unit_client.rb +0 -68
- data/spec/support/shared_examples/capybara_context_holder.rb +0 -33
- data/spec/support/shared_examples/capybara_methods_proxy.rb +0 -94
- data/spec/support/shared_examples/dynamic_section_methods.rb +0 -35
- data/spec/support/shared_examples/element_dsl.rb +0 -242
- data/spec/unit/generators/base_generator_spec.rb +0 -272
- data/spec/unit/generators/config_generator_spec.rb +0 -38
- 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 -72
- data/spec/unit/generators/rspec_generator_spec.rb +0 -36
- data/spec/unit/generators/tasks_generator_spec.rb +0 -31
- data/spec/unit/generators/turnip_generator_spec.rb +0 -52
- data/spec/unit/generators/web_generator_spec.rb +0 -52
- data/spec/unit/lib/cache_spec.rb +0 -85
- data/spec/unit/lib/capybara_helpers_spec.rb +0 -696
- data/spec/unit/lib/email_spec.rb +0 -186
- data/spec/unit/lib/howitzer_spec.rb +0 -40
- 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/mailgun_spec.rb +0 -163
- data/spec/unit/lib/mailgun_api/client_spec.rb +0 -58
- 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/utils/string_extensions_spec.rb +0 -77
- data/spec/unit/lib/web/base_section_spec.rb +0 -43
- data/spec/unit/lib/web/element_dsl_spec.rb +0 -22
- data/spec/unit/lib/web/iframe_dsl_spec.rb +0 -144
- data/spec/unit/lib/web/page_dsl_spec.rb +0 -74
- data/spec/unit/lib/web/page_spec.rb +0 -349
- data/spec/unit/lib/web/page_validator_spec.rb +0 -276
- data/spec/unit/lib/web/section_dsl_spec.rb +0 -165
- data/spec/unit/lib/web/section_spec.rb +0 -63
- data/spec/unit/version_spec.rb +0 -8
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require 'howitzer/exceptions'
|
|
2
|
+
require 'howitzer/mail_adapters/abstract'
|
|
3
|
+
require 'howitzer/gmail_api/client'
|
|
4
|
+
|
|
5
|
+
module Howitzer
|
|
6
|
+
module MailAdapters
|
|
7
|
+
# This class represents Gmail mail adapter
|
|
8
|
+
class Gmail < 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 = get_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.to_s
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [String] html body of the email message
|
|
31
|
+
|
|
32
|
+
def html_body
|
|
33
|
+
message.html_part.to_s
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [String] stripped text
|
|
37
|
+
|
|
38
|
+
def text
|
|
39
|
+
message.text_part.to_s
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [String] an email address specified in `From` field
|
|
43
|
+
|
|
44
|
+
def mail_from
|
|
45
|
+
"#{message.from[0]['mailbox']}@#{message.from[0]['host']}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [Array] recipient emails
|
|
49
|
+
|
|
50
|
+
def recipients
|
|
51
|
+
message.to.inject([]) { |ar, to| ar << "#{to['mailbox']}@#{to['host']}" }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [String] when email was received
|
|
55
|
+
|
|
56
|
+
def received_time
|
|
57
|
+
Time.parse(message.date).strftime('%F %T')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [Array] attachments
|
|
61
|
+
|
|
62
|
+
def mime_part
|
|
63
|
+
message.attachments
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @raise [NoAttachmentsError] if no attachments present
|
|
67
|
+
# @return [Array] attachments
|
|
68
|
+
|
|
69
|
+
def mime_part!
|
|
70
|
+
files = mime_part
|
|
71
|
+
return files if files.present?
|
|
72
|
+
|
|
73
|
+
raise Howitzer::NoAttachmentsError, 'No attachments were found.'
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.get_message(recipient, subject)
|
|
77
|
+
message = Howitzer::GmailApi::Client.new.find_message(recipient, subject)
|
|
78
|
+
raise Howitzer::EmailNotFoundError if message.blank?
|
|
79
|
+
|
|
80
|
+
message
|
|
81
|
+
end
|
|
82
|
+
private_class_method :get_message
|
|
83
|
+
|
|
84
|
+
def self.find_retry_params(wait)
|
|
85
|
+
{
|
|
86
|
+
timeout: wait,
|
|
87
|
+
sleep: Howitzer.mail_sleep_time,
|
|
88
|
+
silent: true,
|
|
89
|
+
logger: Howitzer::Log,
|
|
90
|
+
on: Howitzer::EmailNotFoundError
|
|
91
|
+
}
|
|
92
|
+
end
|
|
93
|
+
private_class_method :find_retry_params
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -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,7 +76,8 @@ module Howitzer
|
|
|
75
76
|
def mime_part!
|
|
76
77
|
files = mime_part
|
|
77
78
|
return files if files.present?
|
|
78
|
-
|
|
79
|
+
|
|
80
|
+
raise Howitzer::NoAttachmentsError, 'No attachments were found.'
|
|
79
81
|
end
|
|
80
82
|
|
|
81
83
|
def self.events
|
|
@@ -95,7 +97,7 @@ module Howitzer
|
|
|
95
97
|
def self.find_retry_params(wait)
|
|
96
98
|
{
|
|
97
99
|
timeout: wait || Howitzer.try(:mailgun_idle_timeout),
|
|
98
|
-
sleep: Howitzer.mailgun_sleep_time,
|
|
100
|
+
sleep: Howitzer.mail_sleep_time || Howitzer.mailgun_sleep_time,
|
|
99
101
|
silent: true,
|
|
100
102
|
logger: Howitzer::Log,
|
|
101
103
|
on: Howitzer::EmailNotFoundError
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require 'howitzer/exceptions'
|
|
2
|
+
require 'howitzer/mail_adapters/abstract'
|
|
3
|
+
require 'howitzer/mailtrap_api/client'
|
|
4
|
+
|
|
5
|
+
module Howitzer
|
|
6
|
+
module MailAdapters
|
|
7
|
+
# This class represents mailtrap mail adapter
|
|
8
|
+
class Mailtrap < 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_body']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [String] html body of the email message
|
|
31
|
+
|
|
32
|
+
def html_body
|
|
33
|
+
message['html_body']
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [String] stripped text
|
|
37
|
+
|
|
38
|
+
def text
|
|
39
|
+
message['text_body']
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [String] an email address specified in `From` field
|
|
43
|
+
|
|
44
|
+
def mail_from
|
|
45
|
+
message['from_email']
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [String] recipient emails separated with `, `
|
|
49
|
+
|
|
50
|
+
def recipients
|
|
51
|
+
message['to_email'].split ', '
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [String] when email was received
|
|
55
|
+
|
|
56
|
+
def received_time
|
|
57
|
+
Time.parse(message['created_at']).to_s
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [String] a real sender email address
|
|
61
|
+
|
|
62
|
+
def sender_email
|
|
63
|
+
message['from_email']
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @return [Array] attachments
|
|
67
|
+
|
|
68
|
+
def mime_part
|
|
69
|
+
retrieve_attachments(message)
|
|
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::MailtrapApi::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
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
def retrieve_attachments(message)
|
|
104
|
+
Howitzer::MailtrapApi::Client.new.find_attachments(message)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
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
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'rest-client'
|
|
3
|
+
|
|
4
|
+
module Howitzer
|
|
5
|
+
module MailtrapApi
|
|
6
|
+
# A Mailtrap::Client object is used to communicate with the Mailtrap API.
|
|
7
|
+
class Client
|
|
8
|
+
BASE_URL = "https://mailtrap.io/api/v1/inboxes/#{Howitzer.mailtrap_inbox_id}".freeze # :nodoc:
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@api_token = Howitzer.mailtrap_api_token
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Finds message according to given parameters
|
|
15
|
+
#
|
|
16
|
+
# @param recipient [String] this is recipient mail address for message filtering
|
|
17
|
+
# @param subject [String] this is subject of the message to filter particular message
|
|
18
|
+
# @return [Hash] json message parsed to ruby hash
|
|
19
|
+
|
|
20
|
+
def find_message(recipient, subject)
|
|
21
|
+
recipient = recipient.gsub('+', '%2B')
|
|
22
|
+
messages = filter_by_subject(messages(recipient), subject)
|
|
23
|
+
latest_message(messages)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Finds attachments for message
|
|
27
|
+
#
|
|
28
|
+
# @param message [Hash] which attachments should be extracted
|
|
29
|
+
# @return [Array] returns array of attachments
|
|
30
|
+
|
|
31
|
+
def find_attachments(message)
|
|
32
|
+
JSON.parse(RestClient.get("#{BASE_URL}/messages/#{message['id']}/attachments", 'Api-Token' => @api_token))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def messages(recipient)
|
|
38
|
+
JSON.parse(RestClient.get("#{BASE_URL}/messages?search=#{recipient}", 'Api-Token' => @api_token))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def latest_message(messages)
|
|
42
|
+
messages[0]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def filter_by_subject(messages, subject)
|
|
46
|
+
result_messages = []
|
|
47
|
+
messages.each { |msg| result_messages << msg if msg['subject'] == subject }
|
|
48
|
+
result_messages
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Howitzer
|
|
2
|
+
module Meta
|
|
3
|
+
# Module with utility actions for elements
|
|
4
|
+
module Actions
|
|
5
|
+
# Highlights element with red border on the page
|
|
6
|
+
# @param args [Array] arguments for elements described with lambda locators
|
|
7
|
+
# @param options [Hash] original Capybara options. For details, see `Capybara::Node::Finders#all`
|
|
8
|
+
def highlight(*args, **options)
|
|
9
|
+
if xpath(*args, **options).blank?
|
|
10
|
+
Howitzer::Log.debug("Element #{name} not found on the page")
|
|
11
|
+
return
|
|
12
|
+
end
|
|
13
|
+
element = escape(xpath(*args, **options))
|
|
14
|
+
context.execute_script(
|
|
15
|
+
"document.evaluate('#{element}', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)." \
|
|
16
|
+
'singleNodeValue.style.border = "thick solid red"'
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Returns xpath for the element
|
|
21
|
+
# @param args [Array] arguments for elements described with lambda locators
|
|
22
|
+
# @param options [Hash] original Capybara options. For details, see `Capybara::Node::Finders#all`
|
|
23
|
+
# @return [String, nil]
|
|
24
|
+
def xpath(*args, **options)
|
|
25
|
+
capybara_element(*args, **options).try(:path)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def escape(xpath)
|
|
31
|
+
xpath.gsub(/(['"])/, '\\\\\\1')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Howitzer
|
|
2
|
+
module Meta
|
|
3
|
+
# This class represents element entity within howitzer meta information interface
|
|
4
|
+
class Element
|
|
5
|
+
attr_reader :name, :context
|
|
6
|
+
|
|
7
|
+
include Howitzer::Meta::Actions
|
|
8
|
+
# Creates new meta element with meta information and utility actions
|
|
9
|
+
# @param name [String] name of the element
|
|
10
|
+
# @param context [Howitzer::Web::Page] page element belongs to
|
|
11
|
+
def initialize(name, context)
|
|
12
|
+
@name = name
|
|
13
|
+
@context = context
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Finds all instances of element on the page and returns them as array of capybara elements
|
|
17
|
+
# @param args [Array] arguments for elements described with lambda locators
|
|
18
|
+
# @param options [Hash] original Capybara options. For details, see `Capybara::Node::Finders#all`
|
|
19
|
+
# @return [Array]
|
|
20
|
+
def capybara_elements(*args, **options)
|
|
21
|
+
if options.present?
|
|
22
|
+
context.send("#{name}_elements", *args, **options)
|
|
23
|
+
else
|
|
24
|
+
context.send("#{name}_elements", *args)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Finds element on the page and returns as a capybara element
|
|
29
|
+
# @param args [Array] arguments for elements described with lambda locators
|
|
30
|
+
# @param options [Hash] original Capybara options. For details, see `Capybara::Node::Finders#all`
|
|
31
|
+
# @param wait [Integer] wait time for element search
|
|
32
|
+
# @return [Capybara::Node::Element, nil]
|
|
33
|
+
def capybara_element(*args, wait: 0, **options)
|
|
34
|
+
context.send("#{name}_element", *args, **options.merge(match: :first, wait: wait))
|
|
35
|
+
rescue Capybara::ElementNotFound
|
|
36
|
+
nil
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Howitzer
|
|
2
|
+
module Meta
|
|
3
|
+
# This class provides access to meta information entities
|
|
4
|
+
class Entry
|
|
5
|
+
attr_reader :context
|
|
6
|
+
|
|
7
|
+
# Creates new meta entry instance for the page which provides access to elements, iframes and sections
|
|
8
|
+
# @param context [Howitzer::Web::Page] page for which entry is created
|
|
9
|
+
def initialize(context)
|
|
10
|
+
@context = context
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Returns array of elements
|
|
14
|
+
# @return [Array]
|
|
15
|
+
def elements
|
|
16
|
+
@elements ||= context
|
|
17
|
+
.private_methods
|
|
18
|
+
.grep(/\A(?!wait_)\w+_element\z/)
|
|
19
|
+
.map { |el| Meta::Element.new(el.to_s.gsub('_element', ''), context) }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Finds element by name
|
|
23
|
+
# @param name [String, Symbol] element name
|
|
24
|
+
# @return [Meta::Element]
|
|
25
|
+
def element(name)
|
|
26
|
+
elements.find { |el| el.name == name.to_s }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns array of sections
|
|
30
|
+
# @return [Array]
|
|
31
|
+
def sections
|
|
32
|
+
@sections ||= context
|
|
33
|
+
.public_methods
|
|
34
|
+
.grep(/\A(?!wait_)\w+_section$\z/)
|
|
35
|
+
.map { |el| Meta::Section.new(el.to_s.gsub('_section', ''), context) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Finds section by name
|
|
39
|
+
# @param name [String, Symbol] section name
|
|
40
|
+
# @return [Meta::Section]
|
|
41
|
+
def section(name)
|
|
42
|
+
sections.find { |el| el.name == name.to_s }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns array of iframes
|
|
46
|
+
# @return [Array]
|
|
47
|
+
def iframes
|
|
48
|
+
@iframes ||= context
|
|
49
|
+
.public_methods
|
|
50
|
+
.grep(/\A(?!wait_)\w+_iframe$\z/)
|
|
51
|
+
.map { |el| Meta::Iframe.new(el.to_s.gsub('_iframe', ''), context) }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Finds iframe by name
|
|
55
|
+
# @param name [String, Symbol] iframe name
|
|
56
|
+
# @return [Meta::Iframe]
|
|
57
|
+
def iframe(name)
|
|
58
|
+
iframes.find { |el| el.name == name.to_s }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Howitzer
|
|
2
|
+
module Meta
|
|
3
|
+
# This class represents iframe entity within howitzer meta information interface
|
|
4
|
+
class Iframe
|
|
5
|
+
attr_reader :name, :context
|
|
6
|
+
|
|
7
|
+
include Howitzer::Meta::Actions
|
|
8
|
+
|
|
9
|
+
# Creates new meta iframe element with meta information and utility actions
|
|
10
|
+
# @param name [String] name of the iframe
|
|
11
|
+
# @param context [Howitzer::Web::Page] page which has this iframe
|
|
12
|
+
def initialize(name, context)
|
|
13
|
+
@name = name
|
|
14
|
+
@context = context
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Finds all instances of iframe on the page and returns them as array of capybara elements
|
|
18
|
+
# @return [Array]
|
|
19
|
+
def capybara_elements
|
|
20
|
+
context.capybara_context.all("iframe[src='#{site_value}']")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Finds iframe on the page and returns as a capybara element
|
|
24
|
+
# @param wait [Integer] wait time for element search
|
|
25
|
+
# @return [Capybara::Node::Element, nil]
|
|
26
|
+
def capybara_element(wait: 0)
|
|
27
|
+
context.capybara_context.find("iframe[src='#{site_value}']", match: :first, wait: wait)
|
|
28
|
+
rescue Capybara::ElementNotFound
|
|
29
|
+
nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns url value for iframe
|
|
33
|
+
# @return [String]
|
|
34
|
+
def site_value
|
|
35
|
+
return @site_value if @site_value.present?
|
|
36
|
+
|
|
37
|
+
context.send("#{name}_iframe") { |frame| @site_value = frame.class.send(:site_value) }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Howitzer
|
|
2
|
+
module Meta
|
|
3
|
+
# This class represents section entity within howitzer meta information interface
|
|
4
|
+
class Section
|
|
5
|
+
attr_reader :name, :context
|
|
6
|
+
|
|
7
|
+
include Howitzer::Meta::Actions
|
|
8
|
+
# Creates meta section element with meta information and utility actions
|
|
9
|
+
# @param name [String] name of the section
|
|
10
|
+
# @param context [Howitzer::Web::Page] page which has this section
|
|
11
|
+
def initialize(name, context)
|
|
12
|
+
@name = name
|
|
13
|
+
@context = context
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Finds all instances of section on the page and returns them as array of capybara elements
|
|
17
|
+
# @return [Array]
|
|
18
|
+
def capybara_elements
|
|
19
|
+
context.send("#{name}_sections").map(&:capybara_context)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Finds section on the page and returns as a capybara element
|
|
23
|
+
# @return [Capybara::Node::Element, nil]
|
|
24
|
+
def capybara_element
|
|
25
|
+
section = context.send("#{name}_sections").first
|
|
26
|
+
section.try(:capybara_context)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module Howitzer
|
|
2
|
+
# This module holds meta-information about elements on the page
|
|
3
|
+
module Meta
|
|
4
|
+
end
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require 'howitzer/meta/actions'
|
|
8
|
+
require 'howitzer/meta/element'
|
|
9
|
+
require 'howitzer/meta/section'
|
|
10
|
+
require 'howitzer/meta/iframe'
|
|
11
|
+
require 'howitzer/meta/entry'
|
|
@@ -7,8 +7,12 @@ module Howitzer
|
|
|
7
7
|
# 'home'.open #=> HomePage.open
|
|
8
8
|
# @see Howitzer::Web::Page.open
|
|
9
9
|
|
|
10
|
-
def open(*args)
|
|
11
|
-
|
|
10
|
+
def open(*args, **options)
|
|
11
|
+
if options.present?
|
|
12
|
+
as_page_class.open(*args, **options)
|
|
13
|
+
else
|
|
14
|
+
as_page_class.open(*args)
|
|
15
|
+
end
|
|
12
16
|
end
|
|
13
17
|
|
|
14
18
|
# Returns an instantiated page by name
|
data/lib/howitzer/version.rb
CHANGED
|
@@ -3,19 +3,21 @@ require 'active_support'
|
|
|
3
3
|
require 'active_support/core_ext'
|
|
4
4
|
|
|
5
5
|
# Remove this monkey patch after fixing the bugs in selenium-webdriver / capybara
|
|
6
|
-
|
|
6
|
+
# :nocov:
|
|
7
7
|
class Capybara::Selenium::Driver # rubocop:disable Style/ClassAndModuleChildren
|
|
8
8
|
#
|
|
9
9
|
# https://github.com/teamcapybara/capybara/issues/1845
|
|
10
10
|
def title
|
|
11
11
|
return browser.title unless within_frame?
|
|
12
|
+
|
|
12
13
|
find_xpath('/html/head/title').map { |n| n[:text] }.first.to_s
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
# Known issue, works differently for
|
|
16
|
+
# Known issue, works differently for real browsers
|
|
16
17
|
# https://github.com/seleniumhq/selenium/issues/1727
|
|
17
18
|
def current_url
|
|
18
19
|
return browser.current_url unless within_frame?
|
|
20
|
+
|
|
19
21
|
execute_script('return document.location.href')
|
|
20
22
|
end
|
|
21
23
|
|
|
@@ -25,13 +27,13 @@ class Capybara::Selenium::Driver # rubocop:disable Style/ClassAndModuleChildren
|
|
|
25
27
|
!(@frame_handles.blank? || @frame_handles[browser.window_handle].blank?)
|
|
26
28
|
end
|
|
27
29
|
end
|
|
28
|
-
|
|
30
|
+
# :nocov:
|
|
29
31
|
|
|
30
32
|
module Howitzer
|
|
31
33
|
module Web
|
|
32
34
|
# This module proxies required original capybara methods to recipient
|
|
33
35
|
module CapybaraMethodsProxy
|
|
34
|
-
PROXIED_CAPYBARA_METHODS = Capybara::Session::SESSION_METHODS +
|
|
36
|
+
PROXIED_CAPYBARA_METHODS = Capybara::Session::SESSION_METHODS + # :nodoc:
|
|
35
37
|
Capybara::Session::MODAL_METHODS +
|
|
36
38
|
%i[driver text]
|
|
37
39
|
|
|
@@ -39,7 +41,13 @@ module Howitzer
|
|
|
39
41
|
# Instead of including Capybara::DSL module, we proxy most interesting Capybara methods and
|
|
40
42
|
# prevent using extra methods which can potentially broke main principles and framework concept
|
|
41
43
|
PROXIED_CAPYBARA_METHODS.each do |method|
|
|
42
|
-
define_method(method)
|
|
44
|
+
define_method(method) do |*args, **options, &block|
|
|
45
|
+
if options.present?
|
|
46
|
+
Capybara.current_session.send(method, *args, **options, &block)
|
|
47
|
+
else
|
|
48
|
+
Capybara.current_session.send(method, *args, &block)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
43
51
|
end
|
|
44
52
|
|
|
45
53
|
# Accepts or declines JS alert box by given flag
|
|
@@ -57,7 +65,8 @@ module Howitzer
|
|
|
57
65
|
private
|
|
58
66
|
|
|
59
67
|
def capybara_scopes
|
|
60
|
-
@
|
|
68
|
+
@capybara_scopes ||= Hash.new { |hash, key| hash[key] = [Capybara.current_session] }
|
|
69
|
+
@capybara_scopes[Howitzer.session_name]
|
|
61
70
|
end
|
|
62
71
|
end
|
|
63
72
|
end
|