howitzer 2.0.1 → 2.0.2
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/.rubocop.yml +6 -0
- data/.travis.yml +4 -3
- data/CHANGELOG.md +18 -1
- data/Gemfile +1 -1
- data/README.md +3 -1
- data/Rakefile +1 -1
- data/bin/howitzer +3 -3
- data/features/cli_new.feature +2 -0
- data/generators/config/templates/capybara.rb +13 -11
- data/generators/config/templates/default.yml +2 -0
- data/generators/cucumber/cucumber_generator.rb +2 -1
- data/generators/cucumber/templates/cuke_sniffer.rake +21 -0
- data/generators/cucumber/templates/env.rb +6 -0
- data/generators/root/templates/Gemfile.erb +1 -0
- data/generators/rspec/templates/spec_helper.rb +2 -1
- data/generators/turnip/templates/spec_helper.rb +2 -1
- data/howitzer.gemspec +2 -1
- data/lib/howitzer.rb +1 -0
- data/lib/howitzer/capybara_helpers.rb +1 -1
- data/lib/howitzer/exceptions.rb +1 -0
- data/lib/howitzer/version.rb +1 -1
- data/lib/howitzer/web/capybara_methods_proxy.rb +26 -1
- data/lib/howitzer/web/element_dsl.rb +16 -3
- data/lib/howitzer/web/iframe_dsl.rb +34 -17
- data/lib/howitzer/web/page.rb +1 -0
- data/lib/howitzer/web/page_dsl.rb +2 -1
- data/lib/howitzer/web/page_validator.rb +5 -1
- data/spec/spec_helper.rb +1 -2
- data/spec/support/shared_examples/capybara_methods_proxy.rb +8 -8
- data/spec/support/shared_examples/dynamic_section_methods.rb +4 -4
- data/spec/support/shared_examples/element_dsl.rb +66 -53
- data/spec/unit/generators/cucumber_generator_spec.rb +8 -2
- data/spec/unit/lib/cache_spec.rb +1 -1
- data/spec/unit/lib/mailgun_api/client_spec.rb +6 -6
- data/spec/unit/lib/web/iframe_dsl_spec.rb +67 -22
- data/spec/unit/lib/web/page_spec.rb +25 -25
- data/spec/unit/lib/web/page_validator_spec.rb +37 -22
- data/spec/unit/lib/web/section_dsl_spec.rb +3 -3
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d72a5c40224b791c09af55a7f96a85783dd9bbec
|
4
|
+
data.tar.gz: 5c06f66b976b7fe0d389ebd516aa99b7ec60b7a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6540a619b0d5d157703116803ed3e3a032ce4570367c1e2dff77fcf97daf516c81fa2220c27cd2ec4a3e788768b2001cf7409d28508b6d5085e26b246652722
|
7
|
+
data.tar.gz: 46d599bfd49cb004da4b7ddb3fe79d8b765df77ae9e4ac4a4c42eb7c02aae385b1b712c22d565cb002e2742b1bc4be33b0418c4d29850ea7a620d16c070f65f0
|
data/.rubocop.yml
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
AllCops:
|
5
5
|
TargetRubyVersion: 2.3
|
6
|
+
DisplayCopNames: true
|
6
7
|
|
7
8
|
LineLength:
|
8
9
|
Max: 120
|
@@ -33,3 +34,8 @@ Metrics/ModuleLength:
|
|
33
34
|
|
34
35
|
Metrics/BlockLength:
|
35
36
|
Enabled: false
|
37
|
+
|
38
|
+
Style/MixinGrouping:
|
39
|
+
EnforcedStyle: separated
|
40
|
+
Exclude:
|
41
|
+
- '**/*_steps.rb'
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,26 @@
|
|
1
|
-
## [In git](https://github.com/strongqa/howitzer/compare/v2.0.
|
1
|
+
## [In git](https://github.com/strongqa/howitzer/compare/v2.0.2...master)
|
2
2
|
|
3
3
|
### New Features
|
4
4
|
|
5
5
|
### Bugfixes
|
6
6
|
|
7
|
+
## [v2.0.2](https://github.com/strongqa/howitzer/compare/v2.0.1...v2.0.2)
|
8
|
+
|
9
|
+
### New Features
|
10
|
+
- Integrate rspec-wait gem
|
11
|
+
- Support Ruby 2.4.0
|
12
|
+
- Support Selenium 3
|
13
|
+
- Integrate cuke-sniffer gem
|
14
|
+
- Activate rspec disable_monkey_patching! mode by default
|
15
|
+
- Support capybara frame options
|
16
|
+
- Add element_presence argument validation
|
17
|
+
- Review and improve tests quality
|
18
|
+
|
19
|
+
### Bugfixes
|
20
|
+
- Fix element capybara options merging
|
21
|
+
- [#211](https://github.com/strongqa/howitzer/issues/211) Validation for iframe does not operate as intended
|
22
|
+
- [#210](https://github.com/strongqa/howitzer/issues/210) Options like "wait" can not be used with iframe methods
|
23
|
+
|
7
24
|
## [v2.0.1](https://github.com/strongqa/howitzer/compare/v2.0.0...v2.0.1)
|
8
25
|
|
9
26
|
### New Features
|
data/Gemfile
CHANGED
@@ -2,9 +2,9 @@ source 'https://rubygems.org'
|
|
2
2
|
# Specify your gem's dependencies in howitzer.gemspec
|
3
3
|
group :test do
|
4
4
|
gem 'coveralls', require: false
|
5
|
-
gem 'simplecov', require: false
|
6
5
|
gem 'repeater', require: false
|
7
6
|
gem 'rest-client', require: false
|
7
|
+
gem 'simplecov', require: false
|
8
8
|
end
|
9
9
|
gemspec
|
10
10
|
|
data/README.md
CHANGED
@@ -44,7 +44,9 @@ You can also find the Rdoc documentation on [Rubygems](https://rubygems.org/gems
|
|
44
44
|
* [Ruby](https://www.ruby-lang.org/en/downloads/) 2.2.2+
|
45
45
|
* [DevKit](https://github.com/oneclick/rubyinstaller/wiki/Development-Kit#installation-instructions) (For **Windows** only)
|
46
46
|
* [PhantomJS](http://phantomjs.org/download.html) (For **phantomjs** and **poltergeist** drivers only)
|
47
|
-
* [ChromeDriver](https://
|
47
|
+
* [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/) (For **chrome** selenium browser)
|
48
|
+
* [GeckoDriver](https://github.com/mozilla/geckodriver/releases) (For **firefox** selenium browser)
|
49
|
+
* [SafariDriver](https://webkit.org/blog/6900/webdriver-support-in-safari-10/) (For **safari** selenium browser)
|
48
50
|
* [QT](https://github.com/thoughtbot/capybara-webkit/wiki/Installing-Qt-and-compiling-capybara-webkit) (For **webkit** driver only)
|
49
51
|
|
50
52
|
## Setup
|
data/Rakefile
CHANGED
data/bin/howitzer
CHANGED
@@ -13,13 +13,13 @@ module HowitzerCli
|
|
13
13
|
arg_name '<PROJECT NAME>'
|
14
14
|
command :new do |c|
|
15
15
|
c.desc 'Integrate Cucumber'
|
16
|
-
c.switch
|
16
|
+
c.switch %i(c cucumber), negatable: false
|
17
17
|
|
18
18
|
c.desc 'Integrate Rspec'
|
19
|
-
c.switch
|
19
|
+
c.switch %i(r rspec), negatable: false
|
20
20
|
|
21
21
|
c.desc 'Integrate Turnip'
|
22
|
-
c.switch
|
22
|
+
c.switch %i(t turnip), negatable: false
|
23
23
|
|
24
24
|
c.action do |_global_options, options, args|
|
25
25
|
if !args.empty?
|
data/features/cli_new.feature
CHANGED
@@ -145,6 +145,7 @@ Feature: Howitzer CLI New Project Creation
|
|
145
145
|
Added 'features/support/transformers.rb' file
|
146
146
|
Added 'features/example.feature' file
|
147
147
|
Added 'tasks/cucumber.rake' file
|
148
|
+
Added 'tasks/cuke_sniffer.rake' file
|
148
149
|
|
149
150
|
"""
|
150
151
|
Then a directory named "test_automation" should exist
|
@@ -166,6 +167,7 @@ Feature: Howitzer CLI New Project Creation
|
|
166
167
|
| test_automation/prerequisites/models/user.rb |
|
167
168
|
| test_automation/tasks/common.rake |
|
168
169
|
| test_automation/tasks/cucumber.rake |
|
170
|
+
| test_automation/tasks/cuke_sniffer.rake |
|
169
171
|
| test_automation/Gemfile |
|
170
172
|
| test_automation/Rakefile |
|
171
173
|
| test_automation/.gitignore |
|
@@ -1,13 +1,13 @@
|
|
1
|
-
HOWITZER_KNOWN_DRIVERS =
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
HOWITZER_KNOWN_DRIVERS = %i(
|
2
|
+
selenium
|
3
|
+
selenium_grid
|
4
|
+
webkit
|
5
|
+
poltergeist
|
6
|
+
phantomjs
|
7
|
+
sauce
|
8
|
+
testingbot
|
9
|
+
browserstack
|
10
|
+
).freeze
|
11
11
|
|
12
12
|
unless HOWITZER_KNOWN_DRIVERS.include?(Howitzer.driver.to_s.to_sym)
|
13
13
|
raise Howitzer::UnknownDriverError, "Unknown '#{Howitzer.driver}' driver." \
|
@@ -83,7 +83,9 @@ Capybara.register_driver :phantomjs do |app|
|
|
83
83
|
desired_capabilities: {
|
84
84
|
javascript_enabled: !Howitzer.phantom_ignore_js_errors
|
85
85
|
},
|
86
|
-
|
86
|
+
driver_opts: {
|
87
|
+
args: ["--ignore-ssl-errors=#{Howitzer.phantom_ignore_ssl_errors ? 'yes' : 'no'}"]
|
88
|
+
}
|
87
89
|
)
|
88
90
|
end
|
89
91
|
|
@@ -36,6 +36,8 @@
|
|
36
36
|
phantom_ignore_js_errors: false
|
37
37
|
phantom_ignore_ssl_errors: true
|
38
38
|
|
39
|
+
rspec_wait_timeout: 10
|
40
|
+
|
39
41
|
###########################################################
|
40
42
|
# Cloud-based Cross-browser Services #
|
41
43
|
###########################################################
|
@@ -11,7 +11,8 @@ module Howitzer
|
|
11
11
|
{ source: 'hooks.rb', destination: 'features/support/hooks.rb' },
|
12
12
|
{ source: 'transformers.rb', destination: 'features/support/transformers.rb' },
|
13
13
|
{ source: 'example.feature', destination: 'features/example.feature' },
|
14
|
-
{ source: 'cucumber.rake', destination: 'tasks/cucumber.rake' }
|
14
|
+
{ source: 'cucumber.rake', destination: 'tasks/cucumber.rake' },
|
15
|
+
{ source: 'cuke_sniffer.rake', destination: 'tasks/cuke_sniffer.rake' }
|
15
16
|
] }
|
16
17
|
end
|
17
18
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'cuke_sniffer'
|
2
|
+
|
3
|
+
def path_to_features
|
4
|
+
@_path_to_features ||= File.expand_path(File.join(__dir__, '..', 'features'))
|
5
|
+
end
|
6
|
+
|
7
|
+
def cuke_sniffer
|
8
|
+
@_cuke_sniffer ||= CukeSniffer::CLI.new(
|
9
|
+
features_location: path_to_features,
|
10
|
+
step_definitions_location: File.join(path_to_features, 'step_definitions'),
|
11
|
+
hooks_location: File.join(path_to_features, 'support'),
|
12
|
+
no_catalog: false
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate cuke_sniffer reports'
|
17
|
+
task :cuke_sniffer do
|
18
|
+
FileUtils.mkdir_p(Howitzer.log_dir)
|
19
|
+
cuke_sniffer.output_html("#{Howitzer.log_dir}/cuke_sniffer_results.html")
|
20
|
+
cuke_sniffer.output_min_html("#{Howitzer.log_dir}/min_cuke_sniffer_results.html")
|
21
|
+
end
|
@@ -4,6 +4,12 @@ require_relative '../../config/boot'
|
|
4
4
|
require_relative '../../config/capybara'
|
5
5
|
|
6
6
|
World(FactoryGirl::Syntax::Methods)
|
7
|
+
World(RSpec::Wait)
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.wait_timeout = Howitzer.rspec_wait_timeout
|
11
|
+
config.disable_monkey_patching!
|
12
|
+
end
|
7
13
|
|
8
14
|
FileUtils.mkdir_p(Howitzer.log_dir)
|
9
15
|
|
@@ -12,8 +12,9 @@ RSpec.configure do |config|
|
|
12
12
|
|
13
13
|
config.include FactoryGirl::Syntax::Methods
|
14
14
|
|
15
|
-
config.disable_monkey_patching
|
15
|
+
config.disable_monkey_patching!
|
16
16
|
config.color = true
|
17
|
+
config.wait_timeout = Howitzer.rspec_wait_timeout
|
17
18
|
|
18
19
|
config.before(:each) do
|
19
20
|
scenario_name =
|
@@ -11,8 +11,9 @@ RSpec.configure do |config|
|
|
11
11
|
|
12
12
|
config.include FactoryGirl::Syntax::Methods
|
13
13
|
|
14
|
-
config.disable_monkey_patching
|
14
|
+
config.disable_monkey_patching!
|
15
15
|
config.color = true
|
16
|
+
config.wait_timeout = Howitzer.rspec_wait_timeout
|
16
17
|
|
17
18
|
config.before(:each) do
|
18
19
|
scenario_name =
|
data/howitzer.gemspec
CHANGED
@@ -26,7 +26,8 @@ Gem::Specification.new do |gem|
|
|
26
26
|
gem.add_runtime_dependency 'nokogiri', '~> 1.6' if gem.platform.to_s =~ /mswin|mingw/
|
27
27
|
gem.add_runtime_dependency 'rake'
|
28
28
|
gem.add_runtime_dependency 'rspec', '~>3.2'
|
29
|
-
gem.add_runtime_dependency '
|
29
|
+
gem.add_runtime_dependency 'rspec-wait'
|
30
|
+
gem.add_runtime_dependency 'selenium-webdriver', '< 4.0'
|
30
31
|
gem.add_runtime_dependency 'sexy_settings'
|
31
32
|
|
32
33
|
gem.add_development_dependency('aruba')
|
data/lib/howitzer.rb
CHANGED
@@ -10,7 +10,7 @@ module Howitzer
|
|
10
10
|
# Testingbot or Browserstack cloud service
|
11
11
|
|
12
12
|
def cloud_driver?
|
13
|
-
|
13
|
+
%i(sauce testingbot browserstack).include?(Howitzer.driver.to_sym)
|
14
14
|
end
|
15
15
|
|
16
16
|
# @return [Boolean] whether or not current browser is
|
data/lib/howitzer/exceptions.rb
CHANGED
data/lib/howitzer/version.rb
CHANGED
@@ -1,12 +1,37 @@
|
|
1
1
|
require 'capybara'
|
2
2
|
|
3
|
+
# Remove this monkey patch after fixing the bugs in selenium-webdriver / capybara
|
4
|
+
#:nocov:
|
5
|
+
class Capybara::Selenium::Driver # rubocop:disable Style/ClassAndModuleChildren
|
6
|
+
#
|
7
|
+
# https://github.com/teamcapybara/capybara/issues/1845
|
8
|
+
def title
|
9
|
+
return browser.title unless within_frame?
|
10
|
+
find_xpath('/html/head/title').map { |n| n[:text] }.first.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
# Known issue, works differently for phantomjs and real browsers
|
14
|
+
# https://github.com/seleniumhq/selenium/issues/1727
|
15
|
+
def current_url
|
16
|
+
return browser.current_url unless within_frame?
|
17
|
+
execute_script('return document.location.href')
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def within_frame?
|
23
|
+
!(@frame_handles.empty? || @frame_handles[browser.window_handle].empty?)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
#:nocov:
|
27
|
+
|
3
28
|
module Howitzer
|
4
29
|
module Web
|
5
30
|
# This module proxies required original capybara methods to recipient
|
6
31
|
module CapybaraMethodsProxy
|
7
32
|
PROXIED_CAPYBARA_METHODS = Capybara::Session::SESSION_METHODS + #:nodoc:
|
8
33
|
Capybara::Session::MODAL_METHODS +
|
9
|
-
|
34
|
+
%i(driver text)
|
10
35
|
|
11
36
|
# Capybara form dsl methods are not compatible with page object pattern and Howitzer gem.
|
12
37
|
# Instead of including Capybara::DSL module, we proxy most interesting Capybara methods and
|
@@ -12,15 +12,28 @@ module Howitzer
|
|
12
12
|
private
|
13
13
|
|
14
14
|
def convert_arguments(args, params)
|
15
|
-
|
15
|
+
args, params, options = merge_element_options(args, params)
|
16
16
|
args = args.map do |el|
|
17
17
|
next(el) unless el.is_a?(Proc)
|
18
18
|
el.call(*params.shift(el.arity))
|
19
19
|
end
|
20
|
-
args <<
|
20
|
+
args << options unless options.blank?
|
21
21
|
args
|
22
22
|
end
|
23
23
|
|
24
|
+
def merge_element_options(args, params)
|
25
|
+
new_args, args_hash = extract_element_options(args)
|
26
|
+
new_params, params_hash = extract_element_options(params)
|
27
|
+
[new_args, new_params, args_hash.merge(params_hash)]
|
28
|
+
end
|
29
|
+
|
30
|
+
def extract_element_options(args)
|
31
|
+
new_args = args.deep_dup
|
32
|
+
args_hash = {}
|
33
|
+
args_hash = new_args.pop if new_args.last.is_a?(Hash)
|
34
|
+
[new_args, args_hash]
|
35
|
+
end
|
36
|
+
|
24
37
|
# This module holds element dsl methods methods
|
25
38
|
module ClassMethods
|
26
39
|
protected
|
@@ -42,7 +55,7 @@ module Howitzer
|
|
42
55
|
#
|
43
56
|
# <b>has_no_<em>element_name</em>_element?</b> - equals capybara #has_no_selector(...) method
|
44
57
|
# @param name [Symbol, String] an unique element name
|
45
|
-
# @param args [Array] original Capybara arguments. For details, see `Capybara::Node::Finders#all
|
58
|
+
# @param args [Array] original Capybara arguments. For details, see `Capybara::Node::Finders#all`.
|
46
59
|
# @example Using in a page class
|
47
60
|
# class HomePage < Howitzer::Web::Page
|
48
61
|
# element :top_panel, '.top'
|
@@ -11,8 +11,24 @@ module Howitzer
|
|
11
11
|
|
12
12
|
private
|
13
13
|
|
14
|
-
def iframe_element_selector(
|
15
|
-
|
14
|
+
def iframe_element_selector(args, params)
|
15
|
+
args = convert_iframe_arguments(args, params)
|
16
|
+
case args[0]
|
17
|
+
when String, Hash
|
18
|
+
[:frame, *args]
|
19
|
+
when Integer
|
20
|
+
idx = args.shift
|
21
|
+
["iframe:nth-of-type(#{idx + 1})", *args]
|
22
|
+
else
|
23
|
+
args
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def convert_iframe_arguments(args, params)
|
28
|
+
new_args = args.deep_dup
|
29
|
+
hash = new_args.pop.merge(params) if new_args.last.is_a?(Hash)
|
30
|
+
new_args << hash if hash.present?
|
31
|
+
new_args
|
16
32
|
end
|
17
33
|
|
18
34
|
# This module holds frame dsl class methods
|
@@ -28,7 +44,7 @@ module Howitzer
|
|
28
44
|
#
|
29
45
|
# <b>has_no_<em>frame_name</em>_iframe?</b> - equals capybara #has_no_selector(...) method
|
30
46
|
# @param name [Symbol, String] an unique iframe name
|
31
|
-
# @param
|
47
|
+
# @param args [Array] original Capybara arguments. For details, see `Capybara::Session#within_frame`.
|
32
48
|
# @example Using in a page class
|
33
49
|
# class FbPage < Howitzer::Web::Page
|
34
50
|
# element :like, :xpath, ".//*[text()='Like']"
|
@@ -54,33 +70,34 @@ module Howitzer
|
|
54
70
|
# HomePage.on { is_expected.to have_fb_iframe }
|
55
71
|
# @!visibility public
|
56
72
|
|
57
|
-
def iframe(name,
|
73
|
+
def iframe(name, *args)
|
74
|
+
raise ArgumentError, 'iframe selector arguments must be specified' if args.blank?
|
58
75
|
klass = "#{name}_page".classify.constantize
|
59
|
-
define_iframe(klass, name,
|
60
|
-
define_has_iframe(name,
|
61
|
-
define_has_no_iframe(name,
|
76
|
+
define_iframe(klass, name, args)
|
77
|
+
define_has_iframe(name, args)
|
78
|
+
define_has_no_iframe(name, args)
|
62
79
|
end
|
63
80
|
|
64
81
|
private
|
65
82
|
|
66
|
-
def define_iframe(klass, name,
|
67
|
-
define_method "#{name}_iframe" do
|
68
|
-
|
69
|
-
|
83
|
+
def define_iframe(klass, name, args)
|
84
|
+
define_method "#{name}_iframe" do |**params, &block|
|
85
|
+
capybara_context.within_frame(*convert_iframe_arguments(args, params)) do
|
86
|
+
klass.displayed?
|
70
87
|
block.call klass.instance
|
71
88
|
end
|
72
89
|
end
|
73
90
|
end
|
74
91
|
|
75
|
-
def define_has_iframe(name,
|
76
|
-
define_method("has_#{name}_iframe?") do
|
77
|
-
capybara_context.has_selector?(*iframe_element_selector(
|
92
|
+
def define_has_iframe(name, args)
|
93
|
+
define_method("has_#{name}_iframe?") do |**params|
|
94
|
+
capybara_context.has_selector?(*iframe_element_selector(args, params))
|
78
95
|
end
|
79
96
|
end
|
80
97
|
|
81
|
-
def define_has_no_iframe(name,
|
82
|
-
define_method("has_no_#{name}_iframe?") do
|
83
|
-
capybara_context.has_no_selector?(*iframe_element_selector(
|
98
|
+
def define_has_no_iframe(name, args)
|
99
|
+
define_method("has_no_#{name}_iframe?") do |**params|
|
100
|
+
capybara_context.has_no_selector?(*iframe_element_selector(args, params))
|
84
101
|
end
|
85
102
|
end
|
86
103
|
end
|