cucumber-rails 1.5.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|