cucumber-rails 1.7.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +197 -19
- data/CONTRIBUTING.md +16 -14
- data/LICENSE +1 -1
- data/README.md +27 -21
- data/lib/cucumber/rails.rb +23 -17
- 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 +42 -21
- data/lib/cucumber/rails/capybara/select_dates_and_times.rb +3 -1
- data/lib/cucumber/rails/database.rb +24 -56
- data/lib/cucumber/rails/database/deletion_strategy.rb +13 -0
- data/lib/cucumber/rails/database/shared_connection_strategy.rb +27 -0
- data/lib/cucumber/rails/database/strategy.rb +33 -0
- data/lib/cucumber/rails/database/truncation_strategy.rb +13 -0
- data/lib/cucumber/rails/hooks.rb +2 -0
- data/lib/cucumber/rails/hooks/active_record.rb +8 -4
- data/lib/cucumber/rails/hooks/allow_rescue.rb +2 -0
- data/lib/cucumber/rails/hooks/database_cleaner.rb +11 -3
- data/lib/cucumber/rails/hooks/mail.rb +3 -1
- 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} +18 -9
- data/lib/generators/cucumber/{install/templates → templates}/config/cucumber.yml.erb +0 -0
- data/lib/generators/cucumber/{install/templates → templates}/script/cucumber +1 -0
- data/lib/generators/cucumber/{install/templates → templates}/support/_rails_each_run.rb.erb +0 -0
- 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 +0 -0
- metadata +100 -169
- data/.github/ISSUE_TEMPLATE.md +0 -52
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -42
- data/.gitignore +0 -13
- data/.rspec +0 -1
- data/.rubocop.yml +0 -1
- data/.rubocop_todo.yml +0 -443
- data/.travis.yml +0 -45
- data/Appraisals +0 -32
- data/Gemfile +0 -7
- data/Rakefile +0 -49
- data/bin/install_geckodriver.sh +0 -19
- data/bin/install_webpacker.sh +0 -9
- data/config/.gitignore +0 -1
- data/config/cucumber.yml +0 -17
- data/cucumber-rails.gemspec +0 -44
- data/dev_tasks/cucumber.rake +0 -3
- data/dev_tasks/rspec.rake +0 -3
- data/dev_tasks/yard.rake +0 -35
- data/dev_tasks/yard/default/layout/html/bubble_32x32.png +0 -0
- data/dev_tasks/yard/default/layout/html/footer.erb +0 -5
- data/dev_tasks/yard/default/layout/html/index.erb +0 -1
- data/dev_tasks/yard/default/layout/html/layout.erb +0 -25
- data/dev_tasks/yard/default/layout/html/logo.erb +0 -1
- data/dev_tasks/yard/default/layout/html/setup.rb +0 -4
- data/features/allow_rescue.feature +0 -65
- data/features/annotations.feature +0 -22
- data/features/capybara_javascript_drivers.feature +0 -73
- data/features/choose_javascript_database_strategy.feature +0 -145
- data/features/database_cleaner.feature +0 -44
- data/features/disable_automatic_database_cleaning.feature +0 -55
- data/features/emulate_javascript.feature +0 -94
- data/features/install_cucumber_rails.feature +0 -14
- data/features/no_database.feature +0 -61
- data/features/raising_errors.feature +0 -16
- data/features/rerun_profile.feature +0 -46
- data/features/rest_api.feature +0 -47
- data/features/step_definitions/cucumber_rails_steps.rb +0 -153
- data/features/support/aruba.rb +0 -3
- data/features/support/bundler_pre_support.rb +0 -28
- data/features/support/env.rb +0 -40
- 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/rails_4_2.gemfile +0 -10
- data/gemfiles/rails_5_0.gemfile +0 -10
- data/gemfiles/rails_5_1.gemfile +0 -10
- data/gemfiles/rails_5_2.gemfile +0 -10
- data/gemfiles/rails_6_0.gemfile +0 -8
- data/lib/cucumber/rails/action_controller.rb +0 -13
- data/spec/cucumber/rails/database_spec.rb +0 -57
- data/spec/generators/cucumber/install/install_generator_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -14
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
ActionController::Base.class_eval do
|
4
|
+
cattr_accessor :allow_rescue
|
5
|
+
end
|
6
|
+
|
7
|
+
module Cucumber
|
8
|
+
module Rails
|
9
|
+
module ActionDispatch
|
10
|
+
module ShowExceptions
|
11
|
+
def call(env)
|
12
|
+
env['action_dispatch.show_detailed_exceptions'] = !ActionController::Base.allow_rescue
|
13
|
+
env['action_dispatch.show_exceptions'] = !env['action_dispatch.show_detailed_exceptions']
|
14
|
+
super(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
ActionDispatch::ShowExceptions.prepend(Cucumber::Rails::ActionDispatch::ShowExceptions)
|
@@ -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
|
@@ -11,7 +13,9 @@ module Cucumber
|
|
11
13
|
|
12
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,29 +48,42 @@ 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
|
-
tag_name == 'a' &&
|
84
|
+
tag_name == 'a' &&
|
85
|
+
element_node['data-method'] &&
|
86
|
+
element_node['data-method'] =~ /(?:delete|put|post)/
|
70
87
|
end
|
71
88
|
|
72
89
|
def emulated_method
|
@@ -74,15 +91,19 @@ module Cucumber
|
|
74
91
|
end
|
75
92
|
|
76
93
|
def element_node
|
77
|
-
|
94
|
+
native
|
78
95
|
end
|
79
96
|
end
|
80
97
|
end
|
81
98
|
end
|
82
99
|
end
|
83
100
|
|
84
|
-
|
85
|
-
|
101
|
+
module Capybara
|
102
|
+
module RackTest
|
103
|
+
class Node
|
104
|
+
include ::Cucumber::Rails::Capybara::JavascriptEmulation
|
105
|
+
end
|
106
|
+
end
|
86
107
|
end
|
87
108
|
|
88
109
|
Before('not @no-js-emulation') do
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Cucumber
|
2
4
|
module Rails
|
3
5
|
module Capybara
|
@@ -9,7 +11,7 @@ module Cucumber
|
|
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
|
|
@@ -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,16 +15,21 @@ 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
|
25
27
|
|
28
|
+
def default_strategy!
|
29
|
+
self.javascript_strategy = :truncation
|
30
|
+
self.autorun_database_cleaner = true
|
31
|
+
end
|
32
|
+
|
26
33
|
def before_js
|
27
34
|
@strategy.before_js
|
28
35
|
end
|
@@ -35,7 +42,7 @@ module Cucumber
|
|
35
42
|
@strategy.after
|
36
43
|
end
|
37
44
|
|
38
|
-
|
45
|
+
private
|
39
46
|
|
40
47
|
def map
|
41
48
|
{
|
@@ -46,68 +53,29 @@ module Cucumber
|
|
46
53
|
}
|
47
54
|
end
|
48
55
|
|
49
|
-
def
|
50
|
-
|
51
|
-
raise(ArgumentError, "Strategy must respond to all of: #{CUSTOM_STRATEGY_INTERFACE.map{ |method| "##{method}" } * ' ' } !")
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
class Strategy
|
57
|
-
def initialize(options = {})
|
58
|
-
@options = options
|
59
|
-
end
|
60
|
-
|
61
|
-
def before_js(strategy)
|
62
|
-
@original_strategy = DatabaseCleaner.connections.first.strategy # that feels like a nasty hack
|
63
|
-
DatabaseCleaner.strategy = strategy, @options
|
64
|
-
end
|
65
|
-
|
66
|
-
def before_non_js
|
67
|
-
# no-op
|
68
|
-
end
|
69
|
-
|
70
|
-
def after
|
71
|
-
return unless @original_strategy
|
72
|
-
DatabaseCleaner.strategy = @original_strategy
|
73
|
-
@original_strategy = nil
|
56
|
+
def throw_invalid_strategy_error(strategy)
|
57
|
+
raise(InvalidStrategy, "The strategy '#{strategy}' is not understood. Please use one of #{mapped_keys}")
|
74
58
|
end
|
75
|
-
end
|
76
59
|
|
77
|
-
|
78
|
-
|
79
|
-
super :truncation
|
60
|
+
def mapped_keys
|
61
|
+
map.keys.join(', ')
|
80
62
|
end
|
81
|
-
end
|
82
63
|
|
83
|
-
|
84
|
-
|
85
|
-
super :deletion
|
86
|
-
end
|
87
|
-
end
|
64
|
+
def validate_interface!
|
65
|
+
return if CUSTOM_STRATEGY_INTERFACE.all? { |m| @strategy.respond_to?(m) }
|
88
66
|
|
89
|
-
|
90
|
-
def before_js
|
91
|
-
# Forces all threads to share a connection on a per-model basis,
|
92
|
-
# as connections may vary per model as per establish_connection. This works
|
93
|
-
# on Capybara because it starts the web server in a thread.
|
94
|
-
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
|
95
|
-
ActiveRecord::Base.descendants.each do |model|
|
96
|
-
model.shared_connection = model.connection
|
97
|
-
end
|
67
|
+
throw_invalid_strategy_interface_error
|
98
68
|
end
|
99
69
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
70
|
+
def throw_invalid_strategy_interface_error
|
71
|
+
raise(
|
72
|
+
ArgumentError,
|
73
|
+
"Strategy must respond to all of: #{CUSTOM_STRATEGY_INTERFACE.map { |method| "##{method}" } * ' '} !"
|
74
|
+
)
|
106
75
|
end
|
107
76
|
end
|
108
77
|
|
109
|
-
|
110
|
-
Database.autorun_database_cleaner = true
|
78
|
+
default_strategy!
|
111
79
|
end
|
112
80
|
end
|
113
81
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
module Rails
|
5
|
+
module Database
|
6
|
+
class SharedConnectionStrategy < Strategy
|
7
|
+
def before_js
|
8
|
+
# Forces all threads to share a connection on a per-model basis,
|
9
|
+
# as connections may vary per model as per establish_connection. This works
|
10
|
+
# on Capybara because it starts the web server in a thread.
|
11
|
+
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
|
12
|
+
ActiveRecord::Base.descendants.each do |model|
|
13
|
+
model.shared_connection = model.connection
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def before_non_js
|
18
|
+
# Do not use a shared connection unless we're in a @javascript scenario
|
19
|
+
ActiveRecord::Base.shared_connection = nil
|
20
|
+
ActiveRecord::Base.descendants.each do |model|
|
21
|
+
model.shared_connection = nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
module Rails
|
5
|
+
module Database
|
6
|
+
class Strategy
|
7
|
+
def initialize(options = {})
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def before_js(strategy)
|
12
|
+
@original_strategy = if defined?(DatabaseCleaner::VERSION) && Gem::Version.new(DatabaseCleaner::VERSION) >= Gem::Version.new('1.8.0.beta')
|
13
|
+
DatabaseCleaner.cleaners.values.first.strategy # that feels like a nasty hack
|
14
|
+
else
|
15
|
+
DatabaseCleaner.connections.first.strategy # that feels like a nasty hack
|
16
|
+
end
|
17
|
+
DatabaseCleaner.strategy = strategy, @options
|
18
|
+
end
|
19
|
+
|
20
|
+
def before_non_js
|
21
|
+
# no-op
|
22
|
+
end
|
23
|
+
|
24
|
+
def after
|
25
|
+
return unless @original_strategy
|
26
|
+
|
27
|
+
DatabaseCleaner.strategy = @original_strategy
|
28
|
+
@original_strategy = nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/cucumber/rails/hooks.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
if defined?(ActiveRecord::Base)
|
2
|
-
|
3
|
-
|
4
|
+
module ActiveRecord
|
5
|
+
class Base
|
6
|
+
class_attribute :shared_connection
|
4
7
|
|
5
|
-
|
6
|
-
|
8
|
+
def self.connection
|
9
|
+
shared_connection || retrieve_connection
|
10
|
+
end
|
7
11
|
end
|
8
12
|
end
|
9
13
|
|
@@ -1,6 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
|
-
require 'database_cleaner'
|
4
|
+
require 'database_cleaner/core'
|
5
|
+
rescue LoadError
|
6
|
+
begin
|
7
|
+
require 'database_cleaner'
|
8
|
+
rescue LoadError
|
9
|
+
Cucumber.logger.debug('neither database_cleaner v1 or v2 present')
|
10
|
+
end
|
11
|
+
end
|
3
12
|
|
13
|
+
if defined?(DatabaseCleaner)
|
4
14
|
Before('not @no-database-cleaner') do
|
5
15
|
DatabaseCleaner.start if Cucumber::Rails::Database.autorun_database_cleaner
|
6
16
|
end
|
@@ -8,6 +18,4 @@ begin
|
|
8
18
|
After('not @no-database-cleaner') do
|
9
19
|
DatabaseCleaner.clean if Cucumber::Rails::Database.autorun_database_cleaner
|
10
20
|
end
|
11
|
-
|
12
|
-
rescue LoadError => ignore_if_database_cleaner_not_present
|
13
21
|
end
|