howitzer 2.2.0 → 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 +4 -4
- data/CHANGELOG.md +16 -1
- data/LICENSE +1 -1
- data/README.md +16 -16
- data/generators/base_generator.rb +1 -1
- data/generators/config/config_generator.rb +1 -4
- data/generators/config/templates/boot.rb +1 -1
- data/generators/config/templates/capybara.rb +1 -3
- data/generators/config/templates/default.yml +5 -19
- data/generators/config/templates/drivers/browserstack.rb +1 -1
- data/generators/config/templates/drivers/crossbrowsertesting.rb +1 -1
- 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/sauce.rb +1 -1
- data/generators/config/templates/drivers/selenium.rb +1 -1
- data/generators/config/templates/drivers/selenium_grid.rb +2 -2
- data/generators/config/templates/drivers/testingbot.rb +1 -1
- data/generators/cucumber/templates/env.rb +1 -1
- data/generators/cucumber/templates/hooks.rb +8 -2
- data/generators/cucumber/templates/transformers.rb +1 -1
- data/generators/prerequisites/templates/factory_bot.rb +1 -1
- data/generators/root/templates/Gemfile.erb +4 -10
- data/generators/rspec/templates/spec_helper.rb +4 -4
- data/generators/turnip/templates/spec_helper.rb +4 -4
- data/generators/web/templates/example_page.rb +1 -1
- data/lib/howitzer/cache.rb +1 -1
- data/lib/howitzer/capybara_helpers.rb +27 -7
- 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/mailgun_api/client.rb +3 -2
- data/lib/howitzer/mailgun_api/response.rb +1 -2
- data/lib/howitzer/mailtrap_api/client.rb +1 -1
- data/lib/howitzer/meta/actions.rb +13 -16
- data/lib/howitzer/meta/element.rb +12 -10
- 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 +24 -161
- 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/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,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 }
|
|
@@ -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
|
|
@@ -3,23 +3,26 @@ module Howitzer
|
|
|
3
3
|
# Module with utility actions for elements
|
|
4
4
|
module Actions
|
|
5
5
|
# Highlights element with red border on the page
|
|
6
|
-
# @param args [Array] arguments for elements described with lambda locators
|
|
7
|
-
#
|
|
8
|
-
def highlight(*args)
|
|
9
|
-
if xpath(*args).blank?
|
|
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
10
|
Howitzer::Log.debug("Element #{name} not found on the page")
|
|
11
11
|
return
|
|
12
12
|
end
|
|
13
|
-
|
|
14
|
-
|
|
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
|
+
)
|
|
15
18
|
end
|
|
16
19
|
|
|
17
20
|
# Returns xpath for the element
|
|
18
|
-
# @param args [Array] arguments for elements described with lambda locators
|
|
19
|
-
#
|
|
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`
|
|
20
23
|
# @return [String, nil]
|
|
21
|
-
def xpath(*args)
|
|
22
|
-
capybara_element(*args).try(:path)
|
|
24
|
+
def xpath(*args, **options)
|
|
25
|
+
capybara_element(*args, **options).try(:path)
|
|
23
26
|
end
|
|
24
27
|
|
|
25
28
|
private
|
|
@@ -27,12 +30,6 @@ module Howitzer
|
|
|
27
30
|
def escape(xpath)
|
|
28
31
|
xpath.gsub(/(['"])/, '\\\\\\1')
|
|
29
32
|
end
|
|
30
|
-
|
|
31
|
-
def convert_args(args)
|
|
32
|
-
new_args = []
|
|
33
|
-
params = args.reject { |v| new_args << v if v.is_a?(Hash) }
|
|
34
|
-
[params, new_args.reduce(:merge)].flatten
|
|
35
|
-
end
|
|
36
33
|
end
|
|
37
34
|
end
|
|
38
35
|
end
|
|
@@ -14,22 +14,24 @@ module Howitzer
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
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
|
-
#
|
|
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
19
|
# @return [Array]
|
|
20
|
-
def capybara_elements(*args)
|
|
21
|
-
|
|
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
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
# Finds element on the page and returns as a capybara element
|
|
25
|
-
# @param args [Array] arguments for elements described with lambda locators
|
|
26
|
-
#
|
|
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`
|
|
27
31
|
# @param wait [Integer] wait time for element search
|
|
28
32
|
# @return [Capybara::Node::Element, nil]
|
|
29
|
-
def capybara_element(*args, wait: 0)
|
|
30
|
-
args
|
|
31
|
-
args = convert_args(args)
|
|
32
|
-
context.send("#{name}_element", *args)
|
|
33
|
+
def capybara_element(*args, wait: 0, **options)
|
|
34
|
+
context.send("#{name}_element", *args, **options.merge(match: :first, wait: wait))
|
|
33
35
|
rescue Capybara::ElementNotFound
|
|
34
36
|
nil
|
|
35
37
|
end
|
|
@@ -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,7 +3,7 @@ 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
|
|
@@ -13,7 +13,7 @@ class Capybara::Selenium::Driver # rubocop:disable Style/ClassAndModuleChildren
|
|
|
13
13
|
find_xpath('/html/head/title').map { |n| n[:text] }.first.to_s
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
# Known issue, works differently for
|
|
16
|
+
# Known issue, works differently for real browsers
|
|
17
17
|
# https://github.com/seleniumhq/selenium/issues/1727
|
|
18
18
|
def current_url
|
|
19
19
|
return browser.current_url unless within_frame?
|
|
@@ -27,13 +27,13 @@ class Capybara::Selenium::Driver # rubocop:disable Style/ClassAndModuleChildren
|
|
|
27
27
|
!(@frame_handles.blank? || @frame_handles[browser.window_handle].blank?)
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
|
-
|
|
30
|
+
# :nocov:
|
|
31
31
|
|
|
32
32
|
module Howitzer
|
|
33
33
|
module Web
|
|
34
34
|
# This module proxies required original capybara methods to recipient
|
|
35
35
|
module CapybaraMethodsProxy
|
|
36
|
-
PROXIED_CAPYBARA_METHODS = Capybara::Session::SESSION_METHODS +
|
|
36
|
+
PROXIED_CAPYBARA_METHODS = Capybara::Session::SESSION_METHODS + # :nodoc:
|
|
37
37
|
Capybara::Session::MODAL_METHODS +
|
|
38
38
|
%i[driver text]
|
|
39
39
|
|
|
@@ -41,7 +41,13 @@ module Howitzer
|
|
|
41
41
|
# Instead of including Capybara::DSL module, we proxy most interesting Capybara methods and
|
|
42
42
|
# prevent using extra methods which can potentially broke main principles and framework concept
|
|
43
43
|
PROXIED_CAPYBARA_METHODS.each do |method|
|
|
44
|
-
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
|
|
45
51
|
end
|
|
46
52
|
|
|
47
53
|
# Accepts or declines JS alert box by given flag
|
|
@@ -3,40 +3,68 @@ module Howitzer
|
|
|
3
3
|
module Web
|
|
4
4
|
# This module combines element dsl methods
|
|
5
5
|
module ElementDsl
|
|
6
|
+
# This module holds element helper methods
|
|
7
|
+
module Helpers
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def lambda_args(*args, **keyword_args)
|
|
11
|
+
{
|
|
12
|
+
lambda_args: {
|
|
13
|
+
args: args,
|
|
14
|
+
keyword_args: keyword_args
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
6
20
|
include CapybaraContextHolder
|
|
21
|
+
include Helpers
|
|
7
22
|
|
|
8
|
-
def self.included(base)
|
|
23
|
+
def self.included(base) # :nodoc:
|
|
9
24
|
base.extend(ClassMethods)
|
|
10
25
|
end
|
|
11
26
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
27
|
+
def convert_arguments(args, options, block_args, block_options)
|
|
28
|
+
conv_args = args.map { |el| el.is_a?(Proc) ? proc_to_selector(el, block_args, block_options) : el }
|
|
29
|
+
args_options = pop_options_from_array(conv_args)
|
|
30
|
+
block_args_options = pop_options_from_array(block_args)
|
|
31
|
+
conv_options = [args_options, options, block_args_options, block_options].map do |el|
|
|
32
|
+
el.transform_keys(&:to_sym)
|
|
33
|
+
end.reduce(&:merge).except(:lambda_args)
|
|
34
|
+
[conv_args, conv_options]
|
|
35
|
+
end
|
|
18
36
|
|
|
19
|
-
|
|
37
|
+
def proc_to_selector(proc, block_args, block_options)
|
|
38
|
+
lambda_args = extract_lambda_args(block_args, block_options)
|
|
39
|
+
if lambda_args
|
|
40
|
+
if lambda_args[:keyword_args].present?
|
|
41
|
+
proc.call(*lambda_args[:args], **lambda_args[:keyword_args])
|
|
42
|
+
else
|
|
43
|
+
proc.call(*lambda_args[:args])
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
puts "WARNING! Passing lambda arguments with element options is deprecated.\n" \
|
|
47
|
+
"Please use 'lambda_args' method, for example: foo_element(lambda_args(title: 'Example'), wait: 10)"
|
|
48
|
+
proc.call(*block_args.shift(proc.arity))
|
|
20
49
|
end
|
|
21
|
-
args << options unless options.blank?
|
|
22
|
-
args
|
|
23
50
|
end
|
|
24
51
|
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
new_params, params_hash = extract_element_options(params)
|
|
28
|
-
[new_args, new_params, args_hash.merge(params_hash)]
|
|
52
|
+
def extract_lambda_args(block_args, block_options)
|
|
53
|
+
(block_args.first.is_a?(Hash) && block_args.first[:lambda_args]) || block_options[:lambda_args]
|
|
29
54
|
end
|
|
30
55
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
56
|
+
def pop_options_from_array(value)
|
|
57
|
+
if value.last.is_a?(Hash) && !value.last.key?(:lambda_args)
|
|
58
|
+
value.pop
|
|
59
|
+
else
|
|
60
|
+
{}
|
|
61
|
+
end
|
|
36
62
|
end
|
|
37
63
|
|
|
38
|
-
# This module holds element dsl methods
|
|
64
|
+
# This module holds element dsl methods
|
|
39
65
|
module ClassMethods
|
|
66
|
+
include Helpers
|
|
67
|
+
|
|
40
68
|
protected
|
|
41
69
|
|
|
42
70
|
# Creates a group of methods to interact with described HTML element(s) on page
|
|
@@ -57,6 +85,7 @@ module Howitzer
|
|
|
57
85
|
# <b>has_no_<em>element_name</em>_element?</b> - equals capybara #has_no_selector(...) method
|
|
58
86
|
# @param name [Symbol, String] an unique element name
|
|
59
87
|
# @param args [Array] original Capybara arguments. For details, see `Capybara::Node::Finders#all`.
|
|
88
|
+
# @param options [Hash] original Capybara options. For details, see `Capybara::Node::Finders#all`.
|
|
60
89
|
# @example Using in a page class
|
|
61
90
|
# class HomePage < Howitzer::Web::Page
|
|
62
91
|
# element :top_panel, '.top'
|
|
@@ -93,14 +122,14 @@ module Howitzer
|
|
|
93
122
|
# @raise [BadElementParamsError] if wrong element arguments
|
|
94
123
|
# @!visibility public
|
|
95
124
|
|
|
96
|
-
def element(name, *args)
|
|
125
|
+
def element(name, *args, **options)
|
|
97
126
|
validate_arguments!(args)
|
|
98
|
-
define_element(name, args)
|
|
99
|
-
define_elements(name, args)
|
|
100
|
-
define_wait_for_element(name, args)
|
|
101
|
-
define_within_element(name, args)
|
|
102
|
-
define_has_element(name, args)
|
|
103
|
-
define_has_no_element(name, args)
|
|
127
|
+
define_element(name, args, options)
|
|
128
|
+
define_elements(name, args, options)
|
|
129
|
+
define_wait_for_element(name, args, options)
|
|
130
|
+
define_within_element(name, args, options)
|
|
131
|
+
define_has_element(name, args, options)
|
|
132
|
+
define_has_no_element(name, args, options)
|
|
104
133
|
end
|
|
105
134
|
|
|
106
135
|
private
|
|
@@ -111,31 +140,51 @@ module Howitzer
|
|
|
111
140
|
raise Howitzer::BadElementParamsError, 'Using more than 1 proc in arguments is forbidden'
|
|
112
141
|
end
|
|
113
142
|
|
|
114
|
-
def define_element(name, args)
|
|
115
|
-
define_method("#{name}_element") do |*block_args|
|
|
116
|
-
|
|
143
|
+
def define_element(name, args, options)
|
|
144
|
+
define_method("#{name}_element") do |*block_args, **block_options|
|
|
145
|
+
conv_args, conv_options = convert_arguments(args, options, block_args, block_options)
|
|
146
|
+
if conv_options.present?
|
|
147
|
+
capybara_context.find(*conv_args, **conv_options)
|
|
148
|
+
else
|
|
149
|
+
capybara_context.find(*conv_args)
|
|
150
|
+
end
|
|
117
151
|
end
|
|
118
152
|
private "#{name}_element"
|
|
119
153
|
end
|
|
120
154
|
|
|
121
|
-
def define_elements(name, args)
|
|
122
|
-
define_method("#{name}_elements") do |*block_args|
|
|
123
|
-
|
|
155
|
+
def define_elements(name, args, options)
|
|
156
|
+
define_method("#{name}_elements") do |*block_args, **block_options|
|
|
157
|
+
conv_args, conv_options = convert_arguments(args, options, block_args, block_options)
|
|
158
|
+
if conv_options.present?
|
|
159
|
+
capybara_context.all(*conv_args, **conv_options)
|
|
160
|
+
else
|
|
161
|
+
capybara_context.all(*conv_args)
|
|
162
|
+
end
|
|
124
163
|
end
|
|
125
164
|
private "#{name}_elements"
|
|
126
165
|
end
|
|
127
166
|
|
|
128
|
-
def define_wait_for_element(name, args)
|
|
129
|
-
define_method("wait_for_#{name}_element") do |*block_args|
|
|
130
|
-
|
|
167
|
+
def define_wait_for_element(name, args, options)
|
|
168
|
+
define_method("wait_for_#{name}_element") do |*block_args, **block_options|
|
|
169
|
+
conv_args, conv_options = convert_arguments(args, options, block_args, block_options)
|
|
170
|
+
if conv_options.present?
|
|
171
|
+
capybara_context.find(*conv_args, **conv_options)
|
|
172
|
+
else
|
|
173
|
+
capybara_context.find(*conv_args)
|
|
174
|
+
end
|
|
131
175
|
return nil
|
|
132
176
|
end
|
|
133
177
|
private "wait_for_#{name}_element"
|
|
134
178
|
end
|
|
135
179
|
|
|
136
|
-
def define_within_element(name, args)
|
|
137
|
-
define_method("within_#{name}_element") do |*block_args, &block|
|
|
138
|
-
|
|
180
|
+
def define_within_element(name, args, options)
|
|
181
|
+
define_method("within_#{name}_element") do |*block_args, **block_options, &block|
|
|
182
|
+
conv_args, conv_options = convert_arguments(args, options, block_args, block_options)
|
|
183
|
+
new_scope = if conv_options.present?
|
|
184
|
+
capybara_context.find(*conv_args, **conv_options)
|
|
185
|
+
else
|
|
186
|
+
capybara_context.find(*conv_args)
|
|
187
|
+
end
|
|
139
188
|
begin
|
|
140
189
|
capybara_scopes.push(new_scope)
|
|
141
190
|
block.call
|
|
@@ -145,15 +194,25 @@ module Howitzer
|
|
|
145
194
|
end
|
|
146
195
|
end
|
|
147
196
|
|
|
148
|
-
def define_has_element(name, args)
|
|
149
|
-
define_method("has_#{name}_element?") do |*block_args|
|
|
150
|
-
|
|
197
|
+
def define_has_element(name, args, options)
|
|
198
|
+
define_method("has_#{name}_element?") do |*block_args, **block_options|
|
|
199
|
+
conv_args, conv_options = convert_arguments(args, options, block_args, block_options)
|
|
200
|
+
if conv_options.present?
|
|
201
|
+
capybara_context.has_selector?(*conv_args, **conv_options)
|
|
202
|
+
else
|
|
203
|
+
capybara_context.has_selector?(*conv_args)
|
|
204
|
+
end
|
|
151
205
|
end
|
|
152
206
|
end
|
|
153
207
|
|
|
154
|
-
def define_has_no_element(name, args)
|
|
155
|
-
define_method("has_no_#{name}_element?") do |*block_args|
|
|
156
|
-
|
|
208
|
+
def define_has_no_element(name, args, options)
|
|
209
|
+
define_method("has_no_#{name}_element?") do |*block_args, **block_options|
|
|
210
|
+
conv_args, conv_options = convert_arguments(args, options, block_args, block_options)
|
|
211
|
+
if conv_options.present?
|
|
212
|
+
capybara_context.has_no_selector?(*conv_args, **conv_options)
|
|
213
|
+
else
|
|
214
|
+
capybara_context.has_no_selector?(*conv_args)
|
|
215
|
+
end
|
|
157
216
|
end
|
|
158
217
|
end
|
|
159
218
|
end
|
|
@@ -5,7 +5,7 @@ module Howitzer
|
|
|
5
5
|
module IframeDsl
|
|
6
6
|
include CapybaraContextHolder
|
|
7
7
|
|
|
8
|
-
def self.included(base)
|
|
8
|
+
def self.included(base) # :nodoc:
|
|
9
9
|
base.extend(ClassMethods)
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -26,7 +26,7 @@ module Howitzer
|
|
|
26
26
|
|
|
27
27
|
def convert_iframe_arguments(args, params)
|
|
28
28
|
new_args = args.deep_dup
|
|
29
|
-
hash = new_args.pop.merge(params) if new_args.last.is_a?(Hash)
|
|
29
|
+
hash = new_args.pop.transform_keys(&:to_sym).merge(params.transform_keys(&:to_sym)) if new_args.last.is_a?(Hash)
|
|
30
30
|
new_args << hash if hash.present?
|
|
31
31
|
new_args
|
|
32
32
|
end
|
data/lib/howitzer/web/page.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Howitzer
|
|
|
14
14
|
module Web
|
|
15
15
|
# This class represents a single web page. This is a parent class for all web pages
|
|
16
16
|
class Page
|
|
17
|
-
UnknownPage = Class.new
|
|
17
|
+
UnknownPage = Class.new # :nodoc:
|
|
18
18
|
include Singleton
|
|
19
19
|
include CapybaraMethodsProxy
|
|
20
20
|
include ElementDsl
|
|
@@ -28,6 +28,7 @@ module Howitzer
|
|
|
28
28
|
# This Ruby callback makes all inherited classes as singleton classes.
|
|
29
29
|
|
|
30
30
|
def self.inherited(subclass)
|
|
31
|
+
super
|
|
31
32
|
subclass.class_eval { include Singleton }
|
|
32
33
|
end
|
|
33
34
|
|
|
@@ -40,7 +41,6 @@ module Howitzer
|
|
|
40
41
|
|
|
41
42
|
def self.open(validate: true, url_processor: nil, **params)
|
|
42
43
|
url = expanded_url(params, url_processor)
|
|
43
|
-
modify_user_agent if Howitzer.user_agent.present?
|
|
44
44
|
Howitzer::Log.info "Open #{name} page by '#{url}' url"
|
|
45
45
|
retryable(tries: 2, logger: Howitzer::Log, trace: true, on: Exception) do |retries|
|
|
46
46
|
Howitzer::Log.info 'Retry...' unless retries.zero?
|
|
@@ -151,22 +151,12 @@ module Howitzer
|
|
|
151
151
|
|
|
152
152
|
def incorrect_page_msg
|
|
153
153
|
"Current page: #{current_page}, expected: #{self}.\n" \
|
|
154
|
-
|
|
154
|
+
"\tCurrent url: #{current_url}\n\tCurrent title: #{instance.title}"
|
|
155
155
|
end
|
|
156
156
|
|
|
157
157
|
def ambiguous_page_msg(page_list)
|
|
158
158
|
"Current page matches more that one page class (#{page_list.join(', ')}).\n" \
|
|
159
|
-
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def modify_user_agent
|
|
163
|
-
driver = Capybara.current_session.driver
|
|
164
|
-
case Howitzer.driver.to_sym
|
|
165
|
-
when CapybaraHelpers::POLTERGEIST
|
|
166
|
-
driver.add_headers('User-Agent' => Howitzer.user_agent)
|
|
167
|
-
when CapybaraHelpers::WEBKIT
|
|
168
|
-
driver.header('User-Agent', Howitzer.user_agent)
|
|
169
|
-
end
|
|
159
|
+
"\tCurrent url: #{current_url}\n\tCurrent title: #{instance.title}"
|
|
170
160
|
end
|
|
171
161
|
end
|
|
172
162
|
|
|
@@ -29,11 +29,15 @@ module Howitzer
|
|
|
29
29
|
# * `out` method extracts an instance variable from an original context if starts from @.
|
|
30
30
|
# Otherwise it executes a method from an original context
|
|
31
31
|
|
|
32
|
-
def method_missing(name, *args, &block)
|
|
32
|
+
def method_missing(name, *args, **options, &block)
|
|
33
33
|
return super if name =~ /\A(?:be|have)_/
|
|
34
|
-
return eval_in_out_context(*args, &block) if name == :out
|
|
34
|
+
return eval_in_out_context(*args, **options, &block) if name == :out
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
if options.present?
|
|
37
|
+
page_klass.given.send(name, *args, **options, &block)
|
|
38
|
+
else
|
|
39
|
+
page_klass.given.send(name, *args, &block)
|
|
40
|
+
end
|
|
37
41
|
end
|
|
38
42
|
|
|
39
43
|
# Makes proxied methods to be evaludated and returned as a proc
|
|
@@ -45,13 +49,17 @@ module Howitzer
|
|
|
45
49
|
|
|
46
50
|
private
|
|
47
51
|
|
|
48
|
-
def eval_in_out_context(*args, &block)
|
|
52
|
+
def eval_in_out_context(*args, **options, &block)
|
|
49
53
|
return nil if args.size.zero?
|
|
50
54
|
|
|
51
55
|
name = args.shift
|
|
52
56
|
return get_outer_instance_variable(name) if name.to_s.start_with?('@')
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
if options.present?
|
|
59
|
+
outer_context.send(name, *args, **options, &block)
|
|
60
|
+
else
|
|
61
|
+
outer_context.send(name, *args, &block)
|
|
62
|
+
end
|
|
55
63
|
end
|
|
56
64
|
|
|
57
65
|
def get_outer_instance_variable(name)
|
|
@@ -61,9 +69,10 @@ module Howitzer
|
|
|
61
69
|
attr_accessor :page_klass, :outer_context
|
|
62
70
|
end
|
|
63
71
|
|
|
64
|
-
def self.included(base)
|
|
72
|
+
def self.included(base) # :nodoc:
|
|
65
73
|
base.extend(ClassMethods)
|
|
66
74
|
end
|
|
75
|
+
|
|
67
76
|
# This module holds page dsl class methods
|
|
68
77
|
module ClassMethods
|
|
69
78
|
# Allows to execute page methods in context of the page.
|