howitzer 2.0.1 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|