cucumber-rails 1.5.0 → 2.1.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/.github/ISSUE_TEMPLATE.md +52 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- data/.gitignore +3 -1
- data/.rspec +4 -1
- data/.rubocop.yml +68 -0
- data/.travis.yml +43 -33
- data/Appraisals +25 -92
- data/{History.md → CHANGELOG.md} +242 -40
- data/CONTRIBUTING.md +15 -24
- data/Gemfile +2 -4
- data/LICENSE +1 -1
- data/README.md +57 -27
- data/Rakefile +18 -14
- data/bin/install_geckodriver.sh +19 -0
- data/bin/install_webpacker.sh +9 -0
- data/config/cucumber.yml +2 -5
- data/cucumber-rails.gemspec +35 -28
- data/dev_tasks/cucumber.rake +2 -0
- data/dev_tasks/rspec.rake +2 -0
- data/dev_tasks/yard.rake +7 -14
- data/dev_tasks/yard/default/layout/html/setup.rb +6 -1
- data/features/allow_rescue.feature +16 -11
- data/features/annotations.feature +8 -11
- data/features/capybara_javascript_drivers.feature +38 -28
- data/features/choose_javascript_database_strategy.feature +37 -57
- data/features/configuration.feature +48 -0
- data/features/database_cleaner.feature +18 -18
- data/features/disable_automatic_database_cleaning.feature +12 -18
- data/features/emulate_javascript.feature +64 -47
- data/features/install_cucumber_rails.feature +4 -4
- data/features/no_database.feature +8 -19
- data/features/raising_errors.feature +9 -3
- data/features/rerun_profile.feature +17 -7
- data/features/rest_api.feature +12 -12
- data/features/step_definitions/cucumber_rails_steps.rb +44 -88
- data/features/support/aruba.rb +3 -1
- data/features/support/cucumber_rails_helper.rb +85 -0
- data/features/support/env.rb +4 -30
- data/features/support/hooks.rb +8 -0
- data/gemfiles/rails_4_2.gemfile +5 -13
- data/gemfiles/rails_5_0.gemfile +5 -12
- data/gemfiles/rails_5_1.gemfile +4 -9
- data/gemfiles/rails_5_2.gemfile +10 -0
- data/gemfiles/rails_6_0.gemfile +9 -0
- data/lib/cucumber/rails.rb +17 -15
- data/lib/cucumber/rails/action_dispatch.rb +21 -0
- data/lib/cucumber/rails/application.rb +16 -7
- data/lib/cucumber/rails/capybara.rb +2 -0
- data/lib/cucumber/rails/capybara/javascript_emulation.rb +45 -37
- data/lib/cucumber/rails/capybara/select_dates_and_times.rb +6 -4
- data/lib/cucumber/rails/database.rb +30 -8
- data/lib/cucumber/rails/hooks.rb +2 -0
- data/lib/cucumber/rails/hooks/active_record.rb +14 -12
- data/lib/cucumber/rails/hooks/allow_rescue.rb +2 -0
- data/lib/cucumber/rails/hooks/database_cleaner.rb +6 -4
- data/lib/cucumber/rails/hooks/mail.rb +4 -4
- data/lib/cucumber/rails/rspec.rb +3 -1
- data/lib/cucumber/rails/world.rb +24 -7
- data/lib/generators/cucumber/{install/USAGE → USAGE} +0 -0
- data/lib/generators/cucumber/{install/install_generator.rb → install_generator.rb} +23 -10
- data/lib/generators/cucumber/{install/templates → templates}/config/cucumber.yml.erb +4 -3
- data/lib/generators/cucumber/{install/templates → templates}/script/cucumber +1 -0
- data/lib/generators/cucumber/{install/templates → templates}/support/_rails_each_run.rb.erb +2 -2
- data/lib/generators/cucumber/{install/templates → templates}/support/_rails_prefork.rb.erb +0 -0
- data/lib/generators/cucumber/{install/templates → templates}/support/capybara.rb +2 -0
- data/lib/generators/cucumber/{install/templates → templates}/support/edit_warning.txt +0 -0
- data/lib/generators/cucumber/{install/templates → templates}/support/rails.rb.erb +0 -0
- data/lib/generators/cucumber/{install/templates → templates}/support/rails_spork.rb.erb +0 -0
- data/lib/generators/cucumber/{install/templates → templates}/tasks/cucumber.rake.erb +9 -9
- data/spec/cucumber/rails/database_spec.rb +46 -33
- data/spec/generators/cucumber/{install/install_generator_spec.rb → install_generator_spec.rb} +17 -9
- data/spec/spec_helper.rb +13 -4
- metadata +105 -139
- data/Gemfile.appraisal +0 -3
- data/features/support/bundler_pre_support.rb +0 -28
- data/features/support/fixtures/bundler-1.0.21.gem +0 -0
- data/features/support/fixtures/bundler-1.1.rc.gem +0 -0
- data/features/support/legacy_web_steps_support.rb +0 -289
- data/gemfiles/lowest_version_bounds.gemfile +0 -26
- data/gemfiles/rails_4_0.gemfile +0 -19
- data/gemfiles/rails_4_1.gemfile +0 -18
- data/lib/cucumber/rails/action_controller.rb +0 -12
@@ -1,17 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rails/application'
|
2
4
|
|
3
5
|
# Make sure the ActionDispatch::ShowExceptions middleware is always enabled,
|
4
6
|
# regardless of what is in config/environments/test.rb
|
5
7
|
# Instead we are overriding ActionDispatch::ShowExceptions to be able to
|
6
8
|
# toggle whether or not exceptions are raised.
|
7
|
-
class Rails::Application
|
8
|
-
alias __cucumber_orig_initialize__ initialize!
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
module Cucumber
|
11
|
+
module Rails
|
12
|
+
module Application
|
13
|
+
def initialize!
|
14
|
+
ad = config.action_dispatch
|
15
|
+
|
16
|
+
def ad.show_exceptions
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
super
|
21
|
+
end
|
14
22
|
end
|
15
|
-
__cucumber_orig_initialize__
|
16
23
|
end
|
17
24
|
end
|
25
|
+
|
26
|
+
Rails::Application.prepend(Cucumber::Rails::Application)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Cucumber
|
2
4
|
module Rails
|
3
5
|
module Capybara
|
@@ -9,9 +11,11 @@ module Cucumber
|
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
12
|
-
def click_with_javascript_emulation
|
14
|
+
def click_with_javascript_emulation(*)
|
13
15
|
if link_with_non_get_http_method?
|
14
|
-
::Capybara::RackTest::Form.new(
|
16
|
+
::Capybara::RackTest::Form.new(
|
17
|
+
driver, js_form(element_node.document, self[:href], emulated_method)
|
18
|
+
).submit(self)
|
15
19
|
else
|
16
20
|
click_without_javascript_emulation
|
17
21
|
end
|
@@ -44,61 +48,65 @@ module Cucumber
|
|
44
48
|
js_form['action'] = action
|
45
49
|
js_form['method'] = method
|
46
50
|
|
47
|
-
|
48
|
-
input = document.create_element('input')
|
49
|
-
input['type'] = 'hidden'
|
50
|
-
input['name'] = '_method'
|
51
|
-
input['value'] = emulated_method
|
52
|
-
js_form.add_child(input)
|
53
|
-
end
|
51
|
+
add_hidden_method_input(document, js_form) unless same?(emulated_method, method)
|
54
52
|
|
55
|
-
# rails will wipe the session if the CSRF token is not sent
|
56
|
-
|
57
|
-
if csrf? && emulated_method.downcase != 'get'
|
58
|
-
input = document.create_element('input')
|
59
|
-
input['type'] = 'hidden'
|
60
|
-
input['name'] = csrf_param
|
61
|
-
input['value'] = csrf_token
|
62
|
-
js_form.add_child(input)
|
63
|
-
end
|
53
|
+
# rails will wipe the session if the CSRF token is not sent with non-GET requests
|
54
|
+
add_hidden_csrf_input(document, js_form) if csrf? && !get?(emulated_method)
|
64
55
|
|
65
56
|
js_form
|
66
57
|
end
|
67
58
|
|
59
|
+
def same?(emulated_method, method)
|
60
|
+
emulated_method.casecmp(method).zero?
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_hidden_method_input(document, js_form)
|
64
|
+
input = document.create_element('input')
|
65
|
+
input['type'] = 'hidden'
|
66
|
+
input['name'] = '_method'
|
67
|
+
input['value'] = emulated_method
|
68
|
+
js_form.add_child(input)
|
69
|
+
end
|
70
|
+
|
71
|
+
def get?(emulated_method)
|
72
|
+
same?(emulated_method, 'get')
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_hidden_csrf_input(document, js_form)
|
76
|
+
input = document.create_element('input')
|
77
|
+
input['type'] = 'hidden'
|
78
|
+
input['name'] = csrf_param
|
79
|
+
input['value'] = csrf_token
|
80
|
+
js_form.add_child(input)
|
81
|
+
end
|
82
|
+
|
68
83
|
def link_with_non_get_http_method?
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
tag_name == 'a' && element_node['onclick'] && element_node['onclick'] =~ /var f = document\.createElement\('form'\); f\.style\.display = 'none';/
|
73
|
-
end
|
84
|
+
tag_name == 'a' &&
|
85
|
+
element_node['data-method'] &&
|
86
|
+
element_node['data-method'] =~ /(?:delete|put|post)/
|
74
87
|
end
|
75
88
|
|
76
89
|
def emulated_method
|
77
|
-
|
78
|
-
element_node['data-method']
|
79
|
-
else
|
80
|
-
element_node['onclick'][/m\.setAttribute\('value', '([^']*)'\)/, 1]
|
81
|
-
end
|
90
|
+
element_node['data-method']
|
82
91
|
end
|
83
92
|
|
84
93
|
def element_node
|
85
|
-
|
86
|
-
self.native
|
87
|
-
else
|
88
|
-
warn 'DEPRECATED: cucumber-rails loves you, just not your version of Capybara. Please update Capybara to >= 0.4.0'
|
89
|
-
self.node
|
90
|
-
end
|
94
|
+
native
|
91
95
|
end
|
92
96
|
end
|
93
97
|
end
|
94
98
|
end
|
95
99
|
end
|
96
100
|
|
97
|
-
|
98
|
-
|
101
|
+
module Capybara
|
102
|
+
module RackTest
|
103
|
+
class Node
|
104
|
+
include ::Cucumber::Rails::Capybara::JavascriptEmulation
|
105
|
+
end
|
106
|
+
end
|
99
107
|
end
|
100
108
|
|
101
|
-
Before('
|
109
|
+
Before('not @no-js-emulation') do
|
102
110
|
# Enable javascript emulation
|
103
111
|
::Capybara::RackTest::Node.class_eval do
|
104
112
|
alias_method :click, :click_with_javascript_emulation
|
@@ -1,19 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Cucumber
|
2
4
|
module Rails
|
3
5
|
module Capybara
|
4
6
|
# This module defines methods for selecting dates and times
|
5
7
|
module SelectDatesAndTimes
|
6
|
-
# Select a Rails date. Options hash must include :
|
8
|
+
# Select a Rails date. Options hash must include from: +label+
|
7
9
|
def select_date(date, options)
|
8
10
|
date = Date.parse(date)
|
9
11
|
base_dom_id = get_base_dom_id_from_label_tag(options[:from])
|
10
12
|
|
11
13
|
find(:xpath, ".//select[@id='#{base_dom_id}_1i']").select(date.year.to_s)
|
12
|
-
find(:xpath, ".//select[@id='#{base_dom_id}_2i']").select(I18n.l
|
14
|
+
find(:xpath, ".//select[@id='#{base_dom_id}_2i']").select(I18n.l(date, format: '%B'))
|
13
15
|
find(:xpath, ".//select[@id='#{base_dom_id}_3i']").select(date.day.to_s)
|
14
16
|
end
|
15
17
|
|
16
|
-
# Select a Rails time. Options hash must include :
|
18
|
+
# Select a Rails time. Options hash must include from: +label+
|
17
19
|
def select_time(time, options)
|
18
20
|
time = Time.zone.parse(time)
|
19
21
|
base_dom_id = get_base_dom_id_from_label_tag(options[:from])
|
@@ -22,7 +24,7 @@ module Cucumber
|
|
22
24
|
find(:xpath, ".//select[@id='#{base_dom_id}_5i']").select(time.min.to_s.rjust(2, '0'))
|
23
25
|
end
|
24
26
|
|
25
|
-
# Select a Rails datetime. Options hash must include :
|
27
|
+
# Select a Rails datetime. Options hash must include from: +label+
|
26
28
|
def select_datetime(datetime, options)
|
27
29
|
select_date(datetime, options)
|
28
30
|
select_time(datetime, options)
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Cucumber
|
2
4
|
module Rails
|
3
5
|
module Database
|
4
|
-
CUSTOM_STRATEGY_INTERFACE = %w
|
6
|
+
CUSTOM_STRATEGY_INTERFACE = %w[before_js before_non_js].freeze
|
5
7
|
|
6
8
|
class InvalidStrategy < ArgumentError; end
|
7
9
|
|
@@ -13,12 +15,12 @@ module Cucumber
|
|
13
15
|
strategy_type =
|
14
16
|
case strategy
|
15
17
|
when Symbol
|
16
|
-
map[strategy] ||
|
18
|
+
map[strategy] || throw_invalid_strategy_error(strategy)
|
17
19
|
when Class
|
18
20
|
strategy
|
19
21
|
end
|
20
22
|
|
21
|
-
@strategy =
|
23
|
+
@strategy = strategy_type.new(*strategy_opts)
|
22
24
|
|
23
25
|
validate_interface!
|
24
26
|
end
|
@@ -35,7 +37,7 @@ module Cucumber
|
|
35
37
|
@strategy.after
|
36
38
|
end
|
37
39
|
|
38
|
-
|
40
|
+
private
|
39
41
|
|
40
42
|
def map
|
41
43
|
{
|
@@ -46,10 +48,25 @@ module Cucumber
|
|
46
48
|
}
|
47
49
|
end
|
48
50
|
|
51
|
+
def throw_invalid_strategy_error(strategy)
|
52
|
+
raise(InvalidStrategy, "The strategy '#{strategy}' is not understood. Please use one of #{mapped_keys}")
|
53
|
+
end
|
54
|
+
|
55
|
+
def mapped_keys
|
56
|
+
map.keys.join(', ')
|
57
|
+
end
|
58
|
+
|
49
59
|
def validate_interface!
|
50
|
-
|
51
|
-
|
52
|
-
|
60
|
+
return if CUSTOM_STRATEGY_INTERFACE.all? { |m| @strategy.respond_to?(m) }
|
61
|
+
|
62
|
+
throw_invalid_strategy_interface_error
|
63
|
+
end
|
64
|
+
|
65
|
+
def throw_invalid_strategy_interface_error
|
66
|
+
raise(
|
67
|
+
ArgumentError,
|
68
|
+
"Strategy must respond to all of: #{CUSTOM_STRATEGY_INTERFACE.map { |method| "##{method}" } * ' '} !"
|
69
|
+
)
|
53
70
|
end
|
54
71
|
end
|
55
72
|
|
@@ -59,7 +76,11 @@ module Cucumber
|
|
59
76
|
end
|
60
77
|
|
61
78
|
def before_js(strategy)
|
62
|
-
@original_strategy = DatabaseCleaner.
|
79
|
+
@original_strategy = if Gem::Version.new(DatabaseCleaner::VERSION) >= Gem::Version.new('1.8.0.beta')
|
80
|
+
DatabaseCleaner.cleaners.values.first.strategy # that feels like a nasty hack
|
81
|
+
else
|
82
|
+
DatabaseCleaner.connections.first.strategy # that feels like a nasty hack
|
83
|
+
end
|
63
84
|
DatabaseCleaner.strategy = strategy, @options
|
64
85
|
end
|
65
86
|
|
@@ -69,6 +90,7 @@ module Cucumber
|
|
69
90
|
|
70
91
|
def after
|
71
92
|
return unless @original_strategy
|
93
|
+
|
72
94
|
DatabaseCleaner.strategy = @original_strategy
|
73
95
|
@original_strategy = nil
|
74
96
|
end
|
data/lib/cucumber/rails/hooks.rb
CHANGED
@@ -1,21 +1,23 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class Base
|
3
5
|
class_attribute :shared_connection
|
4
6
|
|
5
7
|
def self.connection
|
6
|
-
|
8
|
+
shared_connection || retrieve_connection
|
7
9
|
end
|
8
10
|
end
|
11
|
+
end
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
Before('@javascript') do
|
14
|
+
Cucumber::Rails::Database.before_js if Cucumber::Rails::Database.autorun_database_cleaner
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
Before('not @javascript') do
|
18
|
+
Cucumber::Rails::Database.before_non_js if Cucumber::Rails::Database.autorun_database_cleaner
|
19
|
+
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
+
After do
|
22
|
+
Cucumber::Rails::Database.after if Cucumber::Rails::Database.autorun_database_cleaner
|
21
23
|
end
|
@@ -1,13 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
4
|
require 'database_cleaner'
|
3
5
|
|
4
|
-
Before('
|
6
|
+
Before('not @no-database-cleaner') do
|
5
7
|
DatabaseCleaner.start if Cucumber::Rails::Database.autorun_database_cleaner
|
6
8
|
end
|
7
9
|
|
8
|
-
After('
|
10
|
+
After('not @no-database-cleaner') do
|
9
11
|
DatabaseCleaner.clean if Cucumber::Rails::Database.autorun_database_cleaner
|
10
12
|
end
|
11
|
-
|
12
|
-
|
13
|
+
rescue LoadError
|
14
|
+
Cucumber.logger.debug('database_cleaner gem not present.')
|
13
15
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Before do
|
4
|
+
ActionMailer::Base.deliveries = []
|
5
5
|
end
|
data/lib/cucumber/rails/rspec.rb
CHANGED
data/lib/cucumber/rails/world.rb
CHANGED
@@ -1,21 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
4
|
# Try to load it so we can assign @_result below if needed.
|
3
5
|
require 'test/unit/testresult'
|
4
|
-
rescue LoadError
|
6
|
+
rescue LoadError
|
7
|
+
Cucumber.logger.debug('Minitest not found.')
|
8
|
+
end
|
9
|
+
|
10
|
+
module Cucumber
|
11
|
+
module Rails
|
12
|
+
class << self
|
13
|
+
def include_rack_test_helpers?
|
14
|
+
# Using ActiveModel Boolean casting here will give false positives more often than not!
|
15
|
+
!ENV['CR_REMOVE_RACK_TEST_HELPERS']&.casecmp('true')&.zero?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
5
19
|
end
|
6
20
|
|
7
|
-
module Cucumber
|
8
|
-
module Rails
|
9
|
-
class World < ActionDispatch::IntegrationTest
|
10
|
-
include Rack::Test::Methods
|
21
|
+
module Cucumber
|
22
|
+
module Rails
|
23
|
+
class World < ::ActionDispatch::IntegrationTest
|
24
|
+
include Rack::Test::Methods if Cucumber::Rails.include_rack_test_helpers?
|
11
25
|
include ActiveSupport::Testing::SetupAndTeardown if ActiveSupport::Testing.const_defined?('SetupAndTeardown')
|
12
26
|
|
13
|
-
def initialize
|
27
|
+
def initialize
|
14
28
|
@_result = Test::Unit::TestResult.new if defined?(Test::Unit::TestResult)
|
15
29
|
end
|
16
30
|
|
17
31
|
unless defined?(ActiveRecord::Base)
|
18
|
-
|
32
|
+
# Workaround for projects that don't use ActiveRecord
|
33
|
+
def self.fixture_table_names
|
34
|
+
[]
|
35
|
+
end
|
19
36
|
end
|
20
37
|
end
|
21
38
|
end
|
File without changes
|
@@ -1,13 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rbconfig'
|
2
4
|
|
3
5
|
module Cucumber
|
4
6
|
class InstallGenerator < ::Rails::Generators::Base
|
5
|
-
source_root File.expand_path('
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
6
8
|
|
7
9
|
DEFAULT_SHEBANG = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
|
8
10
|
|
9
|
-
class_option :spork,
|
10
|
-
|
11
|
+
class_option :spork,
|
12
|
+
type: :boolean,
|
13
|
+
desc: 'Use Spork'
|
14
|
+
|
15
|
+
class_option :skip_database,
|
16
|
+
type: :boolean,
|
17
|
+
desc: 'Skip modification of database.yml',
|
18
|
+
aliases: '-D',
|
19
|
+
default: false
|
11
20
|
|
12
21
|
def create_templates
|
13
22
|
template 'config/cucumber.yml.erb', 'config/cucumber.yml'
|
@@ -39,13 +48,13 @@ module Cucumber
|
|
39
48
|
|
40
49
|
def create_database
|
41
50
|
return unless File.exist?('config/database.yml')
|
42
|
-
unless File.read('config/database.yml').include? 'cucumber:'
|
43
|
-
gsub_file 'config/database.yml', /^test:.*\n/, "test: &test\n"
|
44
|
-
gsub_file 'config/database.yml', /\z/, "\ncucumber:\n <<: *test\n"
|
51
|
+
return unless File.read('config/database.yml').include? 'cucumber:'
|
45
52
|
|
46
|
-
|
47
|
-
|
48
|
-
|
53
|
+
gsub_file 'config/database.yml', /^test:.*\n/, "test: &test\n"
|
54
|
+
gsub_file 'config/database.yml', /\z/, "\ncucumber:\n <<: *test\n"
|
55
|
+
|
56
|
+
# Since gsub_file doesn't ask the user, just inform user that the file was overwritten.
|
57
|
+
puts ' force config/database.yml'
|
49
58
|
end
|
50
59
|
|
51
60
|
protected
|
@@ -60,7 +69,11 @@ module Cucumber
|
|
60
69
|
|
61
70
|
def embed_template(source, indent = '')
|
62
71
|
template = File.join(self.class.source_root, source)
|
63
|
-
|
72
|
+
if RUBY_VERSION >= '2.6'
|
73
|
+
ERB.new(IO.read(template), trim_mode: '-').result(binding).gsub(/^/, indent)
|
74
|
+
else
|
75
|
+
ERB.new(IO.read(template), nil, '-').result(binding).gsub(/^/, indent)
|
76
|
+
end
|
64
77
|
end
|
65
78
|
end
|
66
79
|
end
|